1. 概览
在此 Codelab 中,您将构建 Neighbor Loop,这是一款可持续的剩余物品分享应用,可将智能视为数据层的一等公民。
通过集成 Gemini 3.0 Flash 和 AlloyDB AI,您将超越基本存储,进入数据库智能领域。您将学习如何在 SQL 中直接执行多模态项目分析和语义发现,从而消除延迟和架构臃肿带来的“AI 税”。

构建内容
一款高性能的“滑动配对”Web 应用,用于社区剩余物品分享。
学习内容
- 一键式配置:如何设置专为 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 对图片和文本数据执行亚秒级推理。
- Cloud Run:用于托管轻量级单文件 Flask 后端。
要求
2. 准备工作
创建项目
- 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。
- 确保您的 Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能。
- 您将使用 Cloud Shell,它是在 Google Cloud 中运行的命令行环境。点击 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”,但命令行仍显示 |
配额 Quags | 如果您使用的是全新试用账号,则可能会达到 AlloyDB 实例的区域配额。如果 |
“隐藏”服务代理 | 有时,AlloyDB 服务代理不会自动获得 |
3. 数据库设置
在本实验中,我们将使用 AlloyDB 作为测试数据的数据库。它使用集群来保存所有资源,例如数据库和日志。每个集群都有一个主实例,可提供对数据的访问点。表将包含实际数据。
我们来创建 AlloyDB 集群、实例和表,以便加载测试数据集。
- 点击相应按钮,或将下方的链接复制到已登录 Google Cloud 控制台用户的浏览器中。
- 完成此步骤后,代码库将克隆到本地 Cloud Shell 编辑器,您将能够从项目文件夹中运行以下命令(请务必确保您位于项目目录中):
sh run.sh
- 现在,使用界面(点击终端中的链接或点击终端中的“在网页上预览”链接)。
- 输入项目 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 扩展程序提供用于访问 Vertex AI 预测端点以在 SQL 中获取预测结果的函数。通过运行以下 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 User 角色
在 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 主账号。
- 分配 Storage Object Viewer 角色(以便所有人都能查看照片)和 Storage Object Creator 角色(用于演示上传)。
替代方案(服务账号):如果您不想使用公开访问权限,请确保为应用的服务账号授予对 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 端口,但如果您使用的是 Auth 代理,AlloyDB 有时需要特定的端口配置。在此实验中,请确保您在主机字符串末尾使用 :5432。 |
“已获授权的网络”Gatekeeper | 即使您拥有公共 IP,AlloyDB 也会“拒绝连接”,除非您已将运行代码的机器的 IP 地址列入许可名单。修复:在 AlloyDB 实例设置中,将 0.0.0.0/0(仅用于临时测试!)或您的特定 IP 添加到“已获授权的网络”。 |
SSL/TLS 握手失败 | AlloyDB 首选安全连接。如果您的 DATABASE_网址 未正确指定驱动程序(例如使用 pg8000),握手可能会静默失败,导致您收到“无法访问数据库”这一通用错误。 |
“主池与读取池”交换 | 如果您不小心复制了读取池的 IP 地址而不是主实例的 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 中调用嵌入模型并将向量发送回数据库,而是使用 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 实现高级向量搜索和智能过滤
标准关键字搜索存在限制。如果您搜索“something to fix my chair”,如果某个商品的标题中没有“chair”一词,传统数据库可能不会返回任何结果。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 不会将数千个结果拉入应用代码中进行过滤,而是在数据库引擎内部执行“氛围检查”。这不仅可以缩短延迟时间、降低出站流量费用,还可以确保结果不仅在数学上相似,而且在上下文上相关。

“滑动配对”循环
界面是一个经典的纸牌组。
向左滑动:舍弃。
向右滑动:配对成功!

当您向右滑动时,后端会在滑动次数表中记录相应互动,并将相应商品标记为已配对。前端会立即触发一个模态框,其中显示提供商的联系信息,以便您安排取货。
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>> 的值
命令运行完毕后,系统会输出服务网址。复制。
- 向 Cloud Run 服务账号授予 AlloyDB Client 角色。这样一来,您的无服务器应用就可以安全地通过隧道连接到数据库。
在 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"
现在,使用服务网址(您之前复制的 Cloud Run 端点)测试应用。上传旧电动工具的照片,然后让 Gemini 完成剩下的工作!
注意事项和问题排查
“修订失败”循环 | 如果部署完成,但网址显示 |
IAM“影子”角色 | 即使您有权进行部署,Cloud Run 服务账号(通常为 |
9. 高级问题排查

10. 演示
您应该能够将端点用于测试。
不过,为了演示目的,您可以在几天内尝试以下操作:
11. 清理
完成本实验后,请务必删除 AlloyDB 集群和实例。
它应清理集群及其实例。
12. 恭喜
您已成功使用 Google Cloud 构建了 Neighbor Loop 应用,以打造可持续发展的社区。通过将嵌入和 Gemini 3 Flash AI 逻辑移至 AlloyDB,应用的速度非常快(取决于部署设置),代码也非常简洁。我们不仅存储数据,还存储意图。
Gemini 3 Flash 的速度与 AlloyDB 优化的向量处理能力相结合,真正为社区驱动型平台开创了新局面。