# v1.7 更新内容: 並列実行の検証と実装
## 概要
v1.7では、EXPLORATIONフェーズにおける検索処理の並列実行を実現するための検証と実装を行います。
**重要**: このバージョンは検証フェーズであり、成功した場合のみ実装を進めます。
---
## 背景
### 現状の問題
複数のフェーズで同一ツールを順次実行:
#### 1. EXPLORATIONフェーズ(Step 4)
```
16:02:48 semantic_search 完了
↓ [8秒: LLM思考]
16:02:56 search_text("modal")
↓ [11秒: LLM待機]
16:03:07 search_text("background")
↓ [9秒: LLM待機]
16:03:16 search_text("overlay")
↓ [7秒: LLM思考]
16:03:23 submit_understanding
```
**ボトルネック**: 中間待機(11秒 + 9秒 = 20秒)
#### 2. READYフェーズ(Step 9: 実装)
```
Read("CartService.php")
↓ [2-3秒: LLM待機]
Read("ProductService.php")
↓ [2-3秒: LLM待機]
Read("OrderService.php")
↓ [コード理解]
Grep("class.*Service")
↓ [2-3秒: LLM待機]
Grep("function.*calculate")
↓ [結果確認]
```
**ボトルネック**: ファイル読み込み間の待機(5-10秒)
#### 3. その他のフェーズ
SEMANTIC(Step 6)、VERIFICATION(Step 7)でもコード確認時に同様の問題(2-5秒)
### 理想的な動作
#### 1. EXPLORATIONフェーズ
```
16:02:48 semantic_search 完了
↓ [8秒: LLM思考 - パターン決定]
16:02:56 search_text(patterns=["modal", "background", "overlay"])
↓ [0.06秒: 並列実行]
↓ [7秒: LLM思考 - 結果統合]
16:03:03 submit_understanding
```
**削減**: 20秒(中間待機がゼロに)
#### 2. READYフェーズ
```
1メッセージで複数Read呼び出し:
Read("CartService.php")
Read("ProductService.php")
Read("OrderService.php")
→ 並列実行(0.1秒)
↓ [コード理解]
1メッセージで複数Grep呼び出し:
Grep("class.*Service")
Grep("function.*calculate")
→ 並列実行(0.05秒)
```
**削減**: 5-10秒(待機がゼロに)
#### 3. その他のフェーズ
同様の並列化で2-5秒削減
### 総削減見込み
**27-35秒**(EXPLORATION 20秒 + READY 5-10秒 + その他 2-5秒)
---
## 課題: LLMの動作パターン
### 問題点
**ラッパーを作るだけでは不十分**
search_textが複数パターンに対応しても、LLMが以下のように呼び出す保証がない:
```python
# 期待する呼び出し方
search_text(patterns=["modal", "background", "overlay"])
# 実際に起こりうる呼び出し方
search_text("modal") # 待機
search_text("background") # 待機
search_text("overlay")
```
理由:
1. **code.mdに並列実行の明示的な指示がない**
2. **LLMの習慣的な動作**(1つずつ確認しながら進める)
---
## v1.7 の実装アプローチ
### Phase 1a: search_text実装(1時間)
**目的**: search_textを複数パターン対応に拡張し、Phase 1bで検証できる状態にする
#### 1a.1: search_text拡張
[tools/ripgrep_tool.py](../tools/ripgrep_tool.py) を修正:
```python
async def search_text(
pattern: str | list[str], # 単一 or 複数に対応
path: str = ".",
file_type: str | None = None,
case_sensitive: bool = True,
context_lines: int = 0,
max_results: int = 100,
regex: bool = True,
) -> dict:
"""
Search for text patterns using ripgrep.
Args:
pattern: Single pattern (str) or multiple patterns (list[str])
Maximum 5 patterns for parallel search.
...
"""
# 単一パターン
if isinstance(pattern, str):
return await _search_single(pattern, path, ...)
# 複数パターン: 上限チェック
if len(pattern) > 5:
return {
"error": "Too many patterns for parallel search. "
f"Maximum 5 patterns allowed, got {len(pattern)}. "
"Please split into multiple search_text calls or reduce patterns.",
"provided_patterns": pattern
}
# 複数パターン(並列実行)
tasks = [
_search_single(p, path, file_type, case_sensitive,
context_lines, max_results, regex)
for p in pattern
]
results = await asyncio.gather(*tasks)
return {
"patterns": pattern,
"path": str(Path(path).resolve()),
"results": {
p: r for p, r in zip(pattern, results)
},
"total_patterns": len(pattern),
}
# 既存のロジックを_search_single関数に抽出
async def _search_single(pattern: str, ...) -> dict:
"""Single pattern search (existing logic)"""
# 現在の search_text の実装をここに移動
...
```
#### 1a.2: ユニットテスト
```python
# tests/test_ripgrep_parallel.py
async def test_search_text_single_pattern():
result = await search_text("import")
assert "matches" in result
assert result["pattern"] == "import"
async def test_search_text_multiple_patterns():
result = await search_text(["import", "export", "const"])
assert "results" in result
assert len(result["results"]) == 3
assert all(p in result["results"] for p in ["import", "export", "const"])
async def test_search_text_pattern_limit():
# 6パターン(上限超過)
result = await search_text(["p1", "p2", "p3", "p4", "p5", "p6"])
assert "error" in result
assert "Maximum 5 patterns" in result["error"]
async def test_search_text_five_patterns():
# 5パターン(上限ギリギリ、成功するはず)
result = await search_text(["import", "export", "const", "let", "var"])
assert "results" in result
assert len(result["results"]) == 5
```
#### 1a.3: code_intel_server.py 更新
MCPツール定義を更新して、`pattern`が`str | list[str]`を受け取れるようにする。
---
### Phase 1b: 検証(1-1.5時間)
**前提**: Phase 1aで search_text が複数パターン対応済み
#### 1b.1: code.md への指示追加
`.claude/commands/code.md` に以下を追加:
##### Step 4: EXPLORATION Phase
```markdown
### 4.2: Text Search - CRITICAL: Use Parallel Execution
**⚠️ MANDATORY: Parallel Pattern Search**
When you need to search for multiple patterns, you MUST use parallel execution:
✅ **CORRECT (saves 15-20 seconds)**:
```python
search_text(patterns=["modal", "dialog", "popup"])
```
→ All patterns execute in parallel (0.06 seconds total)
❌ **WRONG (wastes time)**:
```python
search_text("modal") # Wait 10s
search_text("dialog") # Wait 10s
search_text("popup") # Total: 20s wasted
```
**Pattern Selection Process**:
1. Analyze semantic_search results (Step 4.1)
2. Determine 2-4 search patterns based on the results
3. Call search_text ONCE with ALL patterns as a list
**Example**:
```python
# After analyzing semantic_search results, you identified these patterns:
search_text(patterns=["useAuthContext", "AuthProvider", "withAuth"])
```
```
##### Step 9: READY Phase (Implementation)
```markdown
### Parallel File Reading - CRITICAL: Saves 5-10 seconds
**⚠️ MANDATORY: Read Multiple Files in Parallel**
When you need to read multiple files to understand the codebase:
✅ **CORRECT (parallel execution)**:
Call multiple Read tools in a SINGLE message:
- Read("CartService.php")
- Read("ProductService.php")
- Read("OrderService.php")
→ All files are read in parallel (saves 4-6 seconds)
❌ **WRONG (sequential execution)**:
Read("CartService.php")
[Wait for result]
Read("ProductService.php")
[Wait for result]
Read("OrderService.php")
**Same applies to Grep**:
When searching for multiple patterns, call ALL Grep tools in ONE message:
- Grep("class.*Service")
- Grep("function.*calculate")
- Grep("interface.*Repository")
→ Parallel execution (saves 2-4 seconds)
```
##### All Phases: General Rule
```markdown
## General Principle: Parallel Tool Calls
**IMPORTANT**: Whenever you need to call the SAME tool multiple times:
- Call them ALL in a SINGLE message
- This enables automatic parallel execution
- Saves 2-5 seconds per additional call
**Examples**:
- Multiple Read calls → 1 message with all Reads
- Multiple Grep calls → 1 message with all Greps
- Multiple search_text → Use patterns parameter
**This applies to**:
- Step 4 (EXPLORATION): search_text, Grep
- Step 6 (SEMANTIC): Read, Grep (hypothesis verification)
- Step 7 (VERIFICATION): Read, Grep (evidence gathering)
- Step 9 (READY): Read, Grep (code understanding)
```
#### 1b.2: 検証テスト(3回)
**重要**: `/code`コマンド(402秒)を使うと検証だけで20分以上かかるため、検証専用の軽量コマンドを作成
**新規コマンド**: `.claude/commands/test-parallel.md`
```markdown
# /test-parallel - 並列実行検証コマンド
**目的**: LLMが並列実行指示に従うかを短時間で検証
**実行フェーズ**(約60-90秒):
1. EXPLORATION: search_text 複数パターン呼び出しを確認
2. READY(一部): Read/Grep 並列呼び出しを確認
3. 結果レポート出力
**スキップするフェーズ**:
- SEMANTIC, VERIFICATION, IMPACT_ANALYSIS(並列化対象外)
- 実装(READY後半)、コミット、品質チェック
**検証項目**:
- [ ] search_text を1回で複数パターン呼び出し
- [ ] Read を1メッセージで複数呼び出し
- [ ] Grep を1メッセージで複数呼び出し
```
**検証タスク**(各60-90秒):
1. テストタスク1: モーダル実装タスク
- 軽量タスク: 「Find modal implementation patterns」
- 期待: `search_text(patterns=["modal", "dialog", "popup"])`
2. テストタスク2: サービスクラス理解タスク
- 軽量タスク: 「List all service classes」
- 期待: Read("A.php"), Read("B.php"), Read("C.php") を1メッセージで
3. テストタスク3: エビデンス収集タスク
- 軽量タスク: 「Find authentication patterns」
- 期待: Grep("auth"), Grep("login"), Grep("session") を1メッセージで
**成功条件**(3回中2回以上成功):
- LLMがsearch_textを複数パターンで1回呼び出し
- Read/Grepを1メッセージで複数呼び出し
- 実測で並列実行を確認
**失敗条件**(3回中2回以上失敗):
- LLMが依然として順次呼び出し
- code.mdの指示を無視
**所要時間**:
- `/code`使用: 3回 × 402秒 = 20分以上
- `/test-parallel`使用: 3回 × 90秒 = 4.5分
- **削減**: 約15分
---
### Phase 2: ドキュメント整備と最終テスト(Phase 1b成功時のみ、1時間)
#### 2.1: code_intel_server.py のツール定義更新
search_textツールのスキーマを更新済みか確認:
```python
{
"name": "mcp__code-intel__search_text",
"inputSchema": {
"properties": {
"pattern": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"type": "string"}}
]
}
}
}
}
```
#### 2.2: READMEとCHANGELOG更新
- search_textの複数パターン対応を記載
- 使用例を追加
#### 2.3: 実測テスト
実際のタスクで効果を測定:
- 削減時間の確認
- LLMの動作確認
- エラーがないか確認
---
## 削減見込み
| フェーズ | 対象 | 状態 | 削減時間 | 実装時間 |
|---------|------|------|----------|----------|
| Phase 1a: 実装 | search_text拡張 | 未実施 | 0秒 | 1時間 |
| Phase 1b: 検証 | 並列実行テスト | 未実施 | 0秒 | 1-1.5時間 |
| Phase 2: ドキュメント | 全フェーズ | Phase 1b成功時のみ | 27-35秒 | 1時間 |
| **合計** | - | - | **0-35秒** | **3-3.5時間** |
### 削減内訳
**Phase 1b 成功時(確率 75-85%)→ Phase 2 実施**:
| フェーズ | 削減時間 | 備考 |
|---------|---------|------|
| EXPLORATION(Step 4) | 20秒 | search_text 複数パターン対応(Phase 1a実装済み) |
| READY(Step 9) | 5-10秒 | Read/Grep 並列実行(code.md指示のみ) |
| SEMANTIC(Step 6) | 1-2秒 | コード確認の並列化(code.md指示のみ) |
| VERIFICATION(Step 7) | 1-3秒 | エビデンス収集の並列化(code.md指示のみ) |
| **合計** | **27-35秒** | **全体の7-9%削減** |
**Phase 1b 失敗時(確率 15-25%)→ Phase 2 スキップ**:
- 削減 0秒
- Phase 1a で実装した search_text 拡張は残る(単一パターンの後方互換性あり)
- v1.9以降で別アプローチ検討
---
## リスク評価
### Phase 1b(検証)成功確率
| 対象 | 成功確率 | 理由 |
|------|---------|------|
| search_text 並列化 | 70-80% | 専用パラメータで明確な指示 |
| Read/Grep 並列化 | **80-90%** | Claude Code標準機能(既にサポート済み) |
| **Phase 1b 総合成功確率** | **75-85%** | |
**成功確率が高い理由**:
- Claude Codeは既に複数ツールの並列実行をサポート
- 必要なのは「LLMに1メッセージで複数呼び出しさせる」指示のみ
- Read/Grepは標準ツールで、並列実行の実績が豊富
### 実装リスク
| リスク | 影響 | 確率 | 対策 |
|--------|------|------|------|
| LLMが指示を無視(Phase 1b) | Phase 2 実施不可 | 15-25% | Phase 1b で検証後に判断 |
| search_text拡張のバグ(Phase 1a) | 検索失敗 | 5% | 十分なユニットテスト |
| 返却データのトランケート | 検索結果が切れる | 5-10% | パターン数を5個まで制限、Phase 1bで実測 |
| 並列実行のデッドロック | セッション停止 | < 1% | asyncio.gather の適切な使用 |
**返却データサイズの制約**:
- ツール返却: 30,000文字制限
- 最悪ケース: 5パターン × 100マッチ × 250文字 = 125,000文字(制限超過の可能性)
- **対策**: パターン数を5個まで制限(実用上は2-4個)、トランケート発生時はLLMが対処
---
## 成功基準
### Phase 1a(search_text実装)
**成功**:
- [ ] search_text が str | list[str] を受け取れる
- [ ] 単一パターンで既存の動作を維持(後方互換性)
- [ ] 複数パターンで並列実行(asyncio.gather)
- [ ] ユニットテストがすべてパス
### Phase 1b(検証テスト)
**成功**:
- [ ] LLMがcode.mdの並列実行指示を理解
- [ ] 複数パターンを1回で呼び出す意図を示す
- [ ] 3回のテストで2回以上成功
- [ ] 実測で15-25秒の削減を確認
- [ ] 3-4パターンでトランケートが発生しないことを確認
**失敗**:
- [ ] LLMが依然として順次呼び出し
- [ ] 指示を無視または誤解
- [ ] 3回のテストで2回以上失敗
### Phase 2(ドキュメント整備)
**前提**: Phase 1b 成功
**成功**:
- [ ] スキーマが正しく更新されている
- [ ] README/CHANGELOG に使用例が記載
- [ ] 実測テストでエラーなく動作
- [ ] 27-35秒の削減を確認
---
## 実装状況
### Phase 1a: search_text実装(1時間)
| タスク | 状態 | 所要時間 |
|--------|------|----------|
| tools/ripgrep_tool.py 修正 | ✅ 完了 | 30分 |
| _search_single 関数抽出 | ✅ 完了 | - |
| 複数パターン処理追加 | ✅ 完了 | - |
| ユニットテスト追加 | ✅ 完了 | 20分 |
| code_intel_server.py スキーマ更新 | ✅ 完了 | 10分 |
### Phase 1b: 検証テスト(1-1.5時間)
| タスク | 状態 | 所要時間 |
|--------|------|----------|
| test-parallel.md 作成 | ✅ 完了 | 20分 |
| code.md 指示追加 | ✅ 完了 | 15分 |
| 検証テスト1(EXPLORATION) | ✅ 完了 | 5分 |
| 検証テスト2(READY) | ✅ 完了 | - |
| 検証テスト3(Grep並列) | ✅ 完了 | - |
| トランケート検証(返却サイズ確認) | ✅ 完了 | - |
| 結果分析(成功/失敗判定) | ✅ 完了 | 5分 |
**検証結果**: 3/3テスト成功 → Phase 2実施を決定
### Phase 2: ドキュメント整備(Phase 1b成功時のみ、1時間)
| タスク | 状態 | 所要時間 |
|--------|------|----------|
| code_intel_server.py スキーマ確認 | ✅ 完了 | - |
| README/README_ja.md 更新 | ✅ 完了 | 20分 |
| .claude/README.md 作成(並列実行ガイド) | ✅ 完了 | 15分 |
| 実測テスト(効果確認) | ✅ 完了 | 5分 |
**Phase 2 完了**: 全ドキュメント更新完了
---
## Phase 1b 失敗時の対応
検証テストで効果が得られない場合(LLMが指示を無視する場合)、以下を検討:
### v1.8 以降での再挑戦
1. **より強力な指示**
- code.md の指示をさらに明確化
- 例を増やす
- 警告を追加
2. **プロンプトエンジニアリング**
- 並列実行の重要性を強調
- 時間削減の具体的な数値を提示
3. **別アプローチ**
- search_text の内部で自動的に並列化
- semantic_search と統合
---
## v1.8 への移行
Phase 1b(検証テスト)の結果に応じて:
### Phase 1b 成功した場合(確率 75-85%)
- Phase 2(ドキュメント整備)を完了
- v1.8 に以下を含める:
- search_text 並列化(20秒削減)← Phase 1a で実装済み
- Read/Grep 並列実行の効果(7-15秒削減)← code.md 指示
- prepare_session_batch(5秒削減)
- PRE_COMMIT順序変更(2-3秒削減)
- **v1.8 総削減**: 34-43秒(8-11%)
### Phase 1b 失敗した場合(確率 15-25%)
- Phase 2 をスキップ
- v1.8 は確実な最適化のみ
- prepare_session_batch(5秒削減)
- PRE_COMMIT順序変更(2-3秒削減)
- **v1.8 総削減**: 7-8秒(2%)← v1.6完了分(4-6秒)は含まず
- 並列化は v1.9 以降で別アプローチ検討
---
## まとめ
### v1.7 の目的
**実装 → 検証 → ドキュメント の3段階アプローチ**:
1. **Phase 1a**: search_text を複数パターン対応に拡張(必須、1時間)
2. **Phase 1b**: LLMが並列実行指示に従うか検証(必須、1-1.5時間)
3. **Phase 2**: ドキュメント整備と効果確認(Phase 1b成功時のみ、1時間)
### 期待効果
| Phase 1b 結果 | v1.7 削減時間 | v1.8 総削減 | 確率 |
|--------------|-------------|-----------|------|
| **成功** | **0秒**(実装と検証のみ) | **34-43秒**(並列化 + 他の最適化) | 75-85% |
| **失敗** | **0秒**(検証のみ) | **7-8秒**(他の最適化のみ) | 15-25% |
**注**: v1.7 自体は削減時間 0秒(実装と検証フェーズ)。削減効果は v1.8 で発現。
### 重要な発見
**並列化の影響範囲は予想以上に広い**:
- 当初計画: EXPLORATIONのみ(20秒)
- 実際の範囲: EXPLORATION + READY + その他(27-35秒)
- Read/Grepの並列実行は既にClaude Codeがサポート済み
### 次のステップ
1. **Phase 1a(1時間)**: search_text実装
- tools/ripgrep_tool.py に複数パターン対応を追加
- ユニットテストで動作確認
- code_intel_server.py のスキーマ更新
2. **Phase 1b(1-1.5時間)**: 検証テスト
- test-parallel.md(検証専用コマンド)を作成
- code.md に並列実行の指示を追加
- 3回のテストで並列実行を確認(各90秒、計4.5分)
- LLMが指示に従うか評価(成功/失敗判定)
3. **Phase 2(1時間、Phase 1b成功時のみ)**: ドキュメント整備
- スキーマ確認
- README/CHANGELOG 更新
- 実測テストで効果確認
4. **v1.8 内容確定**: Phase 1bの結果に基づく
- 成功: v1.8に並列実行の効果を含める(34-43秒削減)
- 失敗: v1.8は確実な最適化のみ(11-14秒削減)
---
## 参考資料
- [EXPLORATIONフェーズ詳細分析](../draft/exploration_phase_detailed_analysis.md)
- [v1.8予定内容](v1.8_ja.md)(元v1.7)
- [v1.7最終まとめ](../draft/v1.7_final_summary.md)(v1.8の分析)