이 Codelab 정보
1. 개요
다양한 업계에서 문맥 검색은 애플리케이션의 핵심이 되는 중요한 기능입니다. 검색 증강 생성은 오랫동안 생성형 AI 기반 검색 메커니즘을 통해 이 중요한 기술 혁신의 핵심 동인 역할을 해 왔습니다. 대규모 컨텍스트 창과 인상적인 출력 품질을 갖춘 생성형 모델이 AI를 변화시키고 있습니다. RAG는 AI 애플리케이션과 상담사에게 컨텍스트를 주입하여 구조화된 데이터베이스 또는 다양한 미디어의 정보에 기반하도록 하는 체계적인 방법을 제공합니다. 이러한 문맥 데이터는 사실의 명확성과 출력의 정확성에 매우 중요하지만, 결과의 정확성은 어느 정도일까요? 비즈니스에 이러한 문맥적 일치 및 관련성의 정확성이 크게 영향을 미치나요? 그렇다면 이 프로젝트가 마음에 드실 겁니다.
이제 생성형 모델의 힘을 활용하여 이러한 맥락에 중요한 정보에 기반하고 진실에 입각하여 자율적인 결정을 내릴 수 있는 대화형 에이전트를 구축할 수 있다고 가정해 보세요. 오늘은 바로 이러한 에이전트를 구축해 보겠습니다. 특허 분석 애플리케이션을 위해 AlloyDB의 고급 RAG를 기반으로 하는 Agent Development Kit를 사용하여 엔드 투 엔드 AI 상담사 앱을 빌드합니다.
특허 분석 상담사는 사용자가 검색 텍스트와 문맥상 관련성이 있는 특허를 찾는 것을 지원하고 요청 시 선택한 특허에 대해 명확하고 간결한 설명과 필요한 경우 추가 세부정보를 제공합니다. 방법을 알아볼까요? 시작해 볼까요?
목표
목표는 간단합니다. 사용자가 텍스트 설명을 기반으로 특허를 검색한 후 검색 결과에서 특정 특허에 대한 자세한 설명을 가져올 수 있도록 지원합니다. 이 모든 작업은 Java ADK, AlloyDB, 벡터 검색 (고급 색인이 포함됨), Gemini로 빌드된 AI 에이전트와 Cloud Run에 서버리스 방식으로 배포된 전체 애플리케이션을 사용하여 실행됩니다.
빌드할 항목
이 실습에서는 다음을 수행합니다.
- AlloyDB 인스턴스를 만들고 특허 공개 데이터 세트 데이터 로드
- ScaNN 및 Recall eval 기능을 사용하여 AlloyDB에 고급 벡터 검색 구현
- Java ADK를 사용하여 에이전트 만들기
- Java 서버리스 Cloud Functions에서 데이터베이스 서버 측 로직 구현
- Cloud Run에서 에이전트 배포 및 테스트
다음 다이어그램은 데이터 흐름과 구현에 포함된 단계를 나타냅니다.
High level diagram representing the flow of the Patent Search Agent with AlloyDB & ADK
요구사항
2. 시작하기 전에
프로젝트 만들기
- Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
- Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요 .
- Google Cloud에서 실행되는 명령줄 환경인 Cloud Shell을 사용합니다. Google Cloud 콘솔 상단에서 Cloud Shell 활성화를 클릭합니다.
- Cloud Shell에 연결되면 다음 명령어를 사용하여 이미 인증되었는지, 프로젝트가 프로젝트 ID로 설정되어 있는지 확인합니다.
gcloud auth list
- Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project
- 프로젝트가 설정되지 않은 경우 다음 명령어를 사용하여 설정합니다.
gcloud config set project <YOUR_PROJECT_ID>
- 필요한 API를 사용 설정합니다. Cloud Shell 터미널에서 gcloud 명령어를 사용할 수 있습니다.
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com
gcloud 명령어 대신 콘솔을 통해 각 제품을 검색하거나 이 링크를 사용할 수 있습니다.
gcloud 명령어 및 사용법은 문서를 참조하세요.
3. 데이터베이스 설정
이 실습에서는 AlloyDB를 특허 데이터의 데이터베이스로 사용합니다. 클러스터를 사용하여 데이터베이스 및 로그와 같은 모든 리소스를 보관합니다. 각 클러스터에는 데이터에 대한 액세스 포인트를 제공하는 기본 인스턴스가 있습니다. 테이블에는 실제 데이터가 포함됩니다.
특허 데이터 세트가 로드될 AlloyDB 클러스터, 인스턴스, 테이블을 만들어 보겠습니다.
클러스터 및 인스턴스 만들기
- Cloud 콘솔에서 AlloyDB 페이지로 이동합니다. Cloud Console에서 대부분의 페이지를 찾는 가장 쉬운 방법은 콘솔의 검색창을 사용하는 것입니다.
- 이 페이지에서 클러스터 만들기를 선택합니다.
- 아래와 같은 화면이 표시됩니다. 다음 값으로 클러스터 및 인스턴스를 만듭니다 (저장소에서 애플리케이션 코드를 클론하는 경우 값이 일치하는지 확인).
- 클러스터 ID: '
vector-cluster
' - 비밀번호: "
alloydb
" - PostgreSQL 15 / 최신 버전 권장
- 지역: "
us-central1
" - 네트워킹: '
default
'
- 기본 네트워크를 선택하면 아래와 같은 화면이 표시됩니다.
연결 설정을 선택합니다.
- 여기에서 '자동으로 할당된 IP 범위 사용'을 선택하고 계속을 클릭합니다. 정보를 검토한 후 '연결 만들기'를 선택합니다.
- 네트워크가 설정되면 클러스터를 계속 만들 수 있습니다. 클러스터 만들기를 클릭하여 아래와 같이 클러스터 설정을 완료합니다.
인스턴스 ID (클러스터 / 인스턴스 구성 시 확인 가능)를 다음으로 변경해야 합니다.
vector-instance
. 변경할 수 없는 경우 향후 모든 참조에서 인스턴스 ID를 사용해야 합니다.
클러스터를 만드는 데 약 10분이 소요됩니다. 완료되면 방금 만든 클러스터의 개요를 보여주는 화면이 표시됩니다.
4. 데이터 수집
이제 매장 데이터가 포함된 표를 추가하겠습니다. AlloyDB로 이동하여 기본 클러스터를 선택한 다음 AlloyDB Studio를 선택합니다.
인스턴스 생성이 완료될 때까지 기다려야 할 수 있습니다. 클러스터가 생성되면 클러스터를 만들 때 만든 사용자 인증 정보를 사용하여 AlloyDB에 로그인합니다. PostgreSQL에 인증할 때 다음 데이터를 사용합니다.
- 사용자 이름 : '
postgres
' - 데이터베이스 : '
postgres
' - 비밀번호 : '
alloydb
'
AlloyDB 스튜디오에 성공적으로 인증하면 편집기에 SQL 명령어가 입력됩니다. 마지막 창 오른쪽에 있는 더하기 기호를 사용하여 여러 편집기 창을 추가할 수 있습니다.
필요에 따라 실행, 형식 지정, 지우기 옵션을 사용하여 편집기 창에 AlloyDB 명령어를 입력합니다.
확장 프로그램 사용 설정
이 앱을 빌드하는 데 pgvector
및 google_ml_integration
확장 프로그램을 사용합니다. pgvector 확장 프로그램을 사용하면 벡터 임베딩을 저장하고 검색할 수 있습니다. google_ml_integration 확장 프로그램은 Vertex AI 예측 엔드포인트에 액세스하여 SQL에서 예측을 가져오는 데 사용하는 함수를 제공합니다. 다음 DDL을 실행하여 이러한 확장 프로그램을 사용 설정합니다.
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
데이터베이스에서 사용 설정된 확장 프로그램을 확인하려면 다음 SQL 명령어를 실행합니다.
select extname, extversion from pg_extension;
테이블 만들기
AlloyDB Studio에서 아래 DDL 문을 사용하여 테이블을 만들 수 있습니다.
CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;
abstract_embeddings 열을 사용하면 텍스트의 벡터 값을 저장할 수 있습니다.
권한 부여
아래 문을 실행하여 '삽입' 함수에 실행 권한을 부여합니다.
GRANT EXECUTE ON FUNCTION embedding TO postgres;
AlloyDB 서비스 계정에 Vertex AI 사용자 역할 부여
Google Cloud IAM 콘솔에서 AlloyDB 서비스 계정 (service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com 형식)에 'Vertex AI 사용자' 역할에 대한 액세스 권한을 부여합니다. PROJECT_NUMBER에는 프로젝트 번호가 포함됩니다.
또는 Cloud Shell 터미널에서 아래 명령어를 실행할 수 있습니다.
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
데이터베이스에 특허 데이터 로드
BigQuery의 Google 특허 공개 데이터 세트가 데이터 세트로 사용됩니다. AlloyDB Studio를 사용하여 쿼리를 실행합니다. 데이터는 이 insert_scripts.sql
파일로 가져와서 실행하여 특허 데이터를 로드합니다.
- Google Cloud 콘솔에서 AlloyDB 페이지를 엽니다.
- 새로 만든 클러스터를 선택하고 인스턴스를 클릭합니다.
- AlloyDB 탐색 메뉴에서 AlloyDB 스튜디오를 클릭합니다. 사용자 인증 정보로 로그인합니다.
- 오른쪽에 있는 새 탭 아이콘을 클릭하여 새 탭을 엽니다.
- 위에 언급된
insert_scripts.sql
스크립트에서insert
쿼리 문을 편집기에 복사합니다. 이 사용 사례를 빠르게 데모하려면 10~50개의 삽입 문을 복사하면 됩니다. - 실행을 클릭합니다. 쿼리 결과가 결과 테이블에 표시됩니다.
5. 특허 데이터의 임베딩 만들기
먼저 다음 샘플 쿼리를 실행하여 임베딩 함수를 테스트해 보겠습니다.
SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');
그러면 쿼리의 샘플 텍스트에 대한 부동 소수점 배열처럼 보이는 임베딩 벡터가 반환됩니다. 다음과 같이 표시됩니다.
abstract_embeddings 벡터 필드 업데이트
아래 DML을 실행하여 테이블의 특허 개요를 해당 임베딩으로 업데이트합니다.
UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);
6. 벡터 검색 수행
이제 테이블, 데이터, 임베딩이 모두 준비되었으므로 사용자 검색 텍스트에 대한 실시간 벡터 검색을 실행해 보겠습니다. 다음 쿼리를 실행하여 이를 테스트할 수 있습니다.
SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
이 쿼리에서
- 사용자가 검색한 텍스트는 'Sentiment Analysis'입니다.
- text-embedding-005 모델을 사용하여 embedding() 메서드에서 텍스트를 임베딩으로 변환합니다.
- "<=>"는 COSINE SIMILARITY 거리 메서드의 사용을 나타냅니다.
- 데이터베이스에 저장된 벡터와 호환되도록 임베딩 메서드의 결과를 벡터 유형으로 변환합니다.
- LIMIT 10은 검색 텍스트와 가장 일치하는 10개를 선택한다는 것을 나타냅니다.
AlloyDB는 벡터 검색 RAG를 한 단계 업그레이드합니다.
이번 업데이트에서는 많은 기능이 도입되었습니다. 개발자 중심의 두 가지 기능은 다음과 같습니다.
- 인라인 필터링
- 재현율 평가자
인라인 필터링
이전에는 개발자가 벡터 검색 쿼리를 실행하고 필터링 및 검색을 처리해야 했습니다. AlloyDB 쿼리 최적화 도구는 필터가 있는 쿼리를 실행하는 방법을 선택합니다. 인라인 필터링은 AlloyDB 쿼리 최적화 도구가 메타데이터 필터링 조건과 벡터 검색을 모두 평가할 수 있는 새로운 쿼리 최적화 기법으로, 메타데이터 열의 벡터 색인과 색인을 모두 활용합니다. 이를 통해 리콜 성능이 향상되어 개발자는 AlloyDB가 제공하는 기능을 즉시 활용할 수 있습니다.
인라인 필터링은 선택성이 중간인 케이스에 가장 적합합니다. AlloyDB는 벡터 색인을 검색할 때 메타데이터 필터링 조건 (일반적으로 WHERE 절에서 처리되는 쿼리의 기능 필터)과 일치하는 벡터의 거리만 계산합니다. 이렇게 하면 이러한 쿼리의 성능이 크게 개선되어 사후 필터 또는 사전 필터의 이점을 보완할 수 있습니다.
- pgvector 확장 프로그램 설치 또는 업데이트
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';
pgvector 확장 프로그램이 이미 설치된 경우 벡터 확장 프로그램을 버전 0.8.0.google-3 이상으로 업그레이드하여 검색 평가자 기능을 사용합니다.
ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';
이 단계는 벡터 확장 프로그램이 0.8.0.google-3 미만인 경우에만 실행해야 합니다.
중요 사항: 행 수가 100개 미만인 경우 ScaNN 색인은 적용되지 않으므로 처음부터 ScaNN 색인을 만들 필요가 없습니다. 이 경우 다음 단계를 건너뜁니다.
- ScaNN 색인을 만들려면 alloydb_scann 확장 프로그램을 설치합니다.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- 먼저 색인과 인라인 필터가 사용 설정되지 않은 상태에서 벡터 검색 쿼리를 실행합니다.
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
결과는 다음과 유사합니다.
- Explain Analyze를 실행합니다(색인 또는 인라인 필터링 없음).
실행 시간은 2.4ms입니다.
- num_claims 필드로 필터링할 수 있도록 일반 색인을 만들어 보겠습니다.
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
- 특허 검색 애플리케이션의 ScaNN 색인을 만들어 보겠습니다. AlloyDB Studio에서 다음을 실행합니다.
CREATE INDEX patent_index ON patents_data
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);
중요 사항: (num_leaves=32)
는 행이 1,000개를 초과하는 총 데이터 세트에 적용됩니다. 행 수가 100개 미만인 경우 색인이 적용되지 않으므로 처음부터 색인을 만들 필요가 없습니다.
- ScaNN 색인에서 인라인 필터링을 사용 설정합니다.
SET scann.enable_inline_filtering = on
- 이제 필터와 벡터 검색이 포함된 동일한 쿼리를 실행해 보겠습니다.
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
보시다시피 동일한 벡터 검색의 실행 시간이 크게 단축되었습니다. 벡터 검색에 인라인 필터링이 적용된 ScaNN 색인을 통해 이 작업이 가능해졌습니다.
다음으로 이 ScaNN 지원 벡터 검색의 재현율을 평가해 보겠습니다.
재현율 평가자
유사 검색의 재현율은 검색에서 검색된 관련 인스턴스의 비율(즉, 참양성 수)입니다. 검색 품질을 측정하는 데 가장 일반적으로 사용되는 측정항목입니다. 검색 결과 손실의 한 가지 원인은 근사 최근접 이웃 검색(aNN)과 k(정확한) 최근접 이웃 검색(KNN)의 차이에서 비롯됩니다. AlloyDB의 ScaNN과 같은 벡터 색인은 aNN 알고리즘을 구현하므로 검색 결과의 정확성을 약간 떨어뜨리는 대신 대규모 데이터 세트에서 벡터 검색 속도를 높일 수 있습니다. 이제 AlloyDB를 사용하면 개별 쿼리에 대해 데이터베이스에서 직접 이 절충점을 측정하고 시간이 지남에 따라 안정적으로 유지되도록 할 수 있습니다. 이 정보에 따라 쿼리 및 색인 매개변수를 업데이트하여 더 나은 결과와 성능을 얻을 수 있습니다.
evaluate_query_recall 함수를 사용하여 지정된 구성의 벡터 색인에서 벡터 쿼리의 재현율을 확인할 수 있습니다. 이 함수를 사용하면 원하는 벡터 쿼리 검색 결과를 얻기 위해 매개변수를 조정할 수 있습니다. 재현율은 검색 품질에 사용되는 측정항목으로, 객관적으로 검색어 벡터에 가장 가까운 반환 결과의 백분율로 정의됩니다. evaluate_query_recall 함수는 기본적으로 사용 설정되어 있습니다.
중요사항:
다음 단계에서 HNSW 색인에 대한 권한이 거부되는 오류가 발생하면 지금은 이 전체 검색 결과 평가 섹션을 건너뜁니다. 이 Codelab이 문서화될 때 방금 출시되었으므로 현재 액세스 제한과 관련이 있을 수 있습니다.
- ScaNN 색인 및 HNSW 색인에서 색인 스캔 사용 설정 플래그를 설정합니다.
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
- AlloyDB 스튜디오에서 다음 쿼리를 실행합니다.
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 25 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
evaluate_query_recall 함수는 쿼리를 매개변수로 사용하고 검색 실적을 반환합니다. 성능을 확인하는 데 사용한 쿼리를 함수 입력 쿼리로 사용하고 있습니다. SCaNN을 색인 메서드로 추가했습니다. 자세한 파라미터 옵션은 문서를 참고하세요.
지금까지 사용해 온 이 벡터 검색 쿼리의 검색 결과는 다음과 같습니다.
RECALL이 70%인 것으로 확인됩니다. 이제 이 정보를 사용하여 색인 매개변수, 메서드, 쿼리 매개변수를 변경하고 이 벡터 검색의 검색 결과를 개선할 수 있습니다.
결과 집합의 행 수를 이전의 10개에서 7개로 수정했습니다. RECALL이 약간 개선되어 86%가 되었습니다.
즉, 사용자의 검색 상황에 따라 실시간으로 사용자가 볼 수 있는 검색결과 수를 조정하여 검색결과의 관련성을 개선할 수 있습니다.
좋습니다. 이제 데이터베이스 로직을 배포하고 에이전트로 넘어갈 시간입니다.
7. 서버리스 방식으로 데이터베이스 로직을 웹으로 가져가기
앱을 웹으로 가져갈 준비가 되셨나요? 다음 단계를 따르세요.
- Google Cloud 콘솔의 Cloud Run Functions로 이동하여 새 Cloud Run 함수를 만들거나 https://console.cloud.google.com/functions/add 링크를 사용하세요.
- 환경을 'Cloud Run 함수'로 선택합니다. 함수 이름을 'patent-search'로 지정하고 리전을 'us-central1'로 선택합니다. 인증을 '인증되지 않은 호출 허용'으로 설정하고 다음을 클릭합니다. 런타임으로 Java 17을, 소스 코드의 인라인 편집기로 Java 17을 선택합니다.
- 기본적으로 진입점은 'gcfv2.HelloHttpFunction'으로 설정됩니다. Cloud Run 함수의 HelloHttpFunction.java 및 pom.xml에 있는 자리표시자 코드를 각각 'PatentSearch.java' 및 'pom.xml'의 코드로 바꿉니다. 클래스 파일의 이름을 PatentSearch.java로 변경합니다.
- Java 파일에서 ************* 자리표시자와 AlloyDB 연결 사용자 인증 정보를 값으로 변경해야 합니다. AlloyDB 사용자 인증 정보는 이 Codelab을 시작할 때 사용한 사용자 인증 정보입니다. 다른 값을 사용한 경우 Java 파일에서 동일하게 수정하세요.
- 배포를 클릭합니다.
중요 단계:
배포가 완료되면 Cloud 함수가 AlloyDB 데이터베이스 인스턴스에 액세스할 수 있도록 VPC 커넥터를 만듭니다.
배포가 완료되면 Google Cloud Run Functions 콘솔에서 함수를 볼 수 있습니다. 새로 만든 함수 (patent-search)를 검색하여 클릭한 다음 새 버전 수정 및 배포 (Cloud Run Functions 콘솔 상단의 수정 아이콘 (펜)으로 표시됨)를 클릭하고 다음을 변경합니다.
- 네트워킹 탭으로 이동합니다.
- '아웃바운드 트래픽을 위해 VPC에 연결'을 선택한 다음 '서버리스 VPC 액세스 커넥터 사용'을 선택합니다.
- 네트워크 드롭다운 설정에서 네트워크 드롭다운을 클릭하고 새 VPC 커넥터 추가 옵션을 선택합니다 (아직 기본 커넥터를 구성하지 않은 경우). 그런 다음 표시되는 대화상자의 안내를 따릅니다.
- VPC 커넥터의 이름을 지정하고 리전이 인스턴스와 동일한지 확인합니다. 네트워크 값은 기본값으로 두고 서브넷을 맞춤 IP 범위로 설정하여 IP 범위를 10.8.0.0으로 설정하거나 사용 가능한 유사한 값을 설정합니다.
- '확장 설정 표시'를 펼치고 구성이 다음과 정확히 일치하는지 확인합니다.
- 만들기를 클릭하면 이 커넥터가 이그레스 설정에 표시됩니다.
- 새로 만든 커넥터를 선택합니다.
- 모든 트래픽이 이 VPC 커넥터를 통해 라우팅되도록 선택합니다.
- 다음을 클릭한 후 배포를 클릭합니다.
- 업데이트된 Cloud 함수가 배포되면 생성된 엔드포인트가 표시됩니다. 복사한 후 다음 명령어에서 바꿉니다.
PROJECT_ID=$(gcloud config get-value project)
curl -X POST <<YOUR_ENDPOINT>> \
-H 'Content-Type: application/json' \
-d '{"search":"Sentiment Analysis"}'
작업이 끝났습니다. AlloyDB 데이터에서 임베딩 모델을 사용하여 고급 문맥 유사성 벡터 검색을 실행하는 방법은 간단합니다.
8. Java ADK로 에이전트 빌드
먼저 편집기에서 Java 프로젝트를 시작해 보겠습니다.
- Cloud Shell 터미널로 이동
https://shell.cloud.google.com/?fromcloudshell=true&show=ide%2Cterminal
- 메시지가 표시되면 승인
- Cloud Shell 콘솔 상단에서 편집기 아이콘을 클릭하여 Cloud Shell 편집기로 전환
- 방문한 Cloud Shell 편집기 콘솔에서 새 폴더를 만들고 이름을 'adk-agents'로 지정합니다.
아래와 같이 Cloud Shell의 루트 디렉터리에서 새 폴더 만들기를 클릭합니다.
이름을 'adk-agents'로 지정합니다.
- 다음 구조에서 다음 폴더 구조와 상응하는 파일 이름을 가진 빈 파일을 만듭니다.
adk-agents/
└—— pom.xml
└—— src/
└—— main/
└—— java/
└—— agents/
└—— App.java
- 별도의 탭에서 github 저장소를 열고 App.java 및 pom.xml 파일의 소스 코드를 복사합니다.
- 오른쪽 상단의 '새 탭에서 열기' 아이콘을 사용하여 편집기를 새 탭에서 연 경우 페이지 하단에서 터미널을 열 수 있습니다. 편집기와 터미널을 동시에 열어 두고 자유롭게 작업할 수 있습니다.
- 클론한 후 Cloud Shell 편집기 콘솔로 다시 전환합니다.
- Cloud Run 함수를 이미 만들었으므로 저장소 폴더에서 Cloud Run 함수 파일을 복사할 필요가 없습니다.
ADK Java SDK 시작하기
꽤 간단합니다. 기본적으로 클론 단계에서 다음 사항이 포함되어 있는지 확인해야 합니다.
- 종속 항목 추가:
pom.xml에 google-adk 및 google-adk-dev (웹 UI용) 아티팩트를 포함합니다.
<!-- The ADK core dependency -->
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk</artifactId>
<version>0.1.0</version>
</dependency>
<!-- The ADK dev web UI to debug your agent -->
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-dev</artifactId>
<version>0.1.0</version>
</dependency>
애플리케이션을 실행하는 데 필요한 다른 종속 항목과 구성이 있으므로 소스 저장소에서 pom.xml을 참조해야 합니다.
- 프로젝트 구성:
pom.xml에서 Java 버전 (17 이상 권장) 및 Maven 컴파일러 설정이 올바르게 구성되어 있는지 확인합니다. 아래 구조를 따르도록 프로젝트를 구성할 수 있습니다.
adk-agents/
└—— pom.xml
└—— src/
└—— main/
└—— java/
└—— agents/
└—— App.java
- 에이전트 및 도구 정의 (App.java):
바로 이 지점에서 ADK Java SDK의 마법이 빛을 발합니다. 에이전트, 기능 (안내), 사용할 수 있는 도구를 정의합니다.
여기에서 기본 에이전트 클래스의 몇 가지 코드 스니펫의 단순화된 버전을 확인하세요. 전체 프로젝트는 여기에서 프로젝트 저장소를 참고하세요.
// App.java (Simplified Snippets)
package agents;
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.BaseAgent;
import com.google.adk.agents.InvocationContext;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
// ... other imports
public class App {
static FunctionTool searchTool = FunctionTool.create(App.class, "getPatents");
static FunctionTool explainTool = FunctionTool.create(App.class, "explainPatent");
public static BaseAgent ROOT_AGENT = initAgent();
public static BaseAgent initAgent() {
return LlmAgent.builder()
.name("patent-search-agent")
.description("Patent Search agent")
.model("gemini-2.0-flash-001") // Specify your desired Gemini model
.instruction(
"""
You are a helpful patent search assistant capable of 2 things:
// ... complete instructions ...
""")
.tools(searchTool, explainTool)
.outputKey("patents") // Key to store tool output in session state
.build();
}
// --- Tool: Get Patents ---
public static Map<String, String> getPatents(
@Schema(name="searchText",description = "The search text for which the user wants to find matching patents")
String searchText) {
try {
String patentsJson = vectorSearch(searchText); // Calls our Cloud Run Function
return Map.of("status", "success", "report", patentsJson);
} catch (Exception e) {
// Log error
return Map.of("status", "error", "report", "Error fetching patents.");
}
}
// --- Tool: Explain Patent (Leveraging InvocationContext) ---
public static Map<String, String> explainPatent(
@Schema(name="patentId",description = "The patent id for which the user wants to get more explanation for, from the database")
String patentId,
@Schema(name="ctx",description = "The list of patent abstracts from the database from which the user can pick the one to get more explanation for")
InvocationContext ctx) { // Note the InvocationContext
try {
// Retrieve previous patent search results from session state
String previousResults = (String) ctx.session().state().get("patents");
if (previousResults != null && !previousResults.isEmpty()) {
// Logic to find the specific patent abstract from 'previousResults' by 'patentId'
String[] patentEntries = previousResults.split("\n\n\n\n");
for (String entry : patentEntries) {
if (entry.contains(patentId)) { // Simplified check
// The agent will then use its instructions to summarize this 'report'
return Map.of("status", "success", "report", entry);
}
}
}
return Map.of("status", "error", "report", "Patent ID not found in previous search.");
} catch (Exception e) {
// Log error
return Map.of("status", "error", "report", "Error explaining patent.");
}
}
public static void main(String[] args) throws Exception {
InMemoryRunner runner = new InMemoryRunner(ROOT_AGENT);
// ... (Session creation and main input loop - shown in your source)
}
}
강조 표시된 주요 ADK Java 코드 구성요소:
- LlmAgent.builder(): 에이전트를 구성하기 위한 유창한 API입니다.
- .instruction(...): 어떤 도구를 언제 사용할지 등 LLM의 핵심 프롬프트와 가이드라인을 제공합니다.
- FunctionTool.create(App.class, "methodName"): Java 메서드를 상담사가 호출할 수 있는 도구로 쉽게 등록합니다. 메서드 이름 문자열은 실제 공개 정적 메서드와 일치해야 합니다.
- @Schema(description = ...): 도구 매개변수에 주석을 추가하여 LLM이 각 도구에서 예상하는 입력을 이해하도록 지원합니다. 이 설명은 정확한 도구 선택 및 매개변수 작성에 매우 중요합니다.
- InvocationContext ctx: 도구 메서드에 자동으로 전달되어 세션 상태 (ctx.session().state()), 사용자 정보 등에 액세스할 수 있습니다.
- .outputKey("patents"): 도구가 데이터를 반환하면 ADK는 이 키 아래의 세션 상태에 데이터를 자동으로 저장할 수 있습니다. 이렇게 하면 explainPatent가 getPatents의 결과에 액세스할 수 있습니다.
- VECTOR_SEARCH_ENDPOINT: 특허 검색 사용 사례에서 사용자를 위한 문맥 Q&A의 핵심 기능 로직을 보유하는 변수입니다.
- 여기의 작업 항목: 이전 섹션의 Java Cloud Run 함수 단계를 구현한 후 업데이트된 배포된 엔드포인트 값을 설정해야 합니다.
- searchTool: 사용자와 상호작용하여 사용자의 검색 텍스트와 문맥상 관련성이 높은 특허 데이터베이스에서 특허를 찾습니다.
- explainTool: 사용자에게 심층 분석할 특정 특허를 요청합니다. 그런 다음 특허 개요를 요약하고 보유한 특허 세부정보를 기반으로 사용자의 추가 질문에 답변할 수 있습니다.
중요: VECTOR_SEARCH_ENDPOINT 변수를 배포된 CRF 엔드포인트로 교체해야 합니다.
스테이트풀 상호작용에 InvocationContext 사용
유용한 상담사를 빌드하기 위한 중요한 기능 중 하나는 대화의 여러 차례에 걸쳐 상태를 관리하는 것입니다. ADK의 InvocationContext를 사용하면 간단하게 처리할 수 있습니다.
App.java:
- initAgent()가 정의되면 .outputKey("patents")를 사용합니다. 이렇게 하면 도구 (예: getPatents)가 보고서 필드에 데이터를 반환할 때 해당 데이터가 'patents' 키 아래의 세션 상태에 저장되어야 한다고 ADK에 알립니다.
- explainPatent 도구 메서드에서 InvocationContext ctx를 삽입합니다.
public static Map<String, String> explainPatent(
@Schema(description = "...") String patentId, InvocationContext ctx) {
String previousResults = (String) ctx.session().state().get("patents");
// ... use previousResults ...
}
이렇게 하면 explainPatent 도구가 이전 대화에서 getPatents 도구가 가져온 특허 목록에 액세스하여 대화를 상태 기반으로 일관되게 만들 수 있습니다.
9. 로컬 CLI 테스트
환경 변수 정의
다음 두 가지 환경 변수를 내보내야 합니다.
- AI Studio에서 가져올 수 있는 Gemini 키:
이렇게 하려면 https://aistudio.google.com/apikey로 이동하여 이 애플리케이션을 구현하는 활성 Google Cloud 프로젝트의 API 키를 가져와 키를 어딘가에 저장합니다.
- 키를 가져온 후 Cloud Shell 터미널을 열고 다음 명령어를 실행하여 방금 만든 새 디렉터리 adk-agents로 이동합니다.
cd adk-agents
- 이번에는 Vertex AI를 사용하지 않음을 지정하는 변수입니다.
export GOOGLE_GENAI_USE_VERTEXAI=FALSE
export GOOGLE_API_KEY=AIzaSyDF...
- CLI에서 첫 번째 에이전트 실행
이 첫 번째 에이전트를 실행하려면 터미널에서 다음 Maven 명령어를 사용합니다.
mvn compile exec:java -DmainClass="agents.App"
터미널에 상담사의 대화형 응답이 표시됩니다.
10. Cloud Run에 배포
Cloud Run에 ADK Java 에이전트를 배포하는 방법은 다른 Java 애플리케이션을 배포하는 것과 비슷합니다.
- Dockerfile: Dockerfile을 만들어 Java 애플리케이션을 패키징합니다.
- Docker 이미지 빌드 및 푸시: Google Cloud Build 및 Artifact Registry를 사용합니다.
- 위 단계를 실행하고 단일 명령어로 Cloud Run에 배포할 수 있습니다.
gcloud run deploy --source . --set-env-vars GOOGLE_API_KEY=<<Your_Gemini_Key>>
마찬가지로 Java Cloud Run 함수 (gcfv2.PatentSearch)를 배포합니다. 또는 Cloud Run 함수 콘솔에서 직접 데이터베이스 로직용 Java Cloud Run 함수를 만들고 배포할 수 있습니다.
11. 웹 UI로 테스트
ADK에는 에이전트의 로컬 테스트 및 디버깅을 위한 편리한 웹 UI가 함께 제공됩니다. App.java를 로컬에서 실행하면 (예: 구성된 경우 mvn exec:java -Dexec.mainClass="agents.App" 또는 메인 메서드만 실행) 일반적으로 ADK에서 로컬 웹 서버를 시작합니다.
ADK 웹 UI를 사용하면 다음 작업을 할 수 있습니다.
- 상담사에게 메시지를 보냅니다.
- 이벤트 (사용자 메시지, 도구 호출, 도구 응답, LLM 응답)를 확인합니다.
- 세션 상태 검사
- 로그 및 트레이스를 확인합니다.
이는 에이전트가 요청을 처리하고 도구를 사용하는 방식을 이해하는 데 개발 중에 매우 유용합니다. 여기서는 pom.xml의 mainClass가 com.google.adk.web.AdkWebServer로 설정되어 있고 에이전트가 여기에 등록되어 있거나 이를 노출하는 로컬 테스트 실행기를 실행 중이라고 가정합니다.
콘솔 입력을 위한 InMemoryRunner 및 Scanner를 사용하여 App.java를 실행하면 핵심 상담사 로직을 테스트하는 것입니다. 웹 UI는 더 시각적인 디버깅 환경을 위한 별도의 구성요소로, ADK가 HTTP를 통해 에이전트를 제공할 때 자주 사용됩니다.
루트 디렉터리에서 다음 Maven 명령어를 사용하여 SpringBoot 로컬 서버를 실행할 수 있습니다.
mvn compile exec:java -Dexec.args="--adk.agents.source-dir=src/main/java/ --logging.level.com.google.adk.dev=TRACE --logging.level.com.google.adk.demo.agents=TRACE"
인터페이스는 위 명령어를 실행하여 출력된 URL에서 액세스할 수 있는 경우가 많습니다. Cloud Run 배포인 경우 Cloud Run 배포 링크에서 액세스할 수 있습니다.
대화형 인터페이스에서 결과를 확인할 수 있습니다.
아래 동영상에서 Google의 특허 상담사를 확인하세요.
AlloyDB 인라인 검색 및 검색 결과 재현 평가를 통한 품질 관리 특허 상담사 데모
12. 삭제
이 게시물에서 사용한 리소스의 비용이 Google Cloud 계정에 청구되지 않도록 하려면 다음 단계를 따르세요.
- Google Cloud 콘솔에서 https://console.cloud.google.com/cloud-resource-manager?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog로 이동합니다.
- https://console.cloud.google.com/cloud-resource-manager?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog 페이지
- 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
- 대화상자에서 프로젝트 ID를 입력하고 종료를 클릭하여 프로젝트를 삭제합니다.
13. 축하합니다
축하합니다. ADK, https://cloud.google.com/alloydb/docs?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog, Vertex AI, Vector Search의 기능을 결합하여 Java로 특허 분석 에이전트를 성공적으로 빌드했습니다. 또한 문맥 유사 검색을 혁신적이고 효율적이며 진정으로 의미 중심적으로 만드는 데 큰 진전을 이루었습니다.
지금 시작하기
ADK 문서: [공식 ADK Java 문서 링크]
특허 분석 에이전트 소스 코드: [현재 공개된 GitHub 저장소 링크]
Java 샘플 상담사: [adk-samples 저장소 링크]
ADK 커뮤니티 가입: https://www.reddit.com/r/agentdevelopmentkit/
즐거운 에이전트 빌딩 되세요.