nextjs16+@ai-sdk实现AI对话
功能概览
使用 Next.js 16 App Router、AI SDK 7、@ai-sdk/react 和 DeepSeek Provider 实现流式 AI 对话。
- 前端通过
useChat管理会话消息和请求状态。 - 后端通过
POST /api/chat接收 UI 消息,转换为模型消息并调用 DeepSeek。 - 服务端将模型生成的文本流转换为 AI SDK UI Message Stream,供前端逐步显示。
- 对话页面提供空状态、快捷提问、消息区、加载状态、错误提示和输入区。
请求流程
1 | |
前端对话页面
文件:src/app/page.tsx
Client Component 与 useChat
页面使用 React 状态、事件和 useChat,因此文件顶部需要声明:
1 | |
通过 useChat 获取消息、发送方法、请求状态和错误:
1 | |
messages 中的内容是 UIMessage。每条消息通过 role 区分用户和助手,正文在 parts 中:
1 | |
使用 message.id 作为消息 key;消息正文按 text part 渲染。whitespace-pre-wrap 可保留换行,break-words 可避免长文本撑破布局。
发送消息
输入区使用表单处理点击发送和键盘提交,并在发送前去除首尾空白:
1 | |
输入框的 Enter 提交,Shift + Enter 不触发提交。发送按钮在输入为空或请求进行中时禁用。空状态中的快捷提问也直接调用 sendMessage({ text })。
页面交互状态
messages.length === 0时展示欢迎文案和快捷提示。status为submitted或streaming时显示加载动画,并暂时禁用输入。error存在时显示请求失败提示。useEffect监听消息和加载状态,滚动到消息列表底部。- 新对话按钮通过刷新页面重置当前内存中的会话。
- 使用 Tailwind 的宽度、间距和断点类适配窄屏与桌面布局。
服务端 API Route
文件:src/app/api/chat/route.ts
Next.js App Router 使用命名导出声明 HTTP 方法:
1 | |
转换 UIMessage
前端 useChat 发送的是 UIMessage,而模型调用需要 ModelMessage。不要把收到的 messages 直接放进 prompt;使用 AI SDK 提供的转换函数:
1 | |
随后将转换结果传给 streamText 的 messages 参数:
1 | |
AI SDK 7 流式响应
AI SDK 7 已将 streamText result 上的 toUIMessageStreamResponse() 等便捷方法标记为废弃。当前推荐将 stream 转换和 Response 创建拆开:
1 | |
本项目保留的旧写法仅作为迁移参考,且处于注释状态:
1 | |
错误处理
Route Handler 中捕获同步解析和转换阶段的异常,写入服务端日志并返回 JSON 500:
1 | |
注意:模型流开始返回后发生的 provider 错误通常属于流式阶段,不能只依赖外围 try/catch;调试时还要检查服务端终端日志和客户端 AI SDK 的 error 状态。