研究 25 分钟阅读

从聊天框到 AI 原生交互:跨 Agent、跨平台的应用架构

大多数 AI 产品最初都从聊天框开始:用户说一句,模型回一句。

  • AI 原生交互
  • Agent Protocol
  • Agent Runtime
  • Generative UI
  • MCP
  • 跨平台交互
目录

但 Agent 进入真实应用以后,系统开始发生根本变化。它不再只是“生成答案”,而是会持续执行任务、调用工具、产生中间状态、等待用户决定、生成可操作界面,并把真实业务动作交给后端执行。

于是问题不再是“应该选哪一个 Agent UI 协议”,而是更上游的三个问题:

Agent 应用出现了哪些新的连接边界?哪些语义应该稳定?模型、Runtime、UI 与业务系统应该怎样分工?

MCP、A2A、AG-UI、A2UI、MCP Apps、Apps SDK、Framework-native Generative UI 都是这个问题空间里逐渐长出的实现路线。它们是“果”,不是文章的出发点。

本文先从问题和设计原则出发,再看可选技术体系。后文会把“运行交互协议 + 声明式 UI”作为一个较完整的开放案例深入分析,但不会预设最终一定采用 AG-UI + A2UI。

1. Agent 走进真实应用:交互为什么从聊天变成系统问题

传统应用常见的是:

点击 → API 请求 → 返回结果 → 页面更新。

Agent 应用则更像一个持续工作的协作者:

  • 一个 Task 可能跨很多轮执行;
  • 中间会调用搜索、数据库、浏览器、代码环境等 Tool;
  • 会产生 Text、Artifact、Progress、State;
  • 可能需要用户补充输入或审批;
  • 用户可能直接编辑 AI 生成的结构化内容;
  • 一个任务可能在不同设备、甚至不同 Agent 之间继续。

因此 AI-native interaction 的核心不是“聊天框更丰富”,而是:

自然语言、直接 UI 操作、Agent 执行和业务系统,共同作用于同一个持续存在的任务。

flowchart TB A["用户提出目标"] --> B["Agent 规划并执行"] --> C["调用工具 / 其他 Agent"] --> D["产生文本、Artifact、状态或 UI"] --> E["用户查看、编辑、选择、批准"] --> F["Agent 根据新状态继续执行"] --> G["业务系统产生真实结果"]

这时,一个原本简单的“模型 API”问题,被拆成了多个不同的连接边界。

2. 问题空间与技术版图:Tool、Agent、Host、UI 分别需要什么连接层

从上面的体验变化继续往下拆,会看到至少四条不同连接边界。它们不是同一个问题,也因此长出了不同的协议和实现路线。

flowchart TB A["Agentic Application"] --> T["Agent ↔ Tool / Data"] --> AA["Agent ↔ Agent"] --> H["Agent ↔ Host / User"] --> UI["Agent ↔ Dynamic UI"] T --> MCP["MCP 等 Tool / Context 协议"] AA --> A2A["A2A 等 Agent Interop 协议"] H --> AG["AG-UI / 自定义 Runtime Event Protocol"] UI --> U1["A2UI:声明式 Native UI"] UI --> U2["MCP Apps:HTML App / iframe"] UI --> U3["Framework-native Generative UI"]
连接边界 主要问题 当前代表性路线
Agent ↔ Tool / Data 如何发现和调用外部工具、资源、Prompt MCP
Agent ↔ Agent 不同厂商 / Runtime 的 Agent 如何发现、委派、协作 A2A
Agent ↔ User App 长运行、Tool、State、Interrupt 怎样实时进入应用 AG-UI、应用自定义事件协议
Agent ↔ Dynamic UI Agent 怎样产生可交互 UI,而不是只返回文本 A2UI、MCP Apps、Framework-native Generative UI

MCP 官方把自己定位为连接 AI 应用与 Tool / Data 的开放标准;A2A 则面向独立 Agent 之间的发现、任务和协作。S22 S23

AG-UI 官方也用一张 Protocol Stack 把 MCP、A2A 与 AG-UI 放在不同连接关系中:S02

AG-UI 官方 AI Protocol Stack

所以第一个重要结论是:

Agent 交互并没有一个“总协议”可以解决所有问题。协议生态正在按连接边界分层。

Tool 能返回 JSON,不等于用户就愿意看 JSON。

当用户需要:

  • 比较多个结果;
  • 填写结构化参数;
  • 操作图表;
  • 审阅 Diff;
  • 确认订单或审批;
  • 在任务执行中持续查看状态;

系统就需要从 Agent Response 进一步走向 Agent-driven UI。

这里又产生一个新的设计分叉:

UI 到底应该是“Agent 发送结构,由 Host 渲染”,还是“服务端直接交付一个可运行的小应用”?

这正是 A2UI、MCP Apps,以及各类 Framework-native Generative UI 路线开始分化的地方。

在这个问题空间里,当前公开生态至少有下面几类代表性路线。

2.1 MCP:先解决 Agent 如何获得外部能力

MCP(Model Context Protocol)首先解决的不是 UI,而是:

AI 应用怎样以标准方式连接 Tool、Resource 与 Prompt。

当前 MCP SDK 文档将其定义为连接 AI 应用与数据、工具系统的开放标准;Server 暴露 Tool / Resource,Host 连接 Server,再让模型使用这些能力。S22

MCP 的意义在于把“能力接入”从各家 Agent SDK 的私有 Tool Schema 中抽出来。

