2026-04-15

Utiliser DeepSeek V4 en Node.js : TypeScript, streaming, tool use

DeepSeek V4 étant compatible OpenAI, il suffit du paquet openai côté Node.js. Ce guide décrit en TypeScript : installation, premier appel, streaming dans un route handler Next.js, tool use validé avec Zod et quelques règles pour garder le coût sous contrôle.

1. Installation et configuration

Le paquet openai officiel accepte baseURL pour pointer vers DeepSeek. Clé dans .env, jamais dans Git, jamais côté navigateur.

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

2. Premier appel en TypeScript

Instanciez le client une seule fois. baseURL vers DeepSeek, model deepseek-chat pour l'usage général.

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 dans un route handler Next.js

Pour une UI chat avec des tokens en temps réel, le plus simple est de convertir l'iterable async renvoyé par le SDK en ReadableStream et de le retourner comme Response.

// 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. Valider les arguments de tool use avec Zod

Le tool use de V4 est assez fiable pour des agents en production, mais le modèle peut halluciner sur les arguments. Parsez-les systématiquement avec un schéma Zod avant exécution.

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. Contrôle du coût côté Node.js

Entrée et sortie séparées, sortie à ~2×. System prompt et historique s'ajoutent à l'entrée, donc une conversation qui grossit grossit aussi la facture.

Fixez maxTokens, résumez les vieux tours, cachez les chunks RAG. Pour du volume, /pricing baisse le prix unitaire avec des clés officielles remisées.

FAQ

Appeler DeepSeek depuis le navigateur ?

Non, cela exposerait la clé. Toujours via un serveur Node.js, du serverless ou un route handler Next.js.

Bun, Deno, Cloudflare Workers ?

Oui, le SDK openai fournit un build ESM et requiert fetch. Pour le streaming long, privilégiez Node.js.

Compatible LangChain / Vercel AI SDK ?

Oui, toute librairie acceptant un baseURL compatible OpenAI fonctionne.

Où trouver une clé moins chère ?

/pricing liste des clés officielles remisées.

Si vous expédiez déjà du Node.js ou du Next.js, migrer vers DeepSeek V4 tient en deux lignes : baseURL et model. Vous gardez prompts, outils et retries, et vous divisez par ~10 la facture tokens.