使用 Gemini 3 Flash 和 AlloyDB 构建实时盈余引擎

1. 概览

在此 Codelab 中,您将构建 Neighbor Loop,这是一款可持续的剩余物品分享应用,可将智能视为数据层的一等公民。

通过集成 Gemini 3.0 Flash 和 AlloyDB AI,您将超越基本存储,进入数据库智能领域。您将学习如何在 SQL 中直接执行多模态项目分析和语义发现,从而消除延迟和架构臃肿带来的“AI 税”。

1da27e0c4d9a33e0.jpeg

构建内容

一款高性能的“滑动配对”Web 应用,用于社区剩余物品分享。

学习内容

  • 一键式配置:如何设置专为 AI 工作负载设计的 AlloyDB 集群和实例。
  • 数据库内嵌:直接在 INSERT 语句中生成 text-embedding-005 向量。
  • 多模态推理:使用 Gemini 3.0 Flash“查看”商品,并自动生成诙谐幽默的约会风格个人简介。
  • 语义发现:使用 ai.if() 函数在 SQL 查询中执行基于逻辑的“氛围检查”,以根据上下文(而不仅仅是数学)过滤结果。

架构

Neighbor Loop 可绕过传统的应用层瓶颈。我们不再提取数据进行处理,而是使用:

  1. AlloyDB AI:用于实时生成和存储向量。
  2. Google Cloud Storage:用于存储图片
  3. Gemini 3.0 Flash:直接通过 SQL 对图片和文本数据执行亚秒级推理。
  4. Cloud Run:用于托管轻量级单文件 Flask 后端。

要求

  • 一个浏览器,例如 ChromeFirefox
  • 启用了结算功能的 Google Cloud 项目。
  • 基本熟悉 SQL 和 Python。

2. 准备工作

创建项目

  1. Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目
  2. 确保您的 Cloud 项目已启用结算功能。了解如何检查项目是否已启用结算功能
  1. 您将使用 Cloud Shell,它是在 Google Cloud 中运行的命令行环境。点击 Google Cloud 控制台顶部的“激活 Cloud Shell”。

“激活 Cloud Shell”按钮图片

  1. 连接到 Cloud Shell 后,您可以使用以下命令检查自己是否已通过身份验证,以及项目是否已设置为您的项目 ID:
gcloud auth list
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目。
gcloud config list project
  1. 如果项目未设置,请使用以下命令进行设置:
gcloud config set project <YOUR_PROJECT_ID>
  1. 启用必需的 API:点击链接并启用 API。

或者,您也可以使用 gcloud 命令来完成此操作。如需了解 gcloud 命令和用法,请参阅文档

注意事项和问题排查

“幽灵项目” 综合征

您运行了 gcloud config set project,但实际上在控制台界面中查看的是另一个项目。检查左上角下拉菜单中的项目 ID!

结算 路障

您已启用项目,但忘记了结算账号。AlloyDB 是一款高性能引擎;如果“油箱”(结算)为空,它将无法启动。

API 传播 延迟

您点击了“启用 API”,但命令行仍显示 Service Not Enabled。等待 60 秒。云需要一些时间来唤醒其神经元。

配额 Quags

如果您使用的是全新试用账号,则可能会达到 AlloyDB 实例的区域配额。如果 us-central1 失败,则尝试 us-east1

“隐藏”服务代理

有时,AlloyDB 服务代理不会自动获得 aiplatform.user 角色。如果您的 SQL 查询之后无法与 Gemini 对话,通常是此问题所致。

3. 数据库设置

在本实验中,我们将使用 AlloyDB 作为测试数据的数据库。它使用集群来保存所有资源,例如数据库和日志。每个集群都有一个主实例,可提供对数据的访问点。表将包含实际数据。

