「文章としては正しいのに、なぜか終わらない」
Ollama経由でNemotron系の日本語LLM(Q5_K_M量子化)を動かしている。 ある日、テスト運用中に「生成がいつまで経っても終わらない」という症状に遭遇した。
出力自体はおかしくない。文章としてはちゃんとした日本語が続いている。ただ、本来なら文章の末尾で終わるはずのところで止まらず、延々とテキストを生成し続ける。 タイムアウトするか、こちらが強制的に切るまで止まらない状態だった。
症状の切り分け
最初に疑ったのは、プロンプトの書き方だった。指示が曖昧で「どこまで書けばいいか」をモデルが判断できていないのではと考え、プロンプトに「以上で終了してください」のような文言を追加してみたが、改善しなかった。
次に疑ったのは num_predict などの生成長の設定だが、これも根本原因ではなく、単に生成上限に達するまで生成し続けているだけだった。
ここでようやく、「そもそもモデルが生成を終了すべきタイミングを認識できていないのでは」という方向に切り替えた。 つまり、EOS(End of Sequence)トークンが正しく機能していない可能性を疑い始めた。
原因調査: Ollamaのストリーミング応答を直接確認する
Ollamaのストリーミング応答には done と done_reason というフィールドが含まれている。これを直接確認したところ、生成が stop ではなく length(生成上限到達)で終わっていることが分かった。つまり、モデル側が「ここで終わり」というシグナルを一度も返していないということになる。
一般的なLlama系のモデルであれば <|eot_id|> のようなEOSトークンが使われることが多いが、今回使っていた日本語モデルはそれとは異なるトークン体系を持っていた。
Modelfile(Ollamaのモデル設定ファイル)を確認すると、デフォルトで設定されているstopトークンが、このモデルの実際のEOSトークンと一致していないことが判明した。
犯人は <SPECIAL_12>
トークナイザーの設定ファイルを直接掘り下げて確認したところ、このモデルが実際に使用しているEOSトークンは <SPECIAL_12> という、一見しただけでは何を意味するか分からない特殊トークンだった。
汎用的なテンプレートやドキュメントには載っておらず、モデルカードの記述と実際のtokenizer設定を突き合わせて初めて特定できた。
Modelfileの PARAMETER stop に <SPECIAL_12> を明示的に追加したところ、生成が正しいタイミングでピタッと止まるようになった。
PARAMETER stop "<SPECIAL_12>"
学んだこと
- 日本語LLM、特にベースモデルを日本語向けにファインチューニングしたものは、EOSトークンが本家と異なるケースがある
- Ollamaはstopトークンを自動推定してくれるが、必ずしも正しいとは限らない
- 生成が終わらない・止まらないという症状が出たら、まずプロンプトよりも先に
done_reasonを確認し、stopで終わっているかlengthで強制終了しているかを見るべき - トークナイザー設定(tokenizer_config.json 等)を直接確認することで、ドキュメント化されていない特殊トークンにたどり着けることがある
「生成が終わらない」という症状に遭遇したら、プロンプトを疑う前に done_reason を見る。それだけで調査時間はかなり短縮できるはずだ。



コメント