教程

AI Agent 如何自动发现另一个 Agent?从 Agent Registry、A2A Agent Card 到 JSON Capability Discovery 完整解析

发现失败时,先问走的是哪一跳:搜目录、拉名片,还是已经握着域名却 GET 错了路径。

上一篇 Agent Card 字段教程 把 1.0 必填表摊开了。今天不重填字段,也不重讲 Registry 是目录。编排者的下一问是:我怎么从「需要会办退货的同事」走到一张可调用的 Card?官方答案在 A2A Agent Discovery:策略有三条,Card 只有一种。规范不规定策展目录的查询 API,见同一页的 Considerations。Google Cloud 的目录是其中一种落地,形状对照 Registry JSON schemas。本文按 hop 走查。横向委托和向下调工具的分层,见 A2A vs MCP,今天不重讲。

发现不是协议,Card 才是被找到的东西

A2A 标准化的是自述,不是电话本。远程 Agent 把能力写成 JSON 名片;客户端用这张卡判断适不适合、怎么连、发什么 Task。发现方法随环境变:公网、企业目录、开发机写死,三条都能到同一份 Card。把「发现」说成又一种对话协议,评审会先走偏。协议仍是 A2A;变的是你从哪一扇门走进 well-known 或目录。

官方发现页上的「Role of the Agent Card」仍用 0.3 口气提到顶层 url。新卡按 1.0:端点在 supportedInterfaces,见 v1.0 变更。发现 hop 读到旧字段,不要当 1.0 主合同。字段怎么写,上一篇已经写过。今天只问:这张卡是从哪一跳到手里的,到了之后先核哪几个键。

发现成功,不等于可以 tools/call。对面仍是不透明 Agent。你选出 skill、挑好接口,发送的是 Task。把搜索命中当成函数表,多轮澄清会撑破 arguments。MCP 那一跳怎么核参数,见站内 Schema 文。今天停在「找到谁、凭什么认定他会办这件事」。

策略 你事先知道什么 下一跳
Well-known URI域名或主机GET /.well-known/agent-card.json
策展目录技能关键词 / 标签查目录,再拉 Card 或引用
直接配置URL 或整张卡跳过搜索,直接读卡

三条官方策略,先选路再走路

Well-known 适合公开 Agent,或域名受控的发现。路径跟 RFC 8615:https://{agent-server-domain}/.well-known/agent-card.json。客户端已经知道或能推出域名,发 HTTP GET,拿到 JSON。实现简单,自动化友好。名片里有敏感技能或内网 URL,这个 GET 本身就要鉴权,不能把内网端点裸挂在公网。

策展目录适合企业或市场:中间服务收一批 Card,客户端按 skills、tags、provider、capabilities 查询,目录返回匹配的卡或引用。好处是治理和按能力搜。代价是你要养这份目录。A2A 没有规定目录 API。Google Agent Registry、社区 registry、自建目录,查询形状各写各的。不要拿一份「通用 discover JSON」去校验三家。

直接配置适合紧耦合、私有 Agent、开发机。卡 URL 写在环境变量、配置文件或专有 API。关系静态时最省事;Card 一变,客户端要跟着改。生产里把「开发机写死」当成唯一发现面,就是 2025 年通讯录。三条路可以并存:目录负责搜到谁,well-known 负责目录挂了还能读名片,配置负责启动时的种子主机。

手里有域名:GET well-known

最干净的 hop 只有三步。① 得到域名,例如 returns.agents.example.com。② GET https://returns.agents.example.com/.well-known/agent-card.json。③ 响应是一张过 1.0 Schema 的 Card。路径写错、HTTP 换成内部别名、证书主机名对不上,故障单上会写成「发现失败」,其实 Card 是好的,GET 没打到。

规范建议 Card 端点带缓存头。Cache-Control: max-age=… 让中间层和客户端少打满卡;ETag 可用 version 或内容哈希。过期后先条件请求(If-None-Match),不要每次无条件拉全文。服务器没给缓存头,客户端可以自己设一个合理默认,但不能永久缓存一张会改 skills 的卡。

公开卡够编排者选型即可。敏感技能、内网第二端点,放到认证后的扩展卡。capabilities.extendedAgentCard 为真,才去拉第二份。发现 hop 不要在未认证时假设扩展卡存在。目录按身份选择性返回不同 Card,和 well-known 上一张对所有人相同的卡,是两种披露,评审里要分开写。

手里有目录:搜 tags,再拉 Card

没有域名、只有一句「找会分类退货的同事」时,走策展目录。查询吃的是 Card 上的 skills[].tags 和技能名,不是你幻灯片上的拓扑。Google 项目内的编排者、Gemini Enterprise、Agent Gateway 按技能关键词找登记项——这是产品行为,不是 A2A 标准 RPC。社区或其他云各有各的 search。评审夹具里只断言「查询 → 命中列表 → 每条带 cardUrl 或内嵌 Card」,不要把某一家的路径写成规范。

目录返回引用时,下一跳仍是 well-known 或目录给出的 Card URL。返回内嵌 Card 时,仍要用 1.0 Schema 核一遍:登记成功不等于字段合法。NO_SPEC 那种只有主机、没有 skills 的条目,搜索面是空的——#5 写过,今天只提醒:关键词 hop 打在空索引上,不是协议坏了。

