~/tools / ローカルLLMをサーバーで動かす / Ollama Stream Reader
Ollama Stream Reader — Ollama のストリームを結合し、速度と停止理由を確認
Ollama のストリーミングレスポンス(/api/chat、/api/generate、または OpenAI 互換の /v1/chat/completions のもの)を貼り付けると、細切れの断片を元の全文、thinking、ツール呼び出しに結合します。モデルが止まった理由、生成とプロンプトの速度、ストリームが途中で切れていないかを表示し、次のリクエストに加える assistant メッセージも用意します。データはブラウザの外に出ません。
curl でストリームを保存する方法
-N は curl のバッファリングを切り、> stream.txt はストリームをファイルに保存します。モデルとメッセージは自分のものに置き換えてください。
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/api/chat のストリーム(1行に1つの JSON オブジェクト)として読み取りました。
概要
- モデル
- qwen2.5:7b
- 停止理由
- stop
- チャンク数
- 7
- 生成トークン数
- 7
- 生成速度
- 10.4 トークン/秒
- プロンプトトークン数
- 35
- プロンプト速度(キャッシュになかったトークン)
- 64.1 トークン/秒
- モデルの読み込み時間
- 4.923 秒
- 合計時間
- 6.310 秒
- 最初から最後のチャンクまで
- 0.675 秒
テキスト
Hello, nice to meet.
次のリクエスト用の assistant メッセージ
これを messages に加え、ツール呼び出しの結果があればその後ろに続けます。
{
"role": "assistant",
"content": "Hello, nice to meet."
}eval_count には、テキストとしてストリーミングされないツール呼び出しのトークンも含まれます。私たちのテストでは、ツール呼び出し1回が eval_count 20 の1つのチャンクで届きました。
Ollama のドキュメントによると、prompt_eval_duration はキャッシュになかったプロンプトトークンだけを対象にしています。ここでのプロンプト速度は、そのトークンだけを割ったものです。所要時間はすべてナノ秒で、OpenAI 形式の timings は整数のミリ秒です。
OpenAI 互換の形式では、トークン数は stream_options.include_usage を設定したときだけ、data: [DONE] の前の追加チャンクで送られます。ストリームが途中で切れると、そのチャンクは届きません。
形式は Ollama のストリーミングと使用量のドキュメントおよびソースコード(v0.40.15)に基づき、2026-11-07 に Ollama 0.40.11 の実際のストリームで確認しました。 Ollama: Streaming
処理はすべてブラウザの中で行われます。このツールはどこにも接続しません。
Ollama は既定で回答をストリーミングします。/api/chat と /api/generate は1行に1つの JSON オブジェクトを送ります(newline-delimited JSON)。各行に回答の数文字が入り、最後の行は done が true になり、トークン数と所要時間(ナノ秒)を持ちます。OpenAI 互換の /v1/chat/completions がストリーミングするのは、stream が true のときだけです。このときは server-sent events を送ります。data: で始まる行、空の delta と finish_reason を持つ独立したチャンク、最後の data: [DONE] です。トークン数が付くのは、リクエストで stream_options.include_usage を設定したときだけで、choices が空の追加チャンクに入り、Ollama はそこに timings オブジェクトを加えます。このツールは3つの形式をすべて読み取ります。HTTP ヘッダー付きの curl -i の出力にも対応し、content、thinking(OpenAI 形式では reasoning)、ツール呼び出しを結合して、問題点を一覧にします。done の行がない、または [DONE] がないストリームは途中で切れています。{"error": …} の行は、Ollama が送信を始めた後にエラーで止まったことを意味します。done_reason が length なら、num_predict または max_tokens に達しています。生成速度は eval_count を eval_duration で割った値です。プロンプトについては、Ollama のドキュメントによると prompt_eval_duration はキャッシュになかったプロンプトトークンだけを対象にしているため、このツールはそのトークンだけをその時間で割ります。OpenAI 形式では、Ollama 自身の timings.prompt_per_second が、キャッシュ済みを含むすべてのプロンプトトークンをその時間で割ります。私たちのテストでは、35 トークンのプロンプトのうち 34 トークンがキャッシュから来て、残り 1 トークンに 97 ms かかったとき、360.8 トークン/秒と報告されました。OpenAI 形式のツール呼び出しは、同じ index を持つ断片に分かれて届くことがあるため、このツールは index ごとに arguments を結合します。Ollama 自体は、各ツール呼び出しを1つのチャンクにまとめて送ります。私たちは、このツールを Ollama 0.40.11 と qwen2.5:7b による実際のストリームで、各形式を Ollama のドキュメントとソースコードで確認しました。
このツールの計算部分は、オープンソース(MIT ライセンス)で公開しています。 github.com/seigo5555/toolkitbox-lib/src/ollama-stream.ts
こんな時に使う
- curl で送ったストリーミングリクエストの回答全体を、1行ずつ読まずに確認する
- ストリームが途中で切れたのか、length の上限で止まったのか、エラーで終わったのかを調べる
- 自分のマシンやサーバーでのモデルの生成速度とプロンプト速度を測る
使い方
- curl -sN でリクエストを実行して出力をファイルに保存するか、プログラムが受け取った内容をコピーします。
- ストリーム全体を貼り付けます。/api/chat、/api/generate、/v1/chat/completions のどれかをツールが判別します。
- 問題点と数値を読み、テキストまたは次のリクエスト用の assistant メッセージをコピーします。
FAQ
/v1/chat/completions のストリームにトークン数がないのはなぜですか?
OpenAI 互換の形式では、リクエストで stream_options を {"include_usage": true} に設定したときだけ、トークン数が送られます。data: [DONE] の直前の、choices が空の追加チャンクに入ります。/api/chat と /api/generate は、常に最後の行に入れます。
プロンプト速度が timings.prompt_per_second と大きく違うのはなぜですか?
Ollama のドキュメントによると、prompt_eval_duration はキャッシュになかったプロンプトトークンだけを対象にしています。Ollama の timings.prompt_per_second は、キャッシュ済みを含むすべてのプロンプトトークンをその時間で割るため、キャッシュが使われたときはずっと速く見えます。このツールは、キャッシュになかったトークンだけを割ります。
モデルがツールを呼び出したのに eval_count が 20 です。そのトークンはどこにありますか?
ツール呼び出しのテキストは content としてストリーミングされません。Ollama はそれを tool_calls に変換して、1つのチャンクで送ります。トークンは生成され、数えられています。私たちのテストでは、引数が1つのツール呼び出し1回が、eval_count 20 の1つのチャンクで届きました。
モデルがツールを呼び出したのに、/api/chat が stop と言うのはなぜですか?
/api/chat は done_reason を stop のままにします。OpenAI 互換のエンドポイントは、ツール呼び出しが送られたとき、finish_reason の stop を tool_calls に変えます。
assistant メッセージはどうすればよいですか?
Ollama のドキュメントには、会話履歴を保つにはストリーミングされた断片を結合する必要があり、ツール呼び出しで特に重要だと書かれています。メッセージを messages に加え、各ツール呼び出しの結果を role が tool のメッセージとして加えてから、次のリクエストを送ります。
データはどこかに送られますか?
いいえ。ストリームはブラウザの中で読み取られます。curl コマンドは、あなたが実行するための文字列にすぎません。
関連する記事
- 小さなVPSでOllamaのメモリを見張るOllamaがメモリに何を載せ、どれだけの間そこに置き、どの設定で変わるのかを見ます。ollama ps、keep_alive、各種の上限を、公式FAQから。
- 自分のVPSでDifyとOllamaをつなぐ自分のVPSでDifyを動かし、モデルにOllamaを使う方法です。インストール、プラグインの入力欄、Dockerのアドレスの問題、埋め込みを公式ドキュメントからまとめました。
- 高価なPCなしでローカルLLMを始める:VPSを使う初心者ガイド高性能なPCがなくても大丈夫。VPSを借りて、小さなローカルLLMをブラウザから動かす6ステップ。メモリの見積もりから、外から守られたチャット画面まで、限界も正直に書いています。