但 Tool 能被调用,并不自动解决:

  • Agent 运行状态怎样进入 UI;
  • 用户怎样在中途修改任务;
  • Tool Result 应该怎样变成富交互界面。

所以 MCP 后来又自然延伸出了 MCP Apps 这样的 UI 扩展。

2.2 A2A:当系统里不再只有一个 Agent

A2A(Agent2Agent Protocol)面向的是另一类问题:

一个 Agent 怎样发现、调用、委派任务给另一个独立 Agent。

A2A 1.0 官方规范强调,它面向不同框架、语言、厂商构建的独立 Agent,并通过 Agent Card、Task、Message、Artifact 等公共模型实现互操作,而不要求暴露对方内部 memory、tools 或实现细节。S23

因此在多 Agent Mesh 中,更自然的结构可能是:

flowchart TB U["User / Host"] --> A["Coordinator Agent"] A --> B["Remote Agent B"] A --> C["Remote Agent C"] A --> D["Remote Agent D"] A <-. "A2A" .-> B A <-. "A2A" .-> C A <-. "A2A" .-> D B --> T1["Tools via MCP"] C --> T2["Tools via MCP"]

这里的核心协议可能首先是 A2A + MCP,而不是 AG-UI。

2.3 AG-UI:一个运行交互层

AG-UI(Agent–User Interaction Protocol)解决的是:

Agent 正在做什么,用户应用怎样持续理解它,以及用户操作怎样再回到 Agent。

官方将它定义为开放、轻量、事件驱动的 Agent ↔ User App 协议;Run、Message、Tool、State、Interrupt 等都只是为了让应用获得统一的运行语义。S01 S04

AG-UI 官方 Overview

官方 Overview 的核心含义:不同 Agent Runtime 和不同 Client 可以通过公共交互边界接线。协议统一的是运行语义,不要求 Runtime 内部实现一致。

如果应用完全由自己控制,也可以维护自定义 Runtime Event Protocol。AG-UI 的价值主要在于:当 Agent / Client 数量增加时,不必让每个前端都理解每种 Runtime 的私有事件。

2.4 A2UI:一个声明式 UI 层

A2UI(Agent to UI)解决的是另一个问题:

Agent 怎样表达“需要什么界面”,而不是直接发送 React、HTML 或任意 JavaScript。

官方将 A2UI 描述为声明式 UI 格式:Agent 发送 UI 数据,Host 根据 Catalog 用本地 Renderer 画出真实组件。S09

flowchart TB A["Agent"] --> M["A2UI 声明"] --> C["Catalog:允许使用哪些组件"] --> R["Renderer:映射到本地组件"] --> H["Host UI"] --> U["User"] U --> X["Action / Input"] X --> A

所以 A2UI 的核心不是消息字段本身,而是一个分工:

  • Agent 决定需要什么信息和交互;
  • Catalog 约束它可以使用什么 UI 能力;
  • Renderer / Host 决定这些能力在 React、Flutter 等平台怎样实现;
  • 用户 Action 再回到 Agent 或应用。

具体 JSON 操作、middleware 和内部消息格式属于实现细节,只有真正接入时才需要进入。

2.5 MCP Apps:不是描述 UI,而是直接交付一个受沙箱约束的小应用

MCP Apps 是另一种很不同的路线。

官方定义是:

MCP Server 可以为 Tool 声明一个 ui:// UI Resource,Host 将 HTML App 放在 sandboxed iframe 里运行,并通过 postMessage / JSON-RPC 与它通信。S24

其架构更像:

flowchart TB S["MCP Server"] --> T["Tool"] S --> R["ui:// HTML Resource"] T --> H["MCP Host"] R --> H H --> V["Sandboxed iframe App"] V --> U["User"] V --> H H --> S

这种方式的核心特点是:

  • Server / App 作者拥有完整 HTML / CSS / JS 表达能力;
  • Host 用 iframe 和 CSP 做隔离;
  • Tool 与 UI 可以一起分发;
  • 支持 MCP Apps 的 Host 可以复用同一个 App。

它与 A2UI 的设计哲学并不相同:

A2UI MCP Apps
Agent / Server 发送什么 声明式 Component Blueprint 预构建 HTML App
谁控制最终视觉 Host / Renderer App 作者
隔离方式 不执行远程 UI 代码 sandboxed iframe
跨 Native Renderer 更自然 主要是 Web View / iframe 模型
表达上限 受 Catalog 限制 接近完整 Web App
适合 Host-owned Design System、动态生成 UI Tool-backed 富应用、复杂自定义交互

A2UI 官方自己的生态比较页也将这两种路线明确区分。S11

2.6 OpenAI Apps SDK:MCP Apps 路线上的一个 Host / 产品实现

OpenAI Apps SDK 不是另一套完全独立的底层协议。

当前 OpenAI 官方文档明确建议:新的 UI 先使用开放的 MCP Apps standard,ChatGPT 特有能力再通过可选的 window.openai 扩展增强;组件运行在 ChatGPT iframe 中,并通过 MCP Apps bridge 与 Host 通信。S25

因此如果目标是:

  • 把 Tool + UI 分发到 ChatGPT;
  • 同时希望尽量兼容其他 MCP Apps Host;

这条路线可能比“自建 AG-UI Host + A2UI Renderer”更直接。

2.7 Framework-native Generative UI:在自己控制的技术栈里最快

还有一类路线根本不追求跨 Host 协议标准。

例如 Vercel AI SDK 的 Generative UI 思路,是让模型 Tool Call 的结果直接映射到 React Component;AI SDK UI 提供构建 Chat / Generative UI 的 Framework hooks。S26

