1. 개요
이 Codelab에서는 지능을 데이터 레이어의 일급 시민으로 취급하는 지속 가능한 잉여 공유 앱인 Neighbor Loop를 빌드합니다.
Gemini 3.0 Flash와 AlloyDB AI를 통합하면 기본 스토리지를 넘어 데이터베이스 내 인텔리전스 영역으로 이동할 수 있습니다. SQL 내에서 직접 멀티모달 항목 분석과 시맨틱 검색을 수행하여 지연 시간과 아키텍처 비대화의 'AI 세금'을 없애는 방법을 알아봅니다.

빌드할 항목
커뮤니티 잉여 공유를 위한 고성능 '스와이프하여 매칭' 웹 애플리케이션
학습할 내용
- 원클릭 프로비저닝: AI 워크로드용으로 설계된 AlloyDB 클러스터와 인스턴스를 설정하는 방법
- 데이터베이스 내 임베딩: INSERT 문 내에서 직접 text-embedding-005 벡터를 생성합니다.
- 멀티모달 추론: Gemini 3.0 Flash를 사용하여 항목을 '보고' 위트 있고 데이트 스타일의 자기소개를 자동으로 생성합니다.
- 시맨틱 검색: ai.if() 함수를 사용하여 SQL 쿼리 내에서 논리 기반 '분위기 확인'을 실행하여 수학뿐만 아니라 컨텍스트를 기반으로 결과를 필터링합니다.
아키텍처
Neighbor Loop는 기존 애플리케이션 계층 병목 현상을 우회합니다. 데이터를 가져와 처리하는 대신 다음을 사용합니다.
- AlloyDB AI: 실시간으로 벡터를 생성하고 저장합니다.
- Google Cloud Storage: 이미지를 저장합니다.
- Gemini 3.0 Flash: SQL을 통해 이미지 및 텍스트 데이터에 대한 1초 미만의 추론을 직접 실행합니다.
- Cloud Run: 가벼운 단일 파일 Flask 백엔드를 호스팅합니다.
요구사항
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 사용 설정: 링크를 따라 API를 사용 설정합니다.
또는 gcloud 명령어를 사용할 수 있습니다. gcloud 명령어 및 사용법은 문서를 참조하세요.
주의사항 및 문제 해결
'유령 프로젝트' 증후군 |
|
결제 바리케이드 | 프로젝트를 사용 설정했지만 결제 계정을 잊었습니다. AlloyDB는 고성능 엔진이므로 '연료 탱크' (결제)가 비어 있으면 시작되지 않습니다. |
API 전파 지연 | 'API 사용 설정'을 클릭했지만 명령줄에 여전히 |
할당량 문제 | 새 체험판 계정을 사용하는 경우 AlloyDB 인스턴스의 리전별 할당량에 도달할 수 있습니다. |
'숨겨진' 서비스 에이전트 | AlloyDB 서비스 에이전트에는 |
3. 데이터베이스 설정
이 실습에서는 AlloyDB를 테스트 데이터의 데이터베이스로 사용합니다. 클러스터를 사용하여 데이터베이스, 로그와 같은 모든 리소스를 보유합니다. 각 클러스터에는 데이터에 대한 액세스 포인트를 제공하는 기본 인스턴스가 있습니다. 테이블에는 실제 데이터가 저장됩니다.
테스트 데이터 세트가 로드될 AlloyDB 클러스터, 인스턴스, 테이블을 만들어 보겠습니다.
- 아래 버튼을 클릭하거나 Google Cloud 콘솔 사용자가 로그인한 브라우저에 링크를 복사합니다.
- 이 단계를 완료하면 저장소가 로컬 Cloud Shell 편집기에 복제되며 프로젝트 폴더에서 아래 명령어를 실행할 수 있습니다 (프로젝트 디렉터리에 있는지 확인하는 것이 중요함).
sh run.sh
- 이제 UI를 사용하여 터미널에서 링크를 클릭하거나 터미널에서 '웹에서 미리보기' 링크를 클릭합니다.
- 시작하려면 프로젝트 ID, 클러스터, 인스턴스 이름을 입력하세요.
- 로그가 스크롤되는 동안 커피를 마시세요. 여기에서 백그라운드에서 어떻게 작동하는지 자세히 알아볼 수 있습니다.
주의사항 및 문제 해결
'인내심' 문제 | 데이터베이스 클러스터는 무거운 인프라입니다. 페이지를 새로고침하거나 '멈춘 것 같아' Cloud Shell 세션을 종료하면 부분적으로 프로비저닝되어 수동 개입 없이는 삭제할 수 없는 '고스트' 인스턴스가 생성될 수 있습니다. |
지역 불일치 |
|
좀비 클러스터 | 이전에 클러스터에 동일한 이름을 사용했고 삭제하지 않은 경우 스크립트에서 클러스터 이름이 이미 있다고 표시할 수 있습니다. 클러스터 이름은 프로젝트 내에서 고유해야 합니다. |
Cloud Shell 시간 제한 | 커피를 마시는 데 30분이 걸리면 Cloud Shell이 절전 모드로 전환되어 |
4. 스키마 프로비저닝
AlloyDB 클러스터와 인스턴스가 실행되면 AlloyDB Studio SQL 편집기로 이동하여 AI 확장 프로그램을 사용 설정하고 스키마를 프로비저닝합니다.

