HappyHorse 1.0 リリース今すぐ試す
LLM APIコールにおけるContext Length Exceeded:修正方法、トレードオフ、モデル選択
guide

LLM APIコールにおけるContext Length Exceeded:修正方法、トレードオフ、モデル選択

EvoLink Team
EvoLink Team
Product Team
2026年5月13日
14 分

LLM APIコールから次のようなレスポンスが返ってきました:

{
  "error": {
    "message": "This model's maximum context length is 128000 tokens. However, your messages resulted in 142837 tokens.",
    "type": "invalid_request_error",
    "code": "context_length_exceeded"
  }
}

これは、入力(システムプロンプト + 会話履歴 + ユーザーメッセージ)がモデルのコンテキストウィンドウを超えていることを意味します。トークンが1つも生成される前に、リクエストが拒否されました。

レートリミットエラー(リクエストの頻度に関するもの)とは異なり、コンテキスト長エラーはリクエストのサイズに関するものです。解決策は速度を落とすことではなく、入力を削減するか、リクエストを再構成するか、より大きなコンテキストウィンドウを持つモデルに切り替えることです。

まとめ

  • Context length exceeded = 入力がモデルのトークンウィンドウに対して大きすぎる。
  • 4つの選択肢がある:トランケート、要約、チャンク分割、モデル切り替え。
  • 各選択肢にはコスト、品質、レイテンシのトレードオフがある。
  • 以下の判断基準表を使って、ワークロードに適したアプローチを選択する。
  • 本番システムでは、ユーザーにエラーが見える前に対処する。

クイックフィックスチェックリスト

戦略を選ぶ前に、まずこれらの一般的な原因を確認してください:

確認項目何を探すか即座の対処法
会話履歴が長すぎるマルチターンチャットでメッセージ配列が際限なく増える古いメッセージを削除するかスライディングウィンドウを実装
システムプロンプトが大きすぎる詳細な指示がコンテキスト予算を圧迫しているシステムプロンプトを圧縮するか、固定的な指示をリファレンスに移動
重複コンテンツ同じコンテキストが複数回挿入されている(RAG、ツール結果)送信前に重複を排除
ツール/関数の出力が大きいツールコールが巨大なJSONやテキストを返したツール出力をコンテキストに追加する前にトランケートまたは要約
不要なメタデータ必要なフィールドが少数なのにオブジェクト全体を含めている関連フィールドのみを抽出

これらのクイックフィックスのいずれも該当しない場合は、構造的なアプローチが必要です。

判断基準表:トランケート vs 要約 vs チャンク分割 vs モデル切り替え

戦略仕組み品質への影響コストへの影響レイテンシへの影響最適な用途
トランケート古いメッセージを削除するか入力をトリミング重要なコンテキストが失われる可能性入力トークン削減 = 低コスト高速化(入力が少ない)長い履歴のあるチャットアプリ;直近のコンテキストが最も重要な場合
要約より安価なモデルで過去のコンテキストを要約に圧縮非可逆 — 要約で詳細が漏れる可能性要約用の追加APIコール、ただしメインコールは小さくなる1回の追加コール状態が蓄積されるエージェントワークフロー;知識集約型の会話
チャンク分割 + マージ入力をチャンクに分割し、個別に処理し、結果をマージチャンク間のコンテキスト欠落リスク複数コール = 総コスト増低速化(逐次または並列チャンク)ドキュメント処理、長文テキストの分析
モデル切り替えより大きなコンテキストウィンドウのモデルを使用通常は同等かそれ以上大コンテキストモデルはトークン単価が高いことが多い場合による重要な情報を失わずに入力を削減できない場合

戦略1:トランケート — 重要度の低いものを削除する

トランケーションは最もシンプルなアプローチです。入力の中で最も古い、または最も関連性の低い部分を削除します。

チャット用スライディングウィンドウ