这种方式的优点非常实际:

  • 前端工程路径短;
  • React 组件可以直接复用;
  • 不需要额外设计跨平台 UI Protocol;
  • 适合自己同时控制 Agent 和 Web App 的产品。

它的代价是:

可移植边界更多停留在你的应用框架里,而不是跨 Host / 跨 Renderer 的开放协议层。

这并不是“不够先进”,而是目标不同。

2.8 技术路线真正的分叉点

因此 Agent UI 不应该被简化成“AG-UI vs A2UI”。

更准确的技术地图是:

flowchart TB A["你在构建什么?"] A --> B{"需要接外部 Tool / Data?"} B -->|是| MCP["MCP"] A --> C{"需要独立 Agent 互操作?"} C -->|是| A2A["A2A"] A --> D{"需要自己 App 理解 Agent Runtime?"} D -->|是| AG["AG-UI 或自定义 Runtime Protocol"] A --> E{"需要 Agent-driven UI?"} E -->|是| F{"谁应该拥有 UI 实现?"} F -->|Host 拥有组件 / Design System| A2UI["A2UI / Declarative UI"] F -->|Server/App 作者拥有完整 UI| APPS["MCP Apps / Apps SDK"] F -->|双方都在同一 Web 技术栈| FW["Framework-native Generative UI"]

3. 设计原则:先稳定任务语义,再选择协议和框架

协议和框架都可能变化,但用户正在完成的任务不应该跟着技术栈一起消失。

协议可以替换,Task 不应该跟着消失。

3.1 先稳定业务语义

建议优先稳定:

稳定对象 它回答的问题
Task 用户到底在持续完成哪件事?
Artifact 当前工作的可交付对象是什么?
Action 用户或 Agent 想产生什么业务效果?
State 哪些状态需要被共享、恢复或持久化?
Capability 当前 Agent / Host / Channel 实际能做什么?
Permission 当前操作者是否允许执行这件事?
Version / Revision 用户确认的内容是否还是即将执行的那一版?

相反,不需要为了统一而强行标准化:

  • Agent 内部 Planner;
  • Runtime 私有 checkpoint;
  • Model private memory;
  • React / Flutter 的实现;
  • Slack 与 Web 的像素布局。
flowchart TB A["长期稳定的业务语义"] --> T["Task"] --> AR["Artifact"] --> AC["Action"] --> S["State"] --> C["Capability"] --> P["Permission"] --> V["Version / Revision"] B["可以变化的技术实现"] --> PROTO["AG-UI / A2A / MCP / Custom Protocol"] --> UI["A2UI / MCP Apps / Native UI"] --> R["Runtime / Framework / Renderer"]

核心原则是:

技术体系可以替换;用户正在完成的“同一件事”必须保持稳定。

这也是后面所有架构设计的真正起点。

3.2 再用五个问题决定技术边界

1. Host 是谁控制的?

如果 Web / Mobile / Desktop 都是自己的产品,Host 拥有很强控制权,可以选择:

  • AG-UI;
  • A2UI;
  • Framework-native UI;
  • 自定义协议。

如果 UI 要进入 ChatGPT、Claude Desktop 等第三方 Host,MCP Apps 这种 Host Extension 标准会更自然。

2. 谁应该控制视觉和组件实现?

如果必须严格继承企业 Design System:

Declarative UI / Host Renderer 更合适。

如果集成方必须拥有完整视觉和交互:

Sandboxed App / iframe 路线更合适。

3. 是否真的需要跨 Renderer?

如果产品只有 React Web:

Vercel AI SDK / CopilotKit / 自研 Generative UI 很可能已经足够。

如果目标明确包含 Flutter、Angular、Native 等多个 Renderer:

A2UI 这类声明式中间表示才更有价值。

4. 是否需要跨独立 Agent?

如果只是一个 Runtime 内部的 Sub-agent:

不一定需要 A2A。

如果多个 Agent 属于不同系统、团队或厂商:

A2A 的 Agent Card、Task、Artifact 模型会更重要。S23

5. UI 是任务主体,还是 Tool 的附属交互?

如果 UI 本质上是某个 MCP Tool 的“脸”:

MCP Apps 很自然。

如果 UI 是整个 Agent Application 的长期工作区:

Runtime Interaction + Host-owned UI 的体系通常更自然。

3.3 典型技术组合

目标场景 更自然的技术组合
自有 Web App,需要替换多个 Agent Runtime AG-UI / 自定义 Runtime Protocol + Native UI
自有多端 App,需要 Agent 动态生成 Native UI AG-UI 或 A2A + A2UI
远程 Agent Mesh,同时携带可渲染结果 A2A + A2UI
MCP Tool 希望在 ChatGPT / Claude 等 Host 里提供富 UI MCP + MCP Apps
ChatGPT 内的业务 App,需要额外 Host 能力 MCP Apps + OpenAI Apps SDK extensions
单一 React 产品,前后端都自己控制 Vercel AI SDK / Framework-native Generative UI
复杂 Editor / Canvas / 3D App Native App / MCP Apps,Agent 通过 Tool / Action 控制;不一定适合全量声明式生成

3.4 为什么后文重点观察“运行交互 + 声明式 UI”

不是因为它们已经“赢了”,而是因为这一组合很适合观察一套开放的 AI Interaction Architecture:

  1. 分层清楚:运行交互和 UI 表达被拆成两个独立问题;
  2. 公开、可检查:都有公开规范、SDK / Renderer 以及官方组合路径;A2UI 也不限定只能经 AG-UI 传输。S15 S17
  3. 能暴露真正的架构问题:Host-owned UI、跨 Renderer、State、Action、Capability、Permission 都会在这条路径上出现。

