useChat 不能直接连接 DeepSeek,因其依赖 OpenAI 兼容接口,而 DeepSeek API 在认证头、模型名、字段支持等方面存在差异;需在 app/api/chat/route.ts 中手动适配请求与响应格式,并禁用流式以避免双流冲突。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

useChat 是你在 Next.js App Router 里对接 DeepSeek 最直接的入口,但直接调用它会失败——因为 useChat 默认只认 /api/chat 这个路由,而 DeepSeek 的 API 不是标准 OpenAI 兼容接口,必须自己写适配层。
useChat 为什么不能直接连 DeepSeek
useChat 是 Vercel AI SDK 提供的 React Hook,它内部依赖一个符合 OpenAI Chat Completion API 格式的后端接口。DeepSeek 的官方 API(如 <a href="https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271">https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271</a>)虽然结构接近,但存在几处关键差异:
- 请求头必须带
Authorization: Bearer <deepseek_api_key></deepseek_api_key>,不能复用 OpenAI 的api-key字段名 -
model字段值必须是deepseek-chat或deepseek-r1,不是gpt-4类命名 - 某些字段如
response_format、tool_choice不被支持,传了会报错400 Bad Request - 流式响应的
data:块格式一致,但非流式响应的choices[0].message.content路径是通的
你如果直接在 app/api/chat/route.ts 里转发请求却不做字段清洗,前端就会卡在 isLoading 状态,控制台看不到错误,但 Network 面板里能看到 400。
如何写一个兼容 useChat 的 DeepSeek 路由
你需要在 app/api/chat/route.ts(注意路径必须叫 chat)里手动构造请求,并把 DeepSeek 响应转成 OpenAI 兼容格式:
- 使用
fetch发起 POST 请求到<a href="https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271">https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271</a> - 把
req.json()拿到的原始 body 中的messages、model、temperature等字段原样透传,但过滤掉 DeepSeek 不认的字段(比如response_format) - 设置 headers:
{"Content-Type": "application/json", "Authorization": <code>Bearer ${process.env.DEEPSEEK_API_KEY}} - 对响应做简单转换:提取
choices[0].message.content,包装成{ id, object, created, model, choices: [...] }结构
export async function POST(req: Request) {
const { messages, model = 'deepseek-chat', temperature = 0.7 } = await req.json();
<p>const response = await fetch('<a href="https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271">https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271</a>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': <code>Bearer ${process.env.DEEPSEEK_API_KEY}</code>,
},
body: JSON.stringify({
messages,
model,
temperature,
// 不要加 stream: true —— useChat 自己处理流式,后端统一走非流式即可
}),
});</p><p>const data = await response.json();</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill8483" title="dmap-jsapi-skill"><img
src="https://img.php.cn/upload/skill/000/000/081/179206214475645.jpg" alt="dmap-jsapi-skill" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill8483" title="dmap-jsapi-skill">dmap-jsapi-skill</a>
<p>DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。</p>
</div>
<a href="/xiazai/skill8483" title="dmap-jsapi-skill" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p>return Response.json({
id: data.id || Date.now().toString(),
object: 'chat.completion',
created: data.created || Math.floor(Date.now() / 1000),
model: data.model || model,
choices: [{
index: 0,
message: { role: 'assistant', content: data.choices?.[0]?.message?.content || '' },
finish_reason: data.choices?.[0]?.finish_reason || 'stop',
}],
});
}</p>⚠️ 注意:不要在后端开启
stream: true。Vercel AI SDK 的useChat会自动发起带text/event-stream的请求并解析 SSE;你若在 route.ts 里也用流式响应,容易出现双流嵌套、解码失败或连接中断。
useChat 前端页面怎么写才不踩坑
app/chat/page.tsx 必须标记 'use client',且不能混用服务端组件逻辑:
-
input和messages状态交给useChat管理,别自己用useState同步 -
handleSubmit直接调用handleSubmit(来自useChat返回值),不要手动fetch - 如果想加 loading 效果,用
isLoading,不是靠status === 'pending' - 消息列表渲染时,确保每个
message的role是'user'或'assistant',DeepSeek 返回的role是对的,不用改
'use client';
import { useChat } from '@ai-sdk/react';
<p>export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();</p><p>return (</p><div><form onSubmit={handleSubmit}><input
value={input}
onChange={handleInputChange}
disabled={isLoading}
/><button type="submit" disabled={isLoading}>
{isLoading ? '...' : 'Send'}
</button></form><pre class='brush:php;toolbar:false;'> <div>
{messages.map(m => (
<div key={m.id}>{m.role}: {m.content}</div>
))}
</div>
</div>); }
环境变量和部署时最容易漏的三件事
-
.env.local里必须定义DEEPSEEK_API_KEY,Next.js App Router 默认不注入环境变量到客户端,但route.ts可以读取 - Vercel 部署时,要在项目 Settings → Environment Variables 里手动添加同名变量,否则线上 500
- 本地开发若用
npm run dev,确保 Node 版本 ≥ 18.17,低版本下fetch在route.ts中可能返回undefined而不是 Promise
真正卡住人的往往不是模型调用本身,而是 OpenAI 兼容层那几行字段映射逻辑,以及环境变量在不同运行时的可见性边界。


















