一、聊天模式在Agent应用中的局限性

如果你对AI Agent有所了解,一定会有一个强烈的感受,随着LLM能力越来越强,生态越来越丰富,Agent也越来越聪明,但用户交互方式却还停留在最基础的聊天框模式。

无论是 LangChain、LangGraph,还是 AutoGen或者其他Agent框架,我们已经可以构建具备规划、记忆、工具调用能力的 Agent。但当任务一旦涉及用户输入多个字段、选择配置、分步骤操作时,Agent 往往会退化成输出一大段说明文字,然后再由用户手动去填写、选择或者进行具体的操作。对于Agent和用户而言,存在着天然的交互壁垒,Google在去年年底提出并开源的 A2UI(Agent-to-User Interface),本质上就是为了解决这个问题,允许让 Agent 直接生成界面,而不仅仅是文本

A2UI的直观效果

二、A2UI的本质,一个协议而非框架

1. 一种声明式UI协议

A2UI的核心不是React、Vue 或Flutter组件,而是一套声明式UI协议。与以往的输出不同,Agent不再输出 HTML/JSX,而是输出类似下面的结构化JSON:

{
  "surfaceUpdate": {
    "surfaceId": "main",
    "components": [
      {
        "id": "name",
        "component": {
          "type": "TextField",
          "props": { "label": "姓名" }
        }
      }
    ]
  }
}

而前端只负责一件事,就是把组件的结构化描述映射成真实的本地 UI。

2. 安全性可控

为什么不让 Agent 直接写前端代码?这是 A2UI 非常重要的一点设计哲学:
● Agent生成 HTML/JS代码:存在安全风险,风险不可靠
● Agent生成结构化JSON:前端只渲染白名单组件,风险更加可控
Google官方的表述说这样设计使得Agent的输出像数据一样安全,像代码一样表达

3. 跨平台渲染

A2UI 的组件是抽象的,一次生成,多端渲染,Agent 完全不关心前端技术栈,只描述“我要一个输入框 + 一个按钮”即可渲染出合适的UI界面。

平台 渲染方式
Web React / Angular / Lit
iOS SwiftUI
Android Compose
Flutter Widget

4. 与模型解耦

A2UI是一种协议,那么它就不是必须与Gemini模型绑定。A2UI对模型的要求只有一个:
能不能稳定输出结构化 JSON。所以对于常见的模型以及MaaS提供商,比如:
● OpenAI
● Claude
● Gemini
● 其他模型/API提供商
都完全可以使用。

三、技术原理

A2UI的三层架构

A2UI主要有三层架构,每一层都有清晰的分工。

1. 协议层:Agent-to-UI Communication

比如Agent可能会生成带如下结构的Json输出:

{
  "surfaceUpdate": {
    "surfaceId": "restaurant-search",
    "components": [
      {
        "id": "search-form",
        "component": {
          "type": "Form",
          "children": [
            {"type": "TextField", "props": {"placeholder": "搜索餐厅..."}},
            {"type": "Button", "props": {"text": "搜索"}}
          ]
        }
      }
    ]
  }
}

2. 渲染层:Framework-Agnostic Rendering

A2UI的消息传递过程

客户端与Agent之间是有预先定义好的渲染逻辑,当客户端收到Agent发送来的带有特殊格式的Json时,会对其中有效部分进行渲染。

// 客户端渲染逻辑(伪代码)
class A2UIRenderer {
  render(component, container) {
    switch(component.type) {
      case 'TextField':
        return new TextInput(component.props);
      case 'Button':
        return new Button(component.props);
      case 'Form':
        return new Form(component.children);
      // 更多组件...
    }
  }
}

3. 数据层:双向数据同步

{
  "dataModelUpdate": {
    "surfaceId": "restaurant-search",
    "contents": [
      {
        "key": "searchResults",
        "valueArray": [
          {
            "valueMap": [
              {"key": "name", "valueString": "川香阁"},
              {"key": "rating", "valueNumber": 4.5},
              {"key": "cuisine", "valueString": "川菜"}
            ]
          }
        ]
      }
    ]
  }
}

