GPT-4およびGPT-4oにおける「context_length_exceeded」エラーの解決方法

intermediate🧠 AI Tools2026-05-17

問題点これは通常、実際のデータを使用してアプリをテストする段階で発生します。長いPDFや1週間分のチャット履歴をモデルに読み込ませると、OpenAI APIが即座にリクエストを拒否します。この context_length_exceeded エラーはコードのロジック上のバグではなく、物理的な限界によるものです。すべてのモデルには固定の「メモリ」容量があります。GPT-4oの場合、その制限は128,000トークン(テキスト約300ページ分に相当)で、これには入力とモデルが生成するレスポンスの両方が含まれます。

openai.BadRequestError: Error code: 400 - {'error': {'message': "This model's maximum context length is 128000 tokens. However, your messages resulted in 145823 tokens.", 'type': 'invalid_request_error', 'param': 'messages', 'code': 'context_length_exceeded'}}

なぜAPIはリクエストを拒否するのかGPT-4oやGPT-4-turboなどのOpenAIモデルは、128kのトークンウィンドウを使用します。145,823トークンを送信した場合、APIは一部のレスポンスを処理しようとはせず、非効率な計算リソースの消費を防ぐためにリクエストを完全に遮断します。これは通常、過去のチャットのやり取りを保持しすぎたり、クリーニングされていない生のデータを直接プロンプトに投入したりすることによる「コンテキストの肥大化」が原因で発生します。

ステップ1:送信前にローカルでトークンをカウントする信頼性の高いLLMアプリケーションは、プロンプトが収まるかどうかを「推測」することはありません。代わりに、リクエストがサーバーを離れる前にトークン数を検証します。tiktoken ライブラリを使用すると、モデルがテキストをどのように認識するかを正確に計算できます。GPT-4oは o200k_base エンコーディングを使用し、以前のGPT-4モデルは cl100k_base を使用することに注意してください。

import tiktoken

def num_tokens_from_messages(messages, model="gpt-4o"):
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        encoding = tiktoken.get_encoding("cl100k_base")
    
    num_tokens = 0
    for message in messages:
        # すべてのメッセージは <im_start>{role/name}\n{content}<im_end>\n という形式に従う
        num_tokens += 3 
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens += 1
    num_tokens += 3  # すべての返信は <im_start>assistant で開始される
    return num_tokens

ステップ2:スライディングウィンドウ戦略を適用する会話が長くなりすぎた場合、何を忘れるかを決定する必要があります。「スライディングウィンドウ」アプローチでは、不可欠な system 命令は保持しつつ、最も古いユーザーとアシスタントのやり取りを削除します。これにより、128kの制限内に収めながら、会話の直近のコンテキストを維持できます。

def trim_messages(messages, max_tokens=120000, model="gpt-4o"):
    """合計がセーフティバッファ内に収まるまで、最も古いメッセージを削除する。"""
    system_message = [m for m in messages if m['role'] == 'system']
    chat_history = [m for m in messages if m['role'] != 'system']

    while num_tokens_from_messages(system_message + chat_history, model) > max_tokens:
        if len(chat_history) > 1:
            chat_history.pop(0) # 最も古いやり取りを削除
        else:
            # 1つのメッセージが依然として大きすぎる場合は、文字列を直接切り詰める
            chat_history[0]['content'] = chat_history[0]['content'][:5000]
            break
            
    return system_message + chat_history

ステップ3:大規模なデータセットにはRAGへ移行する切り詰め(Truncation)はチャットには有効ですが、1,000ページの技術マニュアルを分析する必要がある場合には機能しません。そのシナリオでは、マニュアルを丸ごと送信しないでください。検索拡張生成(RAG)を使用して、膨大なデータの中から必要な情報を見つけ出します。データを500トークンのチャンクに分割し、PineconeやChromaDBのようなベクトルデータベースに保存して、最も関連性の高い上位5つのスニペットのみをプロンプトに注入します。これにより、トークン数を低く(多くの場合10,000未満に)抑えつつ、モデルに必要な正確な事実を提供できます。

検証とセーフティバッファ決して制限ギリギリを狙わないでください。モデルの制限が128,000トークンで、127,990トークンを送信した場合、モデルの回答には10トークンしか残されていません。その結果、レスポンスが途中で途切れてしまいます。出力のために、常に少なくとも10〜20%のセーフティバッファを確保してください。

# 例:安全なしきい値の設定
MAX_ALLOWED = 115000 
current_usage = num_tokens_from_messages(messages)

if current_usage > MAX_ALLOWED:
    print(f"Trimming: {current_usage} tokens exceeds safety threshold.")
    messages = trim_messages(messages, max_tokens=MAX_ALLOWED)

迅速な最適化のヒント- 履歴の要約: 古いメッセージを削除する代わりに、最初の20回のやり取りを1つの段落に要約するようGPTに依頼し、それを新しい開始点として使用します。- モデルバージョンの確認: 8,000トークンで制限に達している場合は、レガシーな gpt-4gpt-3.5-turbo を使用している可能性があります。128kウィンドウをフル活用するには gpt-4o に切り替えてください。- データのクリーニング: 入力から不要な空白、HTMLタグ、メタデータを削除することで、トークンコストを即座に5〜10%節約できます。

Related Error Notes