迭代式檢索模式 (Iterative Retrieval Pattern)
解決多代理工作流程中的「背景資訊問題」,即子代理在開始工作前無法預知所需上下文的情況。
何時啟用
- 需要為子代理提供其無法事先預測的程式碼庫上下文時
- 建構需要逐步精煉上下文的多代理工作流程時
- 遇到因「上下文過大」或「遺失上下文」而導致的代理任務失敗時
- 設計用於程式碼探索的 RAG(檢索增強生成)檢索管線時
- 最佳化代理協調過程中的 Token 使用量時
問題
子代理被賦予有限的上下文。它們不知道:
- 哪些檔案包含相關程式碼
- 程式碼庫中存在哪些模式
- 專案使用了哪些術語
標準方法均會失敗:
- 全部發送:超出上下文限制
- 什麼都不發送:代理缺乏關鍵資訊
- 猜測所需內容:通常猜錯
解決方案:迭代式檢索
一個由 4 個階段組成的循環,逐步精煉上下文:
┌─────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 調度 │─────│ 評估 │ │
│ └──────────┘ └──────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 循環 │─────│ 精煉 │ │
│ └──────────┘ └──────────┘ │
│ │
│ 最多 3 個循環,之後繼續進行 │
└─────────────────────────────────────────────┘
階段 1:調度 (DISPATCH)
初始的廣泛查詢,用以收集候選檔案:
// 從高層級意圖開始
const initialQuery = {
patterns: ['src/**/*.ts', 'lib/**/*.ts'],
keywords: ['authentication', 'user', 'session'],
excludes: ['*.test.ts', '*.spec.ts']
};
// 調度給檢索代理
const candidates = await retrieveFiles(initialQuery);
階段 2:評估 (EVALUATE)
評估檢索到的內容之相關性:
function evaluateRelevance(files, task) {
return files.map(file => ({
path: file.path,
relevance: scoreRelevance(file.content, task),
reason: explainRelevance(file.content, task),
missingContext: identifyGaps(file.content, task)
}));
}
評分標準:
- 高 (0.8-1.0):直接實作了目標功能
- 中 (0.5-0.7):包含相關模式或型別
- 低 (0.2-0.4):僅稍微相關
- 無 (0-0.2):不相關,將其排除
階段 3:精煉 (REFINE)
根據評估結果更新搜尋條件:
function refineQuery(evaluation, previousQuery) {
return {
// 新增在高度相關的檔案中發現的模式
patterns: [...previousQuery.patterns, ...extractPatterns(evaluation)],
// 新增在程式碼庫中發現的術語
keywords: [...previousQuery.keywords, ...extractKeywords(evaluation)],
// 排除已確認為不相關的路徑
excludes: [...previousQuery.excludes, ...evaluation
.filter(e => e.relevance < 0.2)
.map(e => e.path)
],
// 針對特定缺口
focusAreas: evaluation
.flatMap(e => e.missingContext)
.filter(unique)
};
}
階段 4:循環 (LOOP)
使用精煉後的條件重複執行(最多 3 次循環):
async function iterativeRetrieve(task, maxCycles = 3) {
let query = createInitialQuery(task);
let bestContext = [];
for (let cycle = 0; cycle < maxCycles; cycle++) {
const candidates = await retrieveFiles(query);
const evaluation = evaluateRelevance(candidates, task);
// 檢查是否已擁有足夠的上下文
const highRelevance = evaluation.filter(e => e.relevance >= 0.7);
if (highRelevance.length >= 3 && !hasCriticalGaps(evaluation)) {
return highRelevance;
}
// 精煉並繼續
query = refineQuery(evaluation, query);
bestContext = mergeContext(bestContext, highRelevance);
}
return bestContext;
}
實務範例
範例 1:錯誤修正上下文
任務:「修復認證 Token 過期錯誤」
循環 1:
調度:在 src/** 中搜尋 "token"、"auth"、"expiry"
評估:找到 auth.ts (0.9)、tokens.ts (0.8)、user.ts (0.3)
精煉:新增 "refresh"、"jwt" 關鍵字;排除 user.ts
循環 2:
調度:使用精煉後的術語搜尋
評估:找到 session-manager.ts (0.95)、jwt-utils.ts (0.85)
精煉:上下文已足夠(2 個高相關性檔案)
結果:auth.ts、tokens.ts、session-manager.ts、jwt-utils.ts
範例 2:功能實作
任務:「為 API 端點新增速率限制」
循環 1:
調度:在 routes/** 中搜尋 "rate"、"limit"、"api"
評估:無相符結果 - 程式碼庫使用 "throttle" 術語
精煉:新增 "throttle"、"middleware" 關鍵字
循環 2:
調度:使用精煉後的術語搜尋
評估:找到 throttle.ts (0.9)、middleware/index.ts (0.7)
精煉:需要路由器模式
循環 3:
調度:搜尋 "router"、"express" 模式
評估:找到 router-setup.ts (0.8)
精煉:上下文已足夠
結果:throttle.ts、middleware/index.ts、router-setup.ts
與代理的整合
在代理提示中使用:
為此任務檢索上下文時:
1. 從廣泛的關鍵字搜尋開始
2. 評估每個檔案的相關性(0-1 級別)
3. 識別仍缺少哪些上下文
4. 精煉搜尋條件並重複(最多 3 次循環)
5. 回傳相關性 >= 0.7 的檔案
最佳實踐
- 由廣到窄,逐步收斂 - 不要過度指定初始查詢
- 學習程式碼庫術語 - 第一個循環通常能揭示命名慣例
- 追蹤遺漏內容 - 明確識別缺口以驅動精煉方向
- 在「夠好」時停止 - 3 個高度相關的檔案勝過 10 個平庸的
- 果斷排除 - 低相關性的檔案不太可能變得相關
相關資源
- The Longform Guide - 子代理協調章節
continuous-learning技能 - 針對隨時間改進的模式- 與 ECC 一同定義的代理(手動安裝路徑:
agents/)