인스턴스 생성이 완료될 때까지 기다려야 할 수 있습니다. 완료되면 클러스터를 만들 때 만든 사용자 인증 정보를 사용하여 AlloyDB에 로그인합니다. PostgreSQL에 인증하려면 다음 데이터를 사용하세요.
- 사용자 이름 : '
postgres' - 데이터베이스 : '
postgres' - 비밀번호 : '
alloydb' (또는 생성 시 설정한 비밀번호)
AlloyDB Studio에 인증되면 편집기에 SQL 명령어가 입력됩니다. 마지막 창 오른쪽에 있는 더하기 기호를 사용하여 여러 편집기 창을 추가할 수 있습니다.

필요에 따라 실행, 형식 지정, 지우기 옵션을 사용하여 편집기 창에 AlloyDB 명령어를 입력합니다.
확장 프로그램 사용 설정
이 앱을 빌드하기 위해 확장 프로그램 pgvector 및 google_ml_integration를 사용합니다. pgvector 확장 프로그램을 사용하면 벡터 임베딩을 저장하고 검색할 수 있습니다. google_ml_integration 확장 프로그램은 SQL에서 예측을 수행하기 위해 Vertex AI 예측 엔드포인트에 액세스하는 데 사용하는 함수를 제공합니다. 다음 DDL을 실행하여 이러한 확장 프로그램을 사용 설정합니다.
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
테이블 만들기
AlloyDB Studio에서 아래 DDL 문을 사용하여 테이블을 만들 수 있습니다.
-- Items Table (The "Profile" you swipe on)
CREATE TABLE items (
item_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
owner_id UUID,
provider_name TEXT,
provider_phone TEXT,
title TEXT,
bio TEXT,
category TEXT,
image_url TEXT,
item_vector VECTOR(768),
status TEXT DEFAULT 'available',
created_at TIMESTAMP DEFAULT NOW()
);
-- Swipes Table (The Interaction)
CREATE TABLE swipes (
swipe_id SERIAL PRIMARY KEY,
swiper_id UUID,
item_id UUID REFERENCES items(item_id),
direction TEXT CHECK (direction IN ('left', 'right')),
is_match BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
);
item_vector 열은 텍스트의 벡터 값을 저장할 수 있습니다.
권한 부여
아래 문을 실행하여 'embedding' 함수에 대한 실행 권한을 부여합니다.
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"
AlloyDB에 Gemini 3 Flash 모델 등록
AlloyDB 쿼리 편집기에서 아래 SQL 문을 실행합니다.
CALL google_ml.create_model(
model_id => 'gemini-3-flash-preview',
model_request_url => 'https://aiplatform.googleapis.com/v1/projects/<<YOUR_PROJECT_ID>>/locations/global/publishers/google/models/gemini-3-flash-preview:generateContent',
model_qualified_name => 'gemini-3-flash-preview',
model_provider => 'google',
model_type => 'llm',
model_auth_type => 'alloydb_service_agent_iam'
);
--replace <<YOUR_PROJECT_ID>> with your project id.
주의사항 및 문제 해결
'비밀번호 기억 상실증' 루프 | '원클릭' 설정을 사용했고 비밀번호가 기억나지 않는 경우 콘솔의 인스턴스 기본 정보 페이지로 이동하여 '수정'을 클릭하여 |
'확장 프로그램을 찾을 수 없음' 오류 |
|
IAM 전파 격차 |
|
벡터 차원 불일치 |
|
프로젝트 ID 오타 |
|
5. 이미지 스토리지 (Google Cloud Storage)
잉여 상품의 사진을 저장하기 위해 GCS 버킷을 사용합니다. 이 데모 앱에서는 스와이프 카드에 이미지가 즉시 렌더링되도록 이미지가 공개적으로 액세스 가능해야 합니다.
- 버킷 만들기: GCP 프로젝트에서 새 버킷 (예: neighborloop-images)을 만듭니다. 데이터베이스 및 애플리케이션과 동일한 리전에 만드는 것이 좋습니다.
- 공개 액세스 구성: * 버킷의 권한 탭으로 이동합니다.
- allUsers 주 구성원을 추가합니다.
- 스토리지 객체 뷰어 역할 (모든 사용자가 사진을 볼 수 있음)과 스토리지 객체 생성자 역할 (데모 업로드용)을 할당합니다.
대안 (서비스 계정): 공개 액세스를 사용하지 않으려면 애플리케이션의 서비스 계정에 AlloyDB에 대한 전체 액세스 권한과 객체를 안전하게 관리하는 데 필요한 스토리지 역할이 부여되어 있는지 확인하세요.
주의사항 및 문제 해결
리전 드래그 | 데이터베이스가 |
버킷 이름의 고유성 | 버킷 이름은 전역 네임스페이스입니다. 버킷 이름을 |
'크리에이터'와 '시청자' 혼동 | '생성자'와 '보기 권한 사용자' 혼동: '보기 권한 사용자'만 추가하면 사용자에게 파일을 쓸 권한이 없으므로 사용자가 새 항목을 나열하려고 할 때 앱이 비정상 종료됩니다. 이 특정 데모 설정에는 둘 다 필요합니다. |
6. 애플리케이션을 만들어 보겠습니다.
이 저장소를 프로젝트에 클론하고 살펴보겠습니다.
- 이 저장소를 클론하려면 Cloud Shell 터미널에서 (루트 디렉터리 또는 이 프로젝트를 만들려는 위치에서) 다음 명령어를 실행합니다.
git clone https://github.com/AbiramiSukumaran/neighbor-loop
이렇게 하면 프로젝트가 생성되며 Cloud Shell 편집기에서 이를 확인할 수 있습니다.

