~/tools / Faire tourner un LLM local sur votre serveur / Ollama Stream Reader

Ollama Stream Reader — Recollez un stream Ollama et voyez sa vitesse et sa raison d'arrêt

Collez une réponse en streaming d'Ollama, de /api/chat, /api/generate ou du /v1/chat/completions compatible OpenAI, et l'outil recolle les morceaux en texte complet, en thinking et en appels d'outils. Il indique pourquoi le modèle s'est arrêté, à quelle vitesse il a généré et traité le prompt, et si le stream a été coupé, et vous donne le message de l'assistant à ajouter à la requête suivante. Rien ne quitte votre navigateur.

Comment enregistrer un stream avec curl

-N désactive la mise en tampon de curl, et > stream.txt enregistre le stream dans un fichier. Remplacez le modèle et le message par les vôtres.

curl -sN http://localhost:11434/api/chat -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"Hello"}]}' > stream.txt

curl -sN http://localhost:11434/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"qwen2.5:7b","stream":true,"stream_options":{"include_usage":true},"messages":[{"role":"user","content":"Hello"}]}' > stream.txt

Lu comme un stream /api/chat (un objet JSON par ligne).

Résumé

Modèle
qwen2.5:7b
Raison de l'arrêt
stop
Chunks
7
Tokens générés
7
Vitesse de génération
10.4 tokens/s
Tokens du prompt
35
Vitesse du prompt (tokens qui n'étaient pas dans le cache)
64.1 tokens/s
Temps de chargement du modèle
4.923 s
Temps total
6.310 s
Du premier au dernier chunk
0.675 s

Texte

Hello, nice to meet.

Message de l'assistant pour la requête suivante

Ajoutez-le à messages, suivi des résultats des appels d'outils, s'il y en a.

{
  "role": "assistant",
  "content": "Hello, nice to meet."
}

eval_count compte aussi les tokens des appels d'outils, qui ne sont pas envoyés comme texte. Dans notre test, un appel d'outil est arrivé dans un seul chunk avec eval_count 20.

La documentation d'Ollama indique que prompt_eval_duration ne couvre que les tokens du prompt qui n'étaient pas dans le cache. La vitesse du prompt affichée ici ne divise que ces tokens. Toutes les durées sont en nanosecondes ; dans la forme OpenAI, les timings sont en millisecondes entières.

Dans la forme compatible OpenAI, les nombres de tokens ne sont envoyés qu'avec stream_options.include_usage, dans un chunk supplémentaire avant data: [DONE]. Si le stream est coupé, ce chunk n'arrive pas.

Formats d'après la documentation d'Ollama sur le streaming et l'usage et son code source (v0.40.15), vérifiés avec de vrais streams d'Ollama 0.40.11 le 2026-11-07. Ollama : Streaming

Tout se fait dans votre navigateur. L'outil ne se connecte à rien.

Ollama envoie ses réponses en streaming par défaut. /api/chat et /api/generate envoient un objet JSON par ligne (newline-delimited JSON) : chaque ligne porte quelques caractères de la réponse, et la dernière ligne a done à true et porte les nombres de tokens et les durées, en nanosecondes. Le /v1/chat/completions compatible OpenAI ne fait du streaming que lorsque stream vaut true. Il envoie alors des server-sent events : des lignes qui commencent par data:, un chunk à part avec un delta vide et le finish_reason, et data: [DONE] à la fin. Les nombres de tokens n'arrivent que si la requête définit stream_options.include_usage, dans un chunk supplémentaire avec une liste choices vide, et Ollama y ajoute un objet timings. Cet outil lit les trois formes, y compris la sortie de curl -i avec ses en-têtes HTTP, recolle content, thinking (reasoning dans la forme OpenAI) et les appels d'outils, et liste ce qui ne va pas : un stream sans ligne done ou sans [DONE] a été coupé ; une ligne {"error": …} signifie qu'Ollama s'est arrêté sur une erreur après avoir commencé à envoyer ; done_reason length signifie que num_predict ou max_tokens a été atteint. La vitesse de génération est eval_count divisé par eval_duration. Pour le prompt, la documentation d'Ollama indique que prompt_eval_duration ne couvre que les tokens du prompt qui n'étaient pas dans le cache, donc l'outil ne divise que ces tokens par cette durée. Dans la forme OpenAI, le timings.prompt_per_second d'Ollama divise tous les tokens du prompt, y compris ceux du cache, par ce temps. Dans notre test, il a indiqué 360.8 tokens par seconde pour un prompt dont 34 tokens sur 35 venaient du cache et dont le seul token restant a pris 97 ms. Les appels d'outils dans la forme OpenAI peuvent arriver en morceaux qui partagent un index, donc l'outil recolle les arguments par index ; Ollama lui-même envoie chaque appel d'outil en entier, dans un seul chunk. Nous avons vérifié l'outil avec de vrais streams d'Ollama 0.40.11 avec qwen2.5:7b, et les formats avec la documentation et le code source d'Ollama.

Le cœur de cet outil est open source, sous licence MIT. github.com/seigo5555/toolkitbox-lib/src/ollama-stream.ts

Cas d'usage

  • Voir la réponse entière d'une requête en streaming faite avec curl, au lieu de la lire morceau par morceau, un par ligne
  • Savoir si un stream a été coupé, s'est arrêté à la limite de longueur ou s'est terminé sur une erreur
  • Mesurer la vitesse de génération et de traitement du prompt d'un modèle sur votre machine ou votre serveur

Utilisation

  1. Lancez votre requête avec curl -sN et enregistrez la sortie dans un fichier, ou copiez ce que votre programme a reçu.
  2. Collez le stream entier. L'outil détecte s'il vient de /api/chat, /api/generate ou /v1/chat/completions.
  3. Lisez les problèmes et les chiffres, et copiez le texte ou le message de l'assistant pour la requête suivante.

FAQ

Pourquoi n'y a-t-il pas de nombres de tokens dans mon stream de /v1/chat/completions ?

Dans la forme compatible OpenAI, les nombres ne sont envoyés que lorsque la requête définit stream_options à {"include_usage": true}. Ils arrivent alors dans un chunk supplémentaire avec une liste choices vide, juste avant data: [DONE]. /api/chat et /api/generate les mettent toujours sur la dernière ligne.

Pourquoi la vitesse du prompt est-elle si différente de timings.prompt_per_second ?

La documentation d'Ollama indique que prompt_eval_duration ne couvre que les tokens du prompt qui n'étaient pas dans le cache. Le timings.prompt_per_second d'Ollama divise tous les tokens du prompt, y compris ceux du cache, par cette durée, donc il paraît bien plus rapide quand le cache a servi. L'outil ne divise que les tokens qui n'étaient pas dans le cache.

Le modèle a appelé un outil mais eval_count vaut 20. Où sont ces tokens ?

Le texte d'un appel d'outil n'est pas envoyé comme content ; Ollama le transforme en tool_calls et l'envoie dans un seul chunk. Les tokens sont quand même générés et comptés. Dans notre test, un appel d'outil avec un argument est arrivé dans un seul chunk avec eval_count 20.

Pourquoi /api/chat indique-t-il stop quand le modèle a appelé un outil ?

/api/chat garde done_reason à stop. Le endpoint compatible OpenAI remplace stop par tool_calls dans finish_reason lorsqu'un appel d'outil a été envoyé.

Que faire du message de l'assistant ?

La documentation d'Ollama note qu'il faut recoller les morceaux du stream pour conserver l'historique de la conversation, ce qui compte surtout pour les appels d'outils. Ajoutez le message à messages, ajoutez le résultat de chaque appel d'outil comme un message avec le rôle tool, et envoyez la requête suivante.

Mes données sont-elles envoyées quelque part ?

Non. Le stream est lu dans votre navigateur. Les commandes curl ne sont que du texte à exécuter vous-même.

Articles liés

Voir aussi