Agent 卡住了,還在查 process、thread、event loop?Agentic 時代的第四種 blocking — protocol blocking。
很多工程師看到 Agent 卡住,第一個反應都是看 process、thread 或 event loop。我最近在研究 Claude Code 的 agent loop 時,發現 Agentic 時代其實多了一種新的 protocol blocking,而且它跟前面三種完全不是同一件事。
前三種 blocking,我們都很熟
以前遇到程式卡住,大概都是從幾個方向開始找。
- process 被作業系統掛起,整個程式不能執行。
- thread 卡在 lock、syscall 或某個同步點,一條執行緒沒辦法繼續往下。
- 到了 async 與 event loop 的時代,事情又更細了一點。某個函式在 await,不代表整個程式真的被 block,它可以先把 promise 收起來,讓 event loop 繼續處理其他工作。
這三種 blocking,本質上都很單純。程式不能繼續執行。
Agent 時代開始出現第四種。它還是可以執行,但是沒有合法的下一步。
Protocol Blocking:卡在 protocol 的第四種 blocking
我是在一個很簡單的現象裡注意到這件事。
Claude Code 在執行一個 long running sub-agent 時,主線上的對話會先卡住。但同一個時間,我輸入 /btw 問另一個問題,它卻可以立刻送出新的 API request,而且很快得到回覆。
這個現象其實排除了很多可能。process 沒有當掉,不然新的 request 發不出去。event loop 也沒有停,不然 UI 不可能還能繼續 render,也不可能處理新的輸入。從外部行為來看,runtime 一直都還活著。
真正卡住的,是主線那條對話本身。
問題不是 runtime,而是 protocol
原因其實很單純。在 Claude Messages API 裡,只要 assistant message 出現一個 tool_use,下一個 user message 就必須帶著對應的 tool_result 回來。
sub-agent 在 protocol 層,其實就是一個 tool。它有自己的 context window、自己的 agent loop,也繼承完整的工具能力。能力上,它就是一個完整的 Agent。但站在 main agent 的角度,它仍然只是一個 tool call。
當 main agent 說:「我要呼叫這個 tool。」在 tool 回來之前,它就組不出下一個合法的 request。
所以卡住的不是 CPU、不是 thread、不是 event loop,而是 protocol 根本沒有定義,現在還能往下說什麼。
這就是我最近看到的第四種 blocking。
為什麼 /btw 可以回答?
/btw 可以立即回答使用者提問,它很有意思。它沒有插進原本那條對話,而是在主線之外另外 launch 一個一次性的 LLM request。所以它可以正常回答。
某種程度上,/btw 反而變成一個很好用的診斷工具。如果主線卡住,但 /btw 還能回答,就代表 runtime 還活著、API 也是通的。真正卡住的是主線那條 protocol。
結果,還是收據?
這時候再看 Codex,就會發現另一種設計。
Codex 的 sub-agent 不會直接回傳結果,而是先回一個 agent id。也就是先回一張收據(handle)。真正需要結果時,再另外 wait。
這個差別看起來很小,但其實會直接影響整個 agentic system 的設計。
如果一個 tool 同時負責「開始工作」和「回傳結果」,呼叫端就必須一路等到它做完。但如果它先回一個 handle,之後再查詢狀態,控制流就自由很多。background task、steering、平行化,甚至人在什麼時候介入,都跟這個介面設計有關。
很多人以為這是在討論 performance。我反而覺得,這是在討論 interface。
Agentic 時代的新 blocking
當然,non-blocking 也不是沒有代價。
像 Claude Code 現在的 background sub-agent,如果執行過程遇到新的 permission approval,就會開始碰到治理問題。哪些權限可以預先批准?哪些一定要有人確認?這些都是另一個層面的設計。所以全部背景化,不一定就是最好的答案。
我現在會把 blocking 粗略分成四種:
- process blocking:程式不能執行。
- thread blocking:執行緒停住。
- event loop/async waiting:目前工作暫停,但 runtime 還能繼續做其他事。
- protocol blocking:控制流其實是自由的,但沒有合法的下一步訊息可以送。
這第四種 blocking,以後設計上只會越來越常見。因為 tool call、sub-agent、MCP、remote runtime、background task,最後都會收斂到同一條對話控制流裡。
設計一個 tool,或串一個 MCP server,第一個會問的是:它回的是結果,還是一張收據?
很多 blocking,是在等待資源。但 Agentic 時代開始出現另一種 blocking。
它等待的,不是資源。
是 protocol 允許 Agent 做的下一步。
