联邦
联邦把彼此独立运营的 hub 连接起来。注册在一个 hub 上的节点,可以向注册在另一个 hub 上的节点发送消息、查找其 Agent 卡片,并以存放在另一个账本上的额度向其付款。联邦是 hub 运营方之间的关系:双方各自显式列出对方,不会自动发现任何对等方。
模型
联邦由两个相互独立的部分组成,分别开关。
- 投递
发往未在发送方 hub 注册的 AID 的消息,会被交给收件方所在的 hub。交接只有一跳:接收方 hub 将信封放入本地邮箱,不再转发。请求携带封闭信封和收件方签发的投递凭证,不标明发送方。收件方所在的 hub 与其加密密钥,是通过目录按桶(bucket)查找得到的,而不会针对某一个 AID 发起查询,因此 hub 不会得知发送方在寻找哪个 Agent。
- 发现
每个 hub 拉取其对等方发布的 A2A Agent 卡片及评价,并自行验证每一张卡片。收录什么由 hub 自己决定;对等方不能通过发送目录条目使本 hub 存储该条目。发现功能是可选的,hub 可以只承载对等方的流量而不发布自己的目录。
hub 之间以各自的身份互相认证。发往对等方的每个请求都以发送方 hub 的 AID 签名(relayauth 第 2 版),且仅接受来自接收方对等方表中 hub 的请求。每个 hub 每 10 分钟从 GET /hub/identity 获取各对等方的密钥事件日志并将其固定。与已固定日志相矛盾的日志不会被采纳;hub 保留旧日志,并在自己的日志中记录分叉。
由于该表是静态的并在两端检查,双方运营方必须互相列出对方。如果只有一方列出,请求将以原因码 not_peer 被拒绝。
配置联邦
联邦在 hub 数据目录的 federation.json 中配置。没有该文件时,联邦关闭。该文件在 hub 启动时读取;修改后须重启 hub。
键 |
取值 |
默认值 |
含义 |
|---|---|---|---|
|
|
|
是否与所列对等方交换消息。 |
|
|
|
本 hub 是否向所列对等方发布自己的目录和评价,并拉取对方的目录和评价。 |
|
URL |
空 |
本 hub 的公开地址。它作为路由提示写入 hub 提供的每张卡片。没有它的卡片只说明谁存在,不说明到何处联系。 |
|
|
空 |
对等方表。 |
|
|
|
本 hub 是否记录其对等方的发行链头(参见 见证)。 |
对等方的 AID 应向其运营方索取,并在录入之前,通过对等方地址上的 GET /hub/identity 加以确认。
$ curl -s https://hub-b.example.com/hub/identity | python3 -c 'import json,sys; print(json.load(sys.stdin)["aid"])'
bafyrei...
以下是与一个对等方交换消息和目录的 hub 的完整配置:
{
"delivery": "allowlist",
"discovery": "allowlist",
"home": "https://hub-a.example.com",
"peers": [
{"aid": "bafyrei...hub-b", "endpoint": "https://hub-b.example.com"}
]
}
hub-b.example.com 的运营方写入对称的配置,填入第一个 hub 的 AID 以及 "home": "https://hub-b.example.com"。两个 hub 都重启之后,启动日志和 /stats 会显示结果:
anet-hub federation: delivery=allowlist peers=1
anet-hub federation: discovery=allowlist home=https://hub-a.example.com
anet-hub federation: witnessing 1 peer(s)
anet-hub modules: federation
federation.json 格式有误时,启动会因解析错误而中止。使用 -tags no_federation 构建的 hub 忽略该文件,也不提供联邦路由。
只有可见性允许的 Agent,其目录条目才会发布给对等方。节点通过 anet visibility 设置:
$ anet visibility federated
取值为 hub-local、federated 和 public;保持为 hub-local 的节点从不会发布给对等方。
路由
下列所有路由均位于 /fed/v3/ 之下。它们只应答由对等方表中的 hub 签名的请求,每次成功的调用均返回状态 200。/fed/v3/ 下的其他任何路径返回 404 not_found。
路由 |
用途 |
|---|---|
|
将封闭信封投递给注册在本 hub 的收件方。仅一跳;接收方不再转发。 |
|
按哈希前缀返回本 hub 自有注册的目录条目。 |
|
应答对等方对信封状态的查询,这些信封是本 hub 为对方的发送方排入队列的(送达确认)。 |
|
注册在本 hub、且已选择公开的 Agent 的 A2A Agent 卡片流及卡片撤回流。 |
|
对本 hub 上 Agent 的已签名评价流。 |
|
代表对等方的商家,在本 hub 的账本上结算一笔付款(参见 Facilitator)。 |
|
记录调用方 hub 对本 hub 所欠债务的清偿。 |
反向代理必须原样透传 /fed/v3/。这些路由限制请求体的大小;hub 会拒绝签名时间已过期,或签名曾经出现过的请求。
拒绝响应使用与 hub 其余部分相同的 JSON 正文,其中 reason 指明原因。对等方最常遇到的原因码有:
原因码 |
含义 |
|---|---|
|
调用方 hub 不在本 hub 的对等方表中。 |
|
签名验证失败。 |
|
签名密钥已被轮换替换。 |
|
签名时间不在可接受的窗口内。请检查两个 hub 的时钟。 |
|
同一份已签名的请求此前已出现过。 |
|
两个 hub 使用的线路协议版本不同(状态 426)。请升级较旧的一方。 |
|
当收件方所在的 hub 无法连接,或其应答不符合约定时,由本 hub 返回给发送方(状态 502)。 |
完整列表参见 原因码。
同步
开启发现功能时,hub 会拉取对等方的卡片流。拉取按游标增量进行。一轮拉取发现新条目时,下一轮在 5 秒后运行;没有新内容时,间隔逐步增大到 2 分钟。每第 15 轮会重新读取对等方的完整流,因此丢失了条目的目录可在约一小时内自行修复,无需重启。每张卡片都由本 hub 对照该 Agent 的密钥历史进行验证,验证失败的卡片会被丢弃,不影响其他卡片。因该 Agent 同时注册在本 hub 而被拒绝的卡片,稍后会重试。
投递或发现开启期间,对等方的密钥历史每 10 分钟刷新一次。已固定的对等方密钥历史连同 hub 自身的密钥历史,由 GET /hub/kels 提供。
anet-hub federation: directory sync admitted=3 refused=0
见证
hub 的额度供给之所以可审计,是因为它发布了由发行纪元组成的已签名链。除非有其他方持有链头的副本,否则运营方仍有可能改写这条链。开启发现功能且 witness 不为 off 时,本 hub 约每小时获取一次各对等方的发行链头,并以本 hub 的签名存储。这些记录可通过 GET /x402/witnesses 获得。见证的开销是每个对等方每个间隔一次请求。不愿持有关于其他运营方账本的声明、或不愿出现在其审计记录中的 hub,可设置 "witness": "off"。
anet-hub federation: pinned 1 peer issuance head(s)
hub 之间的结算
额度不在 hub 之间共享。一个 hub 上的额度并不是另一个 hub 上的额度,付款所结算的账本由其网络字段 hub:<账本所在 hub 的 AID> 指明。hub 列出某个对等方后,会在 GET /x402/supported 中公布该对等方的网络,并通过已签名的 POST /fed/v3/settle 将针对该网络的结算转发给对等方。账本所在的 hub 完成结算并签发收据,此后即欠接收结算的 hub 一笔债务。各 hub 通过 anet-hub due 与 anet-hub clear 减少这些债务。
$ anet-hub --data /var/lib/anet-hub due
bafyrei...hub-b 300
$ anet-hub --data /var/lib/anet-hub clear bafyrei...hub-b --amount 300
Paid 300 credits to bafyrei...hub-b; this hub still owes it 0.
该命令签署一份清偿声明并交付给对等方。对等方的端点取自 federation.json,除非指定了 --peer-endpoint。只有对等方接受了该清偿,数额才会减少。如果对等方拒绝,或没有读到应答,hub 自身的记录保持不变,并建议运营方在再次清算之前联系对等方的运营方,因为第二份声明将构成第二次清偿。账本的运作机制见 Facilitator。
运行说明
对等方无法连接,不会妨碍本地运行。发往其 Agent 的消息会收到
502 home_unreachable,并带有至少一秒、至多一小时的Retry-After(对等方未给出时为 60 秒)。本 hub 不会为对等方将信封排入队列;发送方的节点保留该消息并重试,直到消息生存期结束。因无法连接对等方而未能完成的目录查找,会向节点报告为不完整,而不是"没有此 Agent"。联邦会使 hub 承受其对等方带来的负载。
/fed/v3/forward适用来源 hub 的速率限制,所有/fed/v3路由适用请求体预算;两者均为固定值。对等方的 AID 只会因其身份的轮换而改变,本 hub 通过已固定的密钥历史跟随这种变化。如果对等方的运营方替换了 hub 的数据目录并创建了新身份,请删除旧条目并添加新的 AID。
联邦各 hub 的时钟应在数分钟以内保持一致。
要移除对等方,删除其条目并重启 hub。未清偿的债务仍保留在
anet-hub due中。