☰
构建一个 Agent 只要三分钟,但为什么大多数企业的 Agent 还停留在 Demo 阶段?TaoToken 视角下的 ADK + Gemini + Cloud Run 落地拆解
2026/10/12 15:42:54 网站建设 项目流程

1. 三分钟造 Agent 之后,企业卡在哪:ADK + Gemini + Cloud Run 落地断层

构建一个 Agent 只要三分钟,这句话在 2026 年已经不算夸张。用 ADK 写一个LlmAgent,挂上 Gemini 的模型端点,本地adk web一跑,对话、工具调用、多轮记忆全都有了。问题从来不在“能不能跑起来”,而在“跑起来之后怎么办”。我见过太多团队,Demo 演示时全场鼓掌,一到要接真实业务系统、要过安全审计、要控成本、要多人协作,整个项目就停在原地。

这道断层不是单点问题。它是治理、运行时、安全、可观测性、数据这五件事叠在一起的结果。Demo 阶段你只需要一个能回答问题的模型;生产阶段你需要知道这个 Agent 是谁、能访问什么、花了多少钱、出错时怎么回滚、记忆存在哪、被提示词注入攻击时谁来拦。这些能力没有一个是模型自带的,全部要靠工程化配置补齐。

这篇拆解聚焦一条可跟做的主线:用 ADK 做编排,用 Gemini 做推理,用 Cloud Run 做部署,中间通过 MCP 接入工具,通过统一的 Key/API 通道管理模型访问。我会给出可复制的项目骨架、部署清单、MCP 注册示例,以及本地到云端的端到端验证动作。适合正在把 Agent 从个人玩具推向企业服务的开发者,也适合需要给团队定一套 Agent 工程规范的架构同学。

先说清楚一个认知:Agent 不是一个 API 调用,它是一个有状态的、长时间运行的、需要人机协同的计算过程。你把它当无状态函数部署,就一定会在生产环境翻车。下面按落地顺序拆。

2. TaoToken 前置:统一 Key 与 API 通道,别让模型访问散落在每个人手里

在讲 ADK 代码之前,必须先解决一个企业里最常见、也最容易被忽视的问题:模型访问凭证的管理。Demo 阶段每个人本地export GEMINI_API_KEY=xxx,跑得挺爽。等到十个 Agent、五个环境、三个团队同时用,你会发现密钥散落在.env、CI 变量、同事的聊天记录里,谁在用哪个 Key、花了多少、该不该吊销,完全说不清。

我的做法是引入一个统一的模型访问通道,把所有 Agent 的模型请求收敛到一个入口。TaoToken 在这里扮演的就是这个角色:它提供兼容 OpenAI 风格的 API 端点,同时支持 Gemini 等模型的调用,你只需要维护一套 Key,就能让 ADK、Cline、Codex 这些不同工具走同一个通道。官网在 https://taotoken.net ,API 端点是 https://taotoken.net/api ,注意 API 地址不带任何查询参数。

为什么要在 ADK 项目里做这件事?因为 ADK 的模型层是可替换的。你可以在LlmAgent里指定model,底层通过 LiteLLM 或自定义BaseLlm适配器接入任意兼容端点。把 Base URL 指向统一通道后,你获得三个直接好处:第一,密钥只有一处,轮换和吊销一次搞定;第二,所有模型的 Token 消耗、延迟、错误率可以集中观测;第三,切换模型不用改业务代码,改配置就行。

具体到配置,ADK 支持通过环境变量注入模型端点。你需要在项目根目录建一个.env文件,把模型访问信息写进去。这里给出一个可复制的模板,路径是项目根目录的.env:

# .env —— ADK 项目模型访问配置 TAOTOKEN_API_KEY=sk-your-unified-key-here TAOTOKEN_BASE_URL=https://taotoken.net/api ADK_MODEL=gemini-2.5-flash

然后在 ADK 的 Agent 定义里,通过自定义Llm或 LiteLLM 适配器读取这些变量。如果你用的是 ADK 2.0 的 Graph 工作流,模型配置可以下沉到每个节点,但 Base URL 和 Key 建议全局统一。这样做的工程意义在于:当企业要审计“哪个 Agent 调了哪个模型、花了多少”时,你有一个天然的收敛点,而不是去十个地方捞日志。