def sliding_window(messages: list, max_tokens: int, system_prompt: str) -> list:
    """Keep system prompt + most recent messages within token budget."""
    # Always keep system prompt
    result = [{"role": "system", "content": system_prompt}]
    token_count = count_tokens(system_prompt)

    # Add messages from newest to oldest
    for msg in reversed(messages):
        msg_tokens = count_tokens(msg["content"])
        if token_count + msg_tokens > max_tokens:
            break
        result.insert(1, msg)  # Insert after system prompt
        token_count += msg_tokens

    return result

トランケーションが効果的な場面

  • 直近のコンテキストが最も重要なマルチターンチャット
  • 必要に応じて再取得が可能なRAGパイプライン
  • 順序通りに処理できるバッチ処理

トランケーションが危険な場面

  • 初期の指示が後の動作に影響するエージェントワークフロー
  • 完全性が重要な法的・コンプライアンス関連のコンテキスト
  • ステップの省略が回答を変えてしまう多段階推論

戦略2:要約 — 意味を保ちながら圧縮する

要約は、より安価で高速なモデルを使って過去のコンテキストを圧縮します:

async def summarize_context(messages: list, client) -> str:
    """Compress older messages into a summary."""
    context_text = "\n".join(
        f"{m['role']}: {m['content']}" for m in messages
    )

    response = await client.chat.completions.create(
        model="gpt-4o-mini",  # Cheaper model for summarization
        messages=[{
            "role": "user",
            "content": f"Summarize this conversation context in under 500 tokens. "
                       f"Preserve key decisions, facts, and pending actions:\n\n{context_text}"
        }],
        max_tokens=500
    )

    return response.choices[0].message.content

コスト比較:要約 vs トランケート

アプローチメインモデルへの入力トークン追加APIコール総コスト
管理なし(エラー発生)N/A — リクエスト拒否0無駄なレイテンシ + リトライコスト
80Kトークンにトランケート80K080K入力での基本コスト
古いコンテキストを要約~10K(要約)+ 40K(直近)= 50K要約コール1回(約$0.01)メインコールのコスト低減 + 少額の要約コスト

要約は安価なコール1回を追加しますが、メインコールの入力トークンを大幅に削減することが多く、高額なモデルでは正味のコスト削減になる可能性があります。

戦略3:チャンク分割とマージ — 長文ドキュメント向け

入力が会話ではなく単一の長文ドキュメントの場合、チャンク分割が適切なアプローチであることが多いです:

async def process_long_document(
    document: str,
    question: str,
    client,
    chunk_size: int = 50000
) -> str:
    """Process a long document by chunking."""
    chunks = split_into_chunks(document, chunk_size)
    chunk_results = []

    for i, chunk in enumerate(chunks):
        response = await client.chat.completions.create(
            model="gpt-4o",
            messages=[{
                "role": "user",
                "content": f"Analyze chunk {i+1}/{len(chunks)} of a document.\n"
                           f"Question: {question}\n\n"
                           f"Chunk content:\n{chunk}"
            }]
        )
        chunk_results.append(response.choices[0].message.content)

    # Merge chunk results
    merge_response = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{
            "role": "user",
            "content": f"Merge these partial analyses into a final answer.\n"
                       f"Question: {question}\n\n"
                       f"Partial results:\n" + "\n---\n".join(chunk_results)
        }]
    )

    return merge_response.choices[0].message.content

チャンキングのトレードオフ

  • メリット:任意の長さの入力を処理可能
  • デメリット:チャンク間のコンテキストが失われる
  • デメリット:複数のAPIコール = 総コストとレイテンシの増加
  • 対策:チャンクを10-20%オーバーラップさせて境界のコンテキストを保持

戦略4:より大きなコンテキストのモデルに切り替える

入力を本当に大きいまま保つ必要がある場合は、より大きなコンテキストウィンドウを持つモデルに切り替えます:

モデルファミリー典型的な最大コンテキスト使用場面
GPT-4o128Kトークンほとんどのワークロードのデフォルト
GPT-4o (long context)128Kトークンすでにデフォルト
Claude Sonnet/Opus200Kトークン128K以上が必要な場合
Gemini Pro1M+トークン非常に長いドキュメント、コードベース全体
Gemini Flash1M+トークンコスト重視の長コンテキストタスク

大コンテキストモデルのコストへの影響

