コンテキストウィンドウとは?LLMの上限と超えたときの対処法

この記事の要点
- コンテキストウィンドウ(コンテキスト長)は、LLMが1回のリクエストで扱えるトークン数の上限です。入力と出力の合計がこの枠に収まる必要があります。
- システムプロンプト、会話履歴、ツール定義、取り込んだ文書、出力が同じ枠を分け合い、会話が長くなるほど枠の消費も入力の費用も増えます。
- 上限を超えるとエラーになるか、出力が途中で切れます。枠内でも、詰め込むほど精度は下がります。
- 対処の基本は、古いターンを削る、要約する、渡す情報を絞る、キャッシュを効かせる、の4つです。足りなければ枠の大きいモデルを選びます。
長く使うと急にエラーが返る、応答が途中で切れる、最初の条件をモデルが忘れる。こうした現象の原因の多くはコンテキストウィンドウです。この記事では、APIを呼ぶ開発者の立場から、何が枠を使い、上限で何が起き、コードでどう管理するかを整理します。
コンテキストウィンドウとは
コンテキストウィンドウとは、LLMが応答を生成するときに参照できるトークンの範囲のことで、コンテキスト長とも呼ばれます。モデルにとっての作業メモリにあたり、枠の外にある情報はモデルからは見えません。
大きさはモデルごとに決まっています。Anthropicの公式ドキュメントでは、Claude Opus 5.5やClaude Sonnet 5.5など多くのモデルが100万トークン、それ以外のモデルが20万トークンとされています(2026年10月時点)。FastMetalで使えるDeepSeek V4.1 Flashも100万トークンに対応しています。
コンテキストウィンドウを使うもの
1回のリクエストに含まれるものと、これから生成される出力が、すべて同じ枠を分け合います。
| 枠を使うもの | 見落としやすい点 |
|---|---|
| システムプロンプト | 毎回必ず送られる |
| 会話履歴 | ターンごとに増えていく |
| ツール定義 | ツールを増やすほど重くなる |
| ツールの実行結果 | エージェントでは最も膨らみやすい |
| 検索や貼り付けで取り込んだ文書 | 件数が増えると効いてくる |
| 画像・PDF | 画像もトークンに換算される |
| 出力(推論モデルでは思考の分も含む) | max_tokensの分を空けておく必要がある |
Anthropicのドキュメントも、ツール定義や思考を含む出力までが枠に数えられると明記しています。
会話が進むほど枠が減る理由
Chat Completions APIをはじめ、LLMのAPIは基本的にステートレスです。サーバーは前回のやり取りを覚えていないため、クライアントは毎回、システムプロンプトから直前の応答までを送り直します。1ターン目に約500トークンだった入力が、10ターン目には8,000トークンを超える、といった増え方をします(数値は一例です)。
エージェントはさらに早く埋まる
コーディングエージェントは、1つのタスクでモデルを何十回、何百回と呼び出し、そのたびにファイルの中身やコマンドの出力を履歴に積みます。費用の大半を入力トークンが占めるのはこのためです。Function callingを使うアプリも同様です。
トークンと日本語
コンテキスト長はトークンで数えます。日本語は同じ内容でも英語より多くのトークンを使う傾向があり、英語前提の「何ページ分入る」という目安はそのまま使えません。詳しくはLLMのトークンとはと日本語はトークンを食うで解説しています。
正確な量は数えて確かめるのが確実です。レスポンスの usage に入力と出力のトークン数が返ります。送る前に見積もりたいときは、FastMetalのAnthropic互換APIにあるトークンカウント用のエンドポイントを使います。応答は生成せず、トークン数だけを数えて返します(トークンカウント)。
上限を超えるとどうなるか
入力だけで上限を超える場合
APIはリクエストを受け付けず、エラーを返します。この例外を捕捉し、履歴を減らして送り直す処理を用意しておきます。
出力の途中で上限に達する場合
応答が途中で切れます。OpenAI互換では finish_reason が length になり、Anthropic互換では stop_reason で理由を確かめられます。エラーにならず気づきにくいので、毎回確認しておきます。
枠に収まっていても精度は下がる
Anthropicは、トークン数が増えるにつれて精度と再現率が落ちる現象を context rot(コンテキストの劣化)と呼んでいます。長い入力の中ほどにある情報ほど見落とされやすい、という研究報告もあります。枠の大きさと同じくらい、何を渡すかの選び方が大切です。
ロングコンテキストとRAGの使い分け
長い資料の渡し方は、大きく2つあります。資料を丸ごとコンテキストに入れる方法と、RAG(検索拡張生成)で質問に関係する部分だけを検索して渡す方法です。
| 全部渡す(ロングコンテキスト) | 検索して渡す(RAG) | |
|---|---|---|
| 向いている資料 | 契約書1冊、リポジトリ1つなど、全体のつながりを読むもの | 社内文書やマニュアル群など、量が多く更新されるもの |
| 1回あたりの入力 | 大きい | 小さい |
| 注意点 | 中ほどの情報を見落としやすい | 検索で外すと答えられない |
コストと精度の詳しい比較は、RAGとロングコンテキストの比較にまとめています。
長いコンテキストにかかるコスト
LLMのAPIは、入力と出力それぞれ100万トークンあたりの従量課金が一般的で、送り直した履歴も毎回入力として課金されます。枠の大きいモデルでは何でも入ってしまうため、履歴を管理しないと入力が気づかないうちに膨らみます。
対応するモデルでは、プロンプトキャッシュで前回と同じ先頭部分を再利用でき、その部分の入力は通常より低い単価になります。枠の消費量は同じで、変わるのは支払う額です(Anthropic、OpenAIの公式ドキュメント)。FastMetal経由でも、Claudeのモデルではプロンプトキャッシュが効きます(2026年10月に確認)。
FastMetalでの円建て単価は料金ページ、見積もりはコスト計算ツール、節約の方法はLLM APIのコストを下げる方法で確認できます。
枠に収めるための対処法
古いターンを削る
システムプロンプトは先頭に残し、会話履歴だけを直近の数往復に絞ります。最も手軽な方法です。
古いターンを要約に置き換える
削る部分を、決まったこと、数値、未解決の点を残した短い要約にまとめます。要約は安価なモデルに任せ、履歴が一定量たまったときにまとめて作ると、先頭部分が書き換わる回数が減り、キャッシュも効きやすくなります。
ツールの結果と取り込む文書を絞る
必要な行だけを抜き出す、長い出力は先頭と末尾だけを残す、古いツールの結果は要点に置き換える、といった工夫が効きます。RAGでも、検索結果の件数と長さに上限を設けます。
固定部分を先頭にまとめる
システムプロンプト、ツール定義、毎回使う資料など変わらない部分を先頭に、変わる部分を後ろに置くと、キャッシュが効きやすくなります。
出力の余地をmax_tokensで確保する
コンテキスト長から max_tokens を引いた残りが、入力に使える量の目安です。
コンテキスト長でモデルを選ぶ
長い契約書や大きなリポジトリを丸ごと扱う用途では、最初から枠の大きいモデルを選びます。FastMetalのモデル一覧では、コンテキスト長で絞り込めます(コンテキスト長でLLMを比較)。
コード例:要約しながら会話を続ける
履歴が10往復を超えたら古い分を要約し、直近4往復だけを原文で残す例です。base_url をFastMetalに向ければ、OpenAI SDKがそのまま使えます。
from openai import OpenAI
client = OpenAI(
api_key="<FASTMETAL_API_KEY>",
base_url="https://api.fastmetal.ai/v1",
)
MAX_TURNS = 10 # これを超えたら要約する
KEEP_TURNS = 4 # 直近4往復は原文のまま残す
history = [] # {"role": "user" | "assistant", "content": "..."}
summary = "" # それより古いやり取りの要約
def compact():
"""古いターンを要約にまとめ、履歴から外す"""
global history, summary
old, history = history[:-KEEP_TURNS * 2], history[-KEEP_TURNS * 2:]
text = "\n".join(f'{m["role"]}: {m["content"]}' for m in old)
resp = client.chat.completions.create(
model="deepseek-v4.1-flash", # 要約は安価で速いモデルに任せる
messages=[{"role": "user", "content": (
f"これまでの要約:\n{summary}\n\n追加の会話:\n{text}\n\n"
"決まったこと、数値、未解決の点を残して300字以内で要約してください。"
)}],
max_tokens=800,
)
summary = resp.choices[0].message.content
def ask(question: str) -> str:
if len(history) >= MAX_TURNS * 2:
compact()
system = "簡潔に日本語で答えてください。"
if summary:
system += f"\n\nここまでの会話の要約:\n{summary}"
history.append({"role": "user", "content": question})
resp = client.chat.completions.create(
model="anthropic-claude-sonnet-5",
messages=[{"role": "system", "content": system}] + history,
max_tokens=1024,
)
choice = resp.choices[0]
if choice.finish_reason == "length":
print("出力が上限で切れました。max_tokens か履歴の量を見直してください。")
print("入力トークン:", resp.usage.prompt_tokens)
history.append({"role": "assistant", "content": choice.message.content})
return choice.message.content
要約役と応答役は、model に渡す文字列を変えているだけです。
FastMetalでコンテキスト長の違うモデルを使い分ける
FastMetalは、25のプロバイダーが提供する95以上のモデルを、ひとつのAPIキーで呼び出せる日本のAIゲートウェイです。OpenAI互換とAnthropic互換のAPIがあり、model を変えるだけで、枠の大きいモデルと安価なモデルを切り替えられます。
全体像はAIゲートウェイとは、既存のコードを活かす方法はOpenAI互換APIとは、APIの基本はLLM APIとはで解説しています。
よくある質問
コンテキストウィンドウとmax_tokensは何が違いますか
コンテキストウィンドウは入力と出力を合わせた上限で、max_tokensはそのうち出力に使ってよい量の上限です。入力とmax_tokensの合計が、コンテキスト長に収まるように設計します。
コンテキストウィンドウの目安はどれくらいですか
2026年10月時点では、100万トークン前後を扱えるモデルも珍しくありません。短いチャットなら小さな枠で足り、長い資料や大きなリポジトリを扱うエージェントには大きな枠が向いています。
日本語だと上限に達しやすいですか
はい。日本語は同じ内容でも英語より多くのトークンを使う傾向があり、同じ文字数でも枠を早く使います。履歴の要約やシステムプロンプトの簡潔化が特に効きます。
コンテキストウィンドウが大きいモデルほど優れていますか
一度に扱える量では有利です。ただし、詰め込むほど精度は下がる傾向があり、入力が増えれば費用もかかります。渡す情報を絞ったうえで、足りない用途に大きなモデルを選ぶのが現実的です。
プロンプトキャッシュを使うと、コンテキストウィンドウの消費は減りますか
減りません。キャッシュした部分も、通常の入力と同じだけ枠を使います。キャッシュで変わるのは、繰り返し送る部分にかかる費用です。
FastMetalを試す
アカウントの作成は無料で、無料モデルは¥0で試せます。枠の大きさが異なるモデルを、同じコードのまま比べてみてください。