Ollama などのローカル LLM で詰まった症状を、実測で切り分けて直す
トップ > JSON・構造化出力が壊れる

Ollama で JSON が途中で切れる:num_ctx 4096 の天井を見分けて直す

公開 2026-09-23更新 2026-09-23対象:構造化出力が長い入力のときだけ壊れる人
この記事で分かることdone_reason が length で、入力+出力がちょうど 4,096 なら文脈長の天井。/v1 では num_ctx が効かない

結論:Ollama で長い入力を渡したとき、構造化出力(JSON)が途中で切れてパースに失敗し、done_reasonlength になっているなら、まず 入力トークン+出力トークンの合計が `num_ctx`(既定 4096)にちょうど張り付いていないか を確認してください。私たちの環境では、合計がぴったり 4,096 で打ち切られていました。num_ctx を広げると同じ入力で完結しました。OpenAI 互換の /v1num_ctx を送っても効きませんでした。

対象読者:Ollama の format(JSON スキーマ)で構造化出力を使っていて、入力が長いときだけ JSONDecodeError(EOF)が出る人。

症状の見分け方

次の 3 つが同時に出ていたら、出力上限ではなく 文脈長(num_ctx)の天井 を疑います。

さらに、prompt_eval_count自分が送った入力より明らかに小さい 場合、入力側も黙って切られています。私たちの再現では、6,302 トークン相当の入力が 2,050 トークンしか読まれていませんでした。

検証した条件

項目
ランタイムOllama 0.34.0(Windows 11)
モデルqwen3.5:9b
GPURTX 5070 Ti(16GB)
生成設定temperature 0、think 無効
入力320 項目の一覧を 1 件ずつ要約させる指示(同一の入力を 3 回とも使用)
出力形式JSON スキーマ(items 配列、各要素に idsummary、すべて required)

結果

呼び出し方num_ctx入力出力合計終了理由JSON
ネイティブ /api/chat40962,0502,0464,096length壊れた
ネイティブ /api/chat163846,3026,56812,870stop読めた
OpenAI 互換 /v1num_ctx 16384 を送信)無視された2,0502,0464,096length壊れた

所要時間は順に 26.3 秒、65.0 秒、23.8 秒でした。

自分の環境で確かめる

ネイティブ API の応答に含まれる数値を見るだけで判定できます。次の Python は、Ollama を localhost:11434 で動かしている前提です(モデル名と入力は自分のものに置き換えてください)。

import json, urllib.request

body = {
    "model": "qwen3.5:9b",
    "stream": False,
    "format": your_json_schema,          # 使っている JSON スキーマ
    "messages": [{"role": "user", "content": your_long_prompt}],
    "options": {"num_ctx": 4096},        # いまの値
}
req = urllib.request.Request("http://localhost:11434/api/chat",
                             data=json.dumps(body).encode(),
                             headers={"Content-Type": "application/json"})
d = json.loads(urllib.request.urlopen(req).read())
total = d["prompt_eval_count"] + d["eval_count"]
print(d["done_reason"], d["prompt_eval_count"], d["eval_count"], total)
# length で、total が num_ctx と同じなら文脈長の天井

直し方

当てはまらない条件・未検証の範囲

以前の版からの訂正

以前この記事では、原因を「審査役に書かせる指摘が多すぎて出力が長くなるため」と説明していました。その後の実測で、主因は入力と出力の合計が文脈長 4,096 に達することだと分かったので、全面的に書き直しました。

この記事はローカル LLM が下書きし、記載の数値・固有名は実測ログとの機械照合を通したものです。人による全文の確認はしていません。数値は本文中に示した実測条件でのものです。