コンテキストウィンドウが大きいほど、通常はトークン単価が高くなります。品質向上がコストに見合うかどうかを計算してください:

Option A: 80Kにトランケート + GPT-4o = $X
Option B: 150Kフル入力 + Claude Sonnet = $Y
Option C: 150Kフル入力 + Gemini Flash = $Z

比較:品質差 vs コスト差

ルーティングゲートウェイによるモデル選択

モデル選択をハードコードする代わりに、入力サイズに応じて適切なモデルにルーティングするゲートウェイを利用できます:

from openai import OpenAI

client = OpenAI(
    api_key="your-evolink-key",
    base_url="https://api.evolink.ai/v1"
)

# Let the Smart Router choose based on your workload
response = client.chat.completions.create(
    model="evolink/auto",
    messages=your_messages
)
EvoLinkのSmart Routerは、入力サイズとコスト要件に合ったモデルにルーティングできるため、コンテキストウィンドウの閾値をハードコードする必要がありません。

本番パターン:送信前の事前チェック

APIにリクエストを拒否されるのを待たないでください。送信前に入力サイズを確認しましょう:

import tiktoken

def check_context_length(messages: list, model: str, max_tokens: int) -> dict:
    """Pre-check whether messages fit within the model's context window."""
    encoder = tiktoken.encoding_for_model(model)
    total_tokens = sum(
        len(encoder.encode(m["content"])) for m in messages
    )

    if total_tokens > max_tokens:
        return {
            "fits": False,
            "total_tokens": total_tokens,
            "excess": total_tokens - max_tokens,
            "suggestion": "truncate" if total_tokens < max_tokens * 1.5
                          else "summarize_or_switch"
        }

    return {"fits": True, "total_tokens": total_tokens}

これにより、拒否されたリクエストによるレイテンシの無駄を避け、ユーザーにエラーが表示される前に適切な戦略を適用できます。

関連記事

Explore EvoLink Smart Router

FAQ

「context length exceeded」とは何を意味しますか?

入力(システムプロンプト + メッセージ + 注入されたコンテキスト)がモデルの最大コンテキストウィンドウで許容されるトークン数を超えていることを意味します。生成が開始される前にリクエストが拒否されます。

「context length exceeded」はレートリミットエラーと同じですか?

いいえ。レートリミットエラー(429)はリクエストの頻度に関するもの — 一定時間内にリクエストが多すぎる場合です。コンテキスト長エラーはリクエストのサイズに関するもの — 1つのリクエストが大きすぎる場合です。それぞれ異なる対処法が必要です。

トランケーションと要約、どちらが良いですか?

トランケーションはシンプルで低コストですが情報が失われます。要約は意味を保持しますが、追加のAPIコールが必要で圧縮のアーティファクトが生じます。直近の情報が最も重要なチャット履歴にはトランケーションを、蓄積されたコンテキストが重要なエージェントワークフローには要約を使用してください。

より大きなモデルを使えばコンテキスト長エラーを回避できますか?

はい、ただしコストが伴います。より大きなコンテキストウィンドウを持つモデル(Gemini 1M+、Claude 200K)はより大きな入力を受け付けますが、通常はトークン単価が高くなります。品質の向上が追加コストに見合うかどうかを計算してください。

リクエスト送信前にトークン数を数えるにはどうすればよいですか?

OpenAIモデルにはtiktokenライブラリを、その他のプロバイダーにはそれぞれのトークンカウントエンドポイントを使用してください。正確なトークン数はモデルのトークナイザーに依存するため、ターゲットモデルに適したエンコーダーを使用してください。

このエラーはアプリケーションコードとゲートウェイレベルのどちらで処理すべきですか?

両方です。アプリケーションコードでは入力サイズを事前にチェックし、適切な戦略(トランケート、要約、チャンク分割、切り替え)を適用すべきです。ルーティングゲートウェイは、リクエストに対して十分なコンテキストウィンドウを持つモデルを追加で選択できます。

AIコストを89%削減する準備はできましたか?

今すぐEvoLinkを始めて、インテリジェントなAPIルーティングの力を体験してください。