Microsoft A2A:Agent Card 适配与 host 运行责任分离
Microsoft A2A:Agent Card 适配与 host 运行责任分离
会生成 Agent Card、会转换消息,不等于已经提供可安全部署的 A2A 服务。 应把 discovery、content conversion、executor、session、task store、auth 和 transport 的所有者逐一列出来。
知识点轴:A2A / harness-runtime / context management / sandbox-security。本页是官方文档与固定源码案例,不是已登录企业实例的部署验证。
为什么这对用户重要
Hermes 将来把外部 agent 作为可委派能力接入时,很容易把 streaming=true、自动生成 skills 或某个 SDK helper 当成完整生命周期保证。本案例提供可复用的组件责任分界,可以与 A2A-Agent2Agent-Protocol、a2a-jakarta-cross-node-state-and-effective-security 的跨节点案例一起设计接入验收,而不是再建一个只罗列 Card 的目录。
深读范围:Microsoft 官方 A2A overview/server 文档;microsoft/agent-framework commit 926b4ecacdaa95cb909c9d08f77b4fd898f273c0 的 hosting README、adapter、adapter tests,以及另一个包中的 _a2a_executor.py。仓库 13,503 stars(2026-09-14 API);源码固定不代表本机已安装或运行该版本。
一:同仓库两层 API,不能混写责任
| 对象 | 提供什么 | 不应据此推导什么 |
agent-framework-hosting-a2a | 原生 A2A 值转换、AgentA2AAdapter / WorkflowA2AAdapter、常见 Card 字段生成 | README 明确不提供 executor、task lifecycle、queue/store/routes、session policy、auth 或 deployment |
agent_framework_a2a 的 A2AExecutor | 将 agent 执行和响应转换为 A2A 事件,并使用 session 管理历史 | 不是上面 hosting 包的隐式内置能力;其样例不证明多租户/跨节点部署安全 |
| application-owned native A2A host | 挂载实际 binding、接收请求、管理 state、发布事件与 artifacts | 每项生产保证仍要靠应用实现和测试,不能靠 Card 宣告替代 |
两者可以是不同接入层级,而不是文档互相矛盾。尤其不能把另一个包的 A2AExecutor 功能全部归到轻量 hosting adapter 上。
二:Card 的能力、skills 与运行上下文不是同一个东西
AgentA2AAdapter 从 agent 推断名字/说明,默认保守地给出 text input/output。get_card() 是 async,以便 factory-backed state 解析目标。server capabilities 保持显式:它们描述应用实际提供的服务,不从 agent.run 的存在推断 streaming/push。
默认 infer_skills=True 会从 agent 的 SkillsProvider 发现 Skill,将其 name/description 变成 AgentSkill。文档特别指出:发现发生在 agent run 之外,没有 session。如果技能集合随 tenant/用户/session 改变,应使用显式 skills 或 infer_skills=False,不能让无会话目录变成全租户能力曝光。所读测试明确断言关闭推断后空 skills。
AgentInterface 应只列 host 真实挂载的 URL 和 JSONRPC / HTTP+JSON / GRPC binding。Card 是调用合同,不是自动部署器,也不是授权结果;这与 atlassian-rovo-a2a-live-card-and-enterprise-gates 的公开发现/企业授权分验一致。
三:类型转换有模式合同,也有绕过入口
- 独立
a2a_to_run/a2a_from_run默认宽松;传input_modes/output_modes才按合同校验。 - adapter 方法默认按 Card 的配置模式校验,但
validate_modes=False能关闭;要检查实际调用而非只读默认值。 - 支持 text、JSON、raw bytes、具体媒体类型及 wildcard。自定义 mode 可被宣告,但没有内置 parser 时,宣告不代表能够凭空合成该表示。
- workflow 的推断模式要先通过
await adapter.get_card()解析;输出中待人工输入的请求会抛出异常,交由应用实现 continuation,而不是自动获得持久化审批流程。 a2a_from_run返回扁平 part list,并保留 content-level metadata;message/artifact 分组及其 metadata 边界由应用负责。
这与 Context-Engineering 的关系是:history、media、metadata 和身份都不是可随便丢弃的格式细节。转换失败应该显式暴露,不能静默降为一段文本后继续宣称协议等价。
四:历史、任务与流式输出需要不同键和回执
hosting README 的应用样例使用 a2a:{context.tenant}:{context.context_id} 作为 session key,并显式 get/create、run、set。另一个包的 A2AExecutor 所读路径以 task.context_id 建立 session;这只说明该路径的映射方式,不能从片段断言整个系统有或没有外层 tenant 隔离。
该 executor 的 stream 路径保留稳定的 default artifact ID;同一 artifact 后续 chunk 使用 append,避免每个 chunk 变成新文件。只转换面向用户的 text/data/URI,跳过不能映射的中间 function-call/result。这是有用实现证据,但不证明断流重订阅、跨节点恢复、exactly-once 或底层副作用取消成功。
Harness-Engineering 应分别记录 session key、task ID、artifact ID、caller/tenant、last event cursor 与业务幂等键。上下文连续≠task 可恢复,取消状态≠外部副作用被撤销。
给 Hermes 的隔离接入验收建议
- 固定 Card 与实际 route:只宣告挂载的 binding;对 streaming/push/HITL 分别列 executed / unsupported / not-tested。
- 做双 tenant、同 context ID 的负例;分别检查 session、task、artifact 查询和 registry 可见 skills。
- 对比 standalone 默认、adapter 默认、
validate_modes=False三条路径;加入 media 不匹配和未知自定义 mode。 - 中途断开 stream,检查稳定 artifact ID、append 去重与重订阅;不要把事件能读取当执行已接管。
- 单独验证 token、task ownership、取消副作用与独立业务状态,不从官方样例推出企业保证。
这些是建议,不是本轮已运行的服务。没有调用用户企业 endpoint 或上传会话。
证据边界与下一步
本轮对上述固定代码/测试做 6 项静态检查,全部通过;没有安装 SDK、运行 pytest/TCK、获取部署后的 Agent Card、启动 ASGI、测试鉴权/stream/push 或故障恢复。tests 中存在断言与本机实际通过该测试是不同证据层。
下一轮高价值信号是具体 host 的 task store、授权中间件、取消实现和带 tenant 的实际 trace;仅新增 helper API 名称不再新建来源页。
来源与关联
写入记录
- 2026-09-14 09:15 CST:新增官方 A2A adapter/host 责任案例;明确两包差异、无 session 的 skill discovery、模式校验 opt-out 及 session/task/artifact 分验;只声明静态证据。