ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

A2UI React Shell 实战:用 React 渲染 A2A 协议流式传输的 Agent UI(Restaurant Finder 示例全解)

2026/9/14 12:23:26 拓冰建站 浏览量
A2UI React Shell 实战:用 React 渲染 A2A 协议流式传输的 Agent UI(Restaurant Finder 示例全解) A2UI React Shell 实战用 React 渲染 A2A 协议流式传输的 Agent UIRestaurant Finder 示例全解【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui本指南以 samples/client/react/shell/README.md 为核心完整讲解如何在 A2UI 仓库中搭建一个 React Shell它作为前端外壳通过 Agent-to-AgentA2A协议与 Python 编写的 Restaurant Finder Agent 通信将 Agent 流式返回的 A2UI surfaces 实时渲染为可交互的 Web 界面。读完本文你将掌握从零启动示例、理解「Vite 中间件代理 → A2A 客户端 → SSE 流解析 → MessageProcessor 渲染」整条链路并能读懂 shell 的配置项、Mock 模式与安全边界。一、示例概览React 前端 Python Agent 的分工该示例由一个 React 外壳与一个 Python Agent 组成二者通过 A2A 协议解耦React Shellsamples/client/react/shell纯前端壳负责输入查询、把用户动作action转发给 Agent、并把 Agent 返回的 A2UI 消息解析渲染成界面。它只认识 A2UI 消息协议不关心 Agent 内部用的是什么 LLM 或框架。Restaurant Finder Agentsamples/agent/adk/restaurant_finder基于 Google ADK 编写的「餐厅搜索与订座」Agent作为 A2A 服务器监听localhost:10002通过 A2A 扩展头声明自己支持 A2UIX-A2A-Extensions: https://a2ui.org/a2a-extension/a2ui/v0.9见 middleware/a2a.ts以application/a2uijson类型的消息把 UI 定义推送给前端。从仓库结构看shell 的依赖充分体现了这一分层package.json 中同时引用了a2a-js/sdkA2A 协议客户端、a2ui/reactReact 渲染器、a2ui/web_coreA2UI 消息处理核心与a2ui/markdown-itMarkdown 渲染React 19 Vite 8 作为运行时底座。二、前置条件Prerequisites原文档明确列出三项前置结合仓库可细化为Node.js用于yarn与 Vite 构建仓库根目录使用 Yarn 工作区管理多包。uvPython 包管理器用于启动 AgentAgent 依赖通过 uv workspace 解析。Python版本要求以 Agent 的 pyproject.toml 中requires-python 3.10为准。LLM API KeyAgent 需要 Gemini API Key 才能执行真实查询见下文第四步的环境变量配置。三、运行步骤4 步启动完整示例1. 安装并构建依赖在仓库根目录执行yarn install yarn build:allyarn install会按 Yarn 工作区解析并安装所有子包React 渲染器、Web Core、Markdown 渲染器等yarn build:all负责把a2ui/react等 workspace 包先构建出来供 shell 引用。shell 自身的构建脚本由 package.json 的wireit.build定义其dependencies字段显式声明了「必须先构建renderers/react」这一包间依赖关系。2. 启动 Agent另开一个终端cd samples/agent/adk/restaurant_finder cp .env.example .env # 然后编辑 .env填入 GEMINI_API_KEY不要把 .env 提交进仓库 uv run ..env.example 中只有两个可选变量GEMINI_API_KEY必填与GOOGLE_GENAI_USE_VERTEXAITRUE可选改用 Vertex AI 后端。Agent 默认监听localhost:10002。可通过 Agent 侧 README 提供的命令自检curl http://localhost:10002/.well-known/agent-card.json应返回 AgentCard也可直接发送 JSON-RPC 形式的message/send请求验证消息通路。3. 启动 React 开发服务器再开一个终端cd samples/client/react/shell yarn devVite 配置 表明开发服务器固定占用端口5003strictPort: true并通过a2aPlugin()把/a2a路径的请求代理到运行在localhost:10002的 Agent 上。4. 打开界面浏览器访问 http://localhost:5003或点击终端打印的链接即可在输入框输入如「Top 5 Chinese restaurants in New York」之类的查询这是 restaurant.ts 中的默认 placeholder看到 Agent 流式返回的餐厅列表、订座表单与确认页。四、链路剖析一Vite 中间件如何桥接 A2A/a2a代理是整套架构的中枢实现在 middleware/a2a.ts客户端复用首次请求时通过A2AClient.fromCardUrl(http://localhost:10002/.well-known/agent-card.json)拉取 AgentCard 并建立 A2A 客户端此后复用单例fetchWithCustomHeader为每个请求注入X-A2A-Extensions头声明本次会话启用了 A2UI v0.9 扩展。请求体判定与转发中间件解析 POST 到/a2a的原始请求体——若为合法 JSON则视为 UI 事件用户点击按钮产生的 action包装成kind: data、mimeType: application/a2uijson的 Part否则视为纯文本查询包装成kind: text的 Part。二者都生成随机messageId、role: user的标准 A2A 消息。流式响应默认开启ENABLE_STREAMING环境变量不为false时启用client.sendMessageStream把 Agent 的status-update与message两类事件中的 parts 逐块写成text/event-streamdata: {...}\n\n格式转发给浏览器。降级与非流式兜底若关闭流式则改用sendMessage一次性拿到完整 Task 结果以 JSON 返回出错时按「响应头是否已发送」分别返回{error}或流式错误帧。防护细节请求体上限MAX_PAYLOAD_SIZE 1024 * 10241 MB超限直接返回 413 并销毁请求防止异常 Shell 耗尽开发服务器内存同时客户端断开时res.destroyed会停止继续向 Agent 拉取数据。五、链路剖析二浏览器端的 SSE 流解析client.tssrc/client.ts 中的A2UIClient负责把中间件转发来的流解析回 A2UI 消息按事件流边界切分用\r?\n\r?\n切分 SSE 帧把最后一个不完整块留存在 buffer 中等待下个数据块拼接。Part 级解析每帧是一个 Part 数组逐项判断——kind: error直接抛出错误kind: data则取出其中的 A2UI 消息。关键的去重逻辑A2A 的 status-update 事件携带累积式的 partscreateSurface会在每个 chunk 里重复出现若不去重会导致 MessageProcessor 抛出「Surface already exists」异常。因此seenSurfaceIds集合会记录已转发过的 surfaceId重复的 createSurface 直接跳过。非流式兜底当响应 Content-Type 不是text/event-stream时走response.json()分支同样按 Part 数组提取 A2UI 消息。六、链路剖析三React 渲染层App.tsx 与 MessageProcessorsrc/App.tsx 完成了从消息到界面的最后一公里MessageProcessor 装配用new MessageProcessor([basicCatalog], action ...)创建处理器——basicCatalog是 v0.9 基础组件目录回调中把用户的 action 包装成{version: v0.9, action}客户端消息再发回 Agent实现「按钮点击 → 下一轮 UI」的闭环见 src/App.tsx。Surface 生命周期管理订阅onSurfaceCreated/onSurfaceDeleted把 surfaces 同步进 React statesendAndProcess在发起新一轮请求前会清空旧 surfaces。流式增量渲染client.send的onChunk回调里每个 chunk 先交给processor.processMessages更新底层 SurfaceModel再追加进消息列表A2uiSurface组件通过useSyncExternalStore订阅各自的 surface因此无需手动触发重渲染。UI 状态机无消息时显示搜索表单含 hero 背景与标题请求中显示转动的 loading 文案出错时展示错误条有 surface 时在section classNamesurfaces中逐个渲染A2uiSurface。深浅色模式跟随系统prefers-color-scheme初始化也可点右上角按钮手动切换。Mock 模式不启动 Agent 也能跑通 UI在 URL 后加?mocktrue即进入纯前端演示模式见 src/App.tsxgetMockResponse根据 action 名称返回模拟消息——book_restaurant生成订座表单、submit_booking生成确认页、默认返回餐厅列表数据与 mock/restaurantMessages.ts 中的餐厅样例一致并模拟 800ms 网络延迟。页面左上角会显示Mock Mode徽标。这是快速体验 A2UI 渲染能力、或为前端调试提供稳定数据源的便捷方式。七、Shell 配置项详解AppConfigShell 是「通用外壳 应用配置」的模式只需实现 src/configs/types.ts 中的AppConfig接口即可复用同一外壳承载不同应用当前注册了restaurant见 src/configs/index.ts。完整配置项如下配置项类型是否必填说明keystring是应用唯一标识如restauranttitlestring是页面标题同时写入document.titleplaceholderstring是输入框占位提示文本backgroundstring否页面背景 CSS可通过--background自定义变量覆盖heroImagestring否浅色模式 hero 图片路径heroImageDarkstring否深色模式 hero 图片路径缺省回退到heroImageloadingTextstring \| string[]否请求中的加载文案传数组则每 2 秒轮换一次serverUrlstring否Agent 服务器地址如http://localhost:10002themeTheme否主题覆盖类型来自a2ui/react实际示例见 src/configs/restaurant.tstitle: Restaurant Finder、四段轮换的loadingText以及一组用light-dark()适配明暗两套配色、由四组径向渐变叠加线性渐变组成的背景。启动时 URL 的app参数决定加载哪个配置默认restaurant。八、安全注意事项务必阅读原文档对安全边界有明确且强制的说明此处完整继承并强调该示例代码仅用于演示 A2UI 与 A2A 协议机制。生产环境中必须把任何不受你直接控制的 Agent 视为潜在不可信实体把 Agent 传来的所有运营数据当作不可信输入——包括其 AgentCard、消息、artifacts 与任务状态。恶意 Agent 可以在字段如name、skills.description中植入精心构造的数据若未经净化直接拼接进 LLM 提示词可能引入提示注入prompt injection攻击。收到的 UI 定义与数据流同样不可信恶意 Agent 可能伪装合法界面实施钓鱼通过属性值注入恶意脚本XSS或生成极端复杂的布局拖垮客户端性能DoS。如果应用支持 iframe、web view 等可选内嵌内容还需额外防范跳转到恶意外部站点。开发者责任未正确校验数据、未严格沙箱化渲染内容都可能引入严重漏洞。开发者必须落实输入净化input sanitization、Content Security PolicyCSP、对内嵌内容的严格隔离以及安全的凭据管理。九、延伸阅读Agent 侧完整说明与 A2A 消息自检命令samples/agent/adk/restaurant_finder/README.mdA2UI v0.9 协议规范specification/v0_9/docs/a2ui_protocol.md、specification/v0_9/docs/a2ui_extension_specification.mdReact 渲染器源码与测试renderers/react/src/v0_9、renderers/react/tests/v0_9A2UI 与 MCP 应用的集成指南docs/public/guides/a2ui-in-mcp-apps.md其他语言/框架的 Shell 实现可对照samples/client/angular、samples/client/lit【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考