← 返回藏书阁

Rasa A2A运行合同:context亲和、任务幂等与push投递分账

wiki/ai/sources/rasa-a2a-state-affinity-and-push-delivery-boundaries.md
分类:ai / sources · 更新:2026-10-28 09:18

Rasa A2A运行合同:context亲和、任务幂等与push投递分账

知识点轴:A2A / harness-runtime / sandbox-security / benchmark-evaluation,关联MCP Gateway出站治理。官方3.17文档有原生AgentCard、JSON-RPC、stream/cancel/auth/push细节;这是可操作的官方实现合同案例,不是已核实的用户部署、live Card或跨SDK互通实测。

为什么对用户重要

把业务对话助手包装成A2A sub-agent,比“agent之间互相发消息”多出状态、重试和出站权限。Hermes未来接外部业务agent时,最容易误判的是:共享数据库就能任意扩容、HTTP成功就是业务完成、拿到Card就拥有task权限。Rasa文档明确写出了这些条件,适合给A2A-Agent2Agent-Protocol和Harness-Engineering补真实运行合同,而不是只收一个产品名。

一阶机制:对话持久化与协议状态不是同一个账本

配置a2a_server后,rasa run在与REST/webhook相同的Sanic端口注册A2A JSON-RPC。Card发现是GET /.well-known/agent-card.json;message/send返回终态task,message/stream可发working状态及artifact delta。对话stack/tracker映射到working/input_required/completed/failed/canceled/rejected/auth_required,结构化DataPart可带state、active_flow和slots。

持久tracker不等于持久A2A调度状态。 文档说当前task、messageId去重、in-flight队列、push注册和context容量限制都在每个worker/pod内存里,因此:

  • SANIC_WORKERS=1是启动guardrail,不是任意调优建议。
  • 多副本必须按contextId做亲和路由;tasks/cancel等body没contextId的操作,可用X-A2A-Context-Id或cookie传路由键。
  • 普通round-robin会使后续消息丢协议上下文、重试重执行、cancel找不到工作、另一pod不知道push注册。
  • 亲和路由只让同context常态落同pod,不提供pod崩溃后的状态接管/业务exactly-once。这与a2a-python-cluster-state-stream-execution-boundaries的“有共享存储≠已完成执行接管”是同一类边界。

文档还要求start_session_after_expiry: false,否则复用同contextId时,对话过期启动动作可能悄悄重置slot。input_required保留context,意味着等待用户的任务仍占资源,不能只按当前running计容量。

重试/超时合同:幂等有范围和寿命

去重键是(contextId, messageId):同ID在已完成且缓存有效时重放缓存terminal task;并发重复在in-flight时返回HTTP409,不能当业务失败后另起新messageId重做。默认task超时600秒;计时器按task建立,不被同context后续message延长;缓存TTL默认跟task timeout走,设0会立即过期。

因此要分别记:同ID重放、同ID并发冲突、TTL过期重做、pod重启后重做、业务副作用去重。协议缓存有用,但不证明转账/下单/写库只执行一次。文档的tasks/cancel可发取消信号,真实外部动作是否中止/回滚仍需要业务sink读回;不要把canceled状态当回滚回执。

认证、发现与push是三个边界

边界官方合同不能由此推出
Card及JSON-RPC入口配a2a_server.auth后两者均需Bearer JWT;不配置则开放已有per-task owner/跨租户隔离
身份JWT验证orchestrator;终端用户身份在metadata/slot,不在此JWTmetadata中的用户声明自动可信
claim约束issuer/audience可配置;对称secret须环境变量插值所有实例都设置了issuer/audience
push注册默认禁用;开启后可限制allowed hosts开启后自动安全,或已经可靠送达

Card描述了能力,并不代替task资源验权。对终端用户metadata和可写slot,应依据业务权限做二次过滤;“domain里定义过此slot”只是类型/字段准入,不是该orchestrator有权代用户设置任意值。这是从文档合同导出的工程要求,不是已证实的Rasa越权漏洞。

push文档提供重要的失败分账:callback只允许http/https;拒绝内网、loopback、link-local、内嵌凭据;注册和每次POST前做DNS检查;不跟随redirect。3xx按投递失败记日志且不重试,A2A task仍可正常完成。因此task completed ≠ push delivered,SSE/查询回读与通知可靠性应独立验收。

文档同时承认DNS检查未把解析IP绑定到实际httpx连接,仍有rebinding TOCTOU;host allowlist/HTTPS是缓解,不是连接时IP pinning。对应a2a-push-dial-ip-proxy-final-target-boundaries与contextforge-egress-path-parity-dns-rebinding,最终出口若经过代理还须检查代理的拨号策略。

对Hermes工作流的最小验收矩阵

以下是待实施设计,不是本机跑通声明:

  1. 先保存真实Card与服务版本;对无JWT、错issuer/audience、正确JWT分别测Card和task,不把发现401误诊成agent离线。
  2. 两pod执行同context后续turn与cancel:有/无亲和路由成对;强制pod退出后另验恢复,而不是从常态亲和成功外推高可用。
  3. 同messageId做并发、完成后重放、TTL过期和重启四类测试;从独立业务sink统计effect,别只看taskId。
  4. 合法push、3xx、超时和非法目标各测一次;分别保存task终态与投递状态,不让通知失败被“任务成功”掩盖。
  5. 在测试环境核slot预填来源与业务授权,确保用户可见文字或不可信metadata不能变成高权限业务事实。

深度判断与边界

值得正式入库的是内存状态所有权、去重寿命、路由亲和和push失败语义,能迁移到任何A2A adapter。没有创建独立Rasa实体页,也不把它当已完成enterprise deployment:本轮取得的是官方滚动文档快照,没有固定私有实现、真实endpoint、SDK运行轨迹或外部业务effect。文档升级可能改变条件,后续要以具体release和实际Card重新核验。

写入记录

  • 2026-10-28 09:13 CST:深读Rasa官方架构/服务文档,新增A2A状态亲和、重试寿命、认证/slot边界与push投递合同;保留DNS连接时缺口及无本机部署/互通证据。