因此后文会拿它们做一个较完整的开放案例,但结论仍然适用于 MCP Apps、A2A + UI、Framework-native Generative UI 或自定义体系。

如果产品是 Tool-first、第三方 Chat Host-first,MCP Apps 可能更直接;如果核心是跨组织 Agent Mesh,A2A 更重要;如果只有一个 React App,Framework-native Generative UI 往往更简单。

4. 模型与系统如何协作:Prompt、Tool、Schema、Protocol 各管什么

到这里容易产生一个实际问题:

这些交互到底是靠 Prompt 让模型“听话”,还是靠 Tool Calling,还是协议本身在约束模型?

答案是:它们负责不同层,通常会同时存在。

层 最简单的理解 能保证什么 不能保证什么
Prompt / Context 告诉模型“你有什么能力、什么时候用” 引导模型选择和生成 不能作为安全边界
Tool / Function Schema 给模型一组结构化动作接口 工具名和参数形状更稳定 不代表模型有执行权限
Structured Output / UI Schema 约束模型生成的数据形状 UI / 结果更容易解析和校验 不代表业务内容正确
AG-UI / A2UI / MCP 等协议 在系统之间传递运行事件、Tool、UI、Action 统一通信和生命周期 不负责模型推理本身
Runtime / Business Validation 真正执行前再次校验 权限、版本、幂等、业务规则 不能省略

Tool Calling:最适合“模型需要选择一个动作”

AG-UI 官方的 Tool 结构本质上就是:name + description + JSON Schema parameters。Schema 同时帮助 Agent 生成参数,也帮助应用解析和校验参数。S05

下面是厂商无关的简化示意,不对应某一家模型 API:

const tools = [
  {
    name: "searchOrders",
    description: "查询用户订单",
    parameters: {
      type: "object",
      properties: {
        keyword: { type: "string" }
      },
      required: ["keyword"]
    }
  },
  {
    name: "requestApproval",
    description: "请求用户确认一个高风险动作",
    parameters: {
      type: "object",
      properties: {
        actionId: { type: "string" },
        summary: { type: "string" }
      },
      required: ["actionId", "summary"]
    }
  }
];

// 模型只负责:选哪个 tool、填什么参数
const turn = await model.run({ messages, tools });

// 系统仍然负责最终校验和执行
for (const call of turn.toolCalls) {
  const args = validateSchema(call.name, call.args);
  await dispatchWithPermissionCheck(call.name, args);
}

最重要的一点是:

Tool Calling 是“模型提出一个结构化动作”,不是“模型获得这个动作的权限”。

生成 UI:固定模板优先,动态生成再用 Schema / Structured Output

A2UI 官方 Agent Development Guide 把模型侧流程概括成四步:

理解意图 → 生成 A2UI → 校验并发送 → 处理用户 Action。S27

其中生成阶段可以使用 Prompt 或 Structured Output;Catalog 的 Schema 和示例可以被放进模型上下文,让模型知道自己允许使用哪些组件。S27

工程上可以简单分成两种方式:

flowchart TB A["模型得到用户意图 + Tool / Catalog 描述"] --> B{"UI 是否基本确定?"} B -->|是| C["模型选业务 Tool"] C --> D["代码 / 模板生成 UI"] D --> V["Schema 校验"] B -->|否| E["模型按 Catalog 动态生成 UI"] E --> V V -->|通过| R["发送给 Renderer"] V -->|失败| F["修复 / fallback"]

固定业务流程优先使用代码或模板。
例如审批、订单确认、支付参数这类 UI,不需要为了“AI-native”强行让模型每次重新设计布局。

只有当界面结构本身确实取决于任务内容时,才值得让模型动态生成 A2UI。

Protocol:负责搬运,不负责“教模型思考”

最后要把协议和模型能力彻底分开:

  • AG-UI 搬运 Run / Tool / State / Interrupt;
  • A2UI 搬运声明式 UI 和 Action;
  • MCP 暴露 Tool / Resource;
  • A2A 传递 Agent Task / Artifact。

这些协议并不会让模型自动知道什么时候该调用 Tool,也不会替代 Prompt、Tool Schema、Structured Output 和运行时校验。

更准确的链路是:

flowchart TB U["User Intent"] --> P["Prompt / Context 告诉模型有哪些能力"] --> M["Model 选择 Tool 或生成结构化结果"] --> S["Schema Validation"] --> PR["Protocol / Runtime 传输事件、UI、Action"] --> B["Business Validation Permission / Version / Idempotency"] --> X["真实执行或 Renderer"]

这也是为什么模型侧设计和协议侧设计应该分开评审:前者决定模型会尝试做什么,后者决定系统怎样表达和传递,最后的 Business Gate 决定什么真的允许发生。

5. 推荐架构:Experience、Interaction、Runtime、Control Plane 如何分工

理解问题空间、设计原则和模型侧约束之后,再看完整系统如何组织。

推荐把系统看成四个逻辑层:

flowchart TB E["Experience Layer\nWeb / Mobile / IM / CLI"] --> I["Interaction Layer\nProtocol / Generative UI / Channel Adapter"] --> R["Agent Runtime\nPlanning / Tool / Memory / Sub-agent"] --> B["Business Control Plane\nTask / Artifact / Action / Permission / Audit"]

它们不一定要部署成四个服务,但职责应该尽量清楚。

