ADK A2A 协议远程智能体接入:从零到一的智能体互通实战指南
【免费下载链接】adk-docsAn open-source, code-first toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-docs
如果你有多个 ADK 智能体分布在不同的进程里需要互相调用,A2A 协议就是标准的打通方式。本文用三步从暴露到消费跑通链路,并解决端口冲突、agent 卡片缺失这类高频坑。
先跑起来(Quick Start)
仓库里有一个现成的 Go 示例 examples/go/a2a_basic,直接启动一个远端 A2A 服务:
export GOOGLE_API_KEY=你的模型Key cd examples/go/a2a_basic/remote_a2a/check_prime_agent go run main.go # 启动 A2A 服务,端口 8001 curl http://localhost:8001/.well-known/agent-card.json跑完你会看到go run打出Starting A2A prime checker server on port 8001,而最后那条curl会返回一份 JSON 智能体卡片,里面带name、skills、url三个字段。卡片能取到,就说明这个智能体已经"开门营业",可以被其他智能体调用了。Python 版本则是pip install google-adk[a2a]后用to_a2a()加uvicorn起服务,下文实操部分会展开。
它到底在干什么(A2A 原理拆解)
问题:你的客服智能体跑在自己的服务里,库存智能体是另一个团队维护、跑在另一个进程里。直接 import 对方的代码?对方的任何接口改动都会让你跟着崩,而且根本拿不到人家的源码。
方案:给库存智能体加一层 A2A Server,把它"我是谁、会干什么"写成一份固定地址可访问的智能体卡片(agent card);调用方只需要知道这张卡片的 URL。
机制:ADK 把这件事拆成两个组件。服务提供方用to_a2a()把现成的 Agent 包成一个 Starlette 应用,自动生成智能体卡片——从你的 Agent 配置里提取 description、工具和技能,挂在.well-known/agent-card.json这个约定地址下;消费方用RemoteA2aAgent指向卡片 URL,ADK 会自动拉取卡片、完成网络请求、事件序列化和格式转换。对你的 root agent 来说,它只是sub_agents列表里多了一个成员。
智能体卡片就像门店的招牌加营业时间:顾客不需要知道仓库内部怎么运转,照着招牌上的地址下单就行。
顺带一提,ADK 的 A2A 集成还内置了三个能力:透传模型的推理轨迹(Reasoning)、追踪超长耗时工具调用避免超时、在智能体之间传递文件产物(Artifacts)。
选型对比——什么时候用 A2A,什么时候别用
| 维度 | 本地子智能体(sub_agents) | RemoteA2aAgent(A2A) | 自写 REST API + tool 函数 |
|---|---|---|---|
| 部署复杂度 | 最低,同一进程 | 中,远端需单独跑 A2A 服务 | 中高,接口需自己定义和维护 |
| 延迟 | 内存内调用,最低 | 多一跳网络,毫秒到秒级 | 与 A2A 相当,但鉴权错误处理全靠自己 |
| 适用团队规模 | 单人或同一团队 | 多团队、跨组织协作 | 小规模、固定对接两三个服务 |
| 语言要求 | 与宿主同语言 | 跨语言:Python/Go/Java/Kotlin 均支持 | 任意语言,但接口是私有约定 |
几个判断句:如果你的协作只是"把一个应用内的任务拆成模块",直接写本地子智能体;如果远端智能体由别的团队维护,或用不同语言编写(比如 Python 主智能体接 Java 库存服务),选 A2A;如果只是临时对接一个现成 HTTP 服务、对方又不打算改造成 A2A,先用 tool 函数包一层 REST,等对接面变大再迁移。
明确不适合的情况:高频低延迟的内部调用、子智能体需要直接读写主智能体内存状态的场景——序列化和网络开销会让 A2A 变成负资产。
动手实践:从 A2A 暴露到消费
Step 1:用 to_a2a() 暴露智能体
from google.adk.agents import Agent from google.adk.a2a.utils.agent_to_a2a import to_a2a inventory_agent = Agent( model="gemini-flash-latest", name="inventory_agent", instruction="你是库存查询智能体,查询库存时必须调用 query_stock 工具。", tools=[query_stock], ) a2a_app = to_a2a(inventory_agent, port=8001) # port 只是写进卡片URL,真正监听端口由 uvicorn 决定这一步做了什么:把普通 Agent 变成可被网络访问的 A2A 应用,智能体卡片由 ADK 自动生成,不用手写。
Step 2:起服务并验证卡片
uvicorn my_app:inventory_agent_module --host localhost --port 8001 # 注意 --port 要和 to_a2a 的 port 一致 curl http://localhost:8001/.well-known/agent-card.json预期输出(节选):
{"name": "inventory_agent", "url": "http://localhost:8001", "description": "你是库存查询智能体……", "version": "0.0.1", ...}卡片能取到、url字段指向正确地址,服务端才算就绪。
Step 3:用 RemoteA2aAgent 消费
from google.adk.agents import Agent from google.adk.agents.remote_a2a_agent import RemoteA2aAgent remote_inventory = RemoteA2aAgent( name="inventory_agent", description="远程库存查询智能体", agent_card="http://localhost:8001/.well-known/agent-card.json", # 填 Step 2 验证过的卡片地址 ) root_agent = Agent( model="gemini-flash-latest", name="service_root", sub_agents=[remote_inventory], # 和本地子智能体写法完全一样 )远程智能体和本地智能体在代码里长得一模一样,root agent 用自然语言决定何时把任务委托给它,剩下的网络细节 ADK 全包了。
除了to_a2a(),还有一种暴露方式是adk api_server --a2a:它可以直接和adk web搭配调试,且能指向一个含多个智能体的父目录,但要求每个智能体文件夹里手动写好agent.json卡片,细节见 docs/a2a/quickstart-consuming.md。
一个完整的业务场景
场景:电商客服智能体要回答"这个 SKU 还有货吗",而库存能力在另一个团队维护的库存服务里。
Before(没有 A2A):
- 客服团队没有标准接口可用,只能求库存团队导一个内部 REST API,自己写鉴权、自己解析私有 JSON
- 库存服务接口字段一改,客服侧必须跟着发版
- 两边靠口头约定的契约耦合,出问题时各说各话
After(接入 A2A):
- 库存智能体用
to_a2a()暴露,会干什么、收什么格式全写在卡片里,这就是正式契约 - 客服侧只加一个
RemoteA2aAgent,对话里自然语言即可触发库存查询 - 库存服务升级只改服务端和卡片,客服侧代码不动
调试时把adk web指向消费方智能体,左侧 Trace/Events 面板能看到远程调用事件的完整链路,和调本地工具的体验一致。
踩坑与注意事项
现象:
RemoteA2aAgent拉卡片失败,或调用永远 404。原因:to_a2a(port=8001)只是把 8001 写进卡片 URL,它本身不监听端口;uvicorn --port起在别的端口时,卡片就指向了不存在的地址。解法:port参数必须和uvicorn --port保持一致,起完服务先curl卡片确认再连消费端。现象:
adk api_server --a2a服务正常启动,但对方找不到你的智能体。原因:这条命令只暴露包含agent.json文件的智能体文件夹,没有卡片等于不存在。解法:在智能体目录补上agent.json(至少含name、url、skills),并核对卡片里url与服务的实际路径前缀一致。现象:起调试界面时端口被占用,服务起不来。原因:
adk web默认占 8000 端口,示例里的 A2A 服务在 8001;如果你把 A2A 也改成 8000 就会撞车。解法:保持约定,8000 留给调试 UI,A2A 服务从 8001 起排,多智能体时逐个递增。
一个to_a2a()让你的智能体上线,一个RemoteA2aAgent让对方把它当本地子智能体用,这就是 A2A 的核心链路。Python 暴露与消费的完整流程见 docs/a2a/quickstart-exposing.md 和 docs/a2a/quickstart-consuming.md,Go、Java、Kotlin 版本指南汇总在 docs/a2a/index.md。可运行的双端示例在 examples/go/a2a_basic/,流式模式下遇到消息重复可以再看 docs/a2a/a2a-extension.md。
【免费下载链接】adk-docsAn open-source, code-first toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-docs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考