目录挂了,并不自动等于发现结束。手里若已有域名,客户端仍应 GET well-known。把目录当成唯一真相,等于把发现面单点化。种子配置里留一两个稳定主机,目录恢复后再做关键词搜索,比「目录 500 就停摆」更接近规范写的三条并存。

命中之后:对 skills,挑接口,发 Task

搜索命中只说明「可能是他」。编排者还要对 skills[]:id 是否就是你要委托的那类事,tags 是否真的命中查询词,description 的边界是否接受。不要用 MCP inputSchema 去套 skill。1.0 的提示是 examples 和 MIME。选错 skill 再发 Task,失败发生在委托,不在发现;但夹具要把「命中 ≠ 选定」写成两步。

选定之后读 supportedInterfaces。第一项是首选。客户端按自己会的绑定挑:JSONRPC、GRPC、HTTP+JSON。挑不到共同绑定,发现成功、通话失败。0.3 顶层 url 不要当 1.0 主端点。能力旗标也要看:streaming 为假还订流式,规范要求回能力错误,不是默默改成 unary。

下面是一份走查夹具,不是任何一家目录的官方 API。它把查询、命中、首选接口收成 JSON,方便和仓库里的 Card 并排 diff。下一步才是 message/send。校验清单和签名留给更后面一篇。

{
  "kind": "discovery-trace",
  "note": "CI/review fixture — not an official A2A or Google Registry API",
  "query": {
    "tags": ["returns", "classify"]
  },
  "strategy": "curated-registry",
  "hits": [
    {
      "name": "Returns Specialist",
      "cardUrl": "https://returns.agents.example.com/.well-known/agent-card.json",
      "matchedTags": ["returns", "classify"],
      "skillId": "classify-return"
    }
  ],
  "selected": {
    "skillId": "classify-return",
    "preferredInterface": {
      "url": "https://agents.example.com/returns/a2a",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    },
    "next": "message/send"
  }
}
这一跳 输入 你该断言什么
搜目录tags 或技能名命中列表非空,且带引用
拉 well-known域名或 cardUrlJSON parse,过 1.0 Schema
选型 / 挑接口完整 1.0 Cardskill id 对上,接口客户端会说

缓存、过期与夹具

Card 改得不勤:加技能、改鉴权才会动。发现面却会脏。目录索引滞后,well-known 已是新 version,搜索还指向旧 tags。夹具至少两份:目录命中快照,和刚 GET 到的 Card。keywords 对不上,先查 tags 和索引延迟,再查是不是 1.0 客户端读了 0.3 卡。

{
  "hop": "well-known",
  "method": "GET",
  "url": "https://returns.agents.example.com/.well-known/agent-card.json",
  "requestHeaders": {
    "If-None-Match": "1.0.3"
  },
  "response": {
    "status": 304,
    "etag": "1.0.3",
    "cacheControl": "max-age=3600"
  }
}

规范写:敏感数据必须鉴权,推荐带外动态凭证,不要把静态密钥写进 Card。发现夹具里出现 token、内网密码,评审直接打回。公开卡按会被拉取来写。扩展卡的缓存跟会话走,不要和公开卡的 max-age 混成一个桶。

也不要把 Plugin SKILL.md 或 MCP tools/list 当成发现源。同一仓库里的 Coding Agent 怎么长技能,是箱子的事;另一个团队的退货 Agent 怎么被找到,是 Card 的事。混进同一份「capability.json」,三跳失败会算到同一行。

浏览器里即可完成:JSON 格式化看走查夹具和 Card 能否 parse;JSON Schema 校验核命中后的 1.0 Card;JSON Diff对比目录快照和刚拉到的 Card,抓 tags / 接口 drift。数据不离开本机。延伸阅读:Agent Card 字段教程、Registry 总览。签名与校验清单读下一篇实战。

相关文章:A2A Agent Card JSON Schema、Google Agent Registry、A2A vs MCP。

常见问题 FAQ

有了目录,还要不要 GET well-known?

要。目录消费 Card,不替代 Card。规范把 well-known 写成公开发现的标准路径。目录挂了,拿得到域名的客户端仍应读名片。

A2A 有没有标准的「搜索 Agent」RPC?

没有。发现页写明:当前规范不规定策展目录的 API。各家目录自己定义查询。标准的是 Card 的形状和 well-known 路径。

搜到了能不能直接 tools/call?

不能。命中是发现结果。对面是不透明 Agent,走 Task。确定性参数留给 MCP 工具,不要写进发现 hop。

缓存多久算合理?

先听服务器的 Cache-Control 和 ETag。没给头,用短默认,过期走条件请求。技能或鉴权一变,version 应变,客户端不该抱着旧 tags 做生产路由。

总结与下一步

2026 年说「自动发现另一个 Agent」,可以收成三跳:选策略、拿到 Card、按 skills 和接口决定要不要委托。目录是其中一扇门,不是协议本身。

落地顺序:公开 Agent 先挂对 well-known;要按关键词找,再接入某一家目录并自备查询夹具;命中后核 1.0 Card 再发 Task。字段怎么写读上一篇;目录是什么读 #5;校验与签名读更后面一篇。用 JSONVue 对走查 JSON 和仓库 Card。