AIエージェントを使った開発では、README、CLAUDE.md、AGENTS.mdなどにプロジェクトのルールや仕様を書き、エージェントに最初に読ませるやり方がよく使われる。
これはかなり強力だ。
AIのメモリ機能や、過去の会話履歴に頼るのではなく、リポジトリ内に置かれたドキュメントを唯一の正として扱える。
仕様が変わったらドキュメントを更新する。
次に起動したエージェントも、その最新の仕様を読む。
いわゆる仕様駆動開発とAIエージェントは、かなり相性がいい。
ただ、実際にやっていると一つ気になることがある。
ドキュメントを読むだけで、かなりのトークンを消費する。
仕様書が育つほど、毎回読むコストが高くなる
最初はCLAUDE.md一枚だけだったものが、プロジェクトが育つにつれて増えていく。
たとえば、
- 要件定義
- 技術仕様
- アーキテクチャ設計
- API仕様
- ディレクトリ構成
- コーディング規約
- テスト方針
- ADR
- 運用手順
などだ。
すると、エージェントはタスクを始めるたびに大量の文書を読むことになる。
もちろん、コンテキストウィンドウが大きくなれば全部入れることはできる。
しかし「入れられる」ことと「毎回入れるべき」ことは違う。
数万トークンある仕様書のうち、今回必要なのは認証仕様の一節だけ、ということは珍しくない。
そこでふと思った。
データベースにはインデックスがある。
同じ発想を、AIエージェントのコンテキスト取得にも使えないだろうか。
データベースは毎回Full Scanしない
データベースで大量のデータを検索するとき、毎回すべての行を先頭から読むわけではない。
インデックスを使って、
「必要なデータがどこにあるか」
を先に特定する。
その後、必要なデータだけを取得する。
AIエージェントも同じ構造にできるのではないか。
現在の仕様駆動開発では、エージェントに仕様書そのものを渡している。
これを、
仕様そのものではなく、まず仕様へ到達するためのインデックスを渡す
形に変える。
たとえば、ユーザーから、
「ログイン処理を変更して」
と言われたとする。
エージェントは最初に巨大な仕様書を読むのではなく、まず小さなインデックスを検索する。
capability: auth.login
docs:
- docs/product/auth.md#login
- docs/architecture/session.md#authentication
code:
- src/auth/**
- src/api/login.ts
tests:
- tests/auth/login.test.ts
tools:
- test.auth
- db.schema.users
related:
- auth.session
- security.rate-limit
これを見るだけで、
- どの仕様を読むべきか
- どのコードを見るべきか
- どのテストを実行すべきか
- 必要ならどのツールを使うべきか
が分かる。
そして必要になった箇所だけを読む。
不足していれば、relatedにある次の候補を読む。
それでも足りなければ、通常のgrepや検索にフォールバックする。
つまり、
Index Scan → 必要箇所の取得 → 不足時のみ追加探索
という流れだ。
「仕様書のインデックス」だけではなく「ツールのインデックス」にする
この発想で特に面白いと思っているのが、ドキュメントだけを対象にしないことだ。
LLMは基本的には、テキストを受け取り、テキストを返す。
そこにAPI、MCP、シェル、ブラウザ操作などのツールを組み込むことで、エージェントとして汎用的になる。
であれば、
ドキュメントとツールに共通のインデックスを貼ればいい。
たとえば、
auth.login
という共通IDに、
- 要件
- 設計
- 実装
- テスト
- DBスキーマ
- ブラウザ操作
- 検証コマンド
を紐づける。
イメージとしてはこうだ。
requirement
|
architecture
|
docs ----------- auth.login ----------- code
|
tests
|
tools
エージェントにとって重要なのは、
「何を知っているか」
だけではない。
「その領域について何ができるか」
も同時に知る必要がある。
ならば、知識とアクションを別々の探索空間にする必要はない。
Capability = Knowledge + Action + Validation
という単位でまとめてもいい。
インデックスは真実を持ってはいけない
ただし、この仕組みには重要な原則がある。
インデックス自体を仕様書にしてはいけない。
たとえばインデックスに、
auth.login = JWT認証
と書いてしまう。
その後、本当の仕様書ではCookie Sessionに変更したのに、インデックスの更新を忘れたとする。
すると真実が二つできてしまう。
これは危険だ。
データベースのインデックスも、本体データとは別物だ。
インデックスの役割は、
「データがどこにあるかを示すこと」
であって、
「データそのものになること」
ではない。
同じように、
仕様書はSource of Truth。
インデックスはSource of Location。
と分離するのが重要だと思う。
インデックスには、
id: auth.login
source: docs/product/auth.md
anchor: "#login"
までを書く。
実際の仕様は必ず参照先に置く。
ファイル単位ではなく、セクション単位で参照したい
さらに、インデックスが、
auth.login → docs/auth.md
だけでは不十分だ。
結局auth.md全体を読むことになる。
なので、
auth.login → docs/auth.md#login
のように、できるだけ細かい単位で参照する。
大きなドキュメントなら、
AUTH-LOGIN-BEGIN
...
AUTH-LOGIN-END
のような安定した境界を持たせてもいい。
するとエージェントは、その区間だけを取得できる。
これはトークン削減だけでなく、不要な情報による判断ノイズも減らせる。
AGENTS.mdは「百科事典」ではなく「ブートローダー」にする
この考え方を突き詰めると、AGENTS.mdやCLAUDE.mdの役割も変わる。
大量の仕様を書く場所ではなくなる。
代わりに、
「このリポジトリでどう情報を探すか」
だけを書く。
たとえば、
1. タスクを受け取ったら最初に.agent/indexを検索する
2. capabilityを特定する
3. normativeな仕様だけを読む
4. 不足時のみrelatedを辿る
5. 最後に指定されたvalidationを実行する
6. indexと仕様が矛盾した場合、仕様を優先する
程度でいい。
つまり、
AGENTS.md = ブートローダー
Index = クエリプランナ用メタデータ
docs = Source of Truth
という三層構造になる。
一番難しいのはインデックスの陳腐化
もちろん問題もある。
一番怖いのは、
仕様書は更新されたのに、インデックスだけ古い
状態だ。
通常の全文探索なら遅くても仕様を見つけられる。
インデックス方式は高速だが、インデックスから漏れた情報は見つからない可能性がある。
データベースでインデックスが成立するのは、データ更新とインデックス更新が一体になっているからだ。
AIエージェント用のインデックスも同じで、
document update
↓
index regenerate
↓
validation
↓
commit
という流れにすべきだと思う。
手作業でindex.yamlを更新する方式は、おそらく長期運用では壊れる。
なので各ドキュメントにメタデータを持たせ、
---
id: auth.login
type: product-spec
related:
- auth.session
tests:
- test.auth.login
---
そこからインデックスを自動生成する方がよさそうだ。
つまり、インデックスは手書きの仕様ではなく、生成物にする。
インデックスが外れたらFull Scanに戻ればいい
そして、インデックスは絶対的なものにしない。
検索の最初に使うだけだ。
理想的には、
Task
↓
Index Lookup
↓
候補の仕様を読む
↓
十分?
├─ Yes → 実装
└─ No
↓
relatedを辿る
↓
grep / semantic search
↓
必要ならFull Scan
とする。
データベースのクエリプランナと同じで、
Index Scanが効くなら使う。
効かなければ別の探索手段を使う。
重要なのは、
インデックスによって探索を禁止するのではなく、探索順序を最適化すること
だ。
LLMにプロジェクト全体を覚えさせるのではなく、探索方法を覚えさせる
この発想の本質は、トークン削減だけではないと思っている。
現在のAIエージェント開発では、
「必要な知識を全部コンテキストに入れる」
方向に寄りやすい。
しかし別の考え方もある。
プロジェクト全体をコンテキストとして持たせるのではなく、
プロジェクトを探索する能力をコンテキストとして持たせる。
つまり、
巨大なKnowledge Context
ではなく、
小さなIndex
+
必要な情報を取得するTool
を持たせる。
必要な情報は、その都度取得する。
これは、AIエージェントが巨大なコードベースを扱うようになるほど重要になってくる気がする。
今の多くのエージェント開発は、まだかなり「Full Table Scan」に近い。
その次に来るのは、
semantic key → index scan → pointer chase → 必要なら追加scan
という仕組みなのかもしれない。
仕様駆動開発の次のテーマは、
「何を仕様書に書くか」
だけではなく、
「AIがその仕様へどう到達するか」
になるのではないかと思っている。