Réponse rapide
Comment streamer une chat completion depuis LLMwithCrypto ?
Ajoutez "stream": true au body de POST https://llmwithcrypto.com/api/v1/chat/completions. LLMwithCrypto répond alors avec des server-sent events : chaque ligne data: contient un chat.completion.chunk avec un morceau de texte dans delta.content, et le stream se termine par data: [DONE]. Ajoutez "stream_options": {"include_usage": true} pour obtenir les compteurs de tokens dans un dernier chunk. Cela fonctionne sur tous les modèles, comme documenté au 23 octobre 2026.
Pourquoi streamer ?
Pour les humains, parce que les premiers mots apparaissent en un instant au lieu d'attendre que toute la réponse soit écrite. Une longue réponse d'un grand modèle peut mettre plusieurs secondes à se terminer ; en streaming, le lecteur commence à lire tout de suite.
Pour les programmes, cela compte moins : un script qui a besoin du texte complet ne gagne rien au streaming et a plus de parsing à faire. Streamer quand un humain regarde, et envoyer une requête normale sinon. Le prix est le même dans les deux cas. Vous payez au token depuis votre solde : les tokens d'entrée et de sortie sont comptés par le tokenizer du modèle lui-même et facturés au prix de ce modèle par 1M de tokens. Un appel qui se termine par une erreur ne coûte rien.
curl -sN "https://llmwithcrypto.com/api/v1/chat/completions" \
-H "Authorization: Bearer $LLMWITHCRYPTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4.1-flash",
"messages": [{"role": "user", "content": "Write a haiku about latency."}],
"stream": true,
"stream_options": {"include_usage": true},
"max_tokens": 120
}'
import os
from openai import OpenAI
client = OpenAI(
base_url="https://llmwithcrypto.com/api/v1",
api_key=os.environ["LLMWITHCRYPTO_API_KEY"],
)
stream = client.chat.completions.create(
model="deepseek-v4.1-flash",
messages=[{"role": "user", "content": "Write a haiku about latency."}],
stream=True,
stream_options={"include_usage": True},
max_tokens=120,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\n", chunk.usage.prompt_tokens, "in,", chunk.usage.completion_tokens, "out")
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://llmwithcrypto.com/api/v1',
apiKey: process.env.LLMWITHCRYPTO_API_KEY,
});
const stream = await client.chat.completions.create({
model: 'deepseek-v4.1-flash',
messages: [{ role: 'user', content: 'Write a haiku about latency.' }],
stream: true,
stream_options: { include_usage: true },
max_tokens: 120,
});
for await (const chunk of stream) {
const text = chunk.choices[0]?.delta?.content;
if (text) process.stdout.write(text);
if (chunk.usage) console.log(`\n${chunk.usage.prompt_tokens} in, ${chunk.usage.completion_tokens} out`);
}
À quoi ressemble le stream sur le réseau ?
Chaque événement est une ligne commençant par data: , suivie d'une ligne vide. Le premier chunk porte généralement le role, les suivants quelques caractères de content chacun, et le chunk avec un finish_reason clôt la réponse. Avec include_usage, un chunk de plus suit avec un tableau choices vide et l'objet usage. Le stream se termine toujours par data: [DONE]. Les ids et compteurs ci-dessous sont illustratifs.
data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{"content":"Packets"},"finish_reason":null}]}
data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{"content":" cross the"},"finish_reason":null}]}
data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-5a1e","object":"chat.completion.chunk","created":1792742400,"model":"deepseek-v4.1-flash","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":19,"total_tokens":33}}
data: [DONE]
Et si le stream se coupe ?
Une erreur détectée avant le premier token, comme une mauvaise clé ou un solde vide, revient comme une erreur HTTP normale avec un body JSON, pas comme un stream ; la page des erreurs les liste. Une erreur pendant la génération termine le stream prématurément, sans finish_reason.
Si vous fermez vous-même la connexion, la génération s'arrête. Vous payez alors l'entrée et les tokens déjà générés, comme pour n'importe quel appel. Votre code doit considérer un stream qui se termine sans finish_reason et sans [DONE] comme incomplet, et renvoyer la requête s'il a besoin de la réponse complète.
Streaming : questions fréquentes
Le streaming coûte-t-il plus cher ?
Non. Les mêmes tokens sont facturés au même prix. Vous payez au token depuis votre solde : les tokens d'entrée et de sortie sont comptés par le tokenizer du modèle lui-même et facturés au prix de ce modèle par 1M de tokens. Un appel qui se termine par une erreur ne coûte rien.
Puis-je streamer avec du tool calling ?
Oui, sur les modèles qui prennent en charge les tools : le nom et les arguments de la fonction arrivent en morceaux dans delta.tool_calls et doivent être assemblés avant usage. La page sur le tool calling montre la boucle sans streaming, plus simple pour commencer.
Pourquoi je n'ai pas d'usage dans un appel streamé ?
Ajoutez "stream_options": {"include_usage": true}. Sans cela, un flux ne contient aucun décompte de tokens ; le dashboard les affiche quand même.