对于需要长期跑编码类 Agent 的团队,可以考虑 Coding Plan 这类按周期计费的通道,把成本从“按 Token 不可预测”变成“按周期可预算”。入口在 https://taotoken.net/coding-plan 。模型对话调试入口在 https://taotoken.net/models ,API Key 管理在 https://taotoken.net/api-keys ,接入文档在 https://taotoken.net/doc 。这些地址建议在团队内部文档里统一维护,避免每个人各记一套。

这里要强调一个安全原则:统一通道不等于把生产库直连出去。MCP 工具接入生产数据库时,必须走只读账号、字段脱敏、审批流,通道只负责模型访问的收敛,不负责替你兜底数据权限。这两件事要分开设计。

3. 可复制配置:ADK 项目骨架 + Cloud Run 部署清单 + MCP 注册示例

这一节是全文的技术核心,给出可以直接抄的配置。先看 ADK 项目骨架。一个能上生产的最小 ADK 项目,目录结构建议这样组织:

agent-project/ ├── app/ │ ├── __init__.py │ ├── agent.py # Agent 定义与编排 │ ├── tools.py # 本地工具函数 │ └── mcp_config.py # MCP 服务注册 ├── .env # 模型访问配置(不入库) ├── requirements.txt ├── Dockerfile └── cloudbuild.yaml # Cloud Run 部署清单

agent.py里定义主 Agent。ADK 的核心是LlmAgent,你可以把它理解为一个“带工具和记忆的模型封装”。下面是一个可运行的骨架:

# app/agent.py import os from google.adk.agents import LlmAgent from google.adk.models.lite_llm import LiteLlm from app.tools import query_order_status from app.mcp_config import build_mcp_tools # 通过统一通道接入模型,Base URL 与 Key 从环境变量读取 model = LiteLlm( model=os.environ.get("ADK_MODEL", "gemini-2.5-flash"), api_base=os.environ["TAOTOKEN_BASE_URL"], api_key=os.environ["TAOTOKEN_API_KEY"], ) root_agent = LlmAgent( name="customer_service_agent", model=model, instruction=( "你是企业客服助手。查询订单必须调用工具," "涉及退款必须走审批流程,禁止直接承诺退款金额。" ), tools=[query_order_status, *build_mcp_tools()], )

tools.py放本地工具,注意每个工具都要有清晰的 docstring,因为 ADK 会把 docstring 作为工具描述喂给模型:

# app/tools.py def query_order_status(order_id: str) -> dict: """根据订单号查询订单状态。 Args: order_id: 订单编号,格式为 ORD 开头加数字。 Returns: 包含 status 和 updated_at 的字典。 """ # 实际项目替换为真实查询逻辑,注意使用只读账号 return {"status": "shipped", "updated_at": "2026-01-01T10:00:00Z"}

MCP 服务注册是这一节的重点。MCP 让 Agent 能以标准协议接入外部工具服务,而不是把每个工具都写成 Python 函数。mcp_config.py里用 JSON 描述 MCP Server 的连接方式:

# app/mcp_config.py import json from google.adk.tools.mcp_tool import MCPToolset MCP_SERVERS = { "mcpServers": { "order_service": { "command": "npx", "args": ["-y", "@your-org/order-mcp-server"], "env": { "ORDER_DB_READONLY_URL": "${ORDER_DB_READONLY_URL}" } }, "knowledge_base": { "url": "https://mcp.internal.example.com/kb", "headers": {"Authorization": "Bearer ${KB_MCP_TOKEN}"} } } } def build_mcp_tools(): tools = [] for name, cfg in MCP_SERVERS["mcpServers"].items(): tools.append(MCPToolset.from_config(name, cfg)) return tools

注意这里的环境变量占位符${ORDER_DB_READONLY_URL},生产环境通过 Cloud Run 的 Secret Manager 注入,绝不硬编码。MCP Server 连接生产库时,务必用只读凭证,写操作走独立的审批 Agent。

接下来是 Cloud Run 部署清单。Dockerfile用官方 Python 基础镜像即可:

FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app ./app ENV PORT=8080 CMD ["adk", "api_server", "--host", "0.0.0.0", "--port", "8080"]

cloudbuild.yaml给出部署参数,重点是内存、并发和超时。Agent 是有状态的长时任务,超时不能按普通 API 设:

