跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

DeepSeek与Next.js全栈AI应用的开发教程

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(如
https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271
)虽然结构接近,但存在几处关键差异: 请求头必须带
Authorization: Bearer
,不能复用 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 请求到
https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271
把
req.json()
拿到的原始 body 中的
messages
、
model
、
temperature
等字段原样透传,但过滤掉 DeepSeek 不认的字段(比如
response_format
) 设置 headers:
{"Content-Type": "application/json", "Authorization": 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();

const response = await fetch('https://www.php.cn/link/a4fe3e4de8ad631acb028b271b1fc271', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': Bearer ${process.env.DEEPSEEK_API_KEY}, }, body: JSON.stringify({ messages, model, temperature, // 不要加 stream: true —— useChat 自己处理流式,后端统一走非流式即可 }), });

const data = await response.json();

稿定在线PS

PS软件网页版

下载

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', }], }); }

⚠️ 注意:不要在后端开启
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';

export default function Chat() { const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();

return (

  
{messages.map(m => (
{m.role}: {m.content}
))}
); } 环境变量和部署时最容易漏的三件事
.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 兼容层那几行字段映射逻辑,以及环境变量在不同运行时的可见性边界。

相关文章