AI 聊天
通过 Vercel AI SDK 与 AI Elements 流式返回 OpenAI 响应。
模板在 /ai/chat 提供了一个 Example(示例) 聊天界面,由 AI Elements、
AI SDK 的 useChat Hook 与流式 /api/chat 路由组成。
当前路由对外公开,尚未实现身份认证、限流、配额、内容审核或服务端模型白名单。 请把它当作开发示例,而不是可直接上线的聊天端点。
提供的能力
- 流式 UI 消息,以及文本、推理过程和来源片段的渲染组件。
- 文件附件选择、停止、重试、复制和模型切换控件。
- 使用
streamText()的 OpenAI Route Handler。 - 位于
src/components/ai-elements/的可复用聊天组件。
重要文件
| 文件 | 用途 |
|---|---|
src/components/ai/ChatBot.tsx | 客户端 UI、useChat、传输层和模型选择器 |
src/components/ai-elements/ | 对话、消息、输入、推理和来源 UI |
src/app/api/chat/route.ts | 公开的流式 POST 端点 |
src/app/[locale]/(marketing)/ai/chat/page.tsx | /ai/chat 页面 |
配置
在 .env 中加入仅服务端可见的 OpenAI 密钥:
OPENAI_API_KEY=your-openai-api-key重启 pnpm dev,打开 /ai/chat 并发送消息,确认回答逐步显示。密钥由
@ai-sdk/openai 在服务端读取,绝不能放进 NEXT_PUBLIC_* 变量。
请求与流式响应
ChatBot为/api/chat创建DefaultChatTransport,并把所选model与webSearch放入请求体。useChat管理消息以及submitted、streaming状态。- 路由通过
convertToModelMessages()转换UIMessage[],再调用streamText({ model: openai(modelId), messages })。 toUIMessageStreamResponse({ sendSources: true, sendReasoning: true })把 UI 消息片段流式传回浏览器。- AI Elements 渲染文本、推理、来源、附件和操作按钮。
客户端会把附件作为消息文件片段发送;所选模型能否实际处理附件,仍取决于模型 及提供商的能力。
模型与响应选项
ChatBot.tsx 当前提供:
| 显示名称 | 模型 ID |
|---|---|
| GPT 5.2 | gpt-5.2 |
| Deepseek R1 | deepseek-r1 |
UI 默认选择第一项 gpt-5.2。只有请求没有携带 model 时,服务端路由才会
回退到 gpt-4o。
模型选择器不是安全边界。/api/chat 会把客户端提交的任意模型字符串传给
openai(...)。还应确认 UI 中每个模型 ID 确实可由你的 OpenAI 提供商账户调用;
选择器中出现某个名称,并不等于提供商一定支持它。
修改 ChatBot.tsx 中的 models 即可调整 UI 选项。生产环境还必须在服务端
维护同一份白名单,并在调用 streamText 前拒绝未知 ID:
const allowedModels = new Set(["gpt-5.2"]);
const modelId = allowedModels.has(requestedModel)
? requestedModel
: "gpt-5.2";响应开启了 sendReasoning 与 sendSources,UI 也能渲染这两种片段;但只有
模型或提供商实际返回对应数据时,它们才会出现。
Search 开关
当前 webSearch 选项没有配置联网搜索。开启后,路由只会加入空的
tools: {}。代码没有注册搜索服务、OpenAI 搜索工具或自定义工具,因此模型
无法通过这段实现浏览网页。
若要真正接入搜索,请在服务端路由注册兼容 AI SDK 的搜索工具,校验何时允许调用, 并渲染工具与来源片段。不要把客户端布尔值当作授权或计费依据。
生产加固
向真实用户开放前,请完成:
- 校验服务端会话,并强制执行用户/租户访问边界。
- 校验消息数量、角色、文本长度、附件和请求体大小。
- 在服务端执行模型与工具白名单。
- 增加按用户和 IP 的限流、用量配额与并发限制。
- 增加内容审核和上传内容策略。
- 限制 token、工具调用次数、执行时长和高成本模型访问。
- 记录用量、延迟、失败和成本;默认不要记录敏感提示词。
- 返回安全的结构化错误,并处理主动中止和提供商流式失败。
