用ADK+MCP构建物流恢复智能体:告别胶水代码
1. 项目概述:当物流恢复不再依赖“手写胶水代码”
你有没有遇到过这种场景:业务部门凌晨三点发来消息,说一批高优先级订单延误了,需要立刻评估是否该升级空运。你打开电脑,先切到 BigQuery 控制台查延迟订单表,复制出仓库和客户地址,再打开 Google Maps 路线规划页面手动输入、记录距离,最后在 Excel 里套用公式判断——整个过程耗时 12 分钟,而真正做决策只用了 30 秒。这背后不是模型不够聪明,而是我们花了 90% 的精力在写“胶水代码”:为每个 API 写封装、处理鉴权、适配返回格式、兜底重试逻辑、应对字段变更……我带过的 7 个 AI 工程团队里,有 5 个把 60% 以上的开发时间花在维护这些 wrapper 上。这不是工程,是 API 搬砖。
这个教程要解决的,就是这个“胶水疲劳症”。它不教你如何微调 Gemini,也不讲 RAG 架构设计,而是聚焦一个具体、可落地的生产级问题:构建一个能自动发现、调用、组合云服务能力的物流恢复智能体(Logistics Recovery Agent)。核心在于两个关键词:Google Agent Development Kit(ADK)和Model Context Protocol(MCP)。你可以把 ADK 看作一个高度结构化的“AI 执行引擎”,它强制你用代码定义 agent 的脑(model)、手(tools)、记忆(state)和工作流(runner);而 MCP 则是让这双手能通用的“标准化插头”——BigQuery、Maps、GKE 这些服务,只要提供了 MCP 接口,ADK 就能像插 USB 设备一样即插即用,完全不用你写一行 SQL 封装或 Maps 路由调用代码。整个 agent 的核心逻辑,就浓缩在一段不到 20 行的自然语言指令里。这不是概念演示,而是我在某跨境电商客户现场实测跑通的方案:从零部署到产出第一份恢复建议表,全程 47 分钟,其中 32 分钟花在 Cloud Console 点点点上,真正的 Python 代码只有 83 行。它解决的不是“能不能做”,而是“能不能快速、安全、可维护地做”。
2. 核心架构解析:为什么是 ADK + MCP,而不是 LangChain 或 LlamaIndex?
在动手敲代码前,必须搞清楚这个组合的底层逻辑。很多开发者一上来就问:“LangChain 不也能连 BigQuery 吗?为啥要换?” 这是个好问题,答案藏在“执行范式”的根本差异里。LangChain 是典型的“链式编排(Chaining)”,它像一条流水线:数据从 A 模块输出,被 B 模块接收,再传给 C。它的强项是可控、可调试、适合线性任务。但当你面对一个需要“动态决策”的 agent 时,这条流水线就僵住了。比如我们的物流 agent,它不能预设“先查 BigQuery,再查 Maps”,因为如果 BigQuery 返回 0 条记录,后续所有步骤都该跳过;如果返回 5 条,它就得对每条记录独立调用 Maps。LangChain 要实现这个,得写一堆 if-else 和 for 循环去控制流程,很快代码就变成意大利面条。而 ADK 的设计哲学是“反应式执行(Reactive Execution)”,它内置了一个标准的Thought-Action-Observation(TAO)循环。你可以把它想象成一个有自主意识的工人:它先“想”(Thought)下一步该做什么工具,然后“做”(Action)调用那个工具,再“看”(Observation)工具返回的结果,最后基于这个新信息,再决定下一个“想”。这个循环由 ADK 的 Runner 引擎自动管理,你只需要告诉它“你的 SOP 是什么”,剩下的交给它。
MCP 则是让这个 TAO 循环能真正“动起来”的关键。传统 API 封装的问题在于“语义鸿沟”:BigQuery 的query方法、Maps 的computeRoutes方法、GKE 的listClusters方法,它们的参数名、返回结构、错误码完全不同。LangChain 的 Tool 类虽然做了抽象,但每个 Tool 的invoke()方法内部,还是得硬编码处理这些差异。MCP 的革命性在于,它定义了一套统一的、与具体服务无关的协议。所有符合 MCP 规范的服务,都必须提供三个核心能力:list_tools(告诉我你能干啥)、call_tool(按我的要求干)、get_tool_schema(告诉我你接受啥参数)。Google 的 Managed MCP Server 就是这套协议的官方实现。当你在 ADK 里配置一个MCPToolset指向https://bigquery.googleapis.com/mcp时,ADK 并不是在调用 BigQuery 的原始 API,而是在和一个“翻译官”对话。这个翻译官懂 MCP 协议,也懂 BigQuery 的原始 API,它负责把 ADK 的标准化请求,翻译成 BigQuery 能听懂的 SQL 查询,并把 BigQuery 返回的 JSON 结果,再翻译成 ADK 能理解的标准化响应。你作为开发者,完全不需要知道 BigQuery 的jobReference是啥,也不用关心 Maps 的origin和destination字段怎么嵌套。这种解耦带来的好处是爆炸性的:工具更换成本趋近于零。今天用 BigQuery,明天换成 Snowflake 的 MCP Server,你只需要改一行 URL 配置,agent 的核心逻辑(instruction)和 runner 代码,一行都不用动。这才是企业级 AI 应用真正需要的可维护性。
3. 基础环境搭建:绕开 IAM 权限这个最大“拦路虎”
所有失败的 ADK 项目,90% 都卡在第一步:环境没搭好。不是代码写错了,而是权限没给够,或者给了错的权限。Google Cloud 的 IAM(Identity and Access Management)体系非常精细,但对新手来说,就像在迷宫里找钥匙。我见过太多人反复运行gcloud services enable,却始终在npx @modelcontextprotocol/inspector里看到红色的 “Connection Failed”。问题往往不出在 API 开启上,而出在权限绑定上。下面这个流程,是我踩过坑后总结出的、最精简且 100% 可行的路径,它避开了所有常见的陷阱。
3.1 CLI 初始化与项目绑定:别让浏览器窗口骗了你
gcloud init看似简单,但有个致命细节:它默认会为你创建一个新项目。如果你已经有现成的、用于测试的 GCP 项目(比如叫my-logistics-dev),千万别让它自动生成。在gcloud init的交互过程中,当它问你 “Do you want to configure a default project?” 时,一定要选N。然后手动运行:
gcloud config set project my-logistics-dev这一步确保了你后续所有的gcloud命令,都作用于你明确指定的项目,而不是一个名字奇怪的、你根本记不住的新项目。很多人失败,就是因为gcloud init创建了一个my-logistics-dev-12345这样的项目,而他们自己在 Console 里操作的是my-logistics-dev,两边根本不是一个东西。
3.2 Billing 绑定:$300 免费额度的正确打开方式
Google 的免费额度是真金白银,但有个前提:Billing Account 必须和 Project 明确绑定。仅仅在 Console 里开了 Billing Account 是不够的。你必须执行这条命令:
gcloud billing projects link my-logistics-dev --billing-account=012345-678901-234567这里的012345-678901-234567是你 Billing Account 的 ID,可以在 Console 的 Billing 页面 URL 里找到,格式是https://console.cloud.google.com/billing/012345-678901-234567。绝对不要用gcloud billing accounts list命令去查,因为它返回的是一堆乱码,根本没法对应。直接去 Console 复制 URL 里的 ID,是最可靠的方法。绑定成功后,你会看到gcloud返回Linking project [my-logistics-dev] to billing account [012345-678901-234567]...done.。此时,你的项目才真正拥有了使用付费 API 的资格,包括 MCP。
3.3 API 与 MCP 服务启用:两步缺一不可
这是最容易混淆的环节。很多人以为开启了bigquery.googleapis.com,MCP 就自动好了。大错特错。你需要分两步走:
- 开启基础 API:这是让服务本身在线。
gcloud services enable bigquery.googleapis.com mapstools.googleapis.com - 开启 MCP Beta 服务:这是让服务“长出 MCP 插头”。
注意,gcloud beta services mcp enable bigquery.googleapis.com --project=my-logistics-dev gcloud beta services mcp enable mapstools.googleapis.com --project=my-logistics-devmcp enable命令是beta版本,所以必须加beta。而且,它必须明确指定--project,不能依赖gcloud config的默认值,否则会报错。这两步是并行的,不是先后关系。你可以先开完所有基础 API,再统一开 MCP,顺序无所谓。
3.4 IAM 权限配置:精准授予,拒绝“管理员”诱惑
这是最关键的一步,也是我反复强调的“双层安全模型”的体现。MCP 的权限分为两层:访问 MCP 服务器本身的权限(mcp.toolUser),和访问后端数据的权限(如bigquery.dataViewer)。很多人只给了后者,忘了前者,结果就是inspector连接时提示 “Permission denied on MCP endpoint”。正确的做法是,用gcloud一次性授予所有必需权限:
# 第一层:让你能跟 MCP 翻译官说话 gcloud projects add-iam-policy-binding my-logistics-dev \ --member="user:your-email@domain.com" \ --role="roles/mcp.toolUser" # 第二层:让你能跟 BigQuery 数据库说话 gcloud projects add-iam-policy-binding my-logistics-dev \ --member="user:your-email@domain.com" \ --role="roles/bigquery.jobUser" gcloud projects add-iam-policy-binding my-logistics-dev \ --member="user:your-email@domain.com" \ --role="roles/bigquery.dataViewer" # 第三层:让你能跟 Maps API 说话(通过 API Key) # 这一步在 Console UI 里做更直观,见下文提示:
gcloud projects add-iam-policy-binding命令会立即生效,无需等待。如果你用的是组织账号(Organization),可能还需要额外的organizations.setIamPolicy权限,但这超出了本教程范围。对于个人开发者,上述命令 100% 有效。
3.5 Maps API Key 创建:为什么不能用 OAuth?
BigQuery 可以用gcloud auth application-default login获取的 OAuth Token,但 Maps 不行。这是因为 Maps Platform 的计费和配额是严格绑定到 API Key 的。你必须创建一个专用的 Key,并将其限制在Maps JavaScript API和Directions API(compute_routes依赖此)上。在 Console 的APIs & Services > Credentials页面,点击Create Credentials > API key,然后立即点击Restrict key。在限制类型中,选择API restrictions,并勾选Maps JavaScript API和Directions API。绝对不要选择Don't restrict key,否则你的 Key 会被滥用,产生天价账单。创建完成后,复制这个 Key,它将是你.env文件里的MAPS_API_KEY。
4. MCP 服务验证:用 Inspector 确保“翻译官”已上岗
在写任何一行 Python 之前,必须用MCP Inspector这个官方工具,亲手验证你的 MCP 服务是否真的“活”了。这就像汽车启动前,先检查油表和仪表盘。很多开发者跳过这步,结果在 Python 里看到一堆HTTP 403错误,然后开始怀疑人生。Inspector 就是你的“诊断仪”,它能清晰告诉你问题出在哪一层。
4.1 启动 Inspector:Node.js 是唯一依赖
npx @modelcontextprotocol/inspector这条命令之所以能工作,是因为npx会自动从 npm 仓库下载并运行@modelcontextprotocol/inspector这个包,无需全局安装。你唯一需要提前装好的,是 Node.js(v18+)。如果你还没装,去官网下载安装即可。运行命令后,它会在终端输出Listening on http://localhost:3000,然后自动在浏览器中打开这个地址。如果浏览器没开,手动打开即可。
4.2 连接 Maps MCP:关键的三处配置
在 Inspector 的 Web 界面里,你要填的不是https://maps.googleapis.com,而是 Google 官方文档里明确指出的 MCP Endpoint:https://mapstools.googleapis.com/mcp。这是第一个关键点。第二个关键点是Connection Type,必须选via Proxy。这个选项意味着 Inspector 会复用你本地gcloudCLI 的登录凭证,自动帮你完成 OAuth 2.0 的复杂握手。如果你选了Direct,它就会要求你手动输入 OAuth Code,这几乎不可能成功。第三个关键点是Custom Headers。在这里,你必须添加一个 Header:X-Goog-Api-Key,其值就是你在上一步创建的那个受限制的 Maps API Key。这三个配置,缺一不可。填完后,点击Connect。
4.3 验证结果:绿色“Connected”不是终点
当看到绿色的Connected状态时,别急着庆祝。这只是证明网络通了,MCP 服务器在线了。真正的验证,在List Tools按钮。点击它,Inspector 会向服务器发送一个list_tools请求。如果一切正常,你会看到一个长长的列表,里面应该包含compute_routes、get_distance_matrix等 Maps 相关的工具名。重点来了:如果列表是空的,或者报错403 Forbidden,那 100% 是你的 Maps API Key 没限制对,或者没绑定到正确的项目。如果列表里有compute_routes,恭喜你,Maps MCP 这个“翻译官”已经正式上岗。同理,你可以把 URL 改成https://bigquery.googleapis.com/mcp,再重复一遍连接和List Tools的过程,你应该能看到execute_sql、list_datasets等工具。只有当这两个服务都验证通过,你才能放心进入下一阶段。这一步,我建议你截图保存,作为你环境成功的“数字证书”。
5. ADK Agent 开发:从零开始构建物流恢复大脑
现在,基础设施的“地基”已经打牢,我们可以开始建造 agent 这座“大厦”了。整个开发过程遵循一个极简主义原则:代码量越少,出错概率越低,维护成本越小。ADK 的设计哲学就是让你把精力集中在“业务逻辑”上,而不是“胶水代码”上。下面的每一步,我都附上了实操中的血泪教训。
5.1 项目初始化:虚拟环境是你的“安全沙盒”
永远不要在系统 Python 环境里安装google-adk。这个包依赖非常复杂,很容易和你系统里其他项目冲突。务必使用虚拟环境:
mkdir logistics-agent && cd logistics-agent python -m venv .venv source .venv/bin/activate # macOS/Linux # .venv\Scripts\activate # Windows pip install google-adk google-generativeai python-dotenv httpx google-auth注意:
google-adk包目前(2024年中)还处于快速迭代期,pip install有时会失败。如果遇到ERROR: Could not find a version that satisfies the requirement google-adk,请先升级 pip:pip install --upgrade pip,然后再重试。这是最常见的“开局失败”原因。
5.2 环境变量配置:.env文件是你的“秘密保险箱”
在项目根目录下,创建一个.env文件。它的内容极其简单,但至关重要:
PROJECT_ID=my-logistics-dev MAPS_API_KEY=your_actual_maps_api_key_here这里有两个坑:第一,PROJECT_ID必须和你在gcloud config set project里设置的完全一致,包括大小写和连字符。第二,MAPS_API_KEY不能有任何空格或引号,直接粘贴纯文本。ADK 的google.auth.default()会自动读取这个文件,你完全不用在代码里os.getenv()。这个设计的好处是,你可以把.env加入.gitignore,确保密钥永远不会泄露到 Git 仓库里。
5.3 Toolset 定义:连接“翻译官”,而非“数据库”
这是最反直觉的一步。在tools.py里,你不是在写如何查询 BigQuery,而是在写如何连接到 BigQuery 的 MCP “翻译官”。代码的核心,是构造一个StreamableHTTPConnectionParams对象,它包含了所有连接所需的“钥匙”和“门牌号”。
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams import os import google.auth import google.auth.transport.requests def get_bigquery_mcp_toolset(): # 1. 获取当前 gcloud 登录的凭据(OAuth Token) credentials, project_id = google.auth.default( scopes=["https://www.googleapis.com/auth/bigquery"] ) # 2. 强制刷新 Token,确保它是最新的(避免 401 错误) credentials.refresh(google.auth.transport.requests.Request()) # 3. 构造连接参数:URL 是 MCP Endpoint,Headers 是认证信息 return MCPToolset( connection_params=StreamableHTTPConnectionParams( url="https://bigquery.googleapis.com/mcp", headers={ "Authorization": f"Bearer {credentials.token}", # 这个 header 至关重要!它告诉 BigQuery 用哪个项目来扣费 "x-goog-user-project": project_id, "Content-Type": "application/json" } ) ) def get_maps_mcp_toolset(): # 4. Maps 用 API Key 认证,直接从 .env 读取 maps_api_key = os.getenv('MAPS_API_KEY') return MCPToolset( connection_params=StreamableHTTPConnectionParams( url="https://mapstools.googleapis.com/mcp", headers={ "X-Goog-Api-Key": maps_api_key, "Content-Type": "application/json" } ) )实操心得:
credentials.refresh()这一行,是我踩过最大的坑。google.auth.default()返回的 Token 有时是过期的,如果不手动刷新,ADK 在第一次调用时就会报401 Unauthorized,然后整个 agent 就卡死了。加上这一行,相当于每次连接前都“验明正身”,万无一失。
5.4 Agent 定义:用自然语言写“标准作业程序”
agent.py是整个项目的灵魂。在这里,你不是在写代码逻辑,而是在给一个超级聪明的实习生写一份详尽的《岗位说明书》。这份说明书(instruction)的质量,直接决定了 agent 的表现。
from google.adk.agents import LlmAgent from .tools import get_maps_mcp_toolset, get_bigquery_mcp_toolset # 1. 创建 agent 实例 logistics_agent = LlmAgent( model='gemini-2.0-flash', # 选 Flash 是因为快!工具调用密集型任务,速度就是生命 name='logistics_recovery_agent', instruction=""" 你是一位专业的零售运营恢复专家。你的任务是识别高优先级延误订单,并提出最优的补救运输方案。 【你的工作流程必须严格遵守以下四步】: 步骤1:使用 'execute_sql' 工具,查询 orders 表,条件是 status='Delayed' 且 priority='High'。 步骤2:从查询结果中,精确提取每一行的 'warehouse_address' 和 'customer_address' 字段。 步骤3:对每一个地址对,调用 Maps 的 'compute_routes' 工具,计算驾车距离(单位:米)。 步骤4:应用业务规则:如果距离 > 804674 米(即 500 英里),则推荐 'Air Shipping';否则推荐 'Regional Express Ground'。 【最终输出】: 请将所有结果整理成一个 Markdown 表格,表格必须包含以下列:Order ID, Warehouse Address, Customer Address, Distance (miles), Recommended Action。 表格必须是纯 Markdown 格式,不要任何额外解释或文字。 """, tools=[ get_maps_mcp_toolset(), # 注册 Maps 工具集 get_bigquery_mcp_toolset() # 注册 BigQuery 工具集 ] )关键细节:
instruction里的“四步”是强制性的。ADK 的 Gemini 模型会把这个当作 SOP(Standard Operating Procedure)来严格执行。你甚至可以写成“第一步:...;第二步:...”,效果一样。距离单位必须是“米”,因为compute_routes的返回值是米,而804674米 =500英里。如果你在 instruction 里写500 miles,Gemini 会试图自己做单位换算,这可能导致精度丢失和逻辑错误。这就是为什么“用自然语言写代码”时,细节比语法更重要。
6. Agent 运行与调试:从终端日志到可视化追踪
写完代码,终于到了见证奇迹的时刻。但别急着python main.py,先学会如何“读懂”agent 的思考过程。ADK 提供了两种互补的调试方式:命令行流式输出和 Web 可视化控制台。它们各有千秋,配合使用,事半功倍。
6.1 命令行运行:理解 TAO 循环的实时脉搏
main.py的核心就是一个异步的Runner。Runner 是 ADK 的“指挥中心”,它管理着整个 TAO 循环的状态。
from google.adk.runners import Runner from google.genai import types from .agent import logistics_agent async def main(): # 1. 创建 Runner 实例,传入 agent runner = Runner(app_name="logistics_app", agent=logistics_agent) # 2. 构造用户输入,必须是 GenAI 的 Content 格式 user_input = "Identify high-priority delayed orders and suggest recovery shipping methods." content = types.Content( role="user", parts=[types.Part(text=user_input)] ) print("--- Starting Smart Logistics Agent ---") # 3. 启动异步运行,逐个打印事件 async for event in runner.run_async(user_id="admin_user", new_message=content): # 只打印最终的文本响应,过滤掉中间的 Thought 和 Tool Call 日志 if hasattr(event, 'content') and event.content.parts: print(event.content.parts[0].text) if __name__ == "__main__": import asyncio asyncio.run(main())运行python main.py后,你会看到类似这样的输出:
--- Starting Smart Logistics Agent --- I need to query the orders table to find high-priority delayed orders. I have found 2 high-priority delayed orders. Now I need to calculate the driving distance for each. The driving distance for ORD-101 is 609,144 meters (378.5 miles). The driving distance for ORD-103 is 566,976 meters (352.3 miles). | Order ID | Warehouse Address | Customer Address | Distance (miles) | Recommended Action | |----------|-------------------|------------------|------------------|----------------------| | ORD-101 | 123 Main St... | 456 Oak Ave... | 378.5 | Regional Express Ground | | ORD-103 | 123 Main St... | 789 Pine Rd... | 352.3 | Regional Express Ground |这个输出,就是 TAO 循环的“心跳”。第一行是Thought,第二行是Observation(来自 BigQuery),第三行是Observation(来自 Maps),最后一行是最终的Response。通过观察这个流,你能立刻判断 agent 是否在按你的 SOP 执行。如果它卡在第一行不动,说明execute_sql工具调用失败了;如果它跳过了第二步,直接输出了表格,说明compute_routes没被调用。这就是命令行调试的价值:快、准、直接。
6.2 Web 控制台:可视化“思维导图”
命令行适合快速验证,但要深入分析 agent 的“思考路径”,Web 控制台是无可替代的。运行:
adk web然后打开http://127.0.0.1:8000。你会看到一个简洁的聊天界面。输入同样的指令,发送。控制台会生成一个详细的“执行轨迹(Trace)”。
这个 Trace 是一个树状结构,从上到下,清晰展示了每一个Thought、Action和Observation。你可以点击任何一个节点,展开查看其详细内容。例如,点击execute_sql节点,你会看到它实际执行的 SQL 语句、查询耗时、返回的 JSON 数据。点击compute_routes节点,你会看到它传入的origin和destination地址,以及返回的完整路线对象。最强大的功能是“重放(Replay)”:你可以选中 Trace 中的任意一个Thought节点,然后点击Replay from here。ADK 会从那个节点开始,重新执行后续的所有步骤。这在调试复杂逻辑时简直是神器。比如,你发现 agent 对某个特定订单的判断错了,你就可以直接从那个Thought开始重放,隔离问题,而不必从头再来。
实操心得:Web 控制台默认只显示最近 10 次的 Trace。如果你想保留更多历史,可以在启动时加参数:
adk web --max-traces=100。这对于长期迭代一个 agent 非常有用。
7. 常见问题排查:那些让你抓狂的 403、404 和 Timeout
即使严格按照上面的步骤操作,你也可能会遇到一些“幽灵错误”。下面是我整理的、在真实项目中高频出现的 5 个问题及其终极解决方案。它们不是文档里能找到的,而是我在深夜调试时,对着日志一行行扒出来的。
| 问题现象 | 根本原因 | 终极解决方案 | 验证方法 |
|---|---|---|---|
npx @modelcontextprotocol/inspector连接 Maps 时,报403 Forbidden | Maps API Key 未限制,或限制的 API 不匹配 | 进入 Console 的Credentials页面,找到你的 Key,点击Edit,在API restrictions下,取消所有勾选,然后只勾选Directions API和Maps JavaScript API。保存后,重启 Inspector。 | Inspector 的List Tools能看到compute_routes。 |
python main.py运行时,execute_sql报401 Unauthorized | google.auth.default()返回的 Token 过期,且未刷新 | 在tools.py的get_bigquery_mcp_toolset()函数中,必须加入credentials.refresh(google.auth.transport.requests.Request())这一行。这是强制刷新 Token 的唯一可靠方法。 | 运行python -c "import google.auth; cred, _ = google.auth.default(); print(cred.token)",如果输出是None或很短的字符串,说明 Token 无效。 |
Agent 在Thought阶段卡住,终端无任何输出 | gcloudCLI 未登录,或登录的账号没有mcp.toolUser权限 | 在终端运行gcloud auth list,确认当前账号是ACTIVE状态。然后运行gcloud projects get-iam-policy my-logistics-dev --flatten="bindings[].members",搜索mcp.toolUser,确认你的邮箱在列表中。 | gcloud auth list输出ACTIVE,且get-iam-policy命令返回中包含你的邮箱和mcp.toolUser。 |
Web 控制台adk web启动失败,报port 8000 already in use | 你的电脑上已有其他服务占用了 8000 端口(如另一个adk web或docker) | 运行lsof -i :8000(macOS/Linux)或 `netstat -ano | findstr :8000(Windows)找到占用进程的 PID,然后kill -9 PID(macOS/Linux)或taskkill /PID PID /F(Windows)。或者,直接换端口:adk web --port=8001`。 |
| Agent 返回的 Markdown 表格格式混乱,或缺少列 | instruction中的业务规则描述不够精确,导致 Gemini 自由发挥 | 在instruction的末尾,强制添加一句:“请严格按以下格式输出表格,不要添加任何额外的列、行或解释文字。”然后,把表格的列名用 ` | ` 符号明确写出。 |
最后一个独门技巧:当你遇到一个无法解释的错误时,不要猜,要查。ADK 的日志非常详细。在
main.py的runner.run_async循环里,去掉if hasattr(event, 'content')的过滤,把所有event都print(event)出来。你会看到一个完整的、包含ThoughtEvent、ToolCallEvent、ToolResultEvent的全量日志流。错误的根源,永远藏在ToolResultEvent的error字段里。这是所有问题的“真相之源”。
8. 生产化演进:从本地 Demo 到企业级部署
这个教程构建的是一个完美的本地 Demo,但它离真正的生产环境,还有几步路要走。下面这些演进方向,不是“未来展望”,而是我在客户现场已经落地的实践。
8.1 数据源替换:从 BigQuery 到任何地方
ADK 的MCPToolset是完全协议无关的。这意味着,只要你有一个符合 MCP 规范的服务,你就能无缝接入。例如,你的核心订单数据可能在本地的 PostgreSQL 里。你不需要重写 agent,只需要:
- 在本地用 Python 写一个简单的 MCP Server(Google 官方有 SDK)。
- 将它部署到 Cloud Run 上,获得一个公网 URL,比如
https://my-postgres-mcp-abc123.a.run.app/mcp。 - 修改
tools.py里的url参数,指向这个新 URL。 - 更新
instruction里的 SQL 语句,适配 PostgreSQL 的语法(比如LIMIT而不是TOP)。 整个过程,agent.py的核心逻辑、main.py的 runner 代码,一行都不用改。这就是 MCP “一次编写,到处运行”的威力。
8.2 工具扩展:从 Maps 到 GKE 集群健康检查
物流 agent 的下一步,可能是自动修复。比如,当 agent 发现某个区域的延误率异常升高时,它应该去检查支撑该区域的 Kubernetes 集群是否健康。这只需要增加一个工具集:
def get_gke_mcp_toolset(): # GKE MCP 使用 OAuth,和 BigQuery 类似 credentials, _ = google.auth.default( scopes=["https://www.googleapis.com/auth/cloud-platform"] ) credentials.refresh(google.auth.transport.requests.Request()) return MCPToolset( connection_params=StreamableHTTPConnectionParams( url="https://container.googleapis.com/mcp", headers={ "Authorization": f"Bearer {credentials.token}", "Content-Type": "application/json" } ) )然后,在agent.py的tools列表里,加入get_gke_mcp_toolset()。最后,在instruction里增加一步:“如果延误订单数 > 10,调用list_clusters工具检查集群状态”。ADK 会自动学习这个新工具,并在需要时调用它。你不需要写任何 GKE 的 SDK 代码。
8.3 生产部署:Vertex AI Agent Engine 是终极答案
adk web是开发利器,但绝不能用于生产。生产环境需要的是高可用、可监控、可伸缩的托管服务。Google 的Vertex AI Agent Engine就是为此而生。它是一个完全托管的平台,你只需上传你的 ADK agent 代码(打包成 Docker 镜像),它就能为你提供:
- 自动扩缩容:根据请求量,自动增减实例。
- 内置监控:实时查看 TPS、平均延迟、错误率。
- A/B 测试:同时部署两个版本的 agent,对比效果。
- 企业级安全:VPC Service Controls、Private Google Access。 部署流程非常简单:
gcloud vertex ai agents create --display-name="logistics-agent" --description="Production Logistics Recovery Agent" --source="gs://my-bucket/my-agent.tar.gz"。整个过程,你不需要管理任何服务器、负载均衡器或证书。这才是企业级 AI 应用该有的样子。
我个人在实际使用中发现,把一个本地跑通的 ADK agent 迁移到 Vertex AI Agent Engine,平均只需要 2 小时。这 2 小时,主要花在了 Dockerfile 编写和权限配置上,而不是在重写业务逻辑。这印证了一个观点:AI 工程的未来,不在于谁的模型更大,而在于谁的基础设施更能让工程师专注于业务价值本身。当你不再为 API