5.1 完整架构

flowchart TB U["Web / App / Slack / CLI"] U <--> H["Host / Channel Adapter"] H <--> AG["AG-UI Interaction"] H <--> UI["Native UI / A2UI Renderer"] AG <--> AD["Agent Adapter"] AD <--> A["Agent Runtime"] A <--> MCP["MCP / Tools"] A <--> A2A["A2A / Other Agents"] H <--> CORE["Task · Artifact · Action · Permission · Version"] A <--> CORE

图里真正应该被长期稳定下来的,不是某个协议名称,而是底部的业务 Control Plane。

5.2 Experience Layer:允许不同平台拥有不同体验

Web、移动端、IM、CLI 不应该被迫使用同一种界面。

Host 负责:

  • 呈现任务;
  • 收集用户输入;
  • 提供当前选中对象等语义上下文;
  • 运行本地交互;
  • 在支持时渲染 A2UI;
  • 在受限平台做 Channel Adapter。

统一的是用户正在完成的任务,不是像素。

5.3 Interaction Layer:协议只解决通信和表达

这一层可以包括:

  • AG-UI;
  • A2UI;
  • Native Generative UI;
  • Channel Adapter;
  • Capability / Catalog 解析。

它负责把 Agent 的运行过程和动态 UI 表达转换为 Host 可以理解的公共语义。

但它不应该成为业务数据库。

5.4 Agent Runtime:保留内部自由度

Runtime 可以继续自由选择:

  • LangGraph;
  • ADK;
  • 自研 Runtime;
  • 单 Agent / Multi-agent;
  • MCP;
  • A2A;
  • 私有 checkpoint;
  • private memory。

只要它在公共边界上暴露真实、可验证的能力,就不要求内部实现一致。

5.5 Business Control Plane:为什么服务端不会消失

以下能力不能依赖模型或 Renderer 决定:

  • 用户身份;
  • tenant;
  • 权限;
  • Artifact 版本;
  • Action 幂等;
  • 审批;
  • 审计;
  • 事务;
  • 长任务状态;
  • 真实副作用是否成功。

因此:

协议负责解耦,Business Control Plane 负责连续性、授权和正确性。

“解耦”从来不意味着零耦合。

真正的目标是:

把不稳定、散落的私有耦合,收敛成少数稳定、明确、可测试的边界。

6. 治理边界:状态、权限、能力、组件和协作怎么管

完整架构看起来很干净,但真正决定它能不能进入生产的,是所有权、权限、能力和版本边界。

完整架构看起来很干净,但系统收敛并不是免费的。

真正复杂的地方,往往不在“协议能不能连通”,而在下面这些边界怎样被团队共同维护。

6.1 State Ownership:谁才是权威状态

至少要区分四类状态:

状态 推荐权威来源
Agent checkpoint / private memory Agent Runtime
Task / Artifact / Revision Business Backend
A2UI Data Model Surface / Renderer
未提交输入、焦点、滚动等 Local UI

不要把它们合成一个巨大的共享 JSON,然后所有地方都能 patch。

典型事故是:

用户正在编辑标题,Agent 同时返回整份新状态,把用户尚未提交的输入静默覆盖。

因此需要明确:

  • 哪一层有权覆盖哪一类状态;
  • Artifact 是否有 revision;
  • UI dirty field 如何处理;
  • 冲突是自动合并、提示用户,还是拒绝写入。

6.2 Action:按钮不是权限

A2UI 能让 Agent 生成一个“发布”按钮,但:

生成一个按钮 ≠ 获得发布权限。

真实副作用仍然应该进入统一的业务 Command / Action Handler。

例如:

flowchart TB A["Web Button / Slack Card / Natural Language Confirm"] --> B["统一 Action"] --> C["Authentication"] --> D["Permission"] --> E["Artifact Revision"] --> F["Idempotency"] --> G["Business Command"] --> H["真实执行结果 / Audit"]

这样 Web、Slack 或自然语言“确认”只是不同输入形式,不会形成三个互相独立的业务执行入口。

6.3 Catalog:跨平台能力和跨平台成本来自同一个地方

A2UI 最大的价值之一是 Catalog。

但 Catalog 也是主要成本来源。

一个高阶业务组件通常至少要定义:

  • Schema;
  • 数据语义;
  • Action;
  • Web Renderer;
  • Mobile Renderer;
  • fallback;
  • accessibility 行为。

Catalog 越“业务化”,例如:

  • DiffReview;
  • OrderCard;
  • ApprovalPanel;
  • DashboardChart;
  • RichEditor;

Agent 输出就越短、越稳定,但每个目标 Renderer 的实现成本越高。

Catalog 越“原子化”,只提供 Text / Row / Button / Input,跨平台实现容易,但模型需要生成更长的组件树,UI 一致性也更难控制。

这本质上是一个生成复杂度 vs Renderer 适配成本的粒度权衡。

A2UI 官方也建议生产系统定义自己的 Catalog,并映射到自己的 Design System。S21

6.4 多 Agent 还需要 Surface Ownership

多 Agent 同时工作的系统里,还必须知道:

这个 Surface 到底是谁创建的?

A2UI Actions 文档专门讨论了 Surface Ownership:由哪个 Agent 创建的 Surface,其 Action 和相应 Data Model 应路由回正确的 Agent,而不是广播给所有 Agent。S14

这既是正确性问题,也是数据隔离问题。

6.5 Capability:能连接不等于能力相同