我们来创建 AlloyDB 集群、实例和表,以便加载测试数据集。

  1. 点击相应按钮,或将下方的链接复制到已登录 Google Cloud 控制台用户的浏览器中。

  1. 完成此步骤后,代码库将克隆到本地 Cloud Shell 编辑器,您将能够从项目文件夹中运行以下命令(请务必确保您位于项目目录中):
sh run.sh
  1. 现在,使用界面(点击终端中的链接或点击终端中的“在网页上预览”链接)。
  2. 输入项目 ID、集群名称和实例名称等详细信息,即可开始使用。
  3. 在日志滚动时,您可以去喝杯咖啡,然后点击此处了解该功能在后台的运作方式。

注意事项和问题排查

“耐心”问题

数据库集群是重型基础架构。如果您因 Cloud Shell 会话“看起来卡住了”而刷新页面或终止会话,最终可能会得到一个“幽灵”实例,该实例已部分完成预配,但无法在不进行人工干预的情况下删除。

地区不匹配

如果您在 us-central1 中启用了 API,但尝试在 asia-south1 中预配集群,则可能会遇到配额问题或服务账号权限延迟。在整个实验过程中,请坚持使用一个区域!

僵尸集群

如果您之前曾使用过某个集群名称,但未删除该集群,脚本可能会提示该集群名称已存在。集群名称在项目中必须是唯一的。

Cloud Shell 超时

如果您的咖啡休息时间为 30 分钟,Cloud Shell 可能会进入休眠状态并断开 sh run.sh 进程。让标签页保持活跃状态!

4. 架构配置

在 AlloyDB 集群和实例运行后,前往 AlloyDB Studio SQL 编辑器,启用 AI 扩展程序并预配架构。

1e3ac974b18a8113.png

您可能需要等待实例完成创建。完成后,使用您在创建集群时创建的凭据登录 AlloyDB。使用以下数据向 PostgreSQL 进行身份验证:

  • 用户名:“postgres
  • 数据库:“postgres
  • 密码:“alloydb”(或您在创建时设置的任何密码)

成功通过身份验证进入 AlloyDB Studio 后,您可以在编辑器中输入 SQL 命令。您可以使用最后一个窗口右侧的加号添加多个编辑器窗口。

28cb9a8b6aa0789f.png

您将在编辑器窗口中输入 AlloyDB 命令,并根据需要使用“运行”“格式”和“清除”选项。

启用扩展程序

在构建此应用时,我们将使用扩展程序 pgvectorgoogle_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.

注意事项和问题排查

“密码遗忘”循环

如果您使用了“一键”设置,但不记得密码,请前往控制台中的实例基本信息页面,然后点击“修改”以重置 postgres 密码。

“未找到扩展程序”错误

如果 CREATE EXTENSION 失败,通常是因为实例仍处于初始配置时的“维护”或“更新”状态。检查实例创建步骤是否完成,并在需要时等待几秒钟。

IAM 传播差距

您运行了 gcloud IAM 命令,但 SQL CALL 仍然因权限错误而失败。IAM 更改可能需要一段时间才能通过 Google 主干网传播。深呼吸。

向量维度不匹配

items 表设置为 VECTOR(768)。如果您稍后尝试使用其他模型(例如 1536 维模型),则插入操作会失败。坚持 text-embedding-005

项目 ID 拼写错误

create_model 调用中,如果您遗漏了方括号 « » 或错误地输入了项目 ID,模型注册看起来会成功,但在第一次实际查询期间会失败。请仔细检查您的字符串!

5. 图片存储 (Google Cloud Storage)

为了存储剩余物品的照片,我们使用了一个 GCS 存储分区。在此演示应用中,我们希望图片可公开访问,以便它们在滑动卡片中立即呈现。

  1. 创建存储分区在您的 GCP 项目中创建一个新存储分区(例如 neighborloop-images),最好与您的数据库和应用位于同一区域。
  2. 配置公开访问权限: * 前往存储分区的权限标签页。
  3. 添加 allUsers 主账号。
  4. 分配 Storage Object Viewer 角色(以便所有人都能查看照片)和 Storage Object Creator 角色(用于演示上传)。