- Gemini API 키를 가져오는 방법
- Google AI Studio 방문: aistudio.google.com으로 이동합니다.
- 로그인: Google Cloud 프로젝트에 사용 중인 동일한 Google 계정을 사용합니다.
- API 키 만들기:
- 왼쪽 사이드바에서 'API 키 받기'를 클릭합니다.
- '새 프로젝트에서 API 키 만들기' 버튼을 클릭합니다.
- 키 복사: 키가 생성되면 복사 아이콘을 클릭합니다.
- 이제 .env 파일에서 환경 변수를 설정합니다.
GEMINI_API_KEY=<<YOUR_GEMINI_API_KEY>>
DATABASE_URL=postgresql+pg8000://postgres:<<YOUR_PASSWORD>>@<<HOST_IP>>:<<PORT>>/postgres
GCS_BUCKET_NAME=<<YOUR_GCS_BUCKET>>
자리표시자 <<YOUR_GEMINI_API_KEY>>, <<YOUR_PASSWORD>, <<HOST_IP>>, <<PORT>> and <<YOUR_GCS_BUCKET>>.의 값을 바꿉니다.
주의사항 및 문제 해결
복수 계정 혼동 | 여러 Google 계정 (개인 계정 및 직장 계정)에 로그인한 경우 AI Studio가 잘못된 계정으로 기본 설정될 수 있습니다. 오른쪽 상단의 아바타를 확인하여 GCP 프로젝트 계정과 일치하는지 확인합니다. |
'무료 등급' 할당량 도달 | 무료 등급을 사용하는 경우 비율 제한 (RPM - 분당 요청 수)이 적용됩니다. 이웃 루프에서 너무 빨리 '스와이프'하면 |
노출된 키 보안 | 키가 포함된 |
'연결 제한 시간' 무효화 | .env 파일에서 비공개 IP 주소를 사용했지만 VPC 외부 (예: 로컬 머신)에서 연결하려고 합니다. 비공개 IP는 동일한 Google Cloud 네트워크 내에서만 연결할 수 있습니다. 공개 IP로 전환하세요. |
포트 5432 가정 | 5432는 표준 PostgreSQL 포트이지만 인증 프록시를 사용하는 경우 AlloyDB에 특정 포트 구성이 필요할 수 있습니다. 이 실습에서는 호스트 문자열 끝에 :5432를 사용해야 합니다. |
'승인된 네트워크' 게이트키퍼 | 공개 IP가 있더라도 코드를 실행하는 머신의 IP 주소를 허용 목록에 추가하지 않으면 AlloyDB에서 '연결 거부'가 표시됩니다.해결 방법: AlloyDB 인스턴스 설정의 승인된 네트워크에 0.0.0.0/0 (임시 테스트용) 또는 특정 IP를 추가합니다. |
SSL/TLS 핸드셰이크 실패 | AlloyDB는 보안 연결을 선호합니다. DATABASE_URL이 드라이버를 올바르게 지정하지 않으면 (예: pg8000 사용) 핸드셰이크가 자동으로 실패하여 일반적인 '데이터베이스에 연결할 수 없음' 오류가 표시될 수 있습니다. |
'기본 vs 읽기 풀' 스왑 | 기본 인스턴스 대신 읽기 풀의 IP 주소를 실수로 복사하면 앱이 항목 검색에는 작동하지만 새 항목을 나열하려고 하면 '읽기 전용' 오류와 함께 비정상 종료됩니다. 쓰기에는 항상 기본 인스턴스 IP를 사용합니다. |
7. 코드를 확인해 보겠습니다.
내 물건의 '데이트 프로필'