同样是 AG-UI Agent,不代表都支持:

  • Tool streaming;
  • Shared State;
  • Interrupt / Resume;
  • Multimodal;
  • Cancel;
  • A2UI。

AG-UI 有能力发现机制,但官方也明确:discovery 不等于 negotiation,缺省能力应该视为 unknown。S07

所以 Host 不应该写:

if (agent.protocol === "ag-ui") {
  showAllFeatures();
}

而应该根据真实 Capability 决定功能和降级路径。

6.6 版本矩阵不能只写“支持 A2UI”

A2UI 当前生产基线是 v0.9.1,v1.0 仍是 Candidate。S18 S20

生产环境应该记录整组兼容面:

AG-UI SDK
+ Runtime Adapter
+ A2UI Middleware
+ A2UI Protocol
+ Renderer
+ Catalog

协议名相同,不代表任意版本组合都天然兼容。

6.7 真正需要哪些团队配合

角色 主要责任
Agent / AI 工程 Runtime Adapter、Tool、真实 Capability、必要时生成 A2UI
前端 AG-UI Client、Renderer、Catalog、本地交互
业务后端 Task、Artifact、Action、Permission、Revision、幂等、审计
平台集成 Slack / Teams / Mobile Channel Adapter
Design System 哪些组件进入 Catalog、不同 Renderer 的一致语义
QA / Infra 多 Runtime × 多 Client × 多版本兼容与可观测性

因此这类架构的协作成本主要不是“装几个 SDK”,而是:

让多个团队开始围绕同一组任务、状态、动作和能力语义工作。

7. 系统收敛:真正降低的是语义版本数量和信息熵

知道代价之后,才能准确讨论为什么值得做。

“省开发成本”只是结果之一,更深层的价值是:

减少整个系统里同时存在的语义版本数量,降低工程上的信息熵。

7.1 交互语义收敛

原来不同 Agent 可能分别使用:

waiting_for_user
needs_input
paused
approval_required

不同 UI 又可能定义:

modal_waiting
pending_confirmation
human_required

它们本质上可能都是:

当前 Task 正在等待 Human Input。

当这些语义进入统一 Interaction Model 后,日志、UI、监控和测试都不需要重复解释。

7.2 State 收敛

原来常见的状态混乱是:

  • Runtime 觉得自己拥有完整 state;
  • UI 也保存完整 state;
  • Backend 还有一份数据库 state;
  • A2UI Surface 又有一份 data model。

收敛并不是把它们全部合并,而是明确所有权:

flowchart TB S["State Ownership"] S --> R["Runtime State\ncheckpoint / private memory"] S --> B["Business State\nTask / Artifact / Revision"] S --> U["Surface State\nA2UI Data Model"] S --> L["Local State\nfocus / dirty input / scroll"]

系统因此减少的是同一事实被多处当成权威来源的情况。

7.3 Action 收敛

以前可能是:

Web 按钮 → REST API A
Slack Card → Webhook B
自然语言“确认” → Agent Tool C

最后三条链都可能执行同一项“发布”。

收敛后:

flowchart TB A["Web Button"] B["Slack Card"] C["自然语言确认"] A --> D["统一 Action / Command"] B --> D C --> D D --> E["Permission + Revision + Idempotency"] E --> F["唯一业务执行路径"]

这不仅降低开发重复,也大幅降低权限漂移和重复副作用的风险。

7.4 Capability 收敛

不同 Agent 和不同 Channel 不需要再用大量产品硬编码描述:

“这个入口应该可以做什么。”

Capability、Catalog 和 Channel 能力开始变成显式输入。

系统可以根据真实能力决定:

  • 完整呈现;
  • 降级;
  • 隐藏;
  • 转到更可信的入口。

7.5 N×M → N+M 只是表象

没有公共边界时:

flowchart TB A1["Agent 1"] --> U1["UI 1"] A1 --> U2["UI 2"] A1 --> U3["UI 3"] A2["Agent 2"] --> U1 A2 --> U2 A2 --> U3 A3["Agent 3"] --> U1 A3 --> U2 A3 --> U3

建立公共边界后:

flowchart TB A1["Agent 1"] --> P["公共交互 / UI 契约"] A2["Agent 2"] --> P A3["Agent 3"] --> P P --> U1["UI 1"] P --> U2["UI 2"] P --> U3["UI 3"]

接线模块数量可以从接近 N×M 下降为 N+M。

但这只是表象。

仍然存在:

  1. Component × Renderer:自定义 Catalog 的实现;
  2. Agent × Client:行为兼容测试;
  3. Business Action:安全和业务校验。

所以更准确的收益是:

从大量重复但不完全相同的局部协议,收敛到一组可以治理、测试、观测和演进的公共语义。

真正减少的不是接口数量,而是同一个概念需要被重新解释的次数。

8. 进阶能力:跨 Agent、跨平台能走多远

跨 Agent、跨平台不应该是架构一开始的人为目标。

更自然的关系是:

当 Task、Action、State 和 Capability 已经从具体 Runtime / UI 中抽离,跨 Agent 与跨平台才成为系统收敛后的能力红利。

8.1 跨 Agent:迁移业务事实,不迁移 Runtime

“同一个 UI 可以接 Agent A 和 Agent B”相对容易。

真正困难的是:

Agent A 执行到一半,Agent B 能不能无损接管?

通常不能直接保证。

不同 Runtime 可能持有:

  • 私有 checkpoint;
  • internal memory;
  • pending tool call;
  • planner 状态;
  • 调用栈;
  • 子 Agent 状态。

更可靠的设计是抽取可移交的业务事实:

