05 · Agent 侧:从目录到合法 UI
本章讲什么: 前面四章都在讲「客户端怎么渲染」。这章看反方向——agent 怎么被引导生成合法的 A2UI。内容主要基于设计文档
agent_sdks/agent_sdk_guide.md(一份架构/移植指南),故凡描述 SDK 行为处,均按「指南所述设计」对待,而非逐行实现核验。
1. Agent SDK 负责什么
协议规范把 A2UI 的使用收敛成一个三步循环(a2ui_protocol.md:1133-1146):
- Prompt: 把「想要的 UI + A2UI schema(含目录)+ 合法 JSON 例子」拼进给 LLM 的 prompt。
- Generate: 送给 LLM,拿到生成的 JSON。
- Validate: 按 schema 校验;合法就发给客户端,不合法就把错误回喂给 LLM 让它自 我修正。
Agent SDK 就是把这三步工程化的库,职责是能力管理 + prompt 工程 + 输出校验(agent_sdk_guide.md:5-6)。它的数据流(agent_sdk_guide.md:9-15):定义能力(加载目录)→ 生成 prompt(注入 schema + few-shot)→ 流式解析 LLM 输出 → 校验 → 封装传输。
2. 四个核心接口
指南把 SDK 拆成四个关键接口(agent_sdk_guide.md:21-95):
| 接口 | 干什么 |
|---|---|
CatalogConfig / A2uiCatalog | 定义/加载目录,提供「渲染成 LLM 指令」和校验能力 |
InferenceStrategy | 组装系统 prompt(角色+工作流+UI 描述);标准实现 A2uiSchemaManager(动态注入 schema+例子)与 A2uiTemplateManager(用预定义模板) |
A2uiStreamParser | 流式解析 LLM 输出,边流边产出 UI 消息 |
PayloadFixer + A2uiValidator | 安全网:先修常见格式错,再做深度语义校验 |
3. Prompt 工程:token 省着花
SDK 的主要价值是生成动态、省 token 的系统 prompt(agent_sdk_guide.md:113-133):
- 剪枝 schema: agent 只用 Text+Button,就只把这两个的 schema 放进 prompt,省 token。
- 注入 few-shot 例子: 从目录的
examples/加载,对 LLM 准确率关键。 - 标准信封标签: prompt 要求 LLM 把 A2UI 输出包在
<a2ui-json>...</a2ui-json>里,以便确定性解析。
注意:generate_system_prompt 的签名暴露了一组很实用的开关——allowed_components、allowed_messages、include_schema、include_examples、validate_examples(agent_sdk_guide.md:56-74)。这让同一份目录能按场景裁出不同大小的 prompt。
4. 流式解析:正则块提取
A2uiStreamParser 用基于正则的块解析从 LLM 文本流里抓 A2UI JSON(agent_sdk_guide.md:137-180):
LLM 流: "这是你的表单 <a2ui-json> [ {...} ] </a2ui-json> 还需要什么?"
│ │
缓冲并透传对话文本 检测到闭合标签 → 正则抽出 JSON 块
▼ ▼
产出 text part 产出 a2ui_json part(发给客户端)
机制(agent_sdk_guide.md:159-180):
- 缓冲: 文本块追加进缓冲,见到
<a2ui-json>前的都当对话文本透传。 - 正则抽取: 开闭标签都到齐后,用
<a2ui-json>(.*?)</a2ui-json>(DOTALL)抽 JSON。 - 清洗: 抽出后去掉 LLM 可能误加的
```json围栏。 - 多块: 支持一段流里多个块,交替产出 text / json part。
5. 校验:比 JSON Schema 更深
A2uiValidator 做的不止 schema 校验,还有图结构层面的完整性检查(agent_sdk_guide.md:88-94):
| 检查 | 防什么 |
|---|---|
| JSON Schema 校验 | 字段类型/必填不合规 |
| 组件完整性 | ID 唯一、存在合法 root |
| 拓扑与可达性 | 循环引用(含自引用)、从 root 不可达的孤儿组件 |
| 递归深度限制 | 嵌套过深(如 50 层)、函数调用过深(如 5 层),防客户端栈溢出 |
| 路径语法 | JSON Pointer 绑定路径语法 |
「拓扑可达性」这条对邻接表模型尤其重要:因为树是靠 ID 引用隐式拼的,很容易出现 root 指不到的孤儿或自指环,光靠 JSON Schema 查不出来,得专门走图遍历。PayloadFixer 则在结构解析前先修 LLM 常见的「尾逗号、漏引号、括号没闭合」(agent_sdk_guide.md:84-85)。
6. 封装传输
校验过的 payload 要上网。在典型 Agent-to-App(A2A)拓扑里包成 DataPart(agent_sdk_guide.md:198-206):
- MIME 类型: A2UI JSON 标
application/a2ui+json,告诉前端怎么解读这段流。 createA2uiPart助手: 自动完成封装。- 产出策略: 既支持 LLM 说完后的完整对象,也支持流式解析器的增量产出(配合客户端的渐进渲染)。
7. 跨语言一致性靠 conformance 套件
SDK 是多语言生态(Python 为参考,另有 Kotlin 等)。为保证各语言行为一致,仓库维护一套语言无关的 conformance 测试套件(agent_sdks/conformance/,agent_sdk_guide.md:286-289):用集中的 YAML 用例(suites/parser.yaml、validator.yaml、streaming_parser.yaml 等)验证不同语言实现「在流式与校验边界上行为相同」。移植新语言 SDK 时,跑这套件就能确认行为对齐(agent_sdk_guide.md:243-265 的分阶段移植指南)。
8. 这章与前几章如何对接
[本章: Agent 侧] [01-04 章: Client 侧]
目录 ──► prompt ──► LLM ──► 流式解析 ──► 校验 ──► DataPart ──► MessageProcessor ──► 渲染
│ │ (01 章) (02-04 章)
└── 同一份目录(白名单)── 两头共享 ─────┘
关键洞察:agent 侧和 client 侧共享同一份目录定义——agent 用它生成 prompt 和校验,client 用它渲染和守安全边界。目录是把两端钉在一起的契约。
9. 代码地图
| 主题 | 文件 | 符号 |
|---|---|---|
| Agent SDK 架构 | agent_sdks/agent_sdk_guide.md | A2uiSchemaManager、InferenceStrategy |
| 流式解析设计 | 同上 | A2uiStreamParser、process_chunk |
| 校验设计 | 同上 | A2uiValidator、PayloadFixer |
| conformance 套件 | agent_sdks/conformance/suites/ | parser.yaml、validator.yaml、streaming_parser.yaml |
| 客户端能力生成(实现侧) | renderers/web_core/src/v0_9/processing/message-processor.ts | getClientCapabilities、getClientDataModel |
| 三步循环规范 | specification/v1_0/docs/a2ui_protocol.md | 「prompt-generate-validate loop」节 |
差异点回顾: 客户端能力对象在 v0_9 实现里用的键是
'v0.9'(message-processor.ts:75、getClientDataModel的version: 'v0.9',message-processor.ts:198),而 v1.0 规范用'v1.0'(a2ui_protocol.md:1266)。再次印证「规范候选 vs 实现 v0.9」的错位。