2026-04-15

DeepSeek V4 in Node.js: TypeScript, Streaming, Tool Use

DeepSeek V4 ist OpenAI-kompatibel, also reicht in Node.js das openai-npm-Paket. Dieser Leitfaden zeigt in TypeScript: Setup, erster Call, Streaming über einen Next.js-Route-Handler, Tool Use mit Zod-Validierung und realistische Kostenkontrolle.

1. Installation und Konfiguration

Das offizielle openai-Paket akzeptiert baseURL für DeepSeek. API-Key nur in .env, nicht committen und auf keinen Fall im Browser ausliefern.

npm install openai zod
echo "DEEPSEEK_API_KEY=sk-..." >> .env.local

2. Erster Call in TypeScript

Client einmal instanzieren und wiederverwenden. baseURL auf den DeepSeek-Endpunkt, model ist 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. Streaming im Next.js-Route-Handler

Für eine Chat-UI mit Live-Tokens ist der einfachste Weg, das async iterable des SDKs in einen ReadableStream zu wandeln und direkt als Response zurückzugeben.

// 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. Function Calling mit Zod validieren

V4s Tool Use ist produktionsreif, aber Argumente können gelegentlich halluzinieren. Immer mit Zod parsen, bevor du ausführst.

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. Kostenkontrolle in Node.js

Input und Output getrennt abgerechnet, Output ~2×. System-Prompt und Historie zählen als Input, ungebremste Chats eskalieren schnell.

maxTokens setzen, alte Turns zusammenfassen, RAG-Chunks cachen. Bei hohem Volumen senkt /pricing das Unit-Pricing weiter.

FAQ

Direkt aus dem Browser aufrufen?

Nein — API-Key wäre exponiert. Immer über Node.js, Serverless oder Next.js-Route-Handler proxen.

Läuft in Bun, Deno oder Cloudflare Workers?

Ja. openai-SDK liefert ESM-Build und braucht nur fetch. Für lange Streams bevorzugt Node.js.

Kompatibel mit LangChain / Vercel AI SDK?

Ja, alles mit OpenAI-kompatiblem baseURL funktioniert.

Wo gibt es günstigere Keys?

/pricing bietet offizielle Keys mit Rabatt.

Wer schon Node.js oder Next.js ausliefert, migriert mit zwei Zeilen Code zu DeepSeek V4: baseURL und model. Prompts, Tools und Retries bleiben, die Token-Kosten sinken um eine Größenordnung.