目錄

在深度使用 Claude Code 的日常開發中,許多開發者都曾經歷過這種令人抓狂的場景:
- 終端執行一個簡單的指令,程式碼明明已經改完了,游標卻突然卡住;
- 終端介面停留在最後一行的
Stop Hooks或Evaluating next action,少則乾等三五分鐘,多則十幾分鍾毫無動靜; - 電腦風扇狂轉,Node.js 程序記憶體持續攀升,有時候甚至伴隨著磁碟臨時目錄被佔滿。
很多人的第一反應通常是:「是不是網路又抽風了?」或者是「哪個 MCP 外掛寫壞了?」,接著開始盲目地把本機裝的外掛一個個解除安裝、重灌、重啟終端,結果折騰了一兩個小時,問題依舊反覆出現。
面對這種由複雜 AI 代理鏈路引發的深層卡死,盲目的人工試錯效率極低。
本文記錄一次極具啟發性的實戰案例:我們不靠玄學猜測,而是直接把 Claude Code 自身的效能瓶頸日誌餵給它自己,讓 AI 深入分析自己的執行架構併成功實現「自我修復」。

一、 核心痛點與現象覆盤
在出現嚴重卡頓的會話中,系統的典型異常特徵通常表現為:
- 多工程並行下的記憶體暴漲: 本機啟動 2-3 個工程會話後,系統常駐記憶體飆升至數個 GB,伴隨著大量懸掛的子程序沒有被正確清理;
- 任務收尾階段的假死(Stop Hooks Stalls): 每次程式碼修改和工具呼叫執行完畢,在即將把控制權交還給使用者時,進度條永遠卡在停止鉤子(Stop Hooks)環節;
- 不可預測的長等待: 偶爾能恢復響應,但耗時長達 3 分 30 秒以上,開發者的心流被打得支離破碎。
與其胡亂猜測,我直接在終端提取了當時的追蹤日誌與呼叫棧,向 Claude 下達了一條診斷指令:
请详细分析当前 Claude Code 在执行 Stop Hooks 阶段的所有系统调用、插件注册列表与网络等待耗时。
找出导致最后一次退出评估耗时超过 3 分钟的底层瓶颈,并给出架构级的自愈解决方案。
二、 讓 AI 自己排查自己:兩大根因浮出水面
讓 AI 進行自我診斷的威力在於,它能夠快速把分散在不同設定層級與原始碼模組中的隱蔽線索串聯起來。不到兩分鐘,Claude 輸出了兩個致命的底層瓶頸:
根因 1:多層級冗餘元件重複註冊(MCP 衝突)
在 Claude Code 的擴充功能生態中,MCP(Model Context Protocol)工具可以在多個層級被定義:
- Local(當前專案目錄下的
.claude/); - User(使用者主目錄下的全域設定
~/.claude/); - Built-in(系統內建的預設支援)。
診斷髮現:像 Playwright 這樣的重型自動化元件,居然同時在 Local、User 和 Built-in 三個位置被重複註冊。
這意味著每一次 Agent 初始化或準備退出時,底層框架都會對這三個重複的協議端點進行三次獨立的握手探測與設定載入,極易導致區域性埠爭用與程序掛起。
根因 2:Stop Hooks 評估呼叫缺少超時保護與重試熔斷
這是導致卡死數分鐘的真正元兇。
在 Claude Code 的停止判定邏輯中,當一次任務即將結束時,系統會啟動一個新的子例項或發出一組判定請求,呼叫模型 API 評估:「當前任務是否已完全解決?是否還有殘留報錯需要繼續迴圈?」
這個判定流程包含以下不可控環節:
- 發起遠端 API 請求並等待服務端推理響應;
- 接收資料流並反序列化複雜的 JSON 狀態物件;
- 底層呼叫居然沒有設定硬性的超時時間(Timeout)!
一旦遇到網路瞬時抖動、代理丟包或上游 API 響應遲緩,整個評估函式就會陷入無限等待狀態。沒有任何重試中斷機制,直到底層作業系統 TCP 連線徹底超時斷開(通常需要數分鐘),使用者才能重新拿回終端控制權。
三、 三步組合自愈方案
針對上述定位,我們聯合實施了一套輕量、確定性極高的組合解法。
第 1 步:元件去重與懶載入治理
徹底梳理全域與本機設定:
- 解除安裝全域與本機重複設定的 MCP 例項,同類工具嚴格保持「全域唯一單一事實源」;
- 對於非常駐的高耗能工具(如瀏覽器自動化測試),從開機自啟列表中移除,改為專案需要時再顯式啟用。
完成清理後,終端的啟動時間立竿見影地縮短了 60%。
第 2 步:增加 30 秒硬超時保護(Timeout Circuit Breaker)
在負責執行評估呼叫的 API 封裝層,注入嚴格的 AbortController 機制,封死無限死等的漏洞:
// 伪代码:为评估调用增加硬性超时熔断
async function evaluateStopConditionWithTimeout(context: AgentContext): Promise<boolean> {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
console.warn('[Watchdog] Stop Hook 评估超时(30s),强制熔断交还控制权');
}, 30000); // 30 秒超时上限
try {
const response = await fetch(API_ENDPOINT, {
signal: controller.signal,
method: 'POST',
body: JSON.stringify(buildEvaluationPayload(context)),
});
return await parseEvaluationResult(response);
} catch (err) {
if (err.name === 'AbortError') {
// 超时直接降级为安全退出,杜绝死锁
return true;
}
throw err;
} finally {
clearTimeout(timeoutId);
}
}
第 3 步:引入上下文 MD5 評估快取機制
很多時候,開發者在除錯時會連續執行幾個極其類似的驗證動作,此時程式碼變更極小或對話上下文完全一致。
我們在評估層加入基於上下文指紋的輕量快取:
- 提取當前任務的最後三輪對話文字與核心狀態,計算一個 MD5 雜湊鍵;
- 如果在 5 分鐘內遇到了相同雜湊的判定請求,直接複用上一次的評估結果返回,不再發起遠端 API 呼叫。
四、 效果驗證:立竿見影的效能提升
完成上述最佳化後,我們重新對全鏈路執行了基準壓測,實測資料如下:
| 評估指標 | 最佳化前狀態 | 最佳化後實測 | 提升幅度 |
|---|---|---|---|
| 首次冷啟動任務評估 | 3 分 39 秒 | 1 ~ 2 秒 | 提升 99%+ |
| 重複或連續相似指令評估 | 30 秒 ~ 2 分鐘 | < 1 毫秒(命中快取) | 提升 99.9%+ |
| 異常弱網/API 抖動表現 | 無限掛起死等 | 30 秒強制熔斷交還終端 | 徹底消除死鎖 |
五、 經驗總結
當我們在日常開發中使用越來越複雜的 AI Agent 工具時,遇到效能卡頓或死鎖問題:
- 不要盲目抓瞎解除安裝:AI 代理系統的呼叫鏈路深,靠肉眼猜測往往只能治標不治本;
- 善用「讓 AI 分析 AI」的診斷思路:把堆疊、程序樹和網路時延如實交給大模型,它能比人類更快地指出死鎖與競態條件的根源;
- 給所有非同步判定焊死超時與降級門禁:永遠不要假設外部網路或上游模型會按時響應。在任何自動化 Hook 節點中,30 秒超時熔斷與結果快取,都是保衛開發者流暢體驗的生命線。