06 · 自测题库
自测题库:把五章正文当成一座可检索的题库
前五章建立了 A2A 的概念地图(01)、工作原理与设计取舍(02)、可跑通的 server + client(03)、跨组织系统的失败模式(04),以及把 A2A 与 MCP 叠成两层栈的综合项目(05)。这一章不教新东西——它用三层梯度题逼出检索:概念记不记得住、原理讲不讲得通、场景判别得对不对。
合上其他章,每题先把答案写在纸上或编辑器里,再翻到文末那个折叠块对照——直接看答案等于把这一章当成第六遍重读,检索效果归零。
A概念层(对应 01 章 · 考回忆)
原子级的回忆 / 理解题:每题只问一个点,能用一两句话答完。答不上来,回提示里那一节。
- A2A 把 agent 层的 M×N 互操作收敛成 M+N,省掉的是哪三类两两重复的工作?它治的是「水平」还是「垂直」方向,跟 MCP 治的方向差在哪?(提示:§1.1)
- Agent Card 是什么?固定发布在哪个路径上?别的 agent 靠它发现什么、为什么不需要注册中心?(提示:§1.2)
- Agent Card 里的
securitySchemes有没有装实际凭证(token / 密钥)?这一点为什么决定了 Card 能不能作为公开文档发布?(提示:§1.2) - 用一句话说清 Task / Message / Part / Artifact 四者的嵌套关系。Message 和 Artifact 内容都是 Part[],区别在哪?(提示:§1.3)
- 「不透明 agent(opaque)」原则具体指什么不暴露、只暴露什么?它带来的三条收益和那一条代价分别是什么?(提示:§1.4)
- A2A 与 MCP 的判别口诀是什么?决定用哪个的,是对端的「名字」还是对端的「性质」?(提示:§1.5)
- 为什么说 A2A 与 MCP 是「正交(⊥)」而非竞争?举出同一个 agent 同时用上两者的典型形态。(提示:§1.5)
B原理层(对应 02 + 03 章 · 考理解)
问机制:不是「是什么」,是「wire 上长什么样、为什么这么设计、代价在哪」。这一层最容易被旧博客的 v0.x 形式带偏,逐题核对。
- 委托一件事,v1.0 在 wire 上发的 JSON-RPC
"method"字符串到底叫什么?为什么说message/send是错的、只能当迁移注记?(提示:§2.3) - Task 的
state在实际 JSON 载荷里长什么样(写出一个完整取值)?小写的completed、英式拼写cancelled错在哪?(提示:§2.5) - 三种交互模式——请求/响应、SSE 流、webhook 推送——各自何时用?三者的箭头方向有什么不同?(提示:§2.4)
- webhook 推送里,谁该验证「这个 POST 真来自 agent」?为什么说这条边的信任方向和直觉是反的?(提示:§2.4 + §4.4)
- Task 生命周期里
INPUT_REQUIRED/AUTH_REQUIRED是中途态还是终态?「中途要凭证」和「一上来就 401」差在哪?(提示:§2.5) - Python SDK 的方法名是 snake_case
send_message,它在 wire 上发出的"method"却是SendMessage——这两者是什么关系?这件事提醒你区分什么?(提示:§3.2) - 同一个抽象方法有 JSON-RPC / gRPC / REST 三个对等绑定。既然抽象一致,为什么 v0.x 与 v1.0 的 agent 仍可能 wire 不兼容?(提示:§2.3 + §4.7)
C应用判别层(综合 03–05 · 考判别)
给场景、做选择。每题不只要选项,更要说出理由——选项蒙对而理由说不通,等于没通过。05 已扛了主判别,这里四道强化迁移。
- 场景一 · 调工具还是托对等体(涉及 01 / 03 / 05):你的编排 agent 要接入一个「内部跑着 LLM、会自己规划多步、可能反问你要补充信息、一次任务可能跑十几分钟」的远程服务。该把它当 MCP 工具接、还是当 A2A 对等 agent 接?说出判据,并指出它的「反问」在 A2A 里会落到哪个 Task 状态上。(§1.5 口诀 + §2.5 状态机)
- 场景二 · 同步 / 流式 / 异步选哪种(涉及 02 / 03):同一个「生成季度财报」的委托,分别在三种产品形态下——(a) CLI 脚本,跑完即退;(b) 网页,要实时显示「正在取数 / 正在汇总」的进度;(c) 手机 App,提交后用户会立刻锁屏、任务要跑 20 分钟。每种各该选请求/响应、SSE 流、还是 webhook 推送?逐一给理由。(§2.4 三种交互)
- 场景三 · 该不该验 Card 签名(涉及 01 / 04):你的 host agent 准备把支付相关的任务,委托给一个号称来自某知名银行、从
/.well-known/agent-card.json取到的远程 agent。这张 Card 默认没有签名。你该不该在选用它之前加一道 Card 签名验证(JWS)?不加会被哪个具体攻击打穿?光验签名够不够?(§4.2 伪造 + §4.1 描述注入) - 场景四 · 两层栈各管哪一段(涉及 01 / 05):一个「差旅编排 agent」要订机票,它先把「订票」托付给某航司的远程 agent,航司 agent 内部再去读自家的库存数据库、调订座接口。把这条链拆成几跳,逐跳标出该用 A2A 还是 MCP,并说明为什么这就是 2026 年企业级的默认两层栈。(§1.5 repair-shop + §5.1 两层栈)
合上教程,在纸上画一次「最小委托」的端到端:从 client 发现 Agent Card 起,到它收回一个带 Artifact 的 Task 止。在每条边上标出 wire 上真正搬的东西——发现那条标 GET /.well-known/agent-card.json、委托那条标 SendMessage、回流那条标 Task 的 status.state 取值(写大写蛇形)。画完回 §2.1 对照:哪几条边你标反了方向、哪个状态值你写成了小写?
§参考答案
展开全部参考答案(三层都做完再看)
概念层(对应 01 章)
- 省掉的三类重复工作:怎么发现对端能干什么、用什么线缆格式发请求、对端用什么数据结构回话——A2A 把这三样分别固定成 Agent Card、JSON-RPC/gRPC/REST +
SendMessage、Task/Message/Artifact,于是每端只实现一次「说/听 A2A」,总量从 M×N 降到 M+N。它治水平(agent↔agent);MCP 治垂直(agent↓工具)。同源动机,不同层。 - Agent Card 是一个 agent 公开发布的能力声明 JSON,固定位于
GET /.well-known/agent-card.json(v0.x 旧路径agent.json已弃用)。别的 agent 用一次普通 HTTP GET 就能读到它「能干哪几件事(skills)、走哪个端点(url)、支持哪些可选能力(capabilities)、用哪种认证(securitySchemes)」。因为路径是约定死的、知道域名就能拼出 URL,所以无需中央注册中心——这是去中心发现,像robots.txt。 - 没有。
securitySchemes只声明认证方案的类型(如 OAuth2 / API Key / OIDC / mTLS),绝不包含任何实际 token 或密钥;凭证由调用方带外另行获取,发请求时放进 HTTP 头,不进 Card、也不进 JSON-RPC 载荷。正因为 Card 只说「用哪种锁」而不放「钥匙」,它才能作为公开文档发布而不泄密。 - 嵌套关系:Task(有状态的工作单元,含
id/contextId/status)包住history(一个 Message[])和artifacts(一个 Artifact[]);每条 Message 由 Part[] 组成(kind分 text/file/data);Artifact 内容也是 Part[]。Message 与 Artifact 结构几乎一样,区别在语义:Message 是协作过程的逐条往来,Artifact 是这次托付要交付的成果——分两类是为了让调用方一眼区分「过程」与「结果」。 - 不透明 = 远程 agent 不暴露内部提示词、记忆、内部工具、推理过程;只暴露 Agent Card 声明的能力 + 显式交换的 Message / Task。三条收益:① IP 保护(藏住提示词/工具/私有数据);② 安全面收缩(攻击面只剩声明的接口 + 消息通道);③ 解耦(双方各换内部实现,只要 Card 契约不变对端无感)。一条代价:调用方无法深度自省或细粒度协调对端,只能在「发消息 / 查 Task 状态」这个粒度上交互。
- 口诀:你是在调一个工具(给输入、要结构化结果、一次即结束)还是在托付给一个对等 agent(对方会自己推理、可能多轮、可能跑很久)?前者 MCP,后者 A2A。决定答案的是对端的性质,而不是它叫什么名字——一个名字里带「tool」的服务若其实有状态、会反问,那它该走 A2A。
- 正交是因为两者在不同的层各司其职、不在同一条线上抢位置:MCP 垂直(agent→工具,
tools/call),A2A 水平(agent→对等 agent,SendMessage+ Task)。典型形态:一个 agent 对外用 A2A 暴露成对等体供别人托付,对内用 MCP 调自己的工具去完成那次托付——这正是 2026 年企业级的默认两层栈。
原理层(对应 02 + 03 章)
- wire 上的 JSON-RPC
"method"是SendMessage(PascalCase,抽象名与 wire 字符串在 v1.0+ 完全一致;流式是SendStreamingMessage,查任务GetTask,取消CancelTask)。message/send那套斜杠名是 v0.x 的形式,v1.0 已改命名约定——它只能作为「迁移注记」出现,照旧博客写就会发错方法名。 - 实际 JSON 里是
SCREAMING_SNAKE风格,例如"status":{"state":"TASK_STATE_COMPLETED","timestamp":"…Z"}。全集:TASK_STATE_SUBMITTED / WORKING / INPUT_REQUIRED / AUTH_REQUIRED / COMPLETED / FAILED / CANCELED / REJECTED。小写completed是 v0.3.0 的形式(已弃用);拼写是美式CANCELED,v0.x 的英式cancelled已移除。 - 三种交互按任务时长和客户端形态分:请求/响应——短任务、当场要结果;SSE 流——要实时看进度,服务端用
Content-Type: text/event-stream逐帧推TaskStatusUpdateEvent/TaskArtifactUpdateEvent;webhook 推送——长任务 / 断线(serverless、移动)客户端,不必一直挂着连接。箭头方向不同:前两种是客户端发起、结果顺着回;webhook 推送是服务端反向 POST 到客户端的 url——方向反过来了。 - 该验证的是客户端。直觉是「客户端调服务端、服务端验客户端」,但 webhook 把方向反了:是服务端反向 POST 到客户端给定的 webhook url。于是来源验证的功课落到客户端——它必须用密码学手段(JWT + JWKS 验签 / HMAC / token + 时间戳防重放)确认入站 POST 真来自那个 agent,否则有人能伪造 POST 冒充 agent 推假结果。(SSRF 的责任则在服务端:它要校验 webhook url、封禁内网地址。一条边上两侧各有一份功课。)
- 都是中途态,不是终态——它们是可中断、可恢复的中间状态:Task 在
WORKING途中可落到INPUT_REQUIRED(要补信息)或AUTH_REQUIRED(要补凭证),拿到后再继续往终态走。与「一上来就 401」的区别:AUTH_REQUIRED是一个已在运行的任务中途提出要新凭证,而非连接建立时的前置鉴权失败——所以一个恶意 agent 能用它在任务跑到一半时钓凭证(§4.6)。 - 它们是「SDK 人体工学」与「wire 协议」两个层面的同一个动作:你在 Python 里调的是 snake_case
send_message(...),但 SDK 在底层把它编码成 JSON-RPC 时,"method"字段写的是 PascalCaseSendMessage。提醒你区分SDK 的命名风格 ≠ wire 上的协议字符串——别因为 Python 方法是 snake_case 就以为 wire 上也叫send_message(那其实更接近 v0.x 的斜杠名误区)。 - 因为「同一抽象、三种绑定」保证的是同版本内三种传输等价,并不保证跨版本兼容。v0.x 与 v1.0 在方法名(
message/send→SendMessage)、状态值(小写completed→TASK_STATE_COMPLETED)、Content-Type(如application/jsonvstext/event-stream/application/a2a+json)上都不是全 wire 兼容。所以即便两端都用 JSON-RPC 这同一种传输,一个 v0.x SDK 的 agent 和一个 v1.0 的 agent 仍可能对不上——选传输不解决版本错配(§4.7)。
应用判别层(综合 03–05)
- 当 A2A 对等 agent 接。判据(§1.5 口诀):被调对象有状态、会自己规划多步、可能多轮反问、任务长——符合「被托付一件事的自治对等体」,不符合 MCP「无状态、一次调用即结束的工具」画像。落地:让它发布 Agent Card 声明技能,用
SendMessage+ Task 承载这次有状态委托。它的「反问要补充信息」正好落在TASK_STATE_INPUT_REQUIRED这个中途态上(要补凭证则是AUTH_REQUIRED)——这是 MCP 的tools/call一次性调用根本表达不了的。 - 三种形态各取一种:(a) CLI 脚本——跑完即退、当场要结果,用请求/响应(短链路,不需要进度,也无谓挂长连接)。(b) 网页要实时进度——用 SSE 流,服务端逐帧推
TaskStatusUpdateEvent(正在取数 / 正在汇总)和TaskArtifactUpdateEvent,页面边收边渲染。(c) 手机 App、提交即锁屏、跑 20 分钟——用 webhook 推送:客户端注册一个回调 url 就可以断开,任务完成后服务端反向 POST 过来;让手机挂 20 分钟 SSE 连接既费电又会因切后台断流。判据始终是「任务多长 + 客户端能不能一直在线」。 - 该加,而且这是支付这类高敏场景的硬要求。不加会被 §4.2 的 Agent Card 伪造 / 冒充打穿——Card 默认不签名、没有强制的加密身份绑定,任何人都能在某个域名上摆一张「自称某银行」的 Card,host 无法仅凭 Card 内容确认它真来自那家银行。加一道 JWS 签名验证(配合 JCS 规范化)能挡住伪造。但光验签名不够:① 签名只证明「这张 Card 没被篡改、来自持私钥者」,证明不了「这个 agent 值得托付支付」——信任建立、授权按任务范围限定(§4.6)都还得自己做;② 还要防 §4.1 的描述注入——一张签名合法的 Card 仍可能在
description里塞诱导文本去赢得基于 LLM 的选路。一句话:验签名是必要条件,不是充分条件,因为「A2A-compliant ≠ secure」。 - 这条链拆成三跳:① 差旅编排 agent → 航司 agent=A2A(把「订票」托付给一个会处理、可能反问、要花时间的自治对等体,跨组织黑盒);② 航司 agent → 自家库存数据库 / 订座接口=MCP(航司 agent 往下调自己的工具/数据源,无状态、给输入回结果)。即便把航司内部再拆出一个「定价 agent」,那一跳仍是 agent↔agent 的 A2A,到「读数据库」才落回 MCP。它是企业默认两层栈,因为外层要的是「跨信任边界、把活托付给别家的对等 agent」(水平,A2A 的不透明对等体正好匹配),内层要的是「在自己掌控内调工具拿能力」(垂直,MCP 的无状态原语正好匹配)——两层各自匹配一种对端性质,正交叠用而非二选一。
把一道判别题反过来:哪种「看起来该用 A2A」其实不该
前面的判别题都在练「该用 A2A」。现在反向迁移——给一个看起来像 A2A、其实不该上 A2A 的真实场景,并说清三件事:① 它表面像 A2A 的哪一点(比如「也是两个组件在通信」);② 它实际缺了对等体的哪个本质特征(回到 §1.4 不透明 + §1.3 有状态 Task),所以更该用 MCP、共享 state 的进程内多 agent 框架、或干脆直接函数调用;③ 如果硬用 A2A,会白白付出哪些代价(回 §2.6 opaque 的代价那一笔账)。
提示(卡住再展开)
一类典型反例:你自己掌控的、跑在同一进程/同一信任域里、需要频繁共享中间状态的两个组件。它表面像 A2A(两个「agent」在通信),但 ① 你掌控两端、能看见内部——「不透明黑盒」这个本质特征根本不存在;② 它们要共享大量中间状态、要细粒度协调——而 A2A 的 opaque 原则恰恰堵死了深度自省与细粒度协调(§2.6 那笔代价),这正是 multi-agent-patterns 教的共享 state 框架擅长的。硬上 A2A 的代价:白白背上跨信任边界才需要的认证 / 发现 / 序列化开销、把本可共享的状态强行切成「发消息 + 查 Task」的粗粒度交互、还丢掉了对内部的可观测性。另一类反例:被调对象其实是个无状态、一次就结束的纯函数 / 数据查询——那是 MCP tools/call(甚至直接函数调用)的活,套上有状态 Task 的生命周期管理纯属浪费。判断的根子始终是 §1.5 的口诀:先问对端到底是不是「跨边界、看不见内部、有状态自治的对等体」。