Vercel AI SDK 的 useChat 是怎么工作的?UIMessage 和 ModelMessage 有什么区别?
下面是一段教学用的模拟面试。
🧑💻 面试官:你用 useChat 做聊天页面,它负责哪些事情?
🙋♂️ 我:它管理聊天消息和请求状态,也负责通过 transport 发送请求、接收增量并更新页面。
🧑💻 面试官:模型需要的消息,和页面保存的消息是同一种结构吗?
🙋♂️ 我:不完全一样。页面还需要消息 ID、不同内容片段和工具执行状态,后端要把它们转换成适合模型的消息。
🧑💻 面试官:那页面收到一条带文本的流事件,直接追加字符串就够了吗?中途又出现工具请求呢?
useChat 连接的是一段交互过程:页面消息要保留过程,模型消息要组织推理输入。
面试速答(60 秒版)
useChat 是 AI SDK 提供的聊天界面能力。它维护消息列表和请求状态,通过传输层把用户消息发给后端,再把返回的流更新成页面能展示的消息。
这里要区分 UIMessage 和 ModelMessage。
UIMessage 面向界面,一条消息可以包含文本、工具、文件等不同 parts,还可以保留 ID 和交互状态。ModelMessage 面向模型调用,用来表达模型本轮需要看到的用户输入、历史回答和工具结果。
因此,后端通常需要转换消息,而不是直接把页面对象当成模型报文。工具正在调用、已经返回或者执行失败,也应按对应的消息片段呈现。
同时,useChat 不自动替应用完成权限检查和可靠持久化。刷新恢复、聊天记录归属与高风险工具授权,仍然需要后端设计。

知识点详解:一条消息要经过前端和模型两种使用场景
用户点发送之后,谁先开始工作?
假设咱们做一个资料助手。用户在输入框写“查一下设备维护规定”,点击发送。
输入框只是收集文字。useChat 会把这次输入组织进消息状态,通过配置的 transport 向后端提交请求。
后端收到以后,检查当前用户和会话,组织模型输入,再启动生成。生成过程中的事件返回前端,useChat 把这些增量合成消息状态,React 根据状态重新显示界面。
因此,它并不是一个只负责发 fetch 的快捷函数。请求过程与消息如何逐步形成,也是它管理的一部分。
输入框里的临时文字和已经进入聊天记录的消息,仍然是两种状态。不要照搬旧教程的属性,就假设当前版本会替你管理所有表单状态。
UIMessage 为什么需要 parts?
用户最终看到的可能是:“找到了三份文档,下面是结论。”但这句话形成之前,助手可能先发出搜索工具请求,显示“正在搜索”,接着展示命中文档,最后生成总结。
如果应用只保存一个不断变长的字符串,这些对象就容易混在一起。工具卡片属于哪次调用、有没有执行成功,都得另外猜。
UIMessage 的 parts 让一条消息容纳不同内容。前端可以根据片段类型,把文本显示成正文,把工具调用显示成状态卡,把文件显示成附件。
这里的工具片段是交互记录,不是授权结果。前端显示“等待确认”以后,真正执行仍要在受控的后端流程中完成。

ModelMessage 为什么不能直接拿来展示全部过程?
ModelMessage 的任务是让模型理解这轮输入。它不需要承担页面上全部的加载提示、组件状态和展示细节。
反过来,UIMessage 里为界面保存的字段,也不一定都能直接传给模型。
AI SDK 的聊天文档展示了使用 convertToModelMessages 进行转换的方式。转换前仍要判断哪些消息可以参与本轮推理。例如工具尚未完成时,不应随意伪造一个“成功结果”;只有界面需要的临时字段,也没必要消耗模型输入。
一个实用的排查办法,是同时保存两份可观察记录:转换前的页面消息,以及本次实际调用模型的消息。前端显示正常、模型却接不上话时,这两份记录能帮你找到差异。
流式返回不只是文本碎片
有些流事件会增加文本,有些会推进工具状态,还有些会报告本次运行完成或失败。
如果后端返回普通文本流,而前端按照 UIMessage 流协议读取,双方就可能对不上。使用自定义 transport 时,尤其要核对请求格式、响应类型和事件封装。
这里可以把问题分开测试:先只返回文字,确认消息能形成;再增加一项工具调用,检查调用 ID 和状态变化;最后让工具故意失败,确认界面不会一直显示“正在执行”。
不能因为普通回答显示出来了,就宣布整个 Agent 交互已经接通。

换成 Python 后端,还能用 useChat 吗?
前端 hook 来自 JavaScript/React 生态,不存在可以逐行替换的 Python React hook。
但前后端可以通过兼容的协议连接。Python 后端若能接收约定的消息、调用模型,并输出前端 transport 所理解的流,页面仍可使用 useChat。也可以编写适合自己后端的 transport。
这一步是协议适配,需要实际验证;不能只把 Node 示例翻译成 Python,就认定接口已经兼容。
聊天记录持久化也是另外的工作。页面上有 messages 数组,不代表服务端已经保存了它,更不代表另一个用户能安全访问同一会话。
面试官继续追问
只需要纯文本聊天,还必须展示全部 parts 吗?
不需要把所有片段都画出来,但仍应识别协议中的不同事件。可以只显示文本,把其他状态作为界面提示;遇到暂不支持的类型,要明确处理。
每次发送都能信任前端提交的历史吗?
不能。后端应校验会话归属、输入规模和允许提交的消息类型。重要工具结果最好从可信服务端记录取得,避免客户端伪造执行事实。
useChat 的错误状态等于工具执行失败吗?
不完全一样。传输失败、模型调用失败和某项工具业务失败可以发生在不同层。应用要分别表达,才能决定重试整个请求、重试工具,还是等待用户补充信息。
面试速记卡
- useChat:管理消息与请求交互,通过 transport 收发流。
- UIMessage:保留界面需要的内容片段与过程状态。
- ModelMessage:组织模型本轮需要的输入。
- 转换:检查消息关系,再使用实际 SDK 的转换能力。
- 后端职责:鉴权、执行、持久化与协议兼容需要另外落实。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →