Ollamaのcontext 4K・8K・16Kで何が変わる?長文検索・待ち時間・VRAMを実測

実験日: 2026-08-24
GPU: RTX 5070 Ti 16GB / WSL2 / Ollama 0.32.15
Model: Gemma 3 4B Q4_K_M

Ollamaのnum_ctxを大きくすると、長い論文やcodeを一度に読ませられます。しかし、contextを16Kへ設定しただけでは長文性能を測ったことになりません。実際に何token入力したか、必要VRAMが増えたか、先頭の情報を取り出せたかを分けて確認する必要があります。

とりあえず16Kへ設定しても、実際の入力が短ければ長文性能の確認にはなりません。

Gemma 3 4B Q4_K_Mへ約2.9K、5.7K、11.2K tokenのsynthetic研究logを入力し、秘密codeを先頭・中央・末尾へ置きました。4K・8K・16Kの全9条件でcodeを取得できました。loadを除いた最初の回答までの中央値は0.373、0.563、1.019秒、GPU peakは4,783、5,015、5,189MiBでした。

context設定を4倍にしても、このmodelと実装では総GPU使用量の増加は406MiBです。ただし、これはGemma 3のlocal/global attention構造、Q4 model、Ollama 0.32.15、単一requestの結果です。他modelへそのまま当てはめられません。

4K・8K・16Kの結果

num_ctx 実prompt token 秘密code取得 load除外TTFC prompt処理速度 peak GPU used
4,096 2,873 3/3 0.373秒 7,935 tok/s 4,783MiB
8,192 5,663 3/3 0.563秒 10,339 tok/s 5,015MiB
16,384 11,244 3/3 1.019秒 11,278 tok/s 5,189MiB

このPCで普段の短いchatをするだけなら4Kで十分です。複数fileや長い論文断片を投入するときだけ8K、16Kへ上げます。大きいcontextは無料ではなく、入力を読む待ち時間とmemoryを増やすからです。

Gemma 3 4B Q4_K_MのOllama context 4K・8K・16Kで実prompt token、秘密code取得、TTFC、GPU memoryを比較
Gemma 3 4B Q4_K_MのOllama context 4K・8K・16Kで実prompt token、秘密code取得、TTFC、GPU memoryを比較

context windowは会話の作業領域

LLMは入力tokenと生成済みtokenをcontext window内で扱います。概念的には次の制約があります。

input tokens + output tokens + template等のoverhead <= context window

num_ctx=4096は「4,096文字」ではありません。tokenは文字より細かい場合も、複数文字をまとめる場合もあります。日本語、英語、数字、codeで文字数/token比は変わります。

またnum_ctx=16384へ設定しても、短いpromptを送れば実際のinputは短いままです。context capacityと実prompt lengthを区別します。

KV cacheは何を保存するのか

Transformerは過去tokenへattentionします。生成のたびに過去のkey/valueを最初から再計算すると無駄なので、各layerのkeyとvalueをcacheします。これがKV cacheです。

単純なfull attention modelなら、KV cacheの概算は次の要素へ比例します。

KV cache ∝ layers × context tokens × KV heads × head dimension × 2(K,V) × bytes

contextを2倍にするとKV部分も概ね増えます。ただし実modelはGrouped-Query Attention、sliding-window attention、KV量子化などを使う場合があり、全VRAMが単純に2倍になるわけではありません。weightはcontext長に関係なく大部分を占めます。

Gemma 3はlocalとglobal attentionを混ぜる

Google DeepMindのGemma 3 Technical Reportでは、local sliding-window self-attentionを5 layer、その後global self-attentionを1 layerという5:1 patternで交互に使うと説明されています。

local layerは無制限に全過去tokenを見るのではなく、近傍windowを中心に見ます。global layerは長距離情報を扱います。Gemma 3 model cardでは4B、12B、27Bが128K contextに対応します。

今回4Kから16Kでmemory増加が比較的小さかったことと、このarchitectureは整合します。しかし、実験はOllama内部のlayer別KV allocationを直接測っていません。「5:1構造だけが406MiB増の原因」と断定はできません。

実験環境とmodel

Windows 11 + WSL2 Ubuntu
NVIDIA GeForce RTX 5070 Ti 16GB
driver 595.71
Ollama 0.32.15
gemma3:4b-it-q4_K_M
temperature 0 / seed 42 / think false

前記事のQ4/Q8比較でQ4_K_MはQ8_0より約25%高速、約1.5GiB低memoryでした。今回はcontext costを見やすくするためQ4を固定しました。

実際にcontextの約70%を埋める

recordは次の形式です。

LOG 00042 | sensor=S08 | status=normal | value=0545 | note=no anomaly.

ただ同じ単語をコピーするだけでなく、番号、sensor、valueを変えました。まず100 recordをAPIへ送り、実tokenizerでprompt_eval_count=3,179を得ました。

estimated tokens per record = 3,179 / 100 = 31.79

この値から各contextの70%を目標にrecord数を決めます。

record_count = int(num_ctx * 0.70 / tokens_per_record)

実際にはtemplate、instruction、秘密recordのoverheadがあるため、最終値はAPIのprompt_eval_countを採用します。

num_ctx 4,096   90 records   2,873 tokens
num_ctx 8,192  180 records   5,663 tokens
num_ctx 16,384 360 records  11,244 tokens

どれも設定の約68.6~70.1%です。inputと短いoutputの余裕を残し、意図しない切り捨てを避けました。

needleを先頭・中央・末尾へ置く

各promptへ1つだけ秘密recordを入れます。

IMPORTANT RECORD | SECRET_CODE=CTX16384-BEGINNING-7319 | preserve this exact code.

挿入位置は次の3種類です。

  • beginning: 通常logより前
  • middle: 通常logの中央
  • end: 通常logの後

最後に質問します。

QUESTION: IMPORTANT RECORDのSECRET_CODEは何ですか。
説明せずcodeだけを正確に出力してください。
ANSWER:

回答文字列に完全なcodeが含まれる場合だけ成功です。意味が近い、数字が1桁違う、といった曖昧な採点はしません。

prefix cacheを切って測る

Ollamaは直前のprompt prefixやKV cacheを再利用できる場合があります。同じsynthetic logを続けて送ると、2回目以降のprompt評価が不自然に速くなる可能性があります。

そこで9条件すべてで直前にmodelをunloadしました。

unload(model)  # keep_alive=0
run_streamed(prompt, num_ctx=context)

model loadはAPIのload_durationとして分離できます。stream開始から最初の本文までのwall timeからload durationを引いた値を、この記事では「load除外TTFC」と呼びます。

これは厳密な内訳ではありません。並列処理やtiming境界の差を含む近似ですが、contextを読むcostを見る実用指標になります。

先頭・中央・末尾の9/9で取得できた

実際の回答です。

CTX4096-BEGINNING-7319
CTX4096-MIDDLE-7319
CTX4096-END-7319

CTX8192-BEGINNING-7319
CTX8192-MIDDLE-7319
CTX8192-END-7319

CTX16384-BEGINNING-7319
CTX16384-MIDDLE-7319
CTX16384-END-7319

今回の最大11,245 tokenでも、先頭のneedleを失いませんでした。Gemma 3のglobal attention layerが長距離情報を運べる設計と整合します。

しかし、このtestは非常に簡単です。秘密codeは1件で、質問も明示的、distractorに似たcodeはありません。9/9成功は次を証明しません。

  • 長い論文を正しく要約できる
  • 複数箇所の因果関係を統合できる
  • 多数の似たIDから正しい1件を選べる
  • 16Kの全位置で常に正確

needle retrievalは「情報が届くか」のsmoke testです。長文理解の最終benchmarkではありません。

入力が約4倍で最初の回答まで約2.7倍

実prompt tokenとload除外TTFCです。

 2,873 tokens → 0.373 s
 5,663 tokens → 0.563 s
11,244 tokens → 1.019 s

promptは3.91倍、TTFCは2.73倍です。完全比例より緩く見える理由の1つは固定overheadです。短いpromptではrequest、runner、GPU dispatchなどの固定costが相対的に大きくなります。

prompt evaluation速度の中央値も増えました。

4K setting    7,935 input tok/s
8K setting   10,339 input tok/s
16K setting  11,278 input tok/s

長い入力でGPUを継続的に使い、固定overheadが薄まった可能性があります。ただし各contextは位置3回だけです。温度、電力状態、background processでも変わるため、長いほど常にtok/sが上がるとは一般化しません。

GPU peakは4Kから16Kで406MiB増えた

nvidia-smiを50ms間隔でsampleしたGPU全体のpeakです。

num_ctx 4,096   4,783 MiB
num_ctx 8,192   5,015 MiB  (+232 MiB)
num_ctx 16,384  5,189 MiB  (+174 MiB)

4Kから16Kで+406MiB、約8.5%増です。weightやruntimeの固定部分が大きく、context-dependent部分はその一部でした。

Ollama /api/pssize_vramも記録しました。

4K   2.68 GiB
8K   2.82 GiB
16K  2.84 GiB

nvidia-smiとの差には、Ollamaがmodel sizeとして報告しないCUDA/runtime領域や他processなどが含まれます。2つの値は測定対象が違うため、どちらかが間違いなのではありません。

contextを大きくしても短いpromptは賢くならない

num_ctx=16384はcapacityを増やしますが、同じ短い質問への回答品質を自動で上げません。むしろmemoryを予約し、modelや実装によっては速度を下げます。

contextを増やすべき場面です。

  • 論文本文と質問を同時に入れる
  • 複数sourceをRAGで渡す
  • 長い会話履歴を保持する
  • repositoryの複数fileを読ませる

増やさなくてよい場面です。

  • 1問1答の短いchat
  • 数十行のcode補完
  • RAGで必要箇所を十分絞れている
  • VRAMへ別modelや画像処理も載せたい

「最大contextを常に設定」ではなく、input token分布の上位percentileを測って決めます。

自分のPCで再現する

cd /mnt/c/Users/user/Documents/Codex/2026-08-24/ko
python3 work/ai_lab/experiment_ollama_context_lengths.py

結果です。

work/ai_lab/results/ollama_context_lengths.json

JSONには全9runのprompt token、prompt eval duration、response、needle成否、GPU sample、/api/psを保存します。記事の表だけでなく、position別のraw dataまで追試できます。

自分のdocumentで試す場合は、synthetic logをそのまま信用せず次の段階へ進みます。

  1. 実PDFやcodeをtext化する
  2. 入力tokenをAPIで記録する
  3. 先頭・中央・末尾から検証可能な質問を作る
  4. distractorを追加する
  5. 複数seedまたは複数prompt表現で繰り返す
  6. 正答率、TTFC、VRAMを一緒に比較する

今回の限界

  • Gemma 3 4B Q4_K_Mだけ
  • 4K、8K、16Kだけで128K上限は未検証
  • synthetic log 1形式、秘密code 1件/request
  • 各contextのpositionは3 runだけ
  • 単一requestで並列負荷なし
  • nvidia-smiはGPU全体のmemory
  • load除外TTFCはwall timeとAPI durationの差による近似
  • 16Kで成功しても一般的な長文reasoning性能を示さない

まとめ

  • 実promptは2,873 / 5,663 / 11,244 token
  • beginning・middle・endの秘密codeを全9条件で取得
  • load除外TTFC中央値は0.373 / 0.563 / 1.019秒
  • promptを約3.9倍にしても最初の回答待ちは約2.7倍だった
  • peak GPU usedは4,783 / 5,015 / 5,189MiB
  • 4Kから16KのGPU増加は406MiB
  • Gemma 3の5:1 local/global attention構造と整合するが、因果は直接分解していない
  • num_ctx設定値と実prompt tokenを分けて記録する必要がある

16GB GPU上のGemma 3 4Bでは16K contextも余裕を持って動きました。ただし実用性を判断するには、contextをさらに大きくするより、実際の論文やcodeを使って複数箇所を統合できるかを評価する必要があります。

関連記事