flowchart TB A["Agent A Runtime"] A --> H["Handoff"] H --> T["Task"] H --> AR["Artifact + Revision"] H --> C["Constraints / User Decisions"] H --> P["Pending Action / Permission"] T --> B["Agent B 新 Runtime"] AR --> B C --> B P --> B A -. "通常不要求直接迁移" .-> X["私有 checkpoint / 调用栈"]

因此:

跨 Agent 的可靠边界,是业务状态和交接事实可移植,而不是 Runtime 内部执行状态完全可移植。

8.2 跨平台:迁移 UI 语义,不迁移像素

A2UI 当前提供 Web、Flutter 等 Renderer 路径。S16

其抽象关系是:

flowchart TB A["Agent 输出 A2UI"] A --> C["Catalog:例如 ProductCard"] C --> W["Web Renderer\nReact ProductCard"] C --> M["Mobile Renderer\nFlutter ProductCard"] C --> D["Desktop Renderer\nDesktop ProductCard"]

基础组件越多,跨平台越容易:

  • Text;
  • Button;
  • Card;
  • TextField。

高阶业务组件越多,体验越强,但跨 Renderer 实现成本越高。

所以:

A2UI 降低的是 UI 组合逻辑和 Agent 输出协议的重复,不是消灭跨平台组件开发。

8.3 封闭平台要共享任务语义,而不是强行共享 UI Tree

Slack、Teams、CLI 等平台通常不能直接运行你的完整 Renderer。

这时应该使用 Channel Adapter:

flowchart TB T["统一 Task / Artifact / Action / Permission"] T --> W["Web\n完整 A2UI / Native UI"] T --> M["Mobile\nA2UI Renderer"] T --> S["Slack / Teams\n平台原生 Card / Action"] T --> C["CLI\nText + Structured Selection"]

因此真正需要跨平台保持一致的是:

  • Task;
  • Artifact;
  • Action;
  • Permission;
  • 用户意图;
  • Revision。

而不是同一棵 UI Tree。

8.4 安全语义不能随着平台一起降级

如果某个平台无法完整展示待批准内容,或者无法可靠绑定操作者身份,那么它可以:

  • 展示状态;
  • 提醒用户;
  • 提供只读摘要;
  • 引导到可信入口。

但不应该因为“需要跨平台”就把严格审批降级成一句:

回复 yes 即可。

跨平台能力的正确目标是:

体验可以降级,业务安全语义不能静默降级。

8.5 最终能得到什么

完成这些收敛以后,一个成熟系统可以更自然地实现:

  • 同一个 Task 在 Web 和 Mobile 之间继续;
  • 同一个业务 Action 从 UI、IM、自然语言等不同入口进入统一 Command;
  • Agent 更换后继续使用相同 Artifact / Constraints;
  • Renderer 变化后仍理解相同 Surface / Catalog 语义;
  • 不同平台根据 Capability 选择完整交互或合理降级。

这才是“跨 Agent、跨平台”真正有价值的含义。

9. 演进路线:从单点功能到可治理系统

前面描述的是目标架构。

现实系统不应该一次性把所有协议、Renderer、Channel 和 Runtime 全部重构完。

更稳妥的路线是:

flowchart TB A["1. 先收敛业务语义\nTask / Artifact / Action / Revision"] --> B["2. 再收敛 Agent 交互\n第二个 Runtime 接入"] --> C["3. 再收敛 UI 表达\n固定 A2UI Surface"] --> D["4. 验证 State / Permission 边界"] --> E["5. 增加真正不同的平台"] --> F["6. 最后开放动态 Generative UI"]

9.1 第一步:先定义 Task / Artifact / Action

不要先安装 AG-UI 或 A2UI,然后再寻找业务模型。

先回答:

  • Task 是什么;
  • Artifact 是什么;
  • 哪些 Action 会产生真实副作用;
  • Artifact 怎样版本化;
  • 什么叫“等待用户”;
  • 什么叫“业务完成”。

至少建立稳定的:

taskId
artifactId
revision
actionId
permission

这样未来断线、换端、换 Agent 时,业务事实不会只存在某一个 Runtime 或页面内存里。

9.2 第二步:用第二个 Runtime 验证交互边界

同一个 Web UI 接两个不同 Runtime。

第一版只覆盖:

  • Text;
  • Tool Progress;
  • Error;
  • 一个 Human Input / Interrupt。

验收目标不是功能多,而是:

前端不再需要增加 Runtime 私有判断。

这一步验证 AG-UI / Adapter 边界是否真的成立。

9.3 第三步:A2UI 先做固定结构,不要先追求自由生成

优先选择高价值、确定性强的场景:

  • Result List;
  • Form;
  • Approval;
  • Diff Review。

先由代码或稳定模板产生 Surface,只让数据动态更新。

等 Action、Data Model、Renderer、权限链路跑通以后,再考虑让模型动态组合组件。

9.4 第四步:专门验证最容易出事故的边界

不要只测“能不能渲染”。

至少需要覆盖:

  • 断线重连;
  • 重复 Action;
  • Artifact revision 冲突;
  • 用户编辑时后台状态更新;
  • 权限变化;
  • Action 过期;
  • 多 Agent Surface Ownership;
  • 未知 Catalog / Component;
  • Renderer 版本不匹配;
  • Tool 已产生副作用但客户端取消连接。

9.5 第五步:增加一个真正不同的平台

不要只做另一个 Web 页面。

优先选:

  • Flutter;
  • Slack / Teams;
  • CLI。

