TEI + Qdrantで Claude Code マルチエージェントシステムを構築する
TL;DR
TEI(Text Embeddings Inference)でコードをベクトル化し、Qdrantに格納して、Claude Codeの9つのエージェントがコードを読まずに検索するシステムを構築した。
1. なぜ作ったのか
Claude Codeの限界
Claude Codeは強力だが、コードベース全体を把握する際にファイルを一つずつ開いて読み込む。
Read src/auth.ts → 200行消費
Read src/middleware.ts → 150行消費
Read src/utils/token.ts → 100行消費
...コード品質やセキュリティなど、やむを得ず全体を読む必要がある場合、消費が大きい。
コードレビューやセキュリティ問題をチェックするエージェントがReadツールなしでコードを把握し、トークンコストを削減できるのではないかと考え、試してみた。
2. アーキテクチャ
| レイヤー | 構成 |
|---|---|
| Claude Code | 9つのエージェント (Morpheus, Neo, Seraph, ...) |
| ↓ MCP Protocol (stdio) | |
| mcp-code-rag | Rustバイナリ。インデックス/検索ブリッジ |
| ↓ HTTP / gRPC | |
| TEI (e5-base) | テキスト → ベクトル変換 |
| Qdrant | ベクトル格納 + 類似度検索 |
構成要素
| コンポーネント | 役割 | 配置 |
|---|---|---|
| mcp-code-rag | MCPサーバー。インデックス/検索リクエスト処理 | ローカル (Rustバイナリ) |
| TEI (e5-base) | テキスト → 768次元ベクトル変換 | Docker |
| Qdrant | ベクトル格納 + コサイン類似度検索 | Docker |
| Claude Code Agents | コード探索時にMCPツールで検索 | ローカル |
3. なぜこのスタックか
最新のエンベディングモデルや最適な組み合わせを探すことが目的ではない。GPUのないNASでRAGパイプラインが実際に動作するかテストするのが目的だった。そのため、軽量でセルフホスティングしやすい組み合わせを選んだ。
TEI + e5-base
- TEI — Hugging Face公式エンベディングサーバー。Docker一行でデプロイ完了
- e5-base — 768次元。CPUで~50ms/queryと十分に実用的
query:/passage:プレフィックスで非対称検索をサポートし、短い質問 → 長いコードチャンクのマッチングに有利
RustでMCPサーバーを作った理由
- バイナリ一つ — 実行ファイル一つでデプロイ完了。ランタイム依存性ゼロ
- メモリ — 常駐メモリ~15MB。Pythonサーバーは200MB+
- Claude Code MCP — stdio基盤のJSON-RPC。Rustのserde + tokioが最適
- 外部通信 — HTTP + gRPC非同期処理
4. コアフロー
4.1 インデックス作成 (コード → ベクトル)
プロジェクトディレクトリ
│
▼
[walkdir] ファイル走査 (max depth: 10)
│
▼
[filter] 52ディレクトリ + 60拡張子を除外
(node_modules, target, .git, 画像, バイナリ...)
│
▼
[増分チェック] ファイル更新日時を比較
→ 変更されたファイルのみ処理
│
▼
[chunk] 1500文字単位で分割 (300文字オーバーラップ)
│
▼
[TEI] 各チャンク → "passage: {content}" → 768次元ベクトル
│
▼
[Qdrant] UUID v5ベースのupsert (100件バッチ)
Collection: "code-rag-{project_name}"なぜ1500文字チャンキングか?
- 大きすぎる → 検索精度低下 (ノイズ)
- 小さすぎる → 関数一つが複数チャンクに分割されコンテキスト喪失
- 1500文字 + 300文字オーバーラップ → 関数境界での切断を防止
4.2 検索例 — コードレビューエージェント
[コードレビュー_エージェント] セキュリティ監査開始
│
▼
search_codebase("認証処理ロジック", project_name="my-app")
│
▼
検索結果受信 (Top 10, 類似度0.5以上のみ):
│
▼
search_codebase("SQLクエリ生成", project_name="my-app")
│
▼
search_codebase("ユーザー入力検証", project_name="my-app")
│
▼
収集されたコード断片でセキュリティレポート生成結果: Read 0回、検索3回でレポート完成。 ファイルを一つも開かずにコードベースのセキュリティ脆弱性を分析する。
4.3 自動インデックス作成
エージェント: search_codebase("エラーハンドリング", project_name="blog")
│
▼
[Collection確認] "my-app" は存在する?
│
├─ No → 自動インデックス作成トリガー → インデックス完了後に検索
│
└─ Yes → 即時検索エージェントがインデックス作成を直接呼び出す必要はない。初回検索時に自動でインデックスが生成される。
5. 実測値
| 項目 | 値 |
|---|---|
| TEIエンベディング速度 | ~50ms/query (CPU) |
| インデックス作成 (1000ファイル) | ~3分 (増分時は変更分のみ) |
| 検索応答 | ~200ms (キャッシュmiss), ~5ms (キャッシュhit) |
| mcp-code-ragメモリ | ~15MB |
| ベクトル次元 | 768 (e5-base) |
| キャッシュTTL | 5分 |
| 最大インデックスファイル数 | 5,000件 |
| チャンクサイズ | 1,500文字 (300文字オーバーラップ) |
6. MCPツール
mcp-code-ragがClaude Codeに提供するMCPツールは2つ。
| ツール | 説明 |
|---|---|
| search_codebase | 自然言語クエリでコード検索。プロジェクト名を渡せば自動でコレクション切り替え + 未インデックス時は自動インデックス作成 |
| refresh_index | プロジェクトパスを指定して手動インデックス作成。増分方式で変更されたファイルのみ処理 |
エージェントがコードを探索する際にsearch_codebaseを先に呼び出すようルールを強制すれば、Readツールでファイルを巡回するトークンの無駄遣いを防げる。
利点
- 一度インデックスを作成すれば以降の検索は即時 — インデックス作成は初回のみ遅く、以降は増分方式で変更ファイルのみ処理。検索自体は~200ms
- トークン消費ゼロ — Readでファイルを開かないため、コンテキストウィンドウを検索に消費しない
- 自然言語でコード探索 — 「認証処理」、「SQLクエリ」のような質問で関連コードを即座に見つける
- コードベース全体をスキャンする作業に強い — セキュリティ監査やコードレビューのように広くパターンを把握する用途に適している
限界
「エラーハンドリングが適切に行われているか?」のような精密な意味検索はベクトル類似度だけでは不十分だ。このような場合にはRerankモデルを追加するか、キーワード検索(BM25)とベクトル検索を組み合わせるハイブリッド方式が必要となる。
| 用途 | 現行システム | 追加必要 |
|---|---|---|
| コードベース全体の構造把握 | 適合 | — |
| セキュリティパターンスキャン | 適合 | — |
| 特定ロジックの精密検索 | 不十分 | Rerank、ハイブリッド検索 |
| エラーハンドリング追跡 | 不十分 | Rerank + AST分析 |
7. はじめに
必要なもの
- Docker環境 (Qdrant、TEI実行用)
- Rust (mcp-code-ragビルド用)
- Claude Code (Proプラン)
すべてインストールしてClaude CodeにMCPサーバーを登録すれば、トークンの無駄遣いなく意味ベースで必要なコードだけを取得できる。
Log
- • 2026-01-29: create