把ADK智能体转成A2A服务,一行代码就够了。但真正部署到云端后,问题才浮出水面。
开发者xbill9在GitHub上开源了一个多云A2A子代理项目,用to_a2a()函数把ADK的LlmAgent变成A2A服务器,接入由Bedrock AgentCore上的Strands智能体和Azure Container Apps上的微软Agent Framework智能体组成的混合网络。三个智能体通过A2A v1.0协议应答同一个协调器。
问题出在智能体卡片上
to_a2a()函数会把host:port直接写进智能体卡片的接口URL。在Cloud Run上,进程绑定的是0.0.0.0:8080,部署后的卡片就变成了这样:
{"url": null, "additionalInterfaces": [{"url": "http://0.0.0.0:8080", "protocolBinding": "JSONRPC"}]}
一个公网HTTPS端点,却在广播一个不可路由的明文地址。这个问题在本地开发时完全看不出来——笔记本上绑定地址和拨号地址是同一个字符串,所以能一路带到生产环境。
自家客户端连不上自家服务
最讽刺的是,ADK自己的客户端连不上ADK自己的服务器。两边的代码都通过了Google自己的测试,因为本地测试时两个地址是一致的。唯一完全由第一方代码组成的配对,反而是唯一无法完成一跳通信的组合。
而且报错信息也指向了错误的层级。拨号0.0.0.0:8080失败后,RemoteA2aAgent抛出的异常是:
AttributeError: 'A2AClientError' object has no attribute 'status_code'
错误处理器假设所有A2AClientError都携带状态码,但传输层失败并不包含这个属性。真正的原因——"所有连接尝试均失败"——被记到了另一条日志里。两个缺陷叠加:第一个把客户端引向不可路由的地址,第二个删掉了客户端去向的证据。
同一个回复,被投递了两次
ADK的执行器会把回复作为任务工件附加,同时也在任务历史里留一份副本。这在自家人对话时无所谓,但跟别人通信就出问题了。
微软的A2AExecutor驱动完整的任务生命周期,回复只留在历史记录里,工件列表是空的。所以一个只读工件的客户端——这是最直观的实现方式,也是跟ADK配合时完全正常的做法——从Agent Framework那里会拿到一个空字符串。不是报错,不是超时,而是一次成功调用但没有任何内容。
解决办法是读取规范允许的所有载体,这样ADK的回复就会到达两次。项目早期版本中智能体返回的是汇率数据,重复投递的问题就暴露得更明显。
热门跟贴