OPEN SOURCE DEEP DIVE
assistant-ui:给 AI 编程助手搭生产级 React 对话界面
assistant-ui 把流式消息、工具调用、人工审批、多线程和生成式界面整合为可组合的 React 智能体前端运行时。
assistant-ui 是一个面向 AI 对话产品的 TypeScript 与 React 前端库。它最值得关注的地方,不是把消息气泡做得更像聊天软件,而是把“智能体正在做什么”拆成可组合、可观察、可干预的界面契约:文本与推理过程如何流式到达,工具调用如何显示,权限请求如何暂停执行,用户选择如何回传给后端,以及一次会话如何在不同运行时之间保持一致。
这一定位需要先说清边界。assistant-ui 不负责模型推理,也不替应用执行文件修改、终端命令或外部工具。模型调用、工具实现、权限最终判定与会话持久化仍由后端智能体负责;assistant-ui 提供的是前端运行时、消息投影和交互界面。它适合成为 AI 编程助手的产品外壳,但不能被描述成能够自主完成编码任务的后端智能体。
从聊天组件库到智能体界面层
README 给出的最小示例很直接:应用创建 runtime,把它交给 AssistantRuntimeProvider,再组合 Thread 等界面组件。真正决定可扩展性的,是 runtime 背后的一层抽象。默认的 useChatRuntime 可以连接 Vercel AI SDK,但也可以换成 LangGraph、AG-UI、A2A、Google ADK、OpenCode、数据流协议或自定义 HTTP 后端。
这种结构把产品级聊天界面常见但没有统一答案的问题集中起来:自动滚动、重试、附件、Markdown、代码高亮、语音输入、键盘操作和无障碍状态。应用仍然拥有视觉设计与业务数据,但不需要从零重写一套流式会话状态机。
分层不是目录游戏,而是替换边界
| 层次 | 职责 | 对开发者的意义 |
|---|---|---|
| 核心与状态层 | 消息模型、运行时接口、线程状态、消息部件与外部存储桥接 | 业务界面不必绑定某一家模型供应商 |
| React 原语 | Thread、Message、Composer、ThreadList、ActionBar 等组合单元 |
可以保留自己的设计系统,也可以使用 CLI 提供的主题 |
| 后端适配器 | 把不同协议的流、工具调用、审批和状态映射为统一消息部件 | 智能体实现可替换,前端交互契约保持稳定 |
| 工具链与可选云服务 | 脚手架、主题复制、线程历史、遥测和文件存储 | 从原型到生产部署可以逐步增加能力 |
CLI 的 create 与 init 命令降低了首次集成成本,但重要的不是生成几个文件,而是它把组件源码交给应用维护。团队可以继续使用 Base UI 或 Radix UI 风格,也可以逐层替换布局与交互。相比只能通过属性微调的黑盒聊天组件,这种“先给可运行默认值,再允许完全接管”的方式更适合需要长期演进的产品。
运行时契约决定界面能否承载真实智能体
普通聊天只需要文本增量,AI 编程助手却会产生更多状态:模型输出推理片段,调用读取或写入工具,等待用户批准高风险操作,返回终端流或补丁,甚至启动子智能体。assistant-ui 用“消息部件”表达这些异构内容,让界面可以针对文本、推理、工具调用和审批分别渲染,而不是把一切压成不可操作的长字符串。
运行时还承担会话级行为。切换线程时,界面需要知道哪条消息正在进行、哪些工具调用尚未完成、哪些审批仍然有效;取消一次回答时,也需要把取消信号传到后端并清理前端待处理状态。外部存储 runtime 进一步把线程列表、消息读取与业务侧持久化衔接起来。
这里的关键设计是“投影”而不是复制业务事实。后端事件被转换为前端部件,交互动作再通过 runtime 发回智能体。assistant-ui 在浏览器里保留的是呈现与交互状态,权威会话仍由具体后端决定。理解这一点,才能避免把前端显示的审批按钮误认为真正拥有工具权限。
编程助手需要的是工具,不是更长的文本
在编码场景中,最有信息量的内容往往不是模型解释,而是工具实际返回了什么。读取文件需要显示路径与范围,搜索需要显示命中位置,终端需要保留标准输出与错误输出,编辑需要呈现差异,测试需要把失败摘要做成可扫描的状态。assistant-ui 的可组合工具界面允许应用为每种工具注册专用渲染器。
审批同样属于界面契约。一个写文件或执行命令的请求,必须显示调用的工具、目标与风险上下文,再提供同意、拒绝或长期允许等选项。按钮只负责表达用户选择;真正约束权限的是后端。assistant-ui 的价值在于让“等待人类决定”成为会话中的一等状态,而不是弹出一个与上下文割裂的浏览器确认框。
OpenCode 适配器:把会话事件映射成可操作界面
@assistant-ui/react-opencode 是当前源码中最贴近 AI 编程助手工作流的适配器,但仍标记为实验性。它通过 OpenCode 客户端连接服务端会话,把消息、部件、权限、问题、子智能体和分支操作映射到 assistant-ui 线程。
适配器暴露的不只是发送消息。运行时附加能力包括取消、刷新、回答权限请求、回答或拒绝问题、分叉会话、回退与撤销回退。权限响应有三类:仅允许一次、始终允许和拒绝。问题请求则进入交互界面,用户的选择再回传。对于需要澄清范围、选择实现方案或确认危险操作的编码任务,这些状态比纯文本输入更接近真实工作流。
OpenCode 会话还支持附件、事件重连、流式部件、标题同步与子会话。分叉让用户从某条消息处探索另一条实现路径;回退让界面暂时回到较早消息;恢复则重新推进。这些能力依赖后端提供对应会话语义,前端适配器只负责调用和呈现。
集成时要注意一个源码细节:当前类型定义和运行时实现使用 baseUrl,而该包的 README 示例仍写着旧的 apiUrl。这说明实验性适配器仍可能快速变动,应用应以当前 TypeScript 类型为准,并补充端到端测试锁定实际协议。由于包本身明确标注实验性,生产项目不应把升级视为无风险的小版本替换。
ACP 适配器的边界更严格
@assistant-ui/acp 把 Agent Client Protocol v1 接到 assistant-ui。它目前是私有包,不发布到 npm,API 也可能调整。协议消息通过一条双向 WebSocket 传输 JSON-RPC,但 ACP 目前正式定稿的是标准输入输出传输,WebSocket 仍属于草案,因此使用方需要在智能体前提供兼容桥接。
映射关系覆盖会话、提示、取消、文本增量、推理增量、工具调用、权限请求、计划、会话标题、模式、命令、配置和用量统计。工具调用的名称会优先采用协议中的程序化名称,再回退到类别与人类可读标题,避免界面的工具卡片在更新过程中换键。
ACP 的约束尤其值得工程团队重视。浏览器客户端不会声明文件系统或终端能力,符合协议的智能体不应发送相关请求;即便发送,也会收到“方法不支持”。会话记录由智能体持有,前端不提供历史编辑、重新加载、删除或分支切换,因为这些操作会改变界面显示,却无法同步改变智能体真正保存的记录。断线重连只有在智能体声明支持时才通过 session/load 恢复,否则用户需要新建线程。
权限模式只有“询问”与“自动允许”两种。后者会选择智能体提供的第一个允许类选项,适合低风险或受控环境,不适合默认套用到会修改仓库和执行命令的开发者工具。未实现的认证、模式切换、配置写回与不稳定协议更新也应作为选型门槛,而不是藏在演示之后。
生成式界面必须受组件库约束
assistant-ui 的生成式界面不是让模型直接写任意 HTML。应用先声明一个受类型检查的 React 组件库,例如卡片和文本组件,再通过 present 工具让模型输出 { _type, ...props } 形式的 JSON 树。组件名称由 _type 指定,属性由 schema 验证,最后才交给已注册的渲染器。
默认情况下,完整属性到达后才渲染组件,避免界面基于半截数据做出错误判断。需要提前反馈的组件可以显式开启 streamProperties,并在渲染函数里根据 $status 区分流式状态与完成状态。另一条工具 prompt_user 把结构化问题变成等待用户填写的界面,适用于需要选择、确认或补充参数的智能体步骤。
同一棵 JSON 树还能转换为 Slack Block Kit、Microsoft Teams Adaptive Cards,或接收 A2UI 表面。转换器在不依赖 React 的路径上运行,适合服务端、队列任务和 webhook。未识别组件会被丢弃并产生警告,因此“跨渠道复用”仍受内置词汇表约束,不是任意 React 组件自动跨平台。
VS Code 场景把浏览器限制暴露得更清楚
@assistant-ui/vscode 让 assistant-ui 运行在扩展 webview 中。webview 不能直接访问常规后端请求能力,因此该包通过 postMessage 把 fetch 隧道到扩展宿主,在宿主中运行原有路由处理器,再把流式响应送回 webview。请求中止、服务器销毁和上一页面遗留流都有明确清理路径。
安全策略是这套集成的核心。默认 CSP 禁止任意连接,脚本依赖每次生成的 nonce;远程图片和媒体默认被阻止,因为模型输出中的 URL 可能在消息渲染时泄露聊天数据。外链拦截只允许明确配置的协议,并提醒不要把 command:、vscode: 或 file: 放进白名单,否则模型生成的一条链接可能触发命令或打开本地文件。
线程可以使用 VS Code 的 Memento 持久化,主题也可映射到编辑器颜色与高对比模式。该包版本仍是 0.0.1,但仓库包含专门的 VS Code 测试扩展与探测项,覆盖请求桥接、取消、前端工具的人机确认、CSP、主题、外链和线程重载。这些测试表明它已有可验证的基础,但版本号也提醒集成方应自行覆盖真实扩展环境。
怎样判断是否适合自己的产品
如果团队正在构建面向开发者或知识工作者的智能体产品,并且需要自己的品牌、布局与工具卡片,assistant-ui 能显著减少重复工作。它尤其适合需要同时处理流式文本、工具调用、审批、附件、多线程和结构化输出的应用。已有模型后端时,通过适配器或外部存储 runtime 接入,比重新设计一套消息部件协议更可控。
如果产品只需要一个简单问答框,完整运行时抽象可能超出需求。如果核心任务依赖复杂分支、历史编辑或自定义协议,应该先核对目标适配器的限制,而不是假设所有 assistant-ui 运行时具有同样能力。OpenCode 与 ACP 的证据说明,前端能显示什么,最终受后端协议和权威会话模型约束。
| 部分 | 成熟度判断 | 采用建议 |
|---|---|---|
| React 界面原语与通用运行时 | 项目主路径,示例和组件覆盖较完整 | 可直接用于产品原型,并以自身设计系统重做样式 |
| OpenCode 适配器 | 明确标注实验性,源码与 README 已有漂移 | 适合跟进验证,需锁定版本并覆盖会话、审批与重连测试 |
| ACP 适配器 | 私有、未发布,传输与协议功能仍有限制 | 适合基础设施团队自建桥接,不建议当作稳定公共依赖 |
| VS Code 集成 | 版本很早,但具备 CSP、桥接与持久化测试床 | 适合从模板起步,并在目标扩展环境补完整回归 |
assistant-ui 的真正价值是把 AI 编程助手的交互从“聊天窗口”提升为一套可组合的前端协议:谁能显示,谁能批准,谁拥有会话,哪些状态可以恢复,哪些动作必须交还后端。它并不缩小后端智能体的责任,反而通过清晰的前后端边界,让编码智能体的能力更容易被理解、控制和审计。项目采用 MIT 许可证,CLI 与主 React 运行时适合作为起点;涉及 OpenCode、ACP 和 VS Code 的能力,则应按仓库当前标注的成熟度分别评估。