API & SDKAnleitung
Chat-Antworten in Node.js mit dem OpenAI SDK streamen
Streame eine Chat-Completion Token für Token in Node.js: for-await-Schleife, Stoppen auf Anfrage, Fehlerbehandlung und Token-Nutzung mit dem OpenAI SDK.

Auf dieser Seite
Streaming ermöglicht es deiner App, die Antwort anzuzeigen, während sie generiert wird, anstatt auf die vollständige Antwort zu warten. In dieser Anleitung erstellst du ein kleines Node.js-Skript, das eine Chat-Completion von der CheapTokens-API Token für Token streamt, sie auf Anfrage stoppt und Fehler behandelt. Die Python-Version dieses Themas findest du in Streaming responses in Python.
Was du brauchst#
- Node.js 22 oder neuer (die im
openai-Paket-README angegebene Mindestversion, geprüft am 22. Oktober 2026). - Einen CheapTokens-API-Schlüssel. Wenn du noch keinen hast, folge Your first API request with CheapTokens.
- Das offizielle SDK:
npm install openai.
CheapTokens stellt eine OpenAI-kompatible API unter https:/ bereit, sodass das offizielle openai-Paket funktioniert, indem du nur die Basis-URL und den Schlüssel änderst. Bewahre den Schlüssel in einer Umgebungsvariable auf, nicht im Code:
export CHEAPTOKENS_API_KEY="your-key"Schritt 1. Die Antwort mit for await streamen#
Erstelle stream.mjs (die .mjs-Erweiterung ermöglicht dir die Verwendung von import und Top-Level-await):
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.CHEAPTOKENS_API_KEY,
baseURL: 'https://api.cheaptokens.dev/v1',
});
const stream = await client.chat.completions.create({
model: 'deepseek-ai/DeepSeek-V4-Flash-0731', // take the id from the CheapTokens docs
messages: [{ role: 'user', content: 'Explain streaming in two sentences.' }],
stream: true,
stream_options: { include_usage: true },
});
let usage = null;
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content;
if (delta) process.stdout.write(delta);
if (chunk.usage) usage = chunk.usage;
}
console.log('\n\nusage:', usage);Führe es mit node stream.mjs aus. Das SDK liest die Server-Sent Events von der API und übergibt dir pro Iteration von for await einen Chunk. Drei Details sind wichtig:
- Text kommt in
chunk.an. Manche Chunks enthalten keinen Text (der erste enthält oft nur die Rolle), prüfe also, dasschoices[0]. delta. content deltanicht leer ist. process.gibt ohne Zeilenumbruch aus, sodass die Wörter nacheinander erscheinen.stdout. write - Mit
stream_enthält der letzte Chunk einoptions: { include_ usage: true } usage-Objekt mit Prompt- und Completion-Token-Zählungen, und seinchoices-Array ist leer. Deshalb verwendet der Codechunk.mit optional chaining.choices[0]?.
Die Modell-ID stammt aus der CheapTokens-Dokumentation: Anbieter benennen dasselbe Modell unterschiedlich, kopiere die ID also von dort.
Schritt 2. Den Stream auf Anfrage stoppen#
Benutzer drücken Stop, schließen einen Tab oder wechseln den Chat. Brich die Anfrage ab, damit du nicht auf Tokens wartest, die niemand lesen wird. Übergib ein AbortSignal in den Request-Optionen:
const controller = new AbortController();
process.on('SIGINT', () => controller.abort()); // Ctrl+C stops the stream
const stream = await client.chat.completions.create(
{
model: 'deepseek-ai/DeepSeek-V4-Flash-0731',
messages: [{ role: 'user', content: 'Write a long story about a lighthouse.' }],
stream: true,
},
{ signal: controller.signal },
);Das Stream-Objekt hat auch sein eigenes stream., und das Verlassen der for await-Schleife mit break schließt die Verbindung ebenfalls. Verwende das, was näher an deinem Code liegt: ein Signal, wenn der Abbrechen-Button woanders liegt, break, wenn die Entscheidung innerhalb der Schleife getroffen wird (zum Beispiel, wenn du ein Stoppwort gefunden hast).
Schritt 3. Fehler behandeln#
Ein Stream kann vor dem ersten Token fehlschlagen (falscher Schlüssel, leeres Guthaben) oder mittendrin (Netzwerkabbruch). Umschließe sowohl die Anfrage als auch die Schleife mit einem try:
try {
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}
} catch (err) {
if (err instanceof OpenAI.APIUserAbortError) {
console.log('\n[stopped by user]');
} else if (err instanceof OpenAI.APIError) {
console.error(`\nAPI error ${err.status}: ${err.message}`);
} else {
throw err;
}
}APIUserAbortErrorist das, was du nach deinem eigenenabort()bekommst. Es ist kein Fehler, also zeige es nicht als solchen an.APIErrorhat den HTTP-status: 401 bedeutet ein falscher oder fehlender Schlüssel, 429 bedeutet zu viele Anfragen, und eine Meldung über Tokens bedeutet, dass das Guthaben aufgeladen werden muss. Weitere Ursachen und Lösungen findest du in Common connection errors and how to fix them und "Not enough tokens" error.- Text, der bereits ausgegeben wurde, bleibt nach einem Fehler gültig. Behalte ihn, wenn du die Teilantwort anzeigen möchtest.
Schritt 4. Nutzung lesen und Kosten schätzen#
Das usage-Objekt enthält prompt_tokens und completion_. Zusammen mit dem Modellpreis pro 1M Tokens ergibt sich daraus die exakten Kosten einer Anfrage. Für eine grobe Schätzung vor der Ausführung verwende die Live-Tabelle unten: Sie zeigt die Kosten für 1.000 Anfragen mit jeweils 2.000 Eingabe- und 800 Ausgabe-Tokens.
| Modell | Input $/1M | Output $/1M | Pro Anfrage | 1.000 Anfragen | OpenRouter, 1.000 Anfragen |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.000072 | $0.072 | $0.143 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.00011 | $0.11 | $0.22 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.00022 | $0.22 | $1.56 |
2.000 Input- und 800 Output-Tokens pro Anfrage. Die Preise pro 1 Mio. Tokens sind aktuell und ändern sich zusammen mit unseren Tarifen; die OpenRouter-Spalte zeigt Referenzpreise für dieselbe Arbeitslast.
Für gestreamte Chat-Antworten kostet MiniMax-M2.7 $0.05 pro 1M Eingabe- und $0.15 pro 1M Ausgabe-Tokens, mit einem Kontext von 180K und bis zu 8.192 Ausgabe-Tokens pro Antwort. Der Preis ist pro Modell zu jeder Tageszeit fest, und ein Guthaben deckt alle Modelle ab, sodass das Ändern des model-Strings ausreicht, um sie mit deinen eigenen Prompts zu vergleichen.
Vollständiges Skript#
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.CHEAPTOKENS_API_KEY,
baseURL: 'https://api.cheaptokens.dev/v1',
});
const controller = new AbortController();
process.on('SIGINT', () => controller.abort());
try {
const stream = await client.chat.completions.create(
{
model: 'deepseek-ai/DeepSeek-V4-Flash-0731',
messages: [{ role: 'user', content: 'Explain streaming in two sentences.' }],
stream: true,
stream_options: { include_usage: true },
},
{ signal: controller.signal },
);
let usage = null;
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content;
if (delta) process.stdout.write(delta);
if (chunk.usage) usage = chunk.usage;
}
console.log('\n\nusage:', usage);
} catch (err) {
if (err instanceof OpenAI.APIUserAbortError) {
console.log('\n[stopped by user]');
} else if (err instanceof OpenAI.APIError) {
console.error(`\nAPI error ${err.status}: ${err.message}`);
} else {
throw err;
}
}Nächste Schritte#
- Sende die Chunks mit Server-Sent Events von deinem eigenen Endpunkt an einen Browser, damit der Schlüssel den Server nie verlässt.
- Probiere andere Modelle aus, indem du nur den
model-String änderst: MiniMax-M2.7 ist mit demselben Guthaben und derselben Basis-URL verfügbar. - Hole dir einen Schlüssel und führe das Skript aus: create a CheapTokens API key und lade das Guthaben auf.
Endpunkte, Modell-IDs und Limits für jedes Modell findest du in den CheapTokens docs.