steps: - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/agent-service', '.'] - name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/$PROJECT_ID/agent-service'] - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: - 'run' - 'deploy' - 'agent-service' - '--image=gcr.io/$PROJECT_ID/agent-service' - '--region=asia-east1' - '--memory=2Gi' - '--cpu=2' - '--concurrency=20' - '--timeout=900' - '--min-instances=1' - '--set-secrets=TAOTOKEN_API_KEY=taotoken-key:latest' - '--set-env-vars=TAOTOKEN_BASE_URL=https://taotoken.net/api,ADK_MODEL=gemini-2.5-flash'

--timeout=900是 15 分钟,因为 Agent 处理长任务时可能等待工具调用或人工审批。--min-instances=1避免冷启动导致首请求超时,代价是常驻一个实例,按预算权衡。--concurrency=20控制单实例并发,太高会让内存状态互相干扰。

如果你用 Cline 或 Claude Code 这类工具做本地开发,配置三件套是 Base URL、Key、Model ID。以 Cline 的 MCP 配置为例,在cline_mcp_settings.json里写:

{ "mcpServers": { "taotoken-gateway": { "command": "npx", "args": ["-y", "mcp-remote", "https://taotoken.net/api"], "env": { "API_KEY": "sk-your-key", "MODEL_ID": "gemini-2.5-flash" } } } }

Codex 用户则在~/.codex/auth.json里配置:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-your-key", "model": "gemini-2.5-flash" }

这三件套缺一不可:Base URL 决定请求打到哪,Key 决定身份,Model ID 决定用哪个模型。任何一处写错,都会在验证阶段报错,下一节会讲怎么排查。

4. 验证请求:从本地 adk web 到 Cloud Run 端到端跑通

配置写完不算完,必须验证。验证分三层:本地单 Agent、本地带 MCP 工具、云端部署后远程调用。每一层都有明确的成功标志,不要跳步。

第一层,本地跑通基础 Agent。在项目根目录执行:

adk web --port 8000

浏览器打开http://localhost:8000,你会看到 ADK 的调试界面。输入“帮我查一下订单 ORD12345 的状态”,如果 Agent 正确调用了query_order_status工具并返回状态,说明模型通道和工具注册都通了。这一步的成功标志是:界面里能看到工具调用记录,而不只是模型直接编一个答案。

第二层,验证 MCP 工具接入。在调试界面输入一个必须走 MCP Server 的问题,比如“知识库里关于退货政策的说明是什么”。如果 Agent 通过knowledge_base这个 MCP Server 拿到了内容,说明 MCP 注册配置正确。这一步常见的失败是 MCP Server 启动超时,表现为 Agent 一直转圈然后报工具不可用。排查方法是单独在终端跑一遍 MCP Server 的启动命令,确认它能独立起来。

第三层,云端验证。部署完成后,拿到 Cloud Run 的服务 URL,用 curl 发一个请求:

curl -X POST https://agent-service-xxxx.run.app/run \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $(gcloud auth print-identity-token)" \ -d '{ "session_id": "test-001", "message": "查询订单 ORD12345 状态" }'

成功返回应该是一个 JSON,包含 Agent 的回复和工具调用轨迹。如果返回 401,说明身份令牌有问题;如果返回 500 且日志里出现local proxy failed,说明模型通道的 Base URL 或 Key 没注入成功;如果日志里出现reading choices相关错误,通常是模型返回格式和适配器预期不一致,检查 Model ID 是否写对。

端到端验证的完整动作链是:本地adk web通过 → 本地 MCP 工具调用通过 → Cloud Run 部署成功 → 远程 curl 返回正确结果 → 在统一通道的用量面板看到这次请求的 Token 消耗。五步全过,才算真正从 Demo 走到了可运行的生产雏形。

这里补一个实测经验:Cloud Run 首次部署后,第一个请求往往因为冷启动慢,容易误判为失败。建议部署后先发一个预热请求,或者设--min-instances=1。另外,ADK 的 session 状态默认存在内存里,多实例部署时会出现“同一个会话打到不同实例、上下文丢失”的问题。生产环境要把 session 存储外置到 Firestore 或 Redis,这是从单实例 Demo 到多实例生产必须补的一课。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth 逐条对照

