RAGにおける「ドキュメント枝刈り(Pruning)」の苦悩と、Shioriの Pointer-then-Fetch 設計
1. 概要
検索拡張生成(RAG)やAI駆動開発において、検索したドキュメントやファイルをエージェントに読み込ませる際の「コンテキストウィンドウ(Token Limit)の管理」は、システム設計上の深刻なボトルネックである。 Onyx(onyx-dot-app/onyx#3749)などのエンタープライズRAG製品が直面した課題は、検索したドキュメントをLLMに引き渡すために、複雑な「ドキュメントの枝刈り(DocumentPruningConfig)」や「会話履歴の要約」といった動的バッファ調整を泥臭く実装しなければならない点にある。 本稿では、このコンテキスト調整問題の構造的要因と、shiori が提示する「Pointer-then-Fetch(二段階アクセス)」によるインフラレベルでの解決設計について考察する。
2. インシデントの分析:Onyxにおける「トークン制限」と trim_prompt_piece の泥沼
2.1. 強引な文字列スライス trim_prompt_piece の限界
Onyxの自律エージェント検索機能(onyx-dot-app/onyx#3749)の開発過程において、検索したドキュメントをLLMへ引き渡すプロンプトにねじ込む際、トークン上限の壁に直面した。 これに対応するため、Onyxはドキュメント内容を上限以下に切り詰める trim_prompt_piece(agent_prompt_ops.py 内)という関数を導入せざるを得なかった。 しかし、この実装は単にドキュメントを強引に削る「文字列スライス」のハックであり、コードレビューにおいて以下のような開発者の生々しい困惑(evan-onyx のコメント)が記録されている。
- "Definitely take a look at trim_prompt_piece, see if you think we should design something fancier" (trim_prompt_pieceの挙動をよく見てくれ、もっとマシで凝った設計にできないか?)
単純な切り詰めロジックでは、文脈の途中や重要なパラメータ、型定義、あるいは結論がサイレントに切り落とされてしまい、AIが嘘の回答(ハルシネーション)を出すのを防ぐための「綺麗な枝刈り」をインフラ層で実現できず、設計のジレンマに陥っていた。
2.2. 配分設定(PruningConfig)の肥大化による複雑性
さらに、会話履歴(HISTORY_CONTEXT_SUMMARY)やユーザーの設定、使用するLLMのトークン限界に応じて、動的に切り詰め量を調整する DocumentPruningConfig などの配分パラメータをグラフ(LangGraph等)の各ノードの奥深くまで引き回す必要があった。この「ドキュメントの切り詰め量・配分」を司るコードがインフラ全体に染み出してしまい、システムの結合度と設計難易度を著しく複雑化させていた。
3. shiori による「Pointer-then-Fetch(二段階アクセス)」の適合設計
このトークン飽和問題に対し、shiori(ポインター検索・コード解析エンジン)は、最初から「すべてのドキュメントを一度にロードしない」という、RAGのアクセスパス自体を二段階に分離する設計によって、インフラレベルで問題を完全無力化している。
3.1. 検索フェーズでの「ポインター(メタデータ & スニペット)」のみの返却
shiori_searchを実行した際、システムは検索したファイルの中身そのものを全量コンテキストに展開することはしない。- 返却されるのは、ファイル名、絶対パス、およびヒットした部分の極小の要約(スニペット)という 「ポインター情報」 のみである(トークン消費は極めて微量)。
- AIエージェントは、この軽量なポインターのリストを見て、「どのファイルのどの部分が本当に自分の作業に必要か」を判断する。
3.2. スライスフェーズでの「ピンポイント行範囲フェッチ(Fetch)」
- AIエージェントは、必要なファイルを特定した上で、
shiori_read_fileやshiori_read_pr_fileを呼び出す。 - この際、
StartLineとEndLineによる 「行範囲スライス(Fetch)」 を指定し、本当に参照したい特定のクラス、関数、または差分が含まれる行(スライス)だけを狙い撃ちしてロードする。 - これにより、巨大なファイルを丸ごと読み込んだり、無関係なノイズドキュメントをコンテキストに混ぜ込む必要が一切なくなり、常に 最小のトークン消費で、最も高密度な情報のみ をLLMに渡すことができる。
4. 結論
RAGシステムにおける「ドキュメントの枝刈り(Pruning)」は、大量の非構造化ドキュメントを一度にコンテキストへ詰め込もうとする「一括ロード型アクセス」の限界を示している。 shiori が構築した 「RAG検索では軽量なポインターのみを返し、エージェント自身のインテリジェントな選択に基づいてピンポイントの行スライスをフェッチさせる(Pointer-then-Fetch)」 という二段階のインフラ設計は、複雑なトークン配分ロジックを不要にし、コンテキストを常に清潔でノイズのない状態に保つための、極めて先進的で合理的、かつ軽量なRAGアーキテクチャであるといえる。
5. 参考文献 / 一次情報
- Onyxにおけるエージェント検索機能とDocumentPruningの導入 (Onyx): onyx-dot-app/onyx#pull/3749
- ドキュメント・Web取得時のトークン上限超過エラーの事例: anomalyco/opencode#1212
- ローカルでのトークン数見積もりユーティリティによる巨大ファイル読み込み制限 (OpenCode): anomalyco/opencode#2328