1. 개요
완구점에 가서 가상 또는 직접적으로 완벽한 선물을 쉽게 찾을 수 있다고 상상해 보세요. 원하는 제품을 설명하거나, 장난감 사진을 업로드하거나, 직접 디자인을 할 수도 있습니다. 그러면 스토어에서 사용자의 니즈를 즉시 파악하고 맞춤 환경을 제공합니다. 이는 미래의 공상과학이 아닙니다. AI, 클라우드 기술, 맞춤형 전자상거래에 대한 비전을 바탕으로 한 현실입니다.
과제: 상상과 일치하는 완벽한 제품을 찾는 것조차 쉽지 않을 수 있습니다. 일반적인 검색어, 키워드, 유사 검색어는 종종 효과가 없고, 끝없는 페이지를 탐색하는 것은 지루할 수 있으며, 상상하는 것과 제공되는 항목 간에 불일치가 있으면 불만족스러울 수 있습니다.
해결 방법: 데모 애플리케이션은 AI의 힘을 활용하여 문맥 검색과 검색 맥락에 맞는 제품의 맞춤 생성을 통해 진정으로 맞춤설정되고 원활한 환경을 제공하여 이 문제를 해결합니다.
빌드할 항목
이 실습에서는 다음을 수행합니다.
- AlloyDB 인스턴스 만들기 및 장난감 데이터 세트 로드
- AlloyDB에서 pgvector 및 생성형 AI 모델 확장 프로그램 사용 설정
- 제품 설명에서 임베딩을 생성하고 사용자 검색 텍스트에 대한 실시간 코사인 유사성 검색을 실행합니다.
- Gemini 2.0 Flash를 호출하여 사용자가 컨텍스트 기반 장난감 검색을 위해 업로드한 이미지를 설명합니다.
- Imagen 3을 호출하여 사용자의 관심분야를 기반으로 장난감을 맞춤 제작
- 데이터베이스용 생성형 AI 도구 상자를 사용하여 만든 가격 예측 도구를 호출하여 맞춤 제작된 장난감의 가격 세부정보를 확인합니다.
- 서버리스 Cloud Run 함수에서 솔루션 배포
요구사항
2. 아키텍처
데이터 흐름: 데이터가 시스템을 통해 이동하는 방식을 자세히 살펴보겠습니다.
- AI 기반 RAG (검색 증강 생성)를 사용한 문맥 검색
다음과 같이 생각해 보세요. 시스템은 '빨간색 자동차'를 단순히 찾는 대신 다음을 이해합니다.
'3세 남자 아이에게 적합한 소형 차량'
AlloyDB를 기반으로 사용: Google Cloud의 완전 관리형 PostgreSQL 호환 데이터베이스인 AlloyDB를 사용하여 설명, 이미지 URL, 기타 관련 속성을 비롯한 장난감 데이터를 저장합니다.
시맨틱 검색을 위한 pgvector: PostgreSQL 확장 프로그램인 pgvector를 사용하면 장난감 설명과 사용자 검색어 쿼리의 벡터 임베딩을 모두 저장할 수 있습니다. 이를 통해 시맨틱 검색이 가능해집니다. 즉, 시스템이 정확한 키워드뿐만 아니라 단어의 의미를 이해합니다.
관련성의 코사인 유사도: Google에서는 코사인 유사성을 사용하여 사용자의 검색 벡터와 장난감 설명 벡터 간의 시맨틱 유사성을 측정하여 가장 관련성 높은 결과를 표시합니다.
속도와 정확성을 위한 ScaNN 색인: 특히 장난감 인벤토리가 늘어남에 따라 빠르고 정확한 결과를 얻기 위해 ScaNN (확장 가능한 최근접 이웃) 색인을 통합합니다. 이를 통해 벡터 검색의 효율성과 검색 결과가 크게 개선됩니다.
- Gemini 2.0 Flash를 사용한 이미지 기반 검색 및 이해
사용자가 컨텍스트를 텍스트로 입력하는 대신 검색하려는 익숙한 장난감의 사진을 업로드하려고 한다고 가정해 보겠습니다. 사용자는 좋아하는 장난감의 이미지를 업로드하고 이를 통해 관련 기능을 이용할 수 있습니다. LangChain4j를 사용하여 호출된 Google의 Gemini 2.0 Flash 모델을 활용하여 이미지를 분석하고 장난감의 색상, 재료, 유형, 대상 연령대와 같은 관련 컨텍스트를 추출합니다.
- 생성형 AI로 맞춤설정된 내 꿈의 장난감 만들기: Imagen 3
진정한 마법은 사용자가 직접 장난감을 만들기로 결정할 때 일어납니다. Imagen 3을 사용하면 간단한 텍스트 프롬프트를 사용하여 원하는 장난감을 설명할 수 있습니다. '보라색 날개와 친근한 얼굴을 가진 봉제용 용 인형이 갖고 싶다'라고 말하면 화면에 그 용 인형이 생겨나는 모습을 상상해 보세요. 그런 다음 Imagen 3은 맞춤설계된 장난감의 이미지를 생성하여 사용자가 자신의 창작물을 명확하게 시각화할 수 있도록 합니다.
- 에이전트 기반 가격 예측 및 데이터베이스용 생성형 AI 도구 상자
맞춤 설계된 장난감의 제작 비용을 추정하는 가격 예측 기능을 구현했습니다. 이 기능은 정교한 가격 계산 도구가 포함된 상담사를 통해 제공됩니다.
데이터베이스용 생성형 AI 도구 상자: 이 상자는 Google의 새로운 오픈소스 도구인 데이터베이스용 생성형 AI 도구 상자를 사용하여 데이터베이스와 원활하게 통합됩니다. 이를 통해 상담사는 재료비, 제조 공정, 기타 관련 요소에 대한 실시간 데이터에 액세스하여 정확한 가격 추정치를 제공할 수 있습니다. 여기에서 자세히 알아보세요.
- Java Spring Boot, Gemini Code Assist, Cloud Run을 통한 간소화된 개발 및 서버리스 배포
전체 애플리케이션은 강력하고 확장 가능한 프레임워크인 Java Spring Boot를 사용하여 빌드됩니다. 개발 프로세스 전반에서, 특히 프런트엔드 개발에 Gemini Code Assist를 활용하여 개발 주기를 크게 단축하고 코드 품질을 개선했습니다. 전체 애플리케이션을 배포하는 데 Cloud Run을 사용하고 데이터베이스 및 에이전트 기능을 독립적인 엔드포인트로 배포하는 데 Cloud Run Functions를 사용했습니다.
3. 시작하기 전에
프로젝트 만들기
- Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
- Cloud 프로젝트에 결제가 사용 설정되어 있어야 하므로 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요 .
- bq가 미리 로드되어 제공되는 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>
- Cloud Shell 터미널에서 다음 명령어를 하나씩 실행하여 필수 API를 사용 설정합니다.
아래를 실행하는 단일 명령어도 있지만 무료 체험판 계정 사용자인 경우 일괄 사용 설정 시 할당량 문제가 발생할 수 있습니다. 따라서 명령어는 한 줄에 하나씩 표시됩니다.
gcloud services enable alloydb.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable servicenetworking.googleapis.com
gcloud services enable run.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable cloudfunctions.googleapis.com
gcloud services enable aiplatform.googleapis.com
gcloud 명령어 대신 각 제품을 검색하거나 이 링크를 사용하여 콘솔을 통해 수행할 수도 있습니다.
누락된 API가 있으면 구현 과정에서 언제든지 사용 설정할 수 있습니다.
gcloud 명령어 및 사용법은 문서를 참조하세요.
4. 데이터베이스 설정
이 실습에서는 장난감 가게 데이터를 보관할 데이터베이스로 AlloyDB를 사용합니다. 클러스터를 사용하여 데이터베이스 및 로그와 같은 모든 리소스를 보관합니다. 각 클러스터에는 데이터에 대한 액세스 포인트를 제공하는 기본 인스턴스가 있습니다. 테이블에는 실제 데이터가 포함됩니다.
전자상거래 데이터 세트가 로드될 AlloyDB 클러스터, 인스턴스, 테이블을 만들어 보겠습니다.
클러스터 및 인스턴스 만들기
- Cloud 콘솔에서 AlloyDB 페이지로 이동합니다. Cloud Console에서 대부분의 페이지를 찾는 가장 쉬운 방법은 콘솔의 검색창을 사용하는 것입니다.
- 이 페이지에서 클러스터 만들기를 선택합니다.
- 아래와 같은 화면이 표시됩니다. 다음 값으로 클러스터 및 인스턴스를 만듭니다 (저장소에서 애플리케이션 코드를 클론하는 경우 값이 일치하는지 확인).
- 클러스터 ID: '
vector-cluster
' - 비밀번호: "
alloydb
" - PostgreSQL 15 호환
- 지역: '
us-central1
' - 네트워킹: '
default
'
- 기본 네트워크를 선택하면 아래와 같은 화면이 표시됩니다.
연결 설정을 선택합니다.
- 여기에서 '자동으로 할당된 IP 범위 사용'을 선택하고 계속을 클릭합니다. 정보를 검토한 후 '연결 만들기'를 선택합니다.
- 네트워크가 설정되면 클러스터를 계속 만들 수 있습니다. 클러스터 만들기를 클릭하여 아래와 같이 클러스터 설정을 완료합니다.
인스턴스 ID를 '로 변경해야 합니다.
vector-instance"
.
클러스터를 만드는 데 약 10분이 소요됩니다. 완료되면 방금 만든 클러스터의 개요를 보여주는 화면이 표시됩니다.
5. 데이터 수집
이제 매장 데이터가 포함된 표를 추가하겠습니다. 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;
테이블 만들기
아래 DDL 문을 사용하여 테이블을 만듭니다.
CREATE TABLE toys ( id VARCHAR(25), name VARCHAR(25), description VARCHAR(20000), quantity INT, price FLOAT, image_url VARCHAR(200), text_embeddings vector(768)) ;
위 명령어를 실행하면 데이터베이스에서 테이블을 볼 수 있습니다.
데이터 수집
이 실습에서는 이 SQL 파일에 약 72개의 레코드로 구성된 테스트 데이터가 있습니다. 여기에는 id, name, description, quantity, price, image_url
필드가 포함됩니다. 나머지 필드는 실습 후반부에서 입력합니다.
여기에서 줄/삽입 문을 복사한 다음 빈 편집기 탭에 해당 줄을 붙여넣고 실행을 선택합니다.
테이블 콘텐츠를 보려면 탐색기 섹션을 펼쳐 apparels라는 테이블이 표시될 때까지 펼칩니다. 테이블을 쿼리하는 옵션을 보려면 삼중 콜론 (⋮)을 선택합니다. 새 편집기 탭에 SELECT 문장이 열립니다.
권한 부여
아래 문을 실행하여 embedding
함수에 대한 실행 권한을 사용자 postgres
에게 부여합니다.
GRANT EXECUTE ON FUNCTION embedding TO postgres;
AlloyDB 서비스 계정에 Vertex AI 사용자 역할을 부여합니다.
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"
6. 컨텍스트의 임베딩 만들기
컴퓨터는 텍스트를 처리하는 것보다 숫자를 처리하는 것이 훨씬 쉽습니다. 임베딩 시스템은 텍스트의 표현 방식, 사용하는 언어 등에 관계없이 텍스트를 텍스트를 나타내는 일련의 부동 소수점 수로 변환합니다.
해변가 위치를 설명해 보세요. 'on the water', 'beachfront', 'walk from your room to the ocean', 'sur la mer', 'на берегу океана' 등 다양한 표현이 있을 수 있습니다. 이러한 용어는 모두 다르게 보이지만 의미론적 의미 또는 머신러닝 용어로 보면 임베딩이 서로 매우 근접합니다.
이제 데이터와 컨텍스트가 준비되었으므로 SQL을 실행하여 제품 설명의 임베딩을 embedding
필드의 테이블에 추가합니다. 사용할 수 있는 다양한 임베딩 모델이 있습니다. Vertex AI의 text-embedding-005
를 사용합니다. 프로젝트 전체에서 동일한 임베딩 모델을 사용해야 합니다.
참고: 얼마 전에 만든 기존 Google Cloud 프로젝트를 사용하는 경우 textembedding-gecko와 같은 이전 버전의 텍스트 임베딩 모델을 계속 사용해야 할 수 있습니다.
AlloyDB Studio 탭으로 돌아가서 다음 DML을 입력합니다.
UPDATE toys set text_embeddings = embedding( 'text-embedding-005', description);
toys
표를 다시 살펴보고 임베딩을 확인합니다. 변경사항을 확인하려면 SELECT 문을 다시 실행해야 합니다.
SELECT id, name, description, price, quantity, image_url, text_embeddings FROM toys;
그러면 아래와 같이 장난감 설명에 대한 임베딩 벡터(부동 소수점 배열처럼 보임)가 반환됩니다.
참고: 무료 등급으로 새로 만든 Google Cloud 프로젝트는 삽입 모델에 허용되는 초당 삽입 요청 수와 관련하여 할당량 문제가 발생할 수 있습니다. 임베딩을 생성하는 동안 ID에 필터 쿼리를 사용한 후 1~5개의 레코드 등을 선택적으로 선택하는 것이 좋습니다.
7. 벡터 검색 실행
이제 테이블, 데이터, 임베딩이 모두 준비되었으므로 사용자 검색 텍스트에 대한 실시간 벡터 검색을 실행해 보겠습니다.
사용자가 다음과 같이 묻는다고 가정해 보겠습니다.
"I want a white plush teddy bear toy with a floral pattern
."
다음 쿼리를 실행하여 일치하는 항목을 찾을 수 있습니다.
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;
이 쿼리를 자세히 살펴보겠습니다.
이 쿼리에서
- 사용자의 검색 텍스트는 '
I want a white plush teddy bear toy with a floral pattern.
'입니다. text-embedding-005
모델을 사용하여embedding()
메서드에서 임베딩으로 변환합니다. 이 단계는 테이블의 모든 항목에 삽입 함수를 적용한 마지막 단계와 유사합니다.- '
<=>
'는 COSINE SIMILARITY 거리 메서드의 사용을 나타냅니다. 사용 가능한 모든 유사성 측정값은 pgvector 문서에서 확인할 수 있습니다. - 데이터베이스에 저장된 벡터와 호환되도록 임베딩 메서드의 결과를 벡터 유형으로 변환합니다.
- LIMIT 5는 검색 텍스트의 최근접 이웃 5개를 추출하겠다는 의미입니다.
결과는 다음과 같습니다.
검색 결과에서 볼 수 있듯이 검색어와 상당히 유사한 검색 결과가 표시됩니다. 텍스트를 변경하여 결과가 어떻게 달라지는지 확인해 보세요.
중요사항:
이제 ScaNN 색인을 사용하여 이 벡터 검색 결과의 성능 (쿼리 시간), 효율성, 재현률을 높이고자 한다고 가정해 보겠습니다. 이 블로그의 단계에 따라 색인이 있는 경우와 없는 경우의 결과 차이를 비교하세요.
선택 단계: ScaNN 색인으로 효율성 및 검색 실적 개선
편의를 위해 색인 생성 단계를 나열합니다.
- 이미 클러스터, 인스턴스, 컨텍스트, 임베딩이 생성되었으므로 다음 문을 사용하여 ScaNN 확장 프로그램을 설치하기만 하면 됩니다.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- 다음으로 색인 (ScaNN)을 만듭니다.
CREATE INDEX toysearch_index ON toys
USING scann (text_embeddings cosine)
WITH (num_leaves=9);
위의 DDL에서 apparel_index는 색인의 이름입니다.
'toys'는 테이블입니다.
'scann'은 색인 메서드입니다.
'embedding'은 색인을 생성하려는 테이블의 열입니다.
'cosine'은 색인과 함께 사용할 거리 메서드입니다.
'8'은 이 색인에 적용할 파티션 수입니다. 1~1048576 사이의 값으로 설정합니다. 이 값을 결정하는 방법에 관한 자세한 내용은 ScaNN 색인 조정을 참고하세요.
ScaNN 저장소에서 권장하는 대로 데이터 포인트 수의 제곱근을 사용했습니다. 파티션을 만들 때는 num_leaves가 대략 데이터 포인트 수의 제곱근이어야 합니다.
- 다음 쿼리를 사용하여 색인이 생성되었는지 확인합니다.
SELECT * FROM pg_stat_ann_indexes;
- 색인 없이 사용한 것과 동일한 쿼리를 사용하여 벡터 검색을 실행합니다.
select * from toys
ORDER BY text_embeddings <=> CAST(embedding('text-embedding-005', 'I want a white plush teddy bear toy with a floral pattern') as vector(768))
LIMIT 5;
위 쿼리는 실습의 8단계에서 사용한 쿼리와 동일합니다. 하지만 이제 필드의 색인이 생성되었습니다.
- 색인 유무와 관계없이 간단한 검색 쿼리로 테스트합니다 (색인 삭제).
이 사용 사례에는 레코드가 72개밖에 없으므로 색인이 실제로 적용되지 않습니다. 다른 사용 사례에서 실행된 테스트의 결과는 다음과 같습니다.
색인이 생성된 임베딩 데이터에 동일한 벡터 검색 쿼리를 사용하면 검색 결과의 품질과 효율성이 향상됩니다. 색인을 사용하면 효율성이 크게 향상됩니다 (실행 시간 측면에서 ScaNN 사용 안함: 10.37ms, ScaNN 사용: 0.87ms). 이 주제에 관한 자세한 내용은 이 블로그를 참고하세요.
8. LLM을 사용한 일치 유효성 검사
계속해서 애플리케이션에 가장 적합한 검색 결과를 반환하는 서비스를 만들기 전에 생성형 AI 모델을 사용하여 이러한 잠재적 응답이 실제로 관련성이 높고 사용자와 공유하기에 안전한지 검증해 보겠습니다.
인스턴스가 Gemini용으로 설정되어 있는지 확인
먼저 클러스터와 인스턴스에 Google ML 통합이 이미 사용 설정되어 있는지 확인합니다. AlloyDB Studio에서 다음 명령어를 실행합니다.
show google_ml_integration.enable_model_support;
값이 'on'으로 표시되면 다음 2단계를 건너뛰고 AlloyDB 및 Vertex AI 모델 통합 설정으로 바로 이동할 수 있습니다.
- AlloyDB 클러스터의 기본 인스턴스로 이동하여 '기본 인스턴스 수정'을 클릭합니다.
- 고급 구성 옵션의 플래그 섹션으로 이동합니다.
google_ml_integration.enable_model_support flag
가 아래와 같이 'on
'로 설정되어 있는지 확인합니다.
'사용'으로 설정되어 있지 않으면 '사용'으로 설정한 다음 인스턴스 업데이트 버튼을 클릭합니다. 이 단계는 몇 분 정도 걸립니다.
AlloyDB 및 Vertex AI 모델 통합
이제 AlloyDB 스튜디오에 연결하고 다음 DML 문을 실행하여 표시된 위치에서 프로젝트 ID를 사용하여 AlloyDB에서 Gemini 모델 액세스를 설정할 수 있습니다. 명령어를 실행하기 전에 문법 오류에 대한 경고가 표시될 수 있지만 명령어는 정상적으로 실행됩니다.
먼저 아래와 같이 Gemini 1.5 모델 연결을 만듭니다. 아래 명령어에서 $PROJECT_ID
를 Google Cloud 프로젝트 ID로 바꾸어야 합니다.
CALL
google_ml.create_model( model_id => 'gemini-1.5',
model_request_url => 'https://us-central1-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent',
model_provider => 'google',
model_auth_type => 'alloydb_service_agent_iam');
AlloyDB Studio에서 다음 명령어를 통해 액세스에 구성된 모델을 확인할 수 있습니다.
select model_id,model_type from google_ml.model_info_view;
마지막으로 데이터베이스 사용자가 ml_predict_row 함수를 실행하여 Google Vertex AI 모델을 통해 예측을 실행할 수 있는 권한을 부여해야 합니다. 다음 명령어를 실행합니다.
GRANT EXECUTE ON FUNCTION ml_predict_row to postgres;
참고: 기존 Google Cloud 프로젝트와 얼마 전에 만든 AlloyDB의 기존 클러스터/인스턴스를 사용하는 경우 향후 gemini-1.5 호출 시 문제가 발생할 수 있으므로 gemini-1.5 모델에 대한 이전 참조를 삭제하고 위의 CALL 문을 사용하여 다시 만들고 ml_predict_row 함수에 대한 grant execute를 다시 실행해야 할 수 있습니다.
응답 평가
다음 섹션에서는 쿼리의 응답이 적절한지 확인하기 위해 하나의 큰 쿼리를 사용하게 되지만 쿼리를 이해하기 어려울 수 있습니다. 이제 몇 분 후에 각 부분을 살펴보고 어떻게 조합되는지 확인해 보겠습니다.
- 먼저 데이터베이스에 요청을 보내 사용자 검색어와 가장 일치하는 10개의 항목을 가져옵니다.
- 응답의 유효성을 확인하기 위해 응답을 평가하는 방법을 설명하는 외부 쿼리를 사용합니다. 검색 텍스트인
recommended_text
필드와 내부 테이블의content
(장난감 설명 필드)를 쿼리의 일부로 사용합니다. - 이를 통해 반환된 응답의 '좋음'을 검토합니다.
predict_row
는 결과를 JSON 형식으로 반환합니다. 코드 '-> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text'"
는 해당 JSON에서 실제 텍스트를 추출하는 데 사용됩니다. 반환된 실제 JSON을 보려면 이 코드를 삭제하면 됩니다.- 마지막으로 LLM 응답을 가져오기 위해
REGEXP_REPLACE(gemini_validation,
'[^a-zA-Z,: ]',
'',
'g')
를 사용하여 추출합니다.
SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
CAST(ARRAY_AGG(LLM_RESPONSE) AS TEXT) AS gemini_validation
FROM (SELECT id,
name,
content,
quantity,
price,
image_url,
recommended_text,
json_array_elements(google_ml.predict_row(model_id => 'gemini-1.5',
request_body => CONCAT('{ "contents": [ { "role": "user", "parts": [ { "text": "User wants to buy a toy and this is the description of the toy they wish to buy: ', recommended_text, '. Check if the following product items from the inventory are close enough to really, contextually match the user description. Here are the items: ', content, '. Return a ONE-LINE response with 3 values: 1) MATCH: if the 2 contexts are reasonably matching in terms of any of the color or color family specified in the list, approximate style match with any of the styles mentioned in the user search text: This should be a simple YES or NO. Choose NO only if it is completely irrelevant to users search criteria. 2) PERCENTAGE: percentage of match, make sure that this percentage is accurate 3) DIFFERENCE: A clear one-line easy description of the difference between the 2 products. Remember if the user search text says that some attribute should not be there, and the record has it, it should be a NO match. " } ] } ] }')::JSON)) -> 'candidates' -> 0 -> 'content' -> 'parts' -> 0 -> 'text' :: TEXT AS LLM_RESPONSE
FROM (SELECT id,
name,
description AS content,
quantity,
price,
image_url,
'Pink panther standing' AS recommended_text
FROM toys
ORDER BY text_embeddings <=> embedding('text-embedding-005',
'Pink panther standing')::VECTOR
LIMIT 10) AS xyz) AS X
GROUP BY id,
name,
content,
quantity,
price,
image_url,
recommended_text) AS final_matches
WHERE REGEXP_REPLACE(gemini_validation, '[^a-zA-Z,: ]', '', 'g') LIKE '%MATCH%:%YES%';
여전히 부담스러울 수 있지만 조금 더 이해하기 쉽게 설명해 드리겠습니다. 결과에는 일치 여부, 일치 비율, 등급에 대한 설명이 표시됩니다.
Gemini 모델은 기본적으로 스트리밍이 사용 설정되어 있으므로 실제 응답이 여러 줄에 걸쳐 표시됩니다.
9. 서버리스 방식으로 Cloud로 장난감 검색 가져오기
앱을 웹으로 가져갈 준비가 되셨나요? Cloud Run 함수를 사용하여 이 지식 엔진을 서버리스로 만들려면 다음 단계를 따르세요.
- Google Cloud 콘솔의 Cloud Run 함수로 이동하여 새 Cloud Run 함수를 만들거나 https://console.cloud.google.com/functions/add 링크를 사용하세요.
- 환경을 'Cloud Run 함수'로 선택합니다. 함수 이름 'get-toys-alloydb'를 제공하고 리전을 'us-central1'로 선택합니다. 인증을 '인증되지 않은 호출 허용'으로 설정하고 다음을 클릭합니다. 런타임으로 Java 17을, 소스 코드로 인라인 편집기를 선택합니다.
- 기본적으로 진입점은 '
gcfv2.HelloHttpFunction
'로 설정됩니다. Cloud Run 함수의HelloHttpFunction.java
및pom.xml
에 있는 자리표시자 코드를 각각 HelloHttpFunction.java 및 pom.xml의 코드로 바꿉니다. - Java 파일에서 <<YOUR_PROJECT>> 자리표시자와 AlloyDB 연결 사용자 인증 정보를 값으로 변경해야 합니다. AlloyDB 사용자 인증 정보는 이 Codelab을 시작할 때 사용한 사용자 인증 정보입니다. 다른 값을 사용한 경우 Java 파일에서 동일하게 수정하세요.
- 배포를 클릭합니다.
배포가 완료되면 Cloud 함수가 AlloyDB 데이터베이스 인스턴스에 액세스할 수 있도록 VPC 커넥터를 만듭니다.
중요 단계:
배포가 완료되면 Google Cloud Run Functions 콘솔에 함수가 표시됩니다. 새로 만든 함수 (get-toys-alloydb
)를 검색하여 클릭한 다음 수정을 클릭하고 다음을 변경합니다.
- 런타임, 빌드, 연결, 보안 설정으로 이동
- 시간 제한을 180초로 늘립니다.
- '연결' 탭으로 이동합니다.
- 인그레스 설정에서 '모든 트래픽 허용'이 선택되어 있는지 확인합니다.
- 이그레스 설정에서 네트워크 드롭다운을 클릭하고 '새 VPC 커넥터 추가' 옵션을 선택한 다음 표시되는 대화상자의 안내를 따릅니다.
- VPC 커넥터의 이름을 지정하고 리전이 인스턴스와 동일한지 확인합니다. 네트워크 값은 기본값으로 두고 서브넷을 맞춤 IP 범위로 설정하여 IP 범위를 10.8.0.0으로 설정하거나 사용 가능한 유사한 값을 설정합니다.
- '확장 설정 표시'를 펼치고 구성이 다음과 정확히 일치하는지 확인합니다.
- '만들기'를 클릭하면 이 커넥터가 이그레스 설정에 표시됩니다.
- 새로 만든 커넥터를 선택합니다.
- 모든 트래픽이 이 VPC 커넥터를 통해 라우팅되도록 선택합니다.
- 다음을 클릭한 후 배포를 클릭합니다.
10. Cloud Run 함수 테스트
업데이트된 Cloud 함수가 배포되면 다음 형식의 엔드포인트가 표시됩니다.
https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/get-toys-alloydb
또는 다음과 같이 Cloud Run 함수를 테스트할 수 있습니다.
PROJECT_ID=$(gcloud config get-value project)
curl -X POST https://us-central1-$PROJECT_ID.cloudfunctions.net/get-toys-alloydb \
-H 'Content-Type: application/json' \
-d '{"search":"I want a standing pink panther toy"}' \
| jq .
결과는 다음과 같습니다.
작업이 끝났습니다. AlloyDB 데이터에서 임베딩 모델을 사용하여 유사성 벡터 검색을 실행하는 방법은 간단합니다.
11. 웹 애플리케이션 클라이언트 빌드
이 부분에서는 사용자가 텍스트, 이미지를 기반으로 상호작용하고 일치하는 장난감을 찾고 필요에 따라 새 장난감을 만들 수 있는 웹 애플리케이션을 빌드합니다. 애플리케이션이 이미 빌드되었으므로 아래 단계에 따라 IDE로 복사하고 앱을 실행할 수 있습니다.
- Gemini 2.0 Flash를 사용하여 사용자가 업로드하여 일치하는 장난감을 찾을 수 있는 이미지를 설명하므로 이 애플리케이션의 API 키를 가져와야 합니다. 이렇게 하려면 https://aistudio.google.com/apikey로 이동하여 이 애플리케이션을 구현하는 활성 Google Cloud 프로젝트의 API 키를 가져와 키를 어딘가에 저장합니다.
- Cloud Shell 터미널로 이동합니다.
- 다음 명령어로 저장소를 클론합니다.
git clone https://github.com/AbiramiSukumaran/toysearch
cd toysearch
- 저장소가 클론되면 Cloud Shell 편집기에서 프로젝트에 액세스할 수 있습니다.
- 클론된 프로젝트에서 'get-toys-alloydb' 및 'toolbox-toys' 폴더를 삭제해야 합니다. 이 두 폴더는 필요한 경우 저장소에서 참조할 수 있는 Cloud Run 함수 코드이기 때문입니다.
- 앱을 빌드하고 배포하기 전에 필요한 모든 환경 변수가 설정되어 있는지 확인합니다. Cloud Shell 터미널로 이동하여 다음을 실행합니다.
PROJECT_ID=$(gcloud config get-value project)
export PROJECT_ID $PROJECT_ID
export GOOGLE_API_KEY <YOUR API KEY that you saved>
- 로컬에서 앱을 빌드하고 실행합니다.
프로젝트 디렉터리에 있는지 확인하고 다음 명령어를 실행합니다.
mvn package
mvn spring-boot:run
- Cloud Run에 배포
gcloud run deploy --source .
12. 생성형 AI 세부정보 이해하기
별도의 조치를 취하지 않아도 됩니다. 참고로 다음 사항을 알려드립니다.
이제 배포할 애플리케이션이 있으므로 검색 (텍스트 및 이미지) 및 생성을 실행한 방법을 잠시 살펴보세요.
- 사용자 텍스트 기반 벡터 검색:
이는 '벡터 검색 애플리케이션 웹 사용하기' 섹션에서 배포한 Cloud Run 함수에서 이미 해결되었습니다.
- 이미지 업로드 기반 벡터 검색:
사용자가 컨텍스트를 텍스트로 입력하는 대신 검색하려는 익숙한 장난감의 사진을 업로드하려고 한다고 가정해 보겠습니다. 사용자는 좋아하는 장난감의 이미지를 업로드하고 이를 통해 관련 기능을 이용할 수 있습니다.
LangChain4j를 사용하여 호출된 Google의 Gemini 2.0 Flash 모델을 활용하여 이미지를 분석하고 장난감의 색상, 재료, 유형, 대상 연령대와 같은 관련 컨텍스트를 추출합니다.
오픈소스 프레임워크를 사용하여 단 5단계 만에 사용자 멀티모달 데이터 입력을 대규모 언어 모델 호출과 일치시키는 결과를 얻었습니다. 지도를 공개하는 방법에 대해 알아보세요.
package cloudcode.helloworld.web;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import java.util.Base64;
import java.util.Optional;
public class GeminiCall {
public String imageToBase64String(byte[] imageBytes) {
String base64Img = Base64.getEncoder().encodeToString(imageBytes);
return base64Img;
}
public String callGemini(String base64ImgWithPrefix) throws Exception {
String searchText = "";
// 1. Remove the prefix
String base64Img = base64ImgWithPrefix.replace("data:image/jpeg;base64,", "");
// 2. Decode base64 to bytes
byte[] imageBytes = Base64.getDecoder().decode(base64Img);
String image = imageToBase64String(imageBytes);
// 3. Get API key from environment variable
String apiKey = Optional.ofNullable(System.getenv("GOOGLE_API_KEY"))
.orElseThrow(() -> new IllegalArgumentException("GOOGLE_API_KEY environment variable not set"));
// 4. Invoke Gemini 2.0
ChatLanguageModel gemini = GoogleAiGeminiChatModel.builder()
.apiKey(apiKey)
.modelName("gemini-2.0-flash-001")
.build();
Response<AiMessage> response = gemini.generate(
UserMessage.from(
ImageContent.from(image, "image/jpeg"),
TextContent.from(
"The picture has a toy in it. Describe the toy in the image in one line. Do not add any prefix or title to your description. Just describe that toy that you see in the image in one line, do not describe the surroundings and other objects around the toy in the image. If you do not see any toy in the image, send response stating that no toy is found in the input image.")));
// 5. Get the text from the response and send it back to the controller
searchText = response.content().text().trim();
System.out.println("searchText inside Geminicall: " + searchText);
return searchText;
}
}
- Google에서 Imagen 3을 사용하여 생성형 AI로 사용자 요청에 따라 맞춤 장난감을 빌드한 방법을 알아보세요.
그런 다음 Imagen 3은 맞춤설계된 장난감의 이미지를 생성하여 사용자가 자신의 창작물을 명확하게 시각화할 수 있도록 합니다. 다음은 단 5단계로 이루어진 방법입니다.
// Generate an image using a text prompt using an Imagen model
public String generateImage(String projectId, String location, String prompt)
throws ApiException, IOException {
final String endpoint = String.format("%s-aiplatform.googleapis.com:443", location);
PredictionServiceSettings predictionServiceSettings =
PredictionServiceSettings.newBuilder().setEndpoint(endpoint).build();
// 1. Set up the context and prompt
String context = "Generate a photo-realistic image of a toy described in the following input text from the user. Make sure you adhere to all the little details and requirements mentioned in the prompt. Ensure that the user is only describing a toy. If it is anything unrelated to a toy, politely decline the request stating that the request is inappropriate for the current context. ";
prompt = context + prompt;
// 2. Initialize a client that will be used to send requests. This client only needs to be created
// once, and can be reused for multiple requests.
try (PredictionServiceClient predictionServiceClient =
PredictionServiceClient.create(predictionServiceSettings)) {
// 3. Invoke Imagen 3
final EndpointName endpointName =
EndpointName.ofProjectLocationPublisherModelName(
projectId, location, "google", "imagen-3.0-generate-001"); //"imagegeneration@006"; imagen-3.0-generate-001
Map<String, Object> instancesMap = new HashMap<>();
instancesMap.put("prompt", prompt);
Value instances = mapToValue(instancesMap);
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("sampleCount", 1);
paramsMap.put("aspectRatio", "1:1");
paramsMap.put("safetyFilterLevel", "block_few");
paramsMap.put("personGeneration", "allow_adult");
paramsMap.put("guidanceScale", 21);
paramsMap.put("imagenControlScale", 0.95); //Setting imagenControlScale
Value parameters = mapToValue(paramsMap);
// 4. Get prediction response image
PredictResponse predictResponse =
predictionServiceClient.predict(
endpointName, Collections.singletonList(instances), parameters);
// 5. Return the Base64 Encoded String to the controller
for (Value prediction : predictResponse.getPredictionsList()) {
Map<String, Value> fieldsMap = prediction.getStructValue().getFieldsMap();
if (fieldsMap.containsKey("bytesBase64Encoded")) {
bytesBase64EncodedOuput = fieldsMap.get("bytesBase64Encoded").getStringValue();
}
}
return bytesBase64EncodedOuput.toString();
}
}
가격 예측
위의 이전 섹션에서는 사용자가 직접 디자인하려는 장난감의 이미지를 Imagen이 생성하는 방법을 설명했습니다. 사용자가 구매할 수 있도록 하려면 애플리케이션에서 가격을 설정해야 하며, Google에서는 직관적인 로직을 사용하여 맞춤 주문 장난감의 가격을 정의했습니다. 로직은 사용자가 디자인한 장난감과 가장 유사한 (설명 측면에서) 상위 5개 장난감의 평균 가격을 사용하는 것입니다.
생성된 장난감의 가격 예측은 이 애플리케이션의 중요한 부분이며, 이를 생성하기 위해 대리인 접근 방식을 사용했습니다. 데이터베이스를 위한 생성형 AI 도구 상자를 소개합니다.
13. 데이터베이스용 생성형 AI 도구 상자
데이터베이스용 생성형 AI 도구 상자는 데이터베이스와 상호작용하는 생성형 AI 도구를 더 쉽게 빌드할 수 있는 Google의 오픈소스 서버입니다. 이를 통해 연결 풀링, 인증 등의 복잡성을 처리하여 도구를 더 쉽고 빠르고 안전하게 개발할 수 있습니다. 상담사가 데이터베이스의 데이터에 액세스할 수 있는 생성형 AI 도구를 빌드하는 데 도움이 됩니다.
도구를 준비하고 애플리케이션을 대리하도록 설정하려면 다음 단계를 따르세요. Toolbox Codelab 링크
이제 애플리케이션에서 배포된 Cloud Run 함수 엔드포인트를 사용하여 맞춤 주문 장난감 이미지의 생성된 Imagen 결과와 함께 가격을 채울 수 있습니다.
14. 웹 애플리케이션 테스트
이제 애플리케이션의 모든 구성요소가 빌드되고 배포되었으므로 클라우드에서 제공할 준비가 되었습니다. 모든 시나리오에서 애플리케이션을 테스트합니다. 예상되는 동영상 링크는 다음과 같습니다.
https://www.youtube.com/shorts/ZMqUAWsghYQ
방문 페이지의 모습은 다음과 같습니다.
15. 삭제
이 게시물에서 사용한 리소스의 비용이 Google Cloud 계정에 청구되지 않도록 하려면 다음 단계를 따르세요.
- Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.
- 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
- 대화상자에서 프로젝트 ID를 입력하고 종료를 클릭하여 프로젝트를 삭제합니다.
16. 축하합니다
축하합니다. AlloyDB, pgvector, Imagen, Gemini 2.0을 사용하여 장난감 가게 문맥 검색 및 생성을 실행하고 오픈소스 라이브러리를 활용하여 강력한 통합을 빌드했습니다. Google은 AlloyDB, Vertex AI, 벡터 검색의 기능을 결합하여 문맥 및 벡터 검색을 접근성, 효율성, 의미 중심적으로 개선하는 데 큰 진전을 이루었습니다.