ファイルシステムベースのコンテキストエンジニアリング
エージェントのコンテキストのプライマリオーバーフローレイヤーとしてファイルシステムを使用します。なぜなら、コンテキストウィンドウには制限がある一方、タスクは単一のウィンドウに収まるよりも多くの情報を必要とすることが多いからです。ファイルにより、エージェントは単一のインターフェースを通じて事実上無制限のコンテキストを保存、取得、更新できます。
静的なインクルージョンよりも、動的なコンテキスト発見(必要に応じて関連コンテキストを引き出す)を優先します。なぜなら、静的なコンテキストは関連性に関係なくトークンを消費し、タスク固有の情報のためのスペースを圧迫するからです。
いつアクティベートするか
以下の場合にこのスキルをアクティベートします:
- ツール出力がコンテキストウィンドウを肥大化させている
- エージェントが長い軌道にわたって状態を永続化する必要がある
- サブエージェントが直接メッセージパッシングなしに情報を共有する必要がある
- タスクがウィンドウに収まるよりも多くのコンテキストを必要とする
- 自身の指示を学習し更新するエージェントを構築する
- 中間結果のためのスクラッチパッドを実装する
- ターミナル出力やログをエージェントがアクセス可能にする必要がある
他のスキルに属する隣接する作業にはこのスキルをアクティベートしないでください:
- セマンティックなセッション間メモリ、エンティティ追跡、または時間ナレッジグラフ:
memory-systems - 会話の要約、コンパクション、または永続的なハンドオフ文言:
context-compression - ファイルバックアップストレージを必要としないトークン効率化戦術:
context-optimization - マルチエージェントトポロジーまたはハンドオフプロトコル設計:
multi-agent-patterns - ライブウィンドウ自体からコンテンツを退避させるモデル編集:
self-managed-context
コアコンセプト
これらの4つのモードに対してコンテキスト障害を診断します。それぞれに異なるファイルシステムの救済策が必要だからです:
- 欠落したコンテキスト -- 必要な情報が利用可能なコンテキスト全体に存在しない。ツール出力や中間結果をファイルに永続化して、何も失われないようにすることで修正します。
- 過少検索されたコンテキスト -- 取得されたコンテンツがエージェントのニーズをカプセル化できていない。ファイルをターゲットを絞った検索(grepフレンドリーな形式、明確なセクションヘッダー)のために構造化することで修正します。
- 過剰検索されたコンテキスト -- 取得されたコンテンツが必要以上に多く、トークンを浪費し注意を劣化させている。バルクコンテンツをファイルにオフロードし、コンパクトな参照を返すことで修正します。
- 埋もれたコンテキスト -- ニッチな情報が多くのファイルに散在している。構造的検索のためのglobとgrepと、概念的なクエリのためのセマンティック検索を組み合わせることで修正します。
これら4つすべてに対処する永続的なレイヤーとしてファイルシステムを使用します:一度書き込み、永続的に保存し、選択的に取得します。
詳細トピック
静的コンテキストと動的コンテキストのトレードオフ
静的コンテキスト(システム指示、ツール定義、重要なルール)を高価な不動産として扱います。関連性に関係なく毎ターントークンを消費します。エージェントが機能を蓄積するにつれて、静的コンテキストは成長し、動的な情報を圧迫します。
代わりに動的コンテキスト発見を使用します:最小限の静的ポインタ(名前、一行の説明、ファイルパス)のみを含め、関連する場合に検索ツールを使用してフルコンテンツをロードします。これはよりトークン効率が高く、ウィンドウ内の矛盾する情報や無関係な情報を減らすことで応答品質を向上させることがよくあります。
トレードオフを受け入れます:動的発見には、モデルがより多くのコンテキストが必要なタイミングを認識する必要があります。現在のフロンティアモデルはこれを適切に処理しますが、能力の低いモデルはロードをトリガーできない場合があります。疑わしい場合は、重要な安全性や正確性の制約を静的に含める方向に誤ります。
パターン1: ファイルシステムをスクラッチパッドとして
大きなツール出力をコンテキストに直接返すのではなく、ファイルにリダイレクトします。なぜなら、1回のウェブ検索やデータベースクエリで数千トークンがメッセージ履歴にダンプされ、会話全体にわたって永続化される可能性があるからです。
出力をスクラッチファイルに書き込み、コンパクトなサマリーを抽出し、ファイル参照を返します。その後エージェントは、ターゲットを絞った検索(パターンのgrep、行範囲での読み取り)を使用して、必要なものだけにアクセスします。
def handle_tool_output(output: str, threshold: int = 2000) -> str:
if len(output) < threshold:
return output
file_path = f"scratch/{tool_name}_{timestamp}.txt"
write_file(file_path, output)
key_summary = extract_summary(output, max_tokens=200)
return f"[Output written to {file_path}. Summary: {key_summary}]"
grepを使用してオフロードされたファイルを検索し、read_fileを行範囲とともに使用してターゲットセクションを取得します。これにより、アクティブなコンテキストには約100トークンだけを保持しながら、後で参照するために完全な出力を保存できます。
パターン2: 計画の永続化
計画をファイルシステムに書き込みます。なぜなら、長期的なタスクは、計画が注意から外れたり要約されたりすると一貫性を失うからです。エージェントはいつでも計画を再読し、目的と進捗の認識を回復します。
人間が読めて機械も解析可能なように、構造化された形式で計画を保存します:
# scratch/current_plan.yaml
objective: "認証モジュールのリファクタリング"
status: in_progress
steps:
- id: 1
description: "現在の認証エンドポイントを監査"
status: completed
- id: 2
description: "新しいトークン検証フローを設計"
status: in_progress
- id: 3
description: "変更を実装してテスト"
status: pending
毎ターンの開始時またはコンテキストリフレッシュ後に計画を再読して方向性を再確認します。これは「暗唱による注意の操作」として機能します。
パターン3: ファイルシステムを介したサブエージェント通信
メッセージパッシングの代わりにファイルシステムを介してサブエージェントの調査結果をルーティングします。なぜなら、マルチホップのメッセージチェーンは各ホップでの要約を通じて情報を劣化させるからです(「電話ゲーム」)。
各サブエージェントに自身のワークスペースディレクトリに直接書き込ませます。コーディネーターはこれらのファイルを直接読み取り、完全な忠実度を保持します:
workspace/
agents/
research_agent/
findings.md
sources.jsonl
code_agent/
changes.md
test_results.txt
coordinator/
synthesis.md
エージェントごとのディレクトリ分離を適用して書き込み競合を防ぎ、各出力成果物の明確な所有権を維持します。
パターン4: 動的スキルローディング
スキルをファイルとして保存し、静的コンテキストにはスキル名と簡単な説明のみを含めます。なぜなら、すべての指示をシステムプロンプトに詰め込むとトークンを浪費し、矛盾したガイダンスでモデルを混乱させる可能性があるからです。
利用可能なスキル(関連する場合にread_fileでロード):
- database-optimization: クエリチューニングとインデックス戦略
- api-design: REST/GraphQLのベストプラクティス
- testing-strategies: 単体、統合、E2Eテストパターン
現在のタスクで必要な場合にのみ、完全なスキルファイル(例:skills/database-optimization/SKILL.md)をロードします。これにより、O(n)の静的トークンコストをタスクあたりO(1)に変換します。
パターン5: ターミナルとログの永続化
ターミナル出力を自動的にファイルに永続化し、選択的検索にgrepを使用します。なぜなら、長時間実行プロセスからのターミナル出力は急速に蓄積され、手動のコピーペーストはエラーが発生しやすいからです。
terminals/
1.txt # ターミナルセッション1の出力
2.txt # ターミナルセッション2の出力
ターミナル履歴全体をコンテキストにロードする代わりに、ターゲットを絞ったgrep(grep -A 5 "error" terminals/1.txt)でクエリします。
パターン6: 自己修正による学習
エージェントに学習した好みやパターンを自身の指示ファイルに書き込ませ、後続のセッションがこのコンテキストを自動的にロードできるようにします。手動のシステムプロンプト更新は不要です。
def remember_preference(key: str, value: str):
preferences_file = "agent/user_preferences.yaml"
prefs = load_yaml(preferences_file)
prefs[key] = value
write_yaml(preferences_file, prefs)
自己修正は時間の経過とともに誤ったまたは矛盾した指示を蓄積する可能性があるため、このパターンを検証でガードします。実験的なものとして扱い、永続化された好みを定期的にレビューします。
ファイルシステム検索テクニック
コンテキスト発見のために、ls/list_dir、glob、grep、および行範囲を指定したread_fileを組み合わせます。なぜなら、モデルはファイルシステムのトラバーサルについて特にトレーニングされており、この組み合わせは構造的パターンが明確な技術コンテンツに対してセマンティック検索よりも優れていることが多いからです。
ls/list_dir: ディレクトリ構造を発見glob: パターンに一致するファイルを検索(例:**/*.py)grep: ファイル内容を検索、一致する行とコンテキストを返すread_filewith ranges: ファイル全体をロードせずに特定のセクションを読む
構造的および完全一致クエリにはファイルシステム検索を、概念的なクエリにはセマンティック検索を使用します。包括的な発見のために両方を組み合わせます。
実践的なガイダンス
ファイルシステムコンテキストを使用すべき時
状況がこれらの基準に一致する場合にファイルシステムパターンを適用します。これらはトークン節約または永続化のニーズによってのみ正当化されるI/Oオーバーヘッドを追加するからです:
使用すべき時:
- ツール出力が約2000トークンを超える場合
- タスクが複数の会話ターンにわたる場合
- 複数のエージェントが共有状態を必要とする場合
- スキルや指示が快適なシステムプロンプトサイズを超える場合
- ログやターミナル出力を選択的にクエリする必要がある場合
避けるべき時:
- タスクが単一ターンで完了する場合(オーバーヘッドが正当化されない)
- コンテキストがウィンドウに快適に収まる場合(解決すべき問題がない)
- レイテンシが重要な場合(ファイルI/Oは測定可能な遅延を追加する)
- モデルがファイルシステムツール機能を持たない場合
ファイル整理
エージェントが発見しやすいようにファイルを構造化します。なぜなら、エージェントはディレクトリ名をリストして読み取ることでナビゲートするからです:
project/
scratch/ # 一時的な作業ファイル
tool_outputs/ # 大きなツール結果
plans/ # アクティブな計画とチェックリスト
memory/ # 永続的な学習情報
preferences.yaml # ユーザーの好み
patterns.md # 学習されたパターン
skills/ # ロード可能なスキル定義
agents/ # サブエージェントワークスペース
一貫した命名規則を使用し、曖昧さを排除するためにスクラッチファイルにタイムスタンプやIDを含めます。
自律的な研究ループの場合、消費した実行の隣に生の取得済み証拠を保存します。例:researcher/runs/<run-id>/sources/evidence/raw/。生の研究ダンプをリポジトリルートに残さないでください。ルートレベルのアーティファクトは監査が難しく、出典なしで引用されやすくなります。
トークンアカウンティング
ファイルシステムパターンを適用する前後でトークンの発生源を測定します。なぜなら、測定なしの最適化は無駄な努力につながるからです:
- 静的コンテキストと動的コンテキストの比率を追跡する
- オフロード前後のツール出力サイズを監視する
- 動的にロードされたコンテキストが実際に使用される頻度を測定する
例
例1: ツール出力のオフロード
入力: ウェブ検索が8000トークンを返す
before: 8000トークンがメッセージ履歴に追加される
after:
- scratch/search_results_001.txtに書き込む
- 返す: "[結果はscratch/search_results_001.txtにあります。主な発見: APIレート制限は1000 req/min]"
- エージェントは特定の詳細が必要なときにファイルをgrepする
結果: コンテキストに約100トークン、8000トークンはオンデマンドでアクセス可能
例2: 動的スキルローディング
入力: ユーザーがデータベースインデックスについて質問
静的コンテキスト: "database-optimization: クエリチューニングとインデックス"
エージェントアクション: read_file("skills/database-optimization/SKILL.md")
結果: フルスキルは関連する場合のみロードされる
例3: ファイル参照としてのチャット履歴
トリガー: コンテキストウィンドウ制限に達した、要約が必要
アクション:
1. 完全な履歴をhistory/session_001.txtに書き込む
2. 新しいコンテキストウィンドウ用のサマリーを生成する
3. 参照を含める: "完全な履歴はhistory/session_001.txt"
結果: エージェントは履歴ファイルを検索して、要約で失われた詳細を回復できる
ガイドライン
- 大きな出力はファイルに書き込み、サマリーと参照をコンテキストに返す
- 計画と状態を再読可能な構造化ファイルに保存する
- メッセージチェーンの代わりにサブエージェントファイルワークスペースを使用する
- すべてをシステムプロンプトに詰め込むのではなく、スキルを動的にロードする
- ターミナルとログ出力を検索可能なファイルとして永続化する
- 包括的な発見のためにgrep/globとセマンティック検索を組み合わせる
- 明確な命名でエージェントが発見しやすいようにファイルを整理する
- ファイルシステムパターンが効果的であることを検証するためにトークン節約を測定する
- 無制限の成長を防ぐためにスクラッチファイルのクリーンアップを実装する
- 自己修正パターンを検証でガードする
- 生の証拠をそれを使用した実行、評価、提案の隣に保存する
落とし穴
- スクラッチディレクトリの無制限な成長:エージェントはクリーンアップなしに一時ファイルを作成し、最終的にディスクを消費し、ディレクトリリストをノイズだらけにします。保持ポリシー(経過時間ベースまたはカウントベース)を実装し、セッション境界でクリーンアップを実行します。
- マルチエージェントファイルアクセスでの競合状態:同じファイルへの同時書き込みは状態を静かに破損します。エージェントごとのディレクトリ分離を適用するか、エージェントプレフィックス付きエントリを持つ追記専用ファイルを使用します。
- 移動/名前変更後の古いファイル参照:エージェントは、リファクタリングやファイル再編成後に存在しなくなった以前のターンからのパスを保持します。キャッシュされたパスを読み取る前に常にファイルの存在を確認します。チェックに失敗した場合はglobで再発見します。
- globパターンの誤一致:過度に広いパターン(例:
**/*)は無関係なファイルをコンテキストに引き込み、トークンを浪費しモデルを混乱させます。globを特定のディレクトリと拡張子に限定します。 - ファイルサイズの想定:サイズを確認せずにファイルを読み取ると、1回のツールコールで10万+トークンがコンテキストにダンプされる可能性があります。読み取る前にファイルサイズを確認します。大きなファイルには行範囲読み取りを使用します。
- ファイル存在確認の欠如:エージェントは以前のターンからのファイルが存在すると想定しますが、それらは削除または移動されている可能性があります。常に存在確認で読み取りをガードし、欠落ファイルエラーを適切に処理します。
- スクラッチパッド形式のドリフト:構造化されていないスクラッチパッドは、多くの書き込みの後で形式規則が連続する追加で侵食されるため、解析不能になります。最初の書き込みからスキーマ(YAML、JSON、または構造化マークダウン)を定義して適用します。
- ハードコードされた絶対パス:リポジトリが異なる場所にチェックアウトされたり、コンテナで実行されたりすると壊れます。プロジェクトルートからの相対パスを使用するか、動的にパスを解決します。
統合
このスキルはファイルバックアップのコンテキストストレージを所有します。
…
[翻訳のため省略]