替代方案(服务账号):如果您不想使用公开访问权限,请确保为应用的服务账号授予对 AlloyDB 的完全访问权限以及管理对象所需的存储角色。

注意事项和问题排查

区域拖动

如果您的数据库位于 us-central1,而存储分区位于 europe-west1,那么您实际上是在拖慢 AI 的速度。“氛围检查”会快速完成,但提取界面所需的图片会感觉很慢。请确保它们位于同一区域!

存储分区名称的唯一性

存储分区名称是全局命名空间。如果您尝试将存储分区命名为 neighborloop-images,则很可能其他人已使用该名称。如果创建失败,请添加随机后缀

“创作者”与“观看者”的混淆

“创建者”与“查看者”混淆:如果您只添加了“查看者”,那么当用户尝试列出新商品时,应用会因没有写入文件的权限而崩溃。对于此特定演示设置,您需要同时提供这两者。

6. 我们来创建应用

将此代码库克隆到您的项目中,然后我们来逐步了解一下。

  1. 如需克隆此项目,请在 Cloud Shell 终端中(在根目录中或从您要创建此项目的任何位置)运行以下命令:
git clone https://github.com/AbiramiSukumaran/neighbor-loop

这应该会创建项目,您可以在 Cloud Shell 编辑器中验证这一点。

53a398aff6ba7d5b.png

  1. 如何获取 Gemini API 密钥
  2. 访问 Google AI Studio:前往 aistudio.google.com
  3. 登录:使用您用于 Google Cloud 项目的同一 Google 账号。
  4. 创建 API 密钥:
  5. 在左侧边栏中,点击“获取 API 密钥”。
  6. 点击“在新项目中创建 API 密钥”按钮。
  7. 复制密钥:生成密钥后,点击复制图标。
  8. 现在,在 .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 - 每分钟请求数)。如果您在邻居圈中“滑动”得太快,可能会收到 429 Too Many Requests 错误。慢点!

公开密钥安全性

如果您不小心 git commit 了包含密钥的 .env 文件。请务必将 .env 添加到 .gitignore 中。

“连接超时”无效

您在 .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. 我们来检查一下代码

“约会个人资料”

c2c543562cc9b353.png

用户上传商品照片时,无需撰写长篇说明。我使用 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")
)

21f871a1b549efcf.png

实时数据库内嵌

aa783a459f1b02da.png

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

  1. 通过在克隆项目的 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>> 的值

命令运行完毕后,系统会输出服务网址。复制。

  1. 向 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 完成剩下的工作!

注意事项和问题排查

“修订失败”循环

如果部署完成,但网址显示 500 Internal Server Error,请检查日志!这通常是由于缺少环境变量(例如 DATABASE_URL 中存在拼写错误)或 Cloud Run 服务账号缺少从 GCS 存储分区读取数据的权限所致。

IAM“影子”角色

即使有权进行部署,Cloud Run 服务账号(通常为 [project-number]-compute@developer.gserviceaccount.com)也需要 AlloyDB Client 角色才能实际建立与数据库的连接。

9. 高级问题排查

b6cdd3785d5461a9.jpeg

10. 演示

您应该能够将端点用于测试。

不过,为了演示目的,您可以在几天内尝试以下操作:

11. 清理

完成本实验后,请务必删除 AlloyDB 集群和实例。

它应清理集群及其实例。

12. 恭喜

您已成功使用 Google Cloud 构建了 Neighbor Loop 应用,以打造可持续发展的社区。通过将嵌入和 Gemini 3 Flash AI 逻辑移至 AlloyDB,应用的速度非常快(取决于部署设置),代码也非常简洁。我们不仅存储数据,还存储意图

Gemini 3 Flash 的速度与 AlloyDB 优化的向量处理能力相结合,真正为社区驱动型平台开创了新局面。