这一节把上面提到的报错集中拆开,每条给出真实表现、根因和修复动作。这些是我在把 Agent 推上 Cloud Run 过程中反复踩过的坑,按出现频率排序。

401 Unauthorized。表现是请求直接被拒,日志里明确写 401。根因有三类:Key 没注入、Key 过期、Key 和 Base URL 不匹配。排查顺序是先确认 Cloud Run 的 Secret 挂载成功,用gcloud run services describe看环境变量;再确认 Key 本身有效,在 API Keys 管理页重新生成一个测试;最后确认 Base URL 写的是https://taotoken.net/api,没有多余斜杠或路径。注意 API 地址不要带 UTM 参数,带了某些网关会拒绝。

local proxy failed。这个报错通常出现在本地开发或 Cloud Run 容器内,含义是模型适配器尝试连接 Base URL 时失败了。根因多是网络出口问题或 Base URL 拼写错误。先curl一下 Base URL 看能不能通,再检查.env里有没有多余空格。容器环境里还要确认 Cloud Run 的出口网络策略允许访问外部 API。

reading choices 相关错误。表现是模型返回了内容,但适配器解析时报reading 'choices'或类似字段缺失。根因是返回格式和 OpenAI 兼容格式不一致,常见于 Model ID 写错、或者用了不支持该格式的端点。修复动作是确认 Model ID 在通道支持列表里,并检查请求是否真的打到了兼容端点。如果用的是 Gemini 原生格式而非兼容格式,适配器要相应调整。

OAuth 相关报错。如果你用 Claude Code 或类似工具,可能遇到 OAuth 令牌过期或 scope 不足。表现是工具能启动但调用模型时被拒。修复是重新走一遍授权流程,确认令牌覆盖了模型调用所需的 scope。Codex 用户检查auth.json里的字段是否完整,特别是base_url和api_key是否同时存在。

MCP Server 启动失败。表现是 Agent 报工具不可用,但模型本身正常。根因是 MCP Server 的启动命令在容器里跑不起来,常见于npx找不到包或环境变量缺失。修复是在 Dockerfile 里预装 MCP Server 依赖,别依赖运行时npx下载。生产环境建议把 MCP Server 也容器化,和 Agent 一起部署。

会话上下文丢失。表现是同一个 session_id 第二次请求时 Agent 不记得上一轮。根因是 session 存在内存里,多实例或实例重启后丢失。修复是把 session 存储外置,ADK 支持配置外部 session service,指向 Firestore 或 Redis。

排查的通用方法是看三层日志:Cloud Run 的请求日志、ADK 的应用日志、统一通道的调用日志。三层对时间戳,能快速定位是网络、配置还是模型侧的问题。别一上来就改代码,先确认请求到底打到哪了。

6. 语义一致 CTA:把 Agent 推上生产,从统一通道和可复制骨架开始

回到开头那个问题:为什么大多数企业的 Agent 还停留在 Demo 阶段?因为 Demo 只需要模型能回答,生产需要身份、权限、审计、网关、沙箱、记忆、可观测性、模拟评测和数据飞轮。这些东西没有一个是三分钟能搞定的,但每一个都可以用可复制的配置逐步补齐。

这篇给出的路径是:用 ADK 做编排骨架,用 Gemini 做推理,用 Cloud Run 做部署,用 MCP 接工具,用统一通道收敛模型访问。你可以先把本地adk web跑通,再把 MCP 工具接上,然后按那份cloudbuild.yaml部署到 Cloud Run,最后用 curl 做端到端验证。每一步都有明确的成功标志,不通过就不往下走。

需要统一模型访问通道的,可以从 API Keys 管理入口开始:https://taotoken.net/api-keys ,接入文档在 https://taotoken.net/doc ,模型对话调试在 https://taotoken.net/models 。如果团队要长期跑编码类 Agent,Coding Plan 入口在 https://taotoken.net/coding-plan 。把这些地址和上面的配置模板一起放进团队文档,比每个人各配一套要省心得多。

最后留一个我自己的判断:Agent 从 Demo 到生产,缺的从来不是更聪明的模型,而是把模型当基础设施来管理的工程纪律。先把通道收敛、把配置外置、把验证做全,再谈优化和规模化。这三件事做完,你的 Agent 才算真正离开了 Demo 阶段。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询