因为这会最快暴露:

  • 哪些抽象真的跨平台;
  • 哪些组件只在浏览器成立;
  • 哪些业务动作不能降级;
  • 哪些内容应该进入 Channel Adapter。

9.6 第六步:最后才开放动态 UI

只有当固定模板已经覆盖不了真实需求时,再开放 Agent 在受控 Catalog 内动态组合。

同时限制:

  • Catalog;
  • 组件数量;
  • Schema;
  • Action 类型;
  • Retry 次数;
  • Resource URL;
  • 高风险操作入口。

这样可以避免:

先建设一个很漂亮的“大一统 AI UI 平台”,最后却没有足够真实场景证明它值得存在。

9.7 最终验收不应该只看“能不能跑”

建议至少观察:

场景 合格行为
同一 UI 换 Agent UI 无需增加 Runtime 私有分支
同一 Task 换端 任务和未决 Action 保留
Agent 能力缺失 明确降级,不伪造能力
未知 Component 安全失败或 fallback
用户编辑时后台更新 不静默覆盖输入
重复 Action 不重复产生业务副作用
Artifact 已变化 旧审批不能执行新内容
断线与事件重放 恢复显示,不重新执行已完成命令
多 Agent / 多 Surface Action 不串线、数据不广播
受限平台 体验可降级,安全语义不降级

结语:真正应该统一的是“同一件事”

回到全文,真正的问题从来不是“哪一个协议会成为最终标准”。

协议、Framework、Renderer 和 Host 都可以继续演进;更重要的是,不管技术体系怎样变化,用户正在完成的 Task、Artifact、Action、Permission 与 Version 是否仍然具有稳定含义。

更准确的心智模型是:

flowchart TB A["用户 / Host"] --> B["Interaction Layer\nProtocol / Generative UI / Channel Adapter"] --> C["Agent Runtime"] A <--> D["Task · Artifact · Action · Permission · Version"] C <--> D C <--> E["MCP / Tools"] C <--> F["A2A / Other Agents"]

最后可以得到几个结论:

  • AI-native interaction 的核心不是聊天框变漂亮,而是语言、UI 与执行开始共享同一个 Task。
  • 运行交互层可以采用 AG-UI,也可以是经过治理的自定义 Runtime Protocol。
  • 动态 UI 可以采用 A2UI、MCP Apps、Framework-native Generative UI 或其他适合 Host 所有权模型的方案。
  • 真正长期稳定的不是协议本身,而是 Task、Artifact、Action、State、Capability、Permission 与 Version。
  • 系统收敛最大的收益不是少写几个接口,而是降低语义版本数量,让状态、动作、权限和能力进入统一治理。
  • 跨 Agent 和跨平台是这种收敛后的能力红利,而不是架构一开始的目的。
  • Runtime 私有状态通常不能无损迁移;应该优先迁移业务事实。
  • 跨平台也不是零适配;Renderer、Catalog 和 Channel Adapter 仍然是必要成本。

如果只记住一句:

让“谁在执行”和“怎么呈现”都可以变化,但让“用户正在完成的同一件事”保持稳定。

这才是从聊天框走向 AI 原生应用时,真正值得建立的架构边界。

参考资料

检索核对日期:2026-09-25。优先采用官方文档和维护者仓库;版本状态和集成范围应以实际部署时锁定的 SDK、Adapter、Middleware、Renderer 与 Catalog 为准。

编号 官方资料 用途
S01 AG-UI Overview AG-UI 定位与 Agentic App 背景
S02 MCP, A2A, and AG-UI 官方 Protocol Stack
S03 AG-UI Core Architecture Run / Event / Adapter
S04 AG-UI Events 运行事件语义
S05 AG-UI Tools 前端 / 后端 Tool 边界
S06 AG-UI Interrupts Human-in-the-loop 与恢复
S07 AG-UI Capabilities 能力发现与边界
S08 AG-UI Serialization 历史恢复
S09 What is A2UI? A2UI 背景与核心设计
S10 A2UI Core Concepts Surface、消息与 Data Model
S11 A2UI:How Does A2UI Compare? AG-UI 与 A2UI 的关系
S12 A2UI Catalogs Catalog 与能力边界
S13 A2UI Data Binding Structure / State 分离
S14 A2UI Actions Event、Local Function、Surface Ownership
S15 A2UI Transports Transport-independent 设计
S16 How to Use A2UI Web、Flutter、Agent 接入
S17 A2UI with Any Agent Framework AG-UI + A2UI 官方组合
S18 A2UI v0.9.1 Protocol 当前生产协议
S19 AG-UI A2UI Runtime / Renderer Wiring Middleware、固定 / 动态 UI
S20 A2UI v1.0 Candidate 候选版演进
S21 Defining Your Own Catalog Production Catalog
S22 Model Context Protocol TypeScript SDK MCP 的 Tool / Data 开放标准定位
S23 A2A Protocol v1.0 独立 Agent 的发现、Task、Artifact 与互操作
S24 MCP Apps Overview Tool + HTML UI Resource + sandboxed iframe
S25 OpenAI:Add UI to your MCP server ChatGPT 对开放 MCP Apps 标准及 Host 扩展的实现
S26 Vercel AI SDK:Generative UI Framework-native Generative UI 路线
S27 A2UI Agent Development Guide Prompt / Structured Output / Schema Validation 的模型侧流程

图表

使用 + / − 缩放,按 0 适应窗口;放大后可拖动或滚动查看,Esc 关闭。

评论公开保存在 GitHub Discussions。