AI UI 怎么选:先看三类状态归谁管
接到“给产品加个 AI 助手”的需求后,我最先搜的是聊天组件。
搜索结果里的 Demo 长得都差不多:左边消息、右边消息、底部输入框,回答还能流式吐字。直到真正列开发任务,我才发现自己问错了问题:我不是在选一套聊天气泡,而是在决定三类状态分别交给谁管理。
🎯 本文目标
读完你应该能:分清 UI 状态、对话状态和业务状态;看懂 Ant Design X、AI Elements、assistant-ui、CopilotKit 为什么不能只按“组件库”横向排名;最后用一份最小验证清单,判断候选方案是否值得继续投入。
一个 AI 操作,为什么会产生三类状态
先不看组件库。假设我们在 CRM 中加入一个 AI 助手,用户对它说:
删除客户 A。
这句话进入系统后,会依次发生三件事:
- 聊天窗口显示用户消息,随后弹出“确认删除”按钮。
- AI 发起删除工具调用;用户确认后,对话等待工具返回结果。
- 服务端校验权限、删除客户记录,并写入审计日志。
它们看起来都发生在聊天窗口里,描述的却不是同一种状态:
| 状态 | 它回答的问题 | 在这个例子中 |
|---|---|---|
| UI 状态 | 界面当前长什么样? | 确认弹窗是否打开、结果卡片是否展开 |
| 对话状态 | 这次 AI 交互进行到哪里? | 消息、工具调用、等待结果、停止与重试 |
| 业务状态 | 现实业务中真正发生了什么? | 权限是否通过、客户是否删除、审计是否写入 |
同一件事还可能同时影响三类状态。工具返回“删除成功”,这条返回值属于对话状态;客户记录在数据库中消失,属于业务状态;页面把结果渲染成一张绿色卡片,则属于 UI 状态。
所以,区分它们的关键不是看数据最后出现在哪个页面,而是看它描述的是界面表现、交互过程,还是真实业务事实。
💡 三类状态不是三选一
它们会同时存在于一个 AI 应用中,也不要求放进三个独立的 Store。你完全可以用现成 UI 组件搭配自研对话状态,再连接自己的业务后端。选型真正要确认的是:UI 状态谁管?对话状态谁管?业务状态又由谁管?
第一类:UI 状态——页面“长什么样、怎么操作”
UI 状态包括输入框内容、附件预览、自动滚动、消息布局、思考过程折叠、代码块与引用来源的展示。它们大多只活在浏览器里,不决定 Agent 下一步做什么。
这一层常见的起点有:
- Ant Design X:React 组件完整,包含 Bubble、Sender、Conversations、ThoughtChain、Sources 等;如果项目原本就在 Ant Design 体系里,视觉和交互接入成本低。
- MateChat:面向 Vue 3 的组件方案,适合不想为了 AI 界面切换 React 技术栈的团队。
- Deep Chat:基于 Web Component,官方定位就是 framework agnostic;React、Vue、Svelte、Angular 或原生页面都可以接。
- AI Elements:基于 shadcn/ui 的源码组件集合,消息、输入框、推理过程、工具状态等组件会直接进入你的代码仓库。
这里有一个容易误判的点:“源码归我”不是更高一层的能力,而是一种交付方式。
AI Elements 用 CLI 把代码复制进项目,普通组件库则通过 npm 依赖提供实现。前者方便深度修改,但升级时需要自己处理差异;后者升级集中,但要接受公开 API 的边界。这个差异很重要,却不能说明谁更会管理对话状态。
⚠️ 第一个选型陷阱
不要把“组件源码复制进项目”理解成“消息状态也有人替你管理”。AI Elements 主要提供可修改的 UI 源码;官方示例仍使用 AI SDK 的 useChat 管理消息、流式状态、停止和重试。线程持久化、复杂分支以及业务操作,仍需要额外设计。
第二类:对话状态——一句回答从请求到落库怎么活
对话状态是 AI 界面和普通表单真正分叉的地方。
一条模型消息不是一次性返回的字符串,而会经历:
submitted → streaming → ready
↘ error流里还可能交错出现文本、推理过程、工具调用和工具结果。用户点击停止、重新生成、编辑历史消息时,状态又会继续分叉。只用一个 messages 数组当然也能写,但你很快会在项目里长出一套没有名字的运行时。
这一层要重点看三个方案。
1. Ant Design X v2:已经不只是“纯 UI”
旧印象里,Ant Design X 只是 Bubble 和 Sender。这个判断在 v2 已经过时:官方把 useXChat、useXConversations、Chat Provider、XRequest 等能力放进了 @ant-design/x-sdk。
useXChat 会管理单会话消息及 loading / updating / success / error / abort 等状态,Provider 负责把不同后端的数据格式转换成它能消费的形状。也就是说,它已经覆盖了“UI + 基础对话数据流”。
但“有运行时能力”不等于“替你承包了所有运行时”。分支模型、持久化策略、复杂工具 UI 如何落库,仍然要按你的后端和版本逐项核对。
2. AI SDK useChat:无头的对话状态层
AI SDK 的 useChat不规定页面长什么样,主要管理 messages、status、error、发送与停止等状态,并通过 transport 决定消息如何发给后端。
它适合两类团队:
- 已经在用 Next.js / AI SDK,希望 UI 完全自己控制;
- 使用 AI Elements,把“源码组件”和“对话状态”组合起来。
它的优势是链路直接;边界也很清楚:线程列表、长期持久化、复杂分支和应用侧权限,不会因为调用了一个 Hook 就自动完成。
3. assistant-ui:把对话本身当成产品
assistant-ui 的核心不是一套漂亮气泡,而是 runtime 和围绕 runtime 组织的 primitives。官方状态模型直接包含 thread、message part、tool UI、branch 等概念;线程既可以只放内存,也可以接自己的数据库或托管服务。
如果用户会长期使用对话、切换多个线程、重新生成分支、依赖工具结果渲染,assistant-ui 的价值才真正出现。代价是你需要理解它的 runtime、adapter 和组件上下文,而不是把它当成“复制一个聊天页”来用。
💡 一句话区分
Ant Design X v2 更像“设计体系 + 基础会话 SDK”;AI Elements + useChat 是“源码 UI + 无头状态”;assistant-ui 则把线程、消息和工具 UI 组织成一套更完整的对话运行时。
第三类:业务状态——AI 不只回答,还要动手
如果 AI 只负责回答问题,对话状态通常就是边界;一旦 AI 要操作页面,问题会立刻升级:
- 它能读取哪些页面状态?
- 它能调用哪些前端函数?
- 删除、提交、付款这类动作由谁确认?
- 工具执行了一半,页面卸载了怎么办?
- UI 上看到的成功,是否真的与服务端事务一致?
这已经不是消息气泡能解决的问题,而是 Agent 与真实业务之间的权限和状态同步。
CopilotKit v2 的 useFrontendTool 就属于这一类能力:前端可以注册带参数约束的工具,Agent 调用时在浏览器执行 handler,还能为执行过程和结果提供自定义渲染。
它适合“AI 是产品操作入口”的场景,例如:
用户说“把延期订单筛出来,给金额超过 5 万的负责人发提醒”。AI 先读取当前筛选条件,再调用前端动作切换视图,最后提交一个需要确认的批量操作。
如果你的需求只是“文档问答”,引入这类应用框架会增加协议、权限和部署复杂度;如果核心需求就是“AI 操作应用”,继续用组件库手写动作桥接,也会逐渐造出一个不完整的应用框架。
⚠️ 第二个选型陷阱
“能渲染工具调用”不等于“能安全执行工具”。前者只是把参数和结果画出来;后者还包括权限、确认、幂等、失败恢复和审计。选型演示里至少要亲手跑一次失败和一次人工确认。
把方案放回同一张责任表
这不是排名,而是一张“默认由谁负责”的起点表。项目版本和扩展能力会变化,真正落地时仍要用自己的需求验证。
| 方案 | UI 侧提供什么 | 对话状态由谁管 | 应用动作由谁管 | 适合作为起点的场景 |
|---|---|---|---|---|
| Ant Design X v2 | Ant Design 风格组件与 X SDK | useXChat 等基础会话能力,复杂状态按需补齐 | 业务侧接入 | 已使用 Ant Design 的 React 项目 |
| MateChat | Vue 3 AI 交互组件 | 结合项目的数据层设计 | 业务侧接入 | Vue 3 AI 界面 |
| Deep Chat | 可跨框架嵌入的 Web Component | 组件支持连接与流式,业务会话仍需设计 | 业务侧接入 | 跨框架嵌入、快速原型 |
| AI Elements + AI SDK | 可直接修改的源码组件 | AI SDK useChat 管消息、状态和 transport | 业务侧接入 | Next.js / AI SDK 技术栈 |
| assistant-ui | 可组合的聊天 primitives | runtime 管线程、分支和工具 UI,可接持久化 adapter | 通过 tool / adapter 接入 | 对话本身就是核心产品 |
| CopilotKit | 聊天与生成式 UI | 与 Agent 运行过程协作 | Frontend Tool 连接应用动作 | AI 要直接操作业务应用 |
你会发现,一个方案可以横跨多列,并不存在整齐的“第一层、第二层、第三层”。库是能力组合,状态归属才是稳定的比较坐标。
我会怎么选:先砍需求,再看技术栈
场景一:现有后台加一个知识问答侧栏
优先保留现有设计体系。React + Ant Design 可以先看 Ant Design X;Vue 可以先看 MateChat;跨框架嵌入可以验证 Deep Chat。此时别急着上 Agent 应用框架,因为核心状态仍是“问答”。
场景二:要做一个长期使用的 ChatGPT 类产品
先验证线程持久化、消息分支、工具 UI 和流中断,而不是先挑主题色。assistant-ui 值得优先做 spike;如果团队已深度使用 AI SDK,也可以用 AI Elements + useChat,但要明确哪些高级对话状态由自己补。
场景三:AI 要读页面、改表单、执行操作
先设计权限与确认流程,再看 CopilotKit 这类应用框架。这里最贵的不是 UI,而是“模型建议”和“真实副作用”之间那道闸门。
场景四:公司只是需要一个内部 AI 入口
先确认你是不是根本不该选库。LibreChat、Open WebUI、LobeChat 这类完整应用与组件库不是同一类东西;如果品牌定制和业务嵌入都不重要,直接部署成品可能比开发更合理。
最小选型验证:不要只跑 happy path
我会给每个候选方案接同一个假后端,然后依次做下面六个动作:
| 验证动作 | 真正在测什么 |
|---|---|
| 流式回答到一半点击停止 | 状态是否能从 streaming 正确收口 |
| 让下一段流返回错误 | 错误属于消息、请求还是整个线程 |
| 对历史问题重新生成 | 数据是简单数组还是可表达分支 |
| 切换线程后再切回来 | 运行状态和草稿是否串线 |
| 工具调用返回结构化结果 | 能否稳定映射到业务组件 |
| 工具执行前要求确认 | 是否有真正的动作治理边界 |
六个动作跑完,答案通常比 stars、官网截图和功能清单诚实得多。某个方案缺能力不一定要淘汰,关键是你是否愿意长期拥有那部分状态。
🔍 评审时可以直接问的四句话
- 页面刷新后,线程和未完成消息从哪里恢复?
- 后端事件格式变化时,改 adapter、改 runtime,还是改所有组件?
- 同一条消息出现多个回答分支,数据模型是否表达得出来?
- AI 调用有副作用的工具时,谁负责确认、幂等和审计?
结语:选库,本质是在分配长期责任
AI UI 的 Demo 很会制造错觉:只要气泡能流式吐字,产品就完成了大半。
真正进入迭代后,工作量会沿着三条线长出来:UI 状态决定界面是否好用,对话状态决定产品是否稳定,业务状态决定 Agent 是否真的能安全做事。
所以我现在不会先问“哪个 AI 组件库最好”,而会先把需求写成一句更具体的话:
这三类状态,哪些由库长期负责,哪些由团队自己长期负责?
选型没有免费的能力。你少写的每一段代码,都会变成一个需要理解的框架约定;你拒绝的每一个框架约定,也会变成团队需要维护的状态机。边界想清楚,比榜单上的第一名更重要。
📚 核对范围与官方资料
- 本文为选型方法论与公开文档调研,不是完整性能横评;未声称对所有方案做过生产实测。
- Ant Design X:组件总览、X SDK、
useXChat与 v2 迁移文档。 - assistant-ui:官方 Runtime、Threads、Branching Response 与 Tool UI 文档。
- Vercel:AI SDK
useChat、Transport 与 AI Elements 官方文档。 - CopilotKit:v2
useFrontendTool官方文档。