사용자가 상품 사진을 업로드할 때 긴 설명을 작성하지 않아도 됩니다. Gemini 3 Flash를 사용하여 상품을 '확인'하고 등록정보를 작성합니다.
백엔드에서 사용자는 제목과 사진만 제공합니다. 나머지는 Gemini가 처리합니다.
prompt = """
You are a witty community manager for NeighborLoop.
Analyze this surplus item and return JSON:
{
"bio": "First-person witty dating-style profile bio for the product, not longer than 2 lines",
"category": "One-word category",
"tags": ["tag1", "tag2"]
}
"""
response = genai_client.models.generate_content(
model="gemini-3-flash-preview",
contents=[types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg"), prompt],
config=types.GenerateContentConfig(response_mime_type="application/json")
)

실시간 인데이터베이스 삽입

AlloyDB의 가장 멋진 기능 중 하나는 SQL 컨텍스트를 벗어나지 않고 임베딩을 생성할 수 있다는 것입니다. Python에서 임베딩 모델을 호출하고 벡터를 DB로 다시 전송하는 대신 embedding() 함수를 사용하여 하나의 INSERT 문으로 모든 작업을 실행합니다.
INSERT INTO items (owner_id, provider_name, provider_phone, title, bio, category, image_url, status, item_vector)
VALUES (
:owner, :name, :phone, :title, :bio, :cat, :url, 'available',
embedding('text-embedding-005', :title || ' ' || :bio)::vector
)
이렇게 하면 게시되는 즉시 모든 항목을 의미로 검색할 수 있습니다. 이 부분은 Neighbor Loop 앱의 '제품 등록' 기능을 다룹니다.

Gemini 3.0을 사용한 고급 벡터 검색 및 스마트 필터링
표준 키워드 검색은 제한됩니다. '의자를 고치는 데 필요한 것'을 검색하면 제목에 '의자'라는 단어가 포함되어 있지 않은 경우 기존 데이터베이스는 아무것도 반환하지 않을 수 있습니다. Neighbor Loop는 AlloyDB AI의 고급 벡터 검색으로 이 문제를 해결합니다.
pgvector 확장 프로그램과 AlloyDB의 최적화된 스토리지를 사용하면 매우 빠른 유사성 검색을 실행할 수 있습니다. 하지만 벡터 근접성과 LLM 기반 논리를 결합하면 진정한 '마법'이 일어납니다.
AlloyDB AI를 사용하면 SQL 쿼리 내에서 Gemini와 같은 모델을 직접 호출할 수 있습니다. 즉, ai.if() 함수를 사용하여 논리 기반 '기본 검사'를 포함하는 시맨틱 검색을 실행할 수 있습니다.
SELECT item_id, title, bio, category, image_url,
1 - (item_vector <=> embedding('text-embedding-005', :query)::vector) as score
FROM items
WHERE status = 'available'
AND item_vector IS NOT NULL
AND ai.if(
prompt => 'Does this text: "' || bio ||'" match the user request: "' || :query || '", at least 60%? "',
model_id => 'gemini-3-flash-preview'
)
ORDER BY score DESC
LIMIT 5
이 쿼리는 주요 아키텍처 변화를 나타냅니다. 로직을 데이터로 이동하고 있습니다. Gemini 3 Flash는 수천 개의 결과를 애플리케이션 코드로 가져와 필터링하는 대신 데이터베이스 엔진 내에서 '분위기 확인'을 실행합니다. 이렇게 하면 지연 시간이 줄어들고 이그레스 비용이 낮아지며 결과가 수학적으로 유사할 뿐만 아니라 맥락상 관련성이 있습니다.

'스와이프하여 매칭' 루프
UI는 클래식 카드 덱입니다.
왼쪽으로 스와이프: 삭제
오른쪽으로 스와이프: 매칭되었습니다.

오른쪽으로 스와이프하면 백엔드에서 스와이프 표에 상호작용을 기록하고 항목을 일치로 표시합니다. 프런트엔드에서 즉시 제공업체의 연락처 정보가 표시된 모달을 트리거하므로 픽업을 준비할 수 있습니다.
8. Cloud Run에 배포해 보겠습니다.
- 프로젝트가 클론되고 프로젝트의 루트 폴더 내에 있는지 확인한 Cloud Shell 터미널에서 다음 명령어를 실행하여 Cloud Run에 배포합니다.
Cloud Shell 터미널에서 다음을 실행합니다.
gcloud beta run deploy neighbor-loop \
--source . \
--region=us-central1 \
--network=<<YOUR_NETWORK_NAME>> \
--subnet=<<YOUR_SUBNET_NAME>> \
--allow-unauthenticated \
--vpc-egress=all-traffic \
--set-env-vars GEMINI_API_KEY=<<YOUR_GEMINI_API_KEY>>,DATABASE_URL=postgresql+pg8000://postgres:<<YOUR_PASSWORD>>@<<PRIVATE_IP_HOST>>:<<PORT>>/postgres,GCS_BUCKET_NAME=<<YOUR_GCS_BUCKET>>
자리표시자 <<YOUR_GEMINI_API_KEY>>, <<YOUR_PASSWORD>, <<PRIVATE_IP_HOST>>, <<PORT>> and <<YOUR_GCS_BUCKET>>의 값을 바꿉니다.
명령어가 완료되면 서비스 URL이 출력됩니다. 복사합니다.
- Cloud Run 서비스 계정에 AlloyDB 클라이언트 역할을 부여합니다.이렇게 하면 서버리스 애플리케이션이 데이터베이스로 안전하게 터널링할 수 있습니다.
Cloud Shell 터미널에서 다음을 실행합니다.
# 1. Get your Project ID and Project Number
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
# 2. Grant the AlloyDB Client role
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
--role="roles/alloydb.client"
이제 서비스 URL (앞서 복사한 Cloud Run 엔드포인트)을 사용하여 앱을 테스트합니다. 오래된 전동 공구의 사진을 업로드하면 Gemini가 나머지를 처리합니다.
주의사항 및 문제 해결
'수정 실패' 루프 | 배포가 완료되었지만 URL에서 |
IAM '섀도우' 역할 | 사용자에게 배포 권한이 있더라도 Cloud Run 서비스 계정 (일반적으로 |
9. 고급 문제 해결

10. 데모
테스트에 엔드포인트를 사용할 수 있습니다.
하지만 며칠 동안 데모 목적으로 다음을 사용해 볼 수 있습니다.
11. 삭제
이 실습을 완료한 후에는 AlloyDB 클러스터와 인스턴스를 삭제해야 합니다.
인스턴스와 함께 클러스터를 정리해야 합니다.
12. 축하합니다
Google Cloud를 사용하여 지속 가능한 커뮤니티를 위한 Neighbor Loop 앱을 성공적으로 빌드했습니다. Gemini 3 Flash AI 로직과 삽입을 AlloyDB로 이동하면 앱이 매우 빨라지고 (배포 설정에 따라 다름) 코드가 매우 깔끔해집니다. 데이터만 저장하는 것이 아니라 의도를 저장합니다.
Gemini 3 Flash의 속도와 AlloyDB의 최적화된 벡터 처리의 조합은 커뮤니티 기반 플랫폼의 진정한 차세대 기술입니다.