コードベースにおいて、検索は依然として100万トークンウィンドウを上回る
数週間前、私はサイドプロジェクトの認証バグをデバッグしていました。TypeScript バックエンドで約 140 ファイル、余裕で 100 万トークン以下に収まる規模です。100 万トークンのモデルが手元にあったので、楽な方法を選びました。src/ ツリー全体を一つのプロンプトに突っ込み、エージェントにセッショントークンがどこでリフレッシュされるか、そしてなぜ時々リフレッシュされないかを探してもらいました。
それはすべてを読みました。そのたった一ターンのために、入力トークン代が相当な出費になりました。そしてエージェントは refreshToken ヘルパーを自信満々に指摘しましたが、それは一見正しく見えて実は間違いでした。別のモジュールに同名のものが二つあり、選ばれた方は実際に実行されるパスにはなかったのです。干し草の山を丸ごと渡したら、その中からもっともらしい針を一本引っ張り出されたわけです。
その後、私はそのセッションを閉じ、同じモデルで新しいセッションを開き、普通の方法で作業させました。ツリーを一覧表示し、refreshToken を grep し、一致した 3 つのファイルを読み、インポートを追う。これで本物のバグを約 4 分の 1 のトークンと 3 分の 1 の時間で発見しました。同じモデル。同じリポジトリ。違いは、コードをどのように渡したかだけでした。
要点: 実際のコードベースに対して、すべてを巨大なコンテキストウィンドウに詰め込むことは通常最悪の手です。ウィンドウが小さすぎるからではなく、埋めるほどにモデルの信頼性が測定可能な形で低下し、コードはその失敗の最悪ケース入力だからです。的を絞った検索——grep、シンボルインデックス、依存関係を考慮した読み取り——は、ほとんどのコードタスクでコスト・レイテンシ・精度すべてにおいて勝ります。長いコンテキストが勝つ特定のケースもあるので、最後にその判断規則をお伝えします。
ウィンドウの数字は本物だが、使える部分は違う
まず、本当の部分から:大きな数字は存在します。2026 年 6 月時点で、3 つの主要なコーディングモデル——Claude Opus 4.8、GPT-5.5、Gemini 3.1 Pro——はすべて 100 万トークンのウィンドウを提供しており、13 以上のホスト型フロンティアモデルが 100 万以上を宣伝しています(Morph のコンテキストウィンドウ比較)。Anthropic と OpenAI は長いコンテキストの追加料金も廃止したため、ウィンドウ全体で同じトークン単価が請求されるようになりました。
問題は、宣伝されているものと使えるものが異なる数字だということです。2026 年の独立したリコールテストでは、実効容量がラベルを大幅に下回ることが繰り返し示されています。ある調査では実効コンテキストを公称の約**50〜65%**と算定しており、MRCR マルチニードルスコアがウィンドウ後半で崖から落ちるように低下することも報告されています。Gemini 3.1 Pro は 128K〜256K の帯域では約 84.9% のリコールを維持しますが、512K〜1M の帯域では 26.3% まで崩壊します(CodingFleet の「コンテキストウィンドウの嘘」分析)。正確な数字は方向性の参考として扱ってください——これはベンダーのベンチマーク数値であり、統制研究ではありません——ただし形状はどこでも一致しています:ウィンドウが満杯になる前にリコールが低下します。
この低下には名称と研究の蓄積があり、コードにとってはほぼ他の何よりも重要です。
なぜコードは満杯ウィンドウへの最悪ケース入力なのか
リポジトリを一つのプロンプトに詰め込むとき、2 つのよく再現される効果が不利に働きます。
中央で迷子に。 Liu et al. の論文(TACL に掲載)は、モデルの精度が関連情報の位置に対して U 字型の関数であることを示しました。コンテキストの先頭または末尾にあるときが最も高く、中央に埋もれると 30% 以上低下します——これは 6 つのモデルファミリーでの複数文書 QA とキーバリュー検索において確認されています。コードベースは「中央に関連情報がある」そのものです。必要な関数が、貼り付けた最初や最後のファイルにあることはほぼありません。
コンテキストの腐敗。 Chroma の 2025 年の研究では 18 のフロンティアモデルをテストしました——Claude Opus 4 / Sonnet 4 / 3.7 / 3.5 / Haiku 3.5、OpenAI o3 と GPT-4.1 ファミリー、Gemini 2.5 Pro/Flash、3 つのサイズの Qwen3——そして、文字列を見つけたり繰り返し語を複製したりするような些細なタスクでも、入力長が増えるにつれてパフォーマンスが低下することが確認されました(Chroma の「Context Rot」レポート)。コードエージェント開発者すべてが不安になるべき発見:LongMemEval タスクにおいて、すべてのモデルが同じ関連コンテンツの約 300 トークンの集中した抜粋よりも、約 113k トークンの全履歴の方が低い性能でした。正しい内容の多くのトークンを一括提示しても、厳選された小さな断片より低いスコアになったのです。
そのレポートには、コードを書く人には思わず笑えるような細部があります。干し草のスタックが「アイデアの論理的な流れを保っていた」とき、モデルはシャッフルされていたときよりも悪いスコアを出しました。リポジトリは最大限に論理的に構造化されています——インポート、コールグラフ、型定義、順序付けられたモジュール。あなたはモデルにとって最も扱いにくい入力形式を渡しているのです。
そしてコードは、散文よりも失敗をはるかに厳しく罰します。チャットボットが長いドキュメントの一文を見逃せば、少し曖昧な回答を返します。コードエージェントが本物の refreshToken 定義を見逃せば、存在しないメソッドを呼び出すコードを書いたり、間違った関数を修正したりします——そして自信満々にそれをやります。あるエージェント検索の分析が指摘したように、「コーディングコンテキストにおける RAG の失敗モードはサイレントで複合的だ」のです(MindStudio)。誤った検索はエラーを出しません。それはそのまま出荷されます。
コードにおける「検索」が意味するもの(ほとんどは embeddings ではない)
「検索」と聞くと、ベクトルデータベースを思い浮かべる人が多いでしょう。コードに対して、実際に出荷されるエージェント——Claude Code、Cursor、Devin——のほとんどは最初にそれを使いません。経験豊富な開発者がするように移動します:ファイルツリーを見る、シンボルを grep する、一致した特定のファイルを読む、インポートチェーンをたどる(MindStudio)。Claude Code の主要な検索ツールは ripgrep です——高速で、正確で、行番号付きのテキストマッチングで、前処理なしにあらゆるリポジトリで動作します。
ベクトルがコードのデフォルトでない理由には正当な根拠があり、ノスタルジーではありません。便利な枠組みは 3 つの層で、必要なときだけエスカレートします(AI エージェントのためのコード検索)。
- 字句的(ripgrep): 完全一致、ミリ秒、gitignore 対応。デフォルトの選択肢。
- 構造的(ast-grep): AST パターンマッチング——「すべての async 関数を見つける」「すべての catch-and-rethrow」——正規表現がきれいに表現できないもの。クエリが文字列ではなく形状についてのときにここにエスカレートします。
- 意味的(embeddings / repo-map): 自然言語の概念クエリ。最後の手段。
なぜ意味的が最後の手段で最初ではないのか?コードエージェントが実際に生成するクエリは短くシンボル形式だからです——auth flow、user service、refreshToken——そしてこれはまさに embedding 検索を壊すフォーマットです。CoREB ベンチマークは、短いキーワードクエリが「テストされたほぼすべての意味的モデルをほぼゼロの nDCG@10 に崩壊させる」ことを発見しました。Embeddings は意味の類似性を捉えます。コードは依存関係、インポート、型定義のグラフであり、類似性は問い合わせている関係ではありません。二つの関数は意味的にほぼ同一でありながら構造的に無関係な場合があります。必要なのは呼び出しパス上にある方であり、似た読み方をする方ではありません。
これは意味的インデックスを役に立たなくしません——専門家にするのです。価値を発揮するとき、優れた実装は任意のテストウィンドウを embed しません。tree-sitter で実際の単位——関数、クラス、docstring が intact なインターフェース——にパースし、それらのチャンクを丸ごと保持し、ベクトル類似性を BM25 キーワードマッチングおよび依存関係追跡とブラスト半径分析のためのコールグラフツールと組み合わせます(opencode-codebase-index)。それがコード検索の全ゲームです:キーワードフォールバックを備えた依存関係対応・シンボル境界チャンキング——「512 トークンごとにファイルを分割して祈る」ではなく。
誰もしないコストとレイテンシの計算
精度を脇に置いて、ただ請求書を計算してみましょう。中規模リポジトリが 60 万トークンとします。一ターンにそれを流し込むと、慎重にキャッシュしない限り会話のすべてのターンで 60 万入力トークンを払うことになります。キャッシュしていても、モデルがすべてに注意を向けるレイテンシを負担します。代わりに検索パスを使えば、ツリー(数 KB)、grep 結果(数百トークン)、実際に読む 4 ファイル(約 1.5 万トークン)を送るだけです。これは丸め誤差の違いではありません。ターンあたり 1〜2 桁の差であり、デバッグセッションのすべてのターンに掛け算されます。
レイテンシも同じ曲線をたどります。60 万トークンを推論するモデルは、同じモデルが 1.8 万トークンを推論するより最初のトークンまでも全体でも遅いです。バグを追って 20 ターンこなすインタラクティブなループでは、それが数分の無駄な待機時間として積み重なります。検索は各ターンを小さく保つため、各ターンが速く、ループが引き締まったままになります。
そしてより静かなコストがあります:注意力の予算。ウィンドウ内のすべての無関係ファイルは気散らしであり、Chroma は気散らしが測定可能に精度を下げることを示しました——1 つの気散らしが害を及ぼし、4 つは複合されました。コンテキスト内の完全なリポジトリは、あらゆる質問に対して何千もの気散らしです。より多く払って遅くなるだけではありません。より多く払って遅くなりさらに不正確にもなるのです。
長いコンテキストが本当に勝つとき
これは「常に検索」ではありません。すべてを投入することが正しい選択である真の領域があり、それは支払っているウィンドウのサイズではなく、リポジトリのサイズとタスクの形によって定義されます。
長いコンテキストが勝つのは:
- リポジトリ全体が余裕をもって収まる——たとえば約 15 万トークン以下、ウィンドウの高リコール前半域内——かつタスクが小分けに検索しにくいクロスファイル推論を必要とする場合。すべてが重要な小さなリポジトリは、検索が複雑にしすぎてしまうまさにそのケースです。
- ファイル全体またはモジュール全体の推論を一度にする必要がある——完全にリファクタリングしたい大きなファイル一つ、モジュールの上から下までのセキュリティレビュー、モデルが関係を一度に把握する必要があるアーキテクチャレビュー。検索はこれを断片化します。コンテキストはそれを保持します。
- 反復的なループではなく一度きりの読み取り専用パスである場合。 一度の「この PR をレビューして」や「このサービスの仕組みを要約して」は、コストを 1 ターンで償却します。長いコンテキストを殺す経済——すべてのターンでフルウィンドウを支払う——は、ターンが 1 つだけのときは噛みつきません。
検索はそれ以外のすべてで勝ちます。実際にはほとんどの作業がそれに当たります:快適に収まらないどんなリポジトリも、反復的なものも、全体的な理解よりも特定の定義が必要なものも、そして静かに間違った検索が壊れたコードを出荷してしまうものも。
私が実際に使う大まかな規則:タスクの関連スライスがリポジトリより小さければ、検索する。タスクがリポジトリ全体であり、リポジトリがウィンドウの最初の約 15% に収まるなら、読み込む。 たいていの場合、スライスはリポジトリより小さいです。
まとめ
100 万トークンウィンドウは本物の能力であり、それが得意とする仕事——収まるコードの一度きりレビュー、モジュール全体の推論、すべてが関連する時々の小さなリポジトリ——にサーチャージなしの料金を活用する価値はあります。しかし、コードがどこにあるかを知ることの代替にはなりません。実際に動作するコードエージェントにとって、退屈なスタック——ツリーを一覧表示し、シンボルを grep し、一致した 4 ファイルを読み、インポートをたどり、キーワード検索が空になったときだけ AST や embeddings にエスカレートする——は、印象的な方法よりも安く、速く、正確です。スペックシートの大きな数字はオプションであり、指示ではありません。たいていの場合、それを埋め尽くさないようにしましょう。