四、快速开始

1. 环境准备

在开始使用A2UI之前,确保开发环境满足以下要求:

# 检查Node.js版本(需要16.0+)
node --version

# 检查npm版本
npm --version

2. 安装步骤

方法1:使用官方模板

# 克隆官方快速开始模板
git clone https://github.com/google/A2UI.git
cd A2UI/examples/quick-start

# 安装依赖
npm install

# 启动开发服务器
npm start

方法2:集成到现有项目

# 安装A2UI核心库
npm install @google/a2ui

# 安装渲染器(以React为例)
npm install @google/a2ui-react

# 安装类型定义
npm install -D @types/a2ui

五、一个简单的示例

让我们创建一个简单的"Hello World"应用:

1. 创建Agent

// agent/hello-agent.js
import { A2UIAgent } from '@google/a2ui';

class HelloAgent extends A2UIAgent {
  async handleMessage(userInput) {
    return {
      surfaceUpdate: {
        surfaceId: "hello-world",
        components: [
          {
            id: "greeting-container",
            component: {
              type: "Card",
              props: {
                title: "A2UI问候",
                variant: "elevated"
              },
              children: [
                {
                  type: "Text",
                  props: {
                    content: `你好!您输入的是:${userInput}`,
                    size: "large"
                  }
                },
                {
                  type: "Button",
                  props: {
                    text: "再次问候",
                    action: "greet_again"
                  }
                }
              ]
            }
          }
        ]
      }
    };
  }
}

export default HelloAgent;

2. 创建客户端渲染器

// client/App.jsx
import React, { useState } from 'react';
import { A2UIRenderer } from '@google/a2ui-react';
import HelloAgent from './agent/hello-agent';

function App() {
  const [messages, setMessages] = useState([]);
  const [userInput, setUserInput] = useState('');

  const agent = new HelloAgent();

  const handleSendMessage = async () => {
    const response = await agent.handleMessage(userInput);
    setMessages(prev => [...prev, response]);
    setUserInput('');
  };

  return (
    <div classname="app">
      <main classname="chat-container">
        {messages.map((message, index) => (
          <a2uirenderer key="{index}" surfaceupdate="{message.surfaceUpdate}" onaction="{(action," data)=""> {
              console.log('Action triggered:', action, data);
              if (action === 'greet_again') {
                handleSendMessage();
              }
            }}
          />
        ))}
      </a2uirenderer></main>
      <footer classname="input-container">
        <input type="text" value="{userInput}" onchange="{(e)" ==""> setUserInput(e.target.value)}
          onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
          placeholder="输入消息..."
        />
        <button onclick="{handleSendMessage}">发送</button>
      </footer>
    </div>
  );
}

export default App;

六、关于A2UI的一些疑问

1. 前端需要引入A2UI官方npm包吗?

不用。只需要在现有 React 项目中,加一层「A2UI Renderer」就行,如下所示:

function ChatMessage({ msg }) {
  if (msg.type === "text") return <Bubble>{msg.content}</Bubble>;
  if (msg.type === "a2ui") return <A2UIRenderer surface={msg.surfaceUpdate} />;
}

A2UI官方 SDK 本质上也是在做这件事,只是帮你封装好了。

2. LLM 一定要输出特殊 JSON吗?

是的,这是 A2UI 的关键。但这并不意味着所有回复都要以A2UI的格式返回。真实业务中更合理的方式是大多数情况下依旧以传统的文本形式返回,只有当需要用户操作的时候才渲染为A2UI的格式

七、总结

在笔者看来,A2UI的意义不只是多了一种UI方案,而是在于它补齐了Agent从思考到执行的最后一环。对于Agent的开发者来说,可能不再需要去写各种业务相关的界面,而是可以专注于设计Agent能力边界。而Agent的终极形态,不再是聊天机器人,而是会自己搭界面的智能系统。
A2UI,可能正是这个方向上非常关键的一步。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