Anthropicの"prompt is too long"エラーをContextLengthExceededErrorへマッピング

crmne/ruby_llm

Anthropic API が返す "prompt is too long" エラーメッセージが、RubyLLM で統一的に扱える ContextLengthExceededError に変換されず BadRequestError として送出されていた問題を解消します。エラーハンドリングの一貫性が向上し、呼び出し側はプロバイダーを意識せずに同一例外で対処できるようになります。

背景

Anthropic のコンテキストウィンドウを超えるリクエストでは、400 エラーと共にメッセージ "prompt is too long: <N> tokens > <max> maximum" が返されますが、RubyLLM の ErrorMiddleware が保持する CONTEXT_LENGTH_PATTERNS にこのフレーズが含まれていなかったため、例外は BadRequestError として分類されていました。Issue #755 で報告された通り、他プロバイダーでの ContextLengthExceededError と整合性が取れず、利用者は各プロバイダーごとに例外処理を分岐させる必要がありました。

この不整合は、エラーメッセージパターンの追加という小規模な変更で解決できると判断され、コードベースへの侵入度が低い修正が選択されました。

技術的な変更

ErrorMiddlewareCONTEXT_LENGTH_PATTERNS 配列に正規表現 /prompt is too long/i を追加し、Anthropic 固有のエラーメッセージを一致させます。変更前後を抜粋すると次のようになります。

@@ -27,7 +27,8 @@ class << self
         /token count exceeds/i,
         /input[_\s-]?token/i,
         /input or output tokens? must be reduced/i,
-        /reduce the length of messages/i
+        /reduce the length of messages/i,
+        /prompt is too long/i
       ].freeze

この追加に伴い、テストスイートにも Anthropic のエラーメッセージを対象としたケースを加えました。テストは ErrorMiddleware.parse_error が期待通り ContextLengthExceededError を送出することを検証します。

it "maps Anthropic's 'prompt is too long' 400 error to ContextLengthExceededError" do
  msg = 'prompt is too long: 209025 tokens > 200000 maximum'
  response = Struct.new(:status, :body).new(400, %({"error":{"message":"#{msg}"}}))
  provider = instance_double(RubyLLM::Provider, parse_error: msg)

  expect do
    described_class.parse_error(provider: provider, response: response)
  end.to raise_error(RubyLLM::ContextLengthExceededError)
end

これらの変更は API 互換性を保持 しつつ、エラーハンドリングのロジックを拡張するだけで済んでいます。

設計判断

エラーパターンを 既存の CONTEXT_LENGTH_PATTERNS 配列に追加 する方針が採られました。新規設定キーや専用クラスを導入せず、配列に正規表現を一つ足すだけで済むため、後方互換性 が最大限保たれます。さらに、正規表現は大文字小文字を無視する /i フラグを付与しているため、Anthropic が将来的にメッセージの大小文字を変えてもマッピングが失敗しにくくなります。

この設計は、例外階層を変えずに コンテキスト長エラーの一元管理 を実現するというライブラリの基本方針に沿っており、変更点が限定的であることからリグレッションリスクも低減されています。

まとめ

Anthropic の "prompt is too long" エラーメッセージが ContextLengthExceededError に正しくマッピングされるよう CONTEXT_LENGTH_PATTERNS が拡張され、テストで検証されました。結果として、RubyLLM 利用者はプロバイダーに依存せず同一例外でコンテキスト長超過を捕捉でき、コードベースへの影響は最小限に抑えられました。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
914b0ee3

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文・背景・技術的変更・設計判断・まとめの5セクションが揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは正しい `ruby:filepath` 形式ですが、PRリンクが `[PR #769](URL)` となっており、求められる `[#769](URL)` 形式と異なります。リンク形式の修正が必要です。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

対象は RubyLLM を利用するエンジニアで、専門用語と実装詳細に重点が置かれており、初心者向けの余分な説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の段落構成が保たれ、トピックセンテンスが先頭にあり、1段落1トピック・6文以内で書かれています。段落間も空行で区切られています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供された Diff と完全に一致しています。ファイル名・追加行・削除行とも合致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

ContextLengthExceededError、BadRequestError、Anthropic などの用語は PR 内容と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

変更点の目的・効果・影響についての説明は PR の記述と合致し、技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の全主張は PR のタイトル・説明・Diff で裏付けられており、妄想や憶測は見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #769、Issue番号 #755、正規表現文字列、テスト例のトークン数など、数値・固有名詞は正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の要旨(Anthropic のエラーを ContextLengthExceededError にマッピング)を適切に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事内に PR に記載されていない外部知識(LTS、リリース日程等)は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現は使用されておらず、PR 内容と食い違う表現はありません。