2026-04-15
在 Node.js 中使用 DeepSeek V4:TypeScript、流式、tool use
DeepSeek V4 兼容 OpenAI 协议,所以在 Node.js 里直接用 openai npm 包就能接入。本教程用 TypeScript 走完从安装、第一次调用、流式、tool use 到 Next.js 路由的全链路,并给出实战中的 tokens 成本控制建议。
1. 安装与环境配置
openai 官方包完全支持通过 baseURL 指向 DeepSeek。API Key 放在 .env,不要提交到 Git,更不要写进前端包里。
npm install openai zod
echo "DEEPSEEK_API_KEY=sk-..." >> .env.local2. TypeScript 的第一次调用
实例化客户端只需要一次,整个应用复用。baseURL 指向 DeepSeek endpoint,model 用 deepseek-chat。
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: "https://api.deepseek.com/v1",
});
export async function ask(question: string): Promise<string> {
const res = await client.chat.completions.create({
model: "deepseek-chat",
messages: [
{ role: "system", content: "You are a concise technical assistant." },
{ role: "user", content: question },
],
temperature: 0.2,
});
return res.choices[0].message.content ?? "";
}3. Next.js route handler 流式转发
前端要看到 tokens 边生成边显示,最简单的做法是在 Next.js route handler 里把 OpenAI SDK 的 async iterable 转成 ReadableStream,直接返回给浏览器。
// app/api/chat/route.ts
import OpenAI from "openai";
export const runtime = "nodejs";
const client = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: "https://api.deepseek.com/v1",
});
export async function POST(req: Request) {
const { messages } = await req.json();
const stream = await client.chat.completions.create({
model: "deepseek-chat",
messages,
stream: true,
});
const encoder = new TextEncoder();
const body = new ReadableStream({
async start(controller) {
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content ?? "";
if (delta) controller.enqueue(encoder.encode(delta));
}
controller.close();
},
});
return new Response(body, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}4. 用 Zod 校验 function calling 参数
V4 的 tool use 足够稳定,可以跑真实 agent。但模型偶尔会在参数里出错,所以每个工具都应该先用 Zod schema 校验再执行,别信任 JSON.parse 出来的对象。
import { z } from "zod";
const GetWeatherArgs = z.object({ city: z.string().min(1) });
const tools = [{
type: "function" as const,
function: {
name: "get_weather",
description: "Get the current weather for a city",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
},
}];
const res = await client.chat.completions.create({
model: "deepseek-chat",
messages: [{ role: "user", content: "Weather in Tokyo?" }],
tools,
});
const call = res.choices[0].message.tool_calls?.[0];
if (call?.function.name === "get_weather") {
const args = GetWeatherArgs.parse(JSON.parse(call.function.arguments));
// … execute tool and feed result back as a { role: "tool" } message …
}5. Node.js 场景下的成本控制
输入与输出 tokens 分别计费,输出大约是输入的 2 倍。system prompt 和历史都是输入,长对话如果不摘要,费用会迅速失控。
实战建议:给 maxTokens 设上限、对旧对话做摘要、retrieval chunk 做缓存。流量大的团队建议在 /pricing 走官方折扣 Key,进一步压低单价。
FAQ
能直接在浏览器里调用吗?
不能。API Key 不能暴露到前端,所有调用都走 Node.js server / serverless / Next.js route handler 代理。
Bun、Deno、Cloudflare Workers 支持吗?
支持。openai SDK 提供 ESM 构建,运行时只要有 fetch 就能用。长连接场景优先选 Node.js。
能配合 LangChain、LlamaIndex、Vercel AI SDK 吗?
可以。凡是支持 OpenAI 兼容 baseURL 的库都能指向 DeepSeek。
怎么买更便宜的 API Key?
/pricing 有官方 DeepSeek 折扣 Key,同接口、同 context window、更低单价。
如果你已经在跑 Node.js 或 Next.js,把 OpenAI 换成 DeepSeek V4 只是两行改动:baseURL 和 model。剩下的 prompt、工具、重试逻辑都能原样复用,tokens 费用直接打到 1/5。