沒有循環,就沒有 agent
Claude Code 的整個秘密可以寫成一行:while stop_reason == "tool_use"
一個 agent 到底在做什麼?
當你在終端機裡跑 Claude Code、讓它「把所有 TODO 註解整理成一份清單」,你看到的是:它自己決定先 grep、再 cat 幾個文件、然後輸出 Markdown。 模型本身不會執行程式碼-它只會請求執行。真正讓它看起來「有手有腳」的,是它外面那一圈 30 行左右的膠水代碼。
這一課就是要把那圈膠水拆開看清楚。它叫做 agent loop(智能體循環),結構就是:
while response.stop_reason == "tool_use": response = LLM(messages, tools) # 1. ask the model execute_tools(response.tool_calls) # 2. run what it asked for messages.append(tool_results) # 3. feed results back
就這樣。沒了。 production 的 Claude Code 在這上面疊了權限、hook、子 agent、worktree 隔離、記憶壓縮——但核心還是這四行。
關鍵直覺:模型每次回覆要不是「我想調工具」,就是「我說完了」。只要還在前一種狀態,循環就繼續;一旦進入後一種狀態,循環就退出。 判據是回應裡的 stop_reason 欄位。
看 messages[] 一步步長出來
下面這個循環模擬的任務是:「目前目錄有哪些檔案?然後讀 package.json」。點 Step,每按前進一個循環內的動作。左邊是給人看的對話氣泡,右邊是真正塞給模型的 messages[] 陣列——注意看它如何增長。
工具結果必須重新進入訊息歷史
新手最容易踩的坑,是把「執行工具」當成一個副作用-執行了就完事了。但模型下一輪推理只能看到 messages[],不在裡面的東西它就不知道發生過。少 append 一步,整個循環就錯了。
錯法不是都一樣的。常見兩種:
- 忘記 append:模型下一輪看不到結果,它會再問一次同一個工具--於是你得到一個無限循環。
- append 了但丟掉
tool_use_id:Anthropic API 會直接報錯tool_result must have tool_use_id,循環崩在 API 呼叫那一步。
同一個任務:「統計專案裡有多少個 Python 檔案」。兩個版本並排跑,看結局差。
讀懂 stop_reason
模型每次回都會帶一個 stop_reason。決定要不要繼續循環,就看這個欄位:
tool_use— 模型想調工具,繼續循環。end_turn— 模型覺得說完了,退出循環。max_tokens— 生成到了 token 上限被截斷,退出循環(一般當異常處理,提示用戶輸出不完整)。stop_sequence— 碰到自訂停止串,退出循環。
寫錯成「只要沒 tool_use 就繼續」,或忽略 max_tokens 直接當作正常 end,都是常見 bug。
動手跑一下
本地克隆 shareAI-lab/learn-claude-code:
git clone https://github.com/shareAI-lab/learn-claude-code cd learn-claude-code pip install -r requirements.txt cp .env.example .env # fill in ANTHROPIC_API_KEY python agents/s01_agent_loop.py
然後讓它做點真事:帮我数一下这个仓库里有多少 .py 文件。你會看到它發一條 ls -R、看到輸出、再發一條 find . -name "*.py" | wc -l、然後告訴你答案。整個過程就是這個 loop 在循環。