agent-sdk/agent-loop.md +395 −0 created
1> ## Documentation Index
2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
3> Use this file to discover all available pages before exploring further.
4
5# 代理程式迴圈如何運作
6
7> 了解訊息生命週期、工具執行、上下文視窗和支援 SDK 代理程式的架構。
8
9Agent SDK 讓您可以在自己的應用程式中嵌入 Claude Code 的自主代理程式迴圈。SDK 是一個獨立套件,可讓您以程式設計方式控制工具、權限、成本限制和輸出。您不需要安裝 Claude Code CLI 即可使用它。
10
11當您啟動代理程式時,SDK 會執行與 [Claude Code 相同的執行迴圈](/zh-TW/how-claude-code-works#the-agentic-loop):Claude 評估您的提示、呼叫工具採取行動、接收結果,並重複直到任務完成。本頁說明該迴圈內發生的情況,以便您可以有效地建立、除錯和最佳化代理程式。
12
13## 迴圈概覽
14
15每個代理程式工作階段都遵循相同的週期:
16
17<img src="https://mintcdn.com/claude-code/gvy2DIUELtNA8qD3/images/agent-loop-diagram.svg?fit=max&auto=format&n=gvy2DIUELtNA8qD3&q=85&s=192e1bd6c8a2950a16e5ee0b94e27e26" alt="代理程式迴圈:提示進入、Claude 評估、分支到工具呼叫或最終答案" width="680" height="150" data-path="images/agent-loop-diagram.svg" />
18
191. **接收提示。** Claude 接收您的提示,以及系統提示、工具定義和對話歷史記錄。SDK 會產生一個 [`SystemMessage`](#message-types),其子類型為 `"init"`,包含工作階段中繼資料。
202. **評估並回應。** Claude 評估目前狀態並決定如何進行。它可能會以文字回應、要求一個或多個工具呼叫,或兩者都有。SDK 會產生一個 [`AssistantMessage`](#message-types),包含文字和任何工具呼叫要求。
213. **執行工具。** SDK 執行每個要求的工具並收集結果。每組工具結果都會回饋給 Claude 以進行下一個決定。您可以使用 [hooks](/zh-TW/agent-sdk/hooks) 在工具執行前攔截、修改或阻止工具呼叫。
224. **重複。** 步驟 2 和 3 重複為一個週期。每個完整週期是一個回合。Claude 繼續呼叫工具並處理結果,直到它產生沒有工具呼叫的回應。
235. **返回結果。** SDK 會產生最終的 [`AssistantMessage`](#message-types),包含文字回應(無工具呼叫),然後是 [`ResultMessage`](#message-types),包含最終文字、代幣使用量、成本和工作階段 ID。
24
25一個快速問題(「這裡有什麼檔案?」)可能需要一到兩個回合的 `Glob` 呼叫和結果回應。一個複雜的任務(「重構驗證模組並更新測試」)可以在許多回合中鏈接數十個工具呼叫,讀取檔案、編輯程式碼和執行測試,Claude 根據每個結果調整其方法。
26
27## 回合和訊息
28
29回合是迴圈內的一個往返:Claude 產生包含工具呼叫的輸出,SDK 執行這些工具,結果自動回饋給 Claude。這發生在不將控制權交回給您的程式碼的情況下。回合繼續進行,直到 Claude 產生沒有工具呼叫的輸出,此時迴圈結束並傳遞最終結果。
30
31考慮提示「修復 auth.ts 中失敗的測試」的完整工作階段可能是什麼樣子。
32
33首先,SDK 將您的提示發送給 Claude 並產生一個 [`SystemMessage`](#message-types),包含工作階段中繼資料。然後迴圈開始:
34
351. **回合 1:** Claude 呼叫 `Bash` 執行 `npm test`。SDK 產生一個 [`AssistantMessage`](#message-types),包含工具呼叫,執行命令,然後產生一個 [`UserMessage`](#message-types),包含輸出(三個失敗)。
362. **回合 2:** Claude 在 `auth.ts` 和 `auth.test.ts` 上呼叫 `Read`。SDK 返回檔案內容並產生一個 `AssistantMessage`。
373. **回合 3:** Claude 呼叫 `Edit` 修復 `auth.ts`,然後呼叫 `Bash` 重新執行 `npm test`。所有三個測試都通過。SDK 產生一個 `AssistantMessage`。
384. **最終回合:** Claude 產生一個純文字回應,沒有工具呼叫:「修復了驗證錯誤,所有三個測試現在都通過了。」SDK 產生最終的 `AssistantMessage`,包含此文字,然後是 [`ResultMessage`](#message-types),包含相同的文字加上成本和使用量。
39
40那是四個回合:三個有工具呼叫,一個最終純文字回應。
41
42您可以使用 `max_turns` / `maxTurns` 限制迴圈,它只計算工具使用回合。例如,上面迴圈中的 `max_turns=2` 會在編輯步驟之前停止。您也可以使用 `max_budget_usd` / `maxBudgetUsd` 根據支出閾值限制回合。
43
44沒有限制,迴圈會執行到 Claude 自己完成為止,這對於範圍明確的任務很好,但對於開放式提示(「改進此程式碼庫」)可能會執行很長時間。設定預算是生產代理程式的好預設值。請參閱下面的 [回合和預算](#turns-and-budget) 以了解選項參考。
45
46## 訊息類型
47
48當迴圈執行時,SDK 會產生一串訊息。每個訊息都帶有一個類型,告訴您它來自迴圈的哪個階段。五個核心類型是:
49
50* **`SystemMessage`:** 工作階段生命週期事件。`subtype` 欄位區分它們:`"init"` 是第一個訊息(工作階段中繼資料),`"compact_boundary"` 在 [壓縮](#automatic-compaction) 後觸發。在 TypeScript 中,壓縮邊界是其自己的 [`SDKCompactBoundaryMessage`](/zh-TW/agent-sdk/typescript#sdkcompactboundarymessage) 類型,而不是 `SDKSystemMessage` 的子類型。
51* **`AssistantMessage`:** 在每個 Claude 回應後發出,包括最終純文字回應。包含該回合的文字內容區塊和工具呼叫區塊。
52* **`UserMessage`:** 在每個工具執行後發出,包含發送回 Claude 的工具結果內容。也針對您在迴圈中期串流的任何使用者輸入發出。
53* **`StreamEvent`:** 僅在啟用部分訊息時發出。包含原始 API 串流事件(文字增量、工具輸入區塊)。請參閱 [串流回應](/zh-TW/agent-sdk/streaming-output)。
54* **`ResultMessage`:** 標記代理程式迴圈的結束。包含最終文字結果、代幣使用量、成本和工作階段 ID。檢查 `subtype` 欄位以確定任務是否成功或達到限制。少數尾隨系統事件(例如 `prompt_suggestion`)可能在其後到達,因此請迭代串流至完成,而不是在結果時中斷。請參閱 [處理結果](#handle-the-result)。
55
56這五種類型涵蓋了兩個 SDK 中完整的代理程式迴圈生命週期。TypeScript SDK 還會產生額外的可觀測性事件(hook 事件、工具進度、速率限制、任務通知),提供額外詳細資訊,但不需要驅動迴圈。請參閱 [Python 訊息類型參考](/zh-TW/agent-sdk/python#message-types) 和 [TypeScript 訊息類型參考](/zh-TW/agent-sdk/typescript#message-types) 以了解完整清單。
57
58### 處理訊息
59
60您處理哪些訊息取決於您正在建立的內容:
61
62* **僅最終結果:** 處理 `ResultMessage` 以取得輸出、成本以及任務是否成功或達到限制。
63* **進度更新:** 處理 `AssistantMessage` 以查看 Claude 在每個回合中做什麼,包括它呼叫了哪些工具。
64* **即時串流:** 啟用部分訊息(Python 中的 `include_partial_messages`、TypeScript 中的 `includePartialMessages`)以實時取得 `StreamEvent` 訊息。請參閱 [即時串流回應](/zh-TW/agent-sdk/streaming-output)。
65
66您檢查訊息類型的方式取決於 SDK:
67
68* **Python:** 使用從 `claude_agent_sdk` 匯入的類別檢查訊息類型,使用 `isinstance()`(例如,`isinstance(message, ResultMessage)`)。
69* **TypeScript:** 檢查 `type` 字串欄位(例如,`message.type === "result"`)。`AssistantMessage` 和 `UserMessage` 將原始 API 訊息包裝在 `.message` 欄位中,因此內容區塊位於 `message.message.content`,而不是 `message.content`。
70
71<Accordion title="範例:檢查訊息類型並處理結果">
72 <CodeGroup>
73 ```python Python theme={null}
74 from claude_agent_sdk import query, AssistantMessage, ResultMessage
75
76 async for message in query(prompt="Summarize this project"):
77 if isinstance(message, AssistantMessage):
78 print(f"Turn completed: {len(message.content)} content blocks")
79 if isinstance(message, ResultMessage):
80 if message.subtype == "success":
81 print(message.result)
82 else:
83 print(f"Stopped: {message.subtype}")
84 ```
85
86 ```typescript TypeScript theme={null}
87 import { query } from "@anthropic-ai/claude-agent-sdk";
88
89 for await (const message of query({ prompt: "Summarize this project" })) {
90 if (message.type === "assistant") {
91 console.log(`Turn completed: ${message.message.content.length} content blocks`);
92 }
93 if (message.type === "result") {
94 if (message.subtype === "success") {
95 console.log(message.result);
96 } else {
97 console.log(`Stopped: ${message.subtype}`);
98 }
99 }
100 }
101 ```
102 </CodeGroup>
103</Accordion>
104
105## 工具執行
106
107工具讓您的代理程式能夠採取行動。沒有工具,Claude 只能以文字回應。有了工具,Claude 可以讀取檔案、執行命令、搜尋程式碼並與外部服務互動。
108
109### 內建工具
110
111SDK 包含與 Claude Code 相同的工具:
112
113| 類別 | 工具 | 它們的作用 |
114| :------- | :-------------------------------------------- | :---------------------- |
115| **檔案操作** | `Read`、`Edit`、`Write` | 讀取、修改和建立檔案 |
116| **搜尋** | `Glob`、`Grep` | 按模式查找檔案、使用正規表達式搜尋內容 |
117| **執行** | `Bash` | 執行 shell 命令、指令碼、git 操作 |
118| **Web** | `WebSearch`、`WebFetch` | 搜尋網路、擷取和解析頁面 |
119| **探索** | `ToolSearch` | 動態查找和按需加載工具,而不是預先加載所有工具 |
120| **協調** | `Agent`、`Skill`、`AskUserQuestion`、`TodoWrite` | 生成子代理程式、呼叫技能、詢問使用者、追蹤任務 |
121
122除了內建工具,您還可以:
123
124* **使用 [MCP 伺服器](/zh-TW/agent-sdk/mcp) 連接外部服務**(資料庫、瀏覽器、API)
125* **使用 [自訂工具處理程式](/zh-TW/agent-sdk/custom-tools) 定義自訂工具**
126* **透過 [設定來源](/zh-TW/agent-sdk/claude-code-features) 加載專案技能**以實現可重複使用的工作流程
127
128### 工具權限
129
130Claude 根據任務決定呼叫哪些工具,但您控制這些呼叫是否允許執行。您可以自動批准特定工具、完全阻止其他工具,或要求對所有工具進行批准。三個選項一起工作以確定運行的內容:
131
132* **`allowed_tools` / `allowedTools`** 自動批准列出的工具。具有 `["Read", "Glob", "Grep"]` 在其允許工具清單中的唯讀代理程式會執行這些工具而不提示。未列出的工具仍然可用,但需要權限。
133* **`disallowed_tools` / `disallowedTools`** 阻止列出的工具,無論其他設定如何。請參閱 [權限](/zh-TW/agent-sdk/permissions) 以了解在工具執行前檢查規則的順序。
134* **`permission_mode` / `permissionMode`** 控制對不受允許或拒絕規則涵蓋的工具會發生什麼。請參閱 [權限模式](#permission-mode) 以了解可用的模式。
135
136您也可以使用 `"Bash(npm *)"` 之類的規則來限定個別工具,以僅允許特定命令。請參閱 [權限](/zh-TW/agent-sdk/permissions) 以了解完整的規則語法。
137
138當工具被拒絕時,Claude 會收到一條拒絕訊息作為工具結果,通常會嘗試不同的方法或報告它無法繼續。
139
140### 平行工具執行
141
142當 Claude 在單個回合中要求多個工具呼叫時,兩個 SDK 可以根據工具同時或順序執行它們。唯讀工具(如 `Read`、`Glob`、`Grep` 和標記為唯讀的 MCP 工具)可以同時執行。修改狀態的工具(如 `Edit`、`Write` 和 `Bash`)順序執行以避免衝突。
143
144自訂工具預設為順序執行。要為自訂工具啟用平行執行,請在其註釋中設定 `readOnlyHint`。[TypeScript](/zh-TW/agent-sdk/typescript#tool) 和 [Python](/zh-TW/agent-sdk/python#tool) SDK 都使用 MCP SDK 中的此欄位名稱。
145
146## 控制迴圈如何執行
147
148您可以限制迴圈執行的回合數、成本、Claude 推理的深度,以及工具是否需要在執行前獲得批准。所有這些都是 [`ClaudeAgentOptions`](/zh-TW/agent-sdk/python#claudeagentoptions)(Python)/ [`Options`](/zh-TW/agent-sdk/typescript#options)(TypeScript)上的欄位。
149
150### 回合和預算
151
152| 選項 | 它控制什麼 | 預設值 |
153| :-------------------------------------- | :--------- | :-- |
154| 最大回合(`max_turns` / `maxTurns`) | 最大工具使用往返次數 | 無限制 |
155| 最大預算(`max_budget_usd` / `maxBudgetUsd`) | 停止前的最大成本 | 無限制 |
156
157當達到任一限制時,SDK 會返回一個 `ResultMessage`,其中包含相應的錯誤子類型(`error_max_turns` 或 `error_max_budget_usd`)。請參閱 [處理結果](#handle-the-result) 以了解如何檢查這些子類型,以及 [`ClaudeAgentOptions`](/zh-TW/agent-sdk/python#claudeagentoptions) / [`Options`](/zh-TW/agent-sdk/typescript#options) 以了解語法。
158
159### 努力等級
160
161`effort` 選項控制 Claude 應用多少推理。較低的努力等級每個回合使用更少的代幣並降低成本。並非所有模型都支援努力參數。請參閱 [努力](https://platform.claude.com/docs/en/build-with-claude/effort) 以了解哪些模型支援它。
162
163| 等級 | 行為 | 適合 |
164| :--------- | :-------- | :----------------------- |
165| `"low"` | 最少推理、快速回應 | 檔案查找、列出目錄 |
166| `"medium"` | 平衡推理 | 常規編輯、標準任務 |
167| `"high"` | 徹底分析 | 重構、除錯 |
168| `"xhigh"` | 擴展推理深度 | 編碼和代理任務;建議在 Opus 4.7 上使用 |
169| `"max"` | 最大推理深度 | 需要深入分析的多步驟問題 |
170
171如果您不設定 `effort`,Python SDK 會保留參數未設定,並遵循模型的預設行為。TypeScript SDK 預設為 `"high"`。
172
173<Note>
174 `effort` 在每個回應內交換延遲和代幣成本以獲得推理深度。[擴展思考](https://platform.claude.com/docs/en/build-with-claude/extended-thinking) 是一個單獨的功能,在輸出中產生可見的思考鏈區塊。它們是獨立的:您可以設定 `effort: "low"` 並啟用擴展思考,或 `effort: "max"` 而不啟用它。
175</Note>
176
177對於執行簡單、範圍明確的任務(如列出檔案或執行單個 grep)的代理程式,使用較低的努力來降低成本和延遲。在頂級 `query()` 選項中設定 `effort` 以用於整個工作階段,或在 [`AgentDefinition`](/zh-TW/agent-sdk/subagents#agentdefinition-configuration) 上使用 `effort` 欄位以每個子代理程式為基礎覆蓋工作階段等級。
178
179### 權限模式
180
181權限模式選項(Python 中的 `permission_mode`、TypeScript 中的 `permissionMode`)控制代理程式是否在使用工具前要求批准:
182
183| 模式 | 行為 |
184| :--------------------- | :------------------------------------------------------------------------------------------------ |
185| `"default"` | 不受允許規則涵蓋的工具會觸發您的批准回呼;沒有回呼意味著拒絕 |
186| `"acceptEdits"` | 自動批准檔案編輯和常見的檔案系統命令(`mkdir`、`touch`、`mv`、`cp` 等);其他 Bash 命令遵循預設規則 |
187| `"plan"` | 唯讀工具執行;Claude 探索並產生計畫而不編輯您的原始檔案 |
188| `"dontAsk"` | 永不提示。由 [權限規則](/zh-TW/settings#permission-settings) 預先批准的工具執行,其他所有工具都被拒絕 |
189| `"auto"`(僅 TypeScript) | 使用模型分類器批准或拒絕每個工具呼叫。請參閱 [自動模式](/zh-TW/permission-modes#eliminate-prompts-with-auto-mode) 以了解可用性和行為 |
190| `"bypassPermissions"` | 執行所有允許的工具而不詢問。在 Unix 上以 root 身份執行時無法使用。僅在隔離環境中使用,其中代理程式的操作無法影響您關心的系統 |
191
192對於互動式應用程式,使用 `"default"` 和工具批准回呼來顯示批准提示。對於開發機器上的自主代理程式,`"acceptEdits"` 自動批准檔案編輯和常見的檔案系統命令(`mkdir`、`touch`、`mv`、`cp` 等),同時仍然在允許規則後面限制其他 `Bash` 命令。為 CI、容器或其他隔離環境保留 `"bypassPermissions"`。請參閱 [權限](/zh-TW/agent-sdk/permissions) 以了解完整詳細資訊。
193
194### 模型
195
196如果您不設定 `model`,SDK 會使用 Claude Code 的預設值,這取決於您的驗證方法和訂閱。明確設定它(例如,`model="claude-sonnet-4-6"`)以固定特定模型或使用較小的模型以獲得更快、更便宜的代理程式。請參閱 [模型](https://platform.claude.com/docs/en/about-claude/models) 以了解可用的 ID。
197
198## 上下文視窗
199
200上下文視窗是工作階段期間可用於 Claude 的資訊總量。它不會在工作階段內的回合之間重置。所有內容都會累積:系統提示、工具定義、對話歷史記錄、工具輸入和工具輸出。在回合之間保持相同的內容(系統提示、工具定義、CLAUDE.md)會自動 [提示快取](https://platform.claude.com/docs/en/build-with-claude/prompt-caching),這會減少重複前綴的成本和延遲。
201
202### 什麼消耗上下文
203
204以下是每個元件如何影響 SDK 中上下文的方式:
205
206| 來源 | 何時加載 | 影響 |
207| :--------------- | :------------------------------------------------------------------ | :----------------------------------------------------------------------------- |
208| **系統提示** | 每個請求 | 小的固定成本,始終存在 |
209| **CLAUDE.md 檔案** | 工作階段開始,透過 [`settingSources`](/zh-TW/agent-sdk/claude-code-features) | 每個請求中的完整內容(但提示快取,因此只有第一個請求支付完整成本) |
210| **工具定義** | 每個請求 | 每個工具添加其架構;使用 [MCP 工具搜尋](/zh-TW/agent-sdk/mcp#mcp-tool-search) 按需加載工具,而不是一次全部加載 |
211| **對話歷史記錄** | 在回合中累積 | 隨著每個回合增長:提示、回應、工具輸入、工具輸出 |
212| **技能描述** | 工作階段開始,透過設定來源 | 簡短摘要;完整內容僅在呼叫時加載 |
213
214大型工具輸出消耗大量上下文。讀取大檔案或執行具有詳細輸出的命令可以在單個回合中使用數千個代幣。上下文在回合中累積,因此具有許多工具呼叫的較長工作階段比短工作階段建立更多上下文。
215
216### 自動壓縮
217
218當上下文視窗接近其限制時,SDK 會自動壓縮對話:它總結較舊的歷史記錄以釋放空間,保持您最近的交換和關鍵決定完整。SDK 在串流中發出一個 `type: "system"` 和 `subtype: "compact_boundary"` 的訊息(在 Python 中這是一個 `SystemMessage`;在 TypeScript 中它是一個單獨的 `SDKCompactBoundaryMessage` 類型)。
219
220壓縮用摘要替換較舊的訊息,因此對話早期的特定指示可能不會被保留。持久規則應該在 CLAUDE.md 中(透過 [`settingSources`](/zh-TW/agent-sdk/claude-code-features) 加載),而不是在初始提示中,因為 CLAUDE.md 內容在每個請求時重新注入。
221
222您可以透過多種方式自訂壓縮行為:
223
224* **CLAUDE.md 中的摘要指示:** 壓縮器像任何其他上下文一樣讀取您的 CLAUDE.md,因此您可以包含一個部分,告訴它在摘要時要保留什麼。部分標題是自由格式的(不是魔法字串);壓縮器根據意圖匹配。
225* **`PreCompact` hook:** 在壓縮發生前執行自訂邏輯,例如存檔完整成績單。hook 接收一個 `trigger` 欄位(`manual` 或 `auto`)。請參閱 [hooks](/zh-TW/agent-sdk/hooks)。
226* **手動壓縮:** 將 `/compact` 作為提示字串發送以按需觸發壓縮。(以這種方式發送的斜線命令是 SDK 輸入,而不是僅限 CLI 的快捷方式。請參閱 [SDK 中的斜線命令](/zh-TW/agent-sdk/slash-commands)。)
227
228<Accordion title="範例:CLAUDE.md 中的摘要指示">
229 將一個部分添加到您的專案的 CLAUDE.md,告訴壓縮器要保留什麼。標題名稱不是特殊的;使用任何清晰的標籤。
230
231 ```markdown CLAUDE.md theme={null}
232 # Summary instructions
233
234 When summarizing this conversation, always preserve:
235 - The current task objective and acceptance criteria
236 - File paths that have been read or modified
237 - Test results and error messages
238 - Decisions made and the reasoning behind them
239 ```
240</Accordion>
241
242### 保持上下文高效
243
244長時間執行代理程式的幾個策略:
245
246* **為子任務使用子代理程式。** 每個子代理程式以新鮮的對話開始(沒有先前的訊息歷史記錄,儘管它確實加載自己的系統提示和專案級上下文,如 CLAUDE.md)。它看不到父級的回合,只有其最終回應作為工具結果返回給父級。主代理程式的上下文增長該摘要,而不是完整的子任務成績單。請參閱 [子代理程式繼承什麼](/zh-TW/agent-sdk/subagents#what-subagents-inherit) 以了解詳細資訊。
247* **選擇性地使用工具。** 每個工具定義都佔用上下文空間。在 [`AgentDefinition`](/zh-TW/agent-sdk/subagents#agentdefinition-configuration) 上使用 `tools` 欄位將子代理程式限制在它們需要的最小集合,並使用 [MCP 工具搜尋](/zh-TW/agent-sdk/mcp#mcp-tool-search) 按需加載工具,而不是預先加載所有工具。
248* **監視 MCP 伺服器成本。** 每個 MCP 伺服器將其所有工具架構添加到每個請求。具有許多工具的幾個伺服器可以在代理程式執行任何工作之前消耗大量上下文。`ToolSearch` 工具可以透過按需加載工具而不是預先加載所有工具來幫助。請參閱 [MCP 工具搜尋](/zh-TW/agent-sdk/mcp#mcp-tool-search) 以了解配置。
249* **為常規任務使用較低的努力。** 為僅需要讀取檔案或列出目錄的代理程式設定 [努力](#effort-level) 為 `"low"`。這會減少代幣使用量和成本。
250
251有關每個功能上下文成本的詳細分解,請參閱 [了解上下文成本](/zh-TW/features-overview#understand-context-costs)。
252
253## 工作階段和連續性
254
255與 SDK 的每次互動都會建立或繼續一個工作階段。從 `ResultMessage.session_id`(在兩個 SDK 中都可用)捕獲工作階段 ID 以稍後恢復。TypeScript SDK 也將其公開為初始化 `SystemMessage` 上的直接欄位;在 Python 中,它嵌套在 `SystemMessage.data` 中。
256
257當您恢復時,先前回合的完整上下文會被恢復:讀取的檔案、執行的分析和採取的操作。您也可以分叉一個工作階段以分支到不同的方法,而不修改原始工作階段。
258
259請參閱 [工作階段管理](/zh-TW/agent-sdk/sessions) 以了解恢復、繼續和分叉模式的完整指南。
260
261<Note>
262 在 Python 中,`ClaudeSDKClient` 在多個呼叫中自動處理工作階段 ID。請參閱 [Python SDK 參考](/zh-TW/agent-sdk/python#choosing-between-query-and-claudesdkclient) 以了解詳細資訊。
263</Note>
264
265## 處理結果
266
267當迴圈結束時,`ResultMessage` 告訴您發生了什麼並給您輸出。`subtype` 欄位(在兩個 SDK 中都可用)是檢查終止狀態的主要方式。
268
269| 結果子類型 | 發生了什麼 | `result` 欄位可用? |
270| :------------------------------------ | :----------------------- | :------------: |
271| `success` | Claude 正常完成了任務 | 是 |
272| `error_max_turns` | 在完成前達到 `maxTurns` 限制 | 否 |
273| `error_max_budget_usd` | 在完成前達到 `maxBudgetUsd` 限制 | 否 |
274| `error_during_execution` | 錯誤中斷了迴圈(例如,API 失敗或取消的請求) | 否 |
275| `error_max_structured_output_retries` | 結構化輸出驗證在配置的重試限制後失敗 | 否 |
276
277`result` 欄位(最終文字輸出)僅在 `success` 變體上存在,因此在讀取它之前始終檢查子類型。所有結果子類型都帶有 `total_cost_usd`、`usage`、`num_turns` 和 `session_id`,因此您可以追蹤成本並在錯誤後恢復。在 Python 中,`total_cost_usd` 和 `usage` 被類型化為可選的,在某些錯誤路徑上可能是 `None`,因此在格式化它們之前進行保護。請參閱 [追蹤成本和使用量](/zh-TW/agent-sdk/cost-tracking) 以了解有關解釋 `usage` 欄位的詳細資訊。
278
279結果還包括一個 `stop_reason` 欄位(TypeScript 中的 `string | null`、Python 中的 `str | None`),指示模型為什麼在最後一個回合停止生成。常見值是 `end_turn`(模型正常完成)、`max_tokens`(達到輸出代幣限制)和 `refusal`(模型拒絕了請求)。在錯誤結果子類型上,`stop_reason` 帶有迴圈結束前最後一個助手回應的值。要檢測拒絕,請檢查 `stop_reason === "refusal"`(TypeScript)或 `stop_reason == "refusal"`(Python)。請參閱 [`SDKResultMessage`](/zh-TW/agent-sdk/typescript#sdkresultmessage)(TypeScript)或 [`ResultMessage`](/zh-TW/agent-sdk/python#resultmessage)(Python)以了解完整類型。
280
281## Hooks
282
283[Hooks](/zh-TW/agent-sdk/hooks) 是在迴圈中的特定點觸發的回呼:在工具執行前、執行後、代理程式完成時等。一些常用的 hooks 是:
284
285| Hook | 何時觸發 | 常見用途 |
286| :------------------------------- | :----------- | :------------ |
287| `PreToolUse` | 在工具執行前 | 驗證輸入、阻止危險命令 |
288| `PostToolUse` | 在工具返回後 | 審計輸出、觸發副作用 |
289| `UserPromptSubmit` | 當提示被發送時 | 將額外上下文注入提示 |
290| `Stop` | 當代理程式完成時 | 驗證結果、保存工作階段狀態 |
291| `SubagentStart` / `SubagentStop` | 當子代理程式生成或完成時 | 追蹤和聚合平行任務結果 |
292| `PreCompact` | 在上下文壓縮前 | 在摘要前存檔完整成績單 |
293
294Hooks 在您的應用程式進程中執行,而不是在代理程式的上下文視窗內,因此它們不消耗上下文。Hooks 也可以短路迴圈:拒絕工具呼叫的 `PreToolUse` hook 會阻止它執行,Claude 會收到拒絕訊息。
295
296兩個 SDK 都支援上述所有事件。TypeScript SDK 包含 Python 尚不支援的額外事件。請參閱 [使用 hooks 控制執行](/zh-TW/agent-sdk/hooks) 以了解完整的事件清單、每個 SDK 的可用性和完整的回呼 API。
297
298## 將其全部整合在一起
299
300此範例將本頁的關鍵概念組合成一個修復失敗測試的單個代理程式。它使用允許的工具(自動批准,以便代理程式自主執行)、專案設定和回合和推理努力的安全限制來配置代理程式。當迴圈執行時,它捕獲工作階段 ID 以進行潛在恢復、處理最終結果並列印總成本。
301
302<CodeGroup>
303 ```python Python theme={null}
304 import asyncio
305 from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
306
307
308 async def run_agent():
309 session_id = None
310
311 async for message in query(
312 prompt="Find and fix the bug causing test failures in the auth module",
313 options=ClaudeAgentOptions(
314 allowed_tools=[
315 "Read",
316 "Edit",
317 "Bash",
318 "Glob",
319 "Grep",
320 ], # Listing tools here auto-approves them (no prompting)
321 setting_sources=[
322 "project"
323 ], # Load CLAUDE.md, skills, hooks from current directory
324 max_turns=30, # Prevent runaway sessions
325 effort="high", # Thorough reasoning for complex debugging
326 ),
327 ):
328 # Handle the final result
329 if isinstance(message, ResultMessage):
330 session_id = message.session_id # Save for potential resumption
331
332 if message.subtype == "success":
333 print(f"Done: {message.result}")
334 elif message.subtype == "error_max_turns":
335 # Agent ran out of turns. Resume with a higher limit.
336 print(f"Hit turn limit. Resume session {session_id} to continue.")
337 elif message.subtype == "error_max_budget_usd":
338 print("Hit budget limit.")
339 else:
340 print(f"Stopped: {message.subtype}")
341 if message.total_cost_usd is not None:
342 print(f"Cost: ${message.total_cost_usd:.4f}")
343
344
345 asyncio.run(run_agent())
346 ```
347
348 ```typescript TypeScript theme={null}
349 import { query } from "@anthropic-ai/claude-agent-sdk";
350
351 let sessionId: string | undefined;
352
353 for await (const message of query({
354 prompt: "Find and fix the bug causing test failures in the auth module",
355 options: {
356 allowedTools: ["Read", "Edit", "Bash", "Glob", "Grep"], // Listing tools here auto-approves them (no prompting)
357 settingSources: ["project"], // Load CLAUDE.md, skills, hooks from current directory
358 maxTurns: 30, // Prevent runaway sessions
359 effort: "high" // Thorough reasoning for complex debugging
360 }
361 })) {
362 // Save the session ID to resume later if needed
363 if (message.type === "system" && message.subtype === "init") {
364 sessionId = message.session_id;
365 }
366
367 // Handle the final result
368 if (message.type === "result") {
369 if (message.subtype === "success") {
370 console.log(`Done: ${message.result}`);
371 } else if (message.subtype === "error_max_turns") {
372 // Agent ran out of turns. Resume with a higher limit.
373 console.log(`Hit turn limit. Resume session ${sessionId} to continue.`);
374 } else if (message.subtype === "error_max_budget_usd") {
375 console.log("Hit budget limit.");
376 } else {
377 console.log(`Stopped: ${message.subtype}`);
378 }
379 console.log(`Cost: $${message.total_cost_usd.toFixed(4)}`);
380 }
381 }
382 ```
383</CodeGroup>
384
385## 後續步驟
386
387現在您了解了迴圈,以下是根據您正在建立的內容去往何處:
388
389* **還沒有執行代理程式?** 從 [快速入門](/zh-TW/agent-sdk/quickstart) 開始,以安裝 SDK 並查看完整範例端到端執行。
390* **準備好連接到您的專案?** [加載 CLAUDE.md、技能和檔案系統 hooks](/zh-TW/agent-sdk/claude-code-features),以便代理程式自動遵循您的專案約定。
391* **建立互動式 UI?** 啟用 [串流](/zh-TW/agent-sdk/streaming-output) 以在迴圈執行時顯示即時文字和工具呼叫。
392* **需要對代理程式可以做什麼進行更嚴格的控制?** 使用 [權限](/zh-TW/agent-sdk/permissions) 鎖定工具存取,並使用 [hooks](/zh-TW/agent-sdk/hooks) 在工具執行前審計、阻止或轉換工具呼叫。
393* **執行長期或昂貴的任務?** 將隔離的工作卸載到 [子代理程式](/zh-TW/agent-sdk/subagents) 以保持主上下文精簡。
394
395有關代理程式迴圈的更廣泛概念圖片(不是 SDK 特定的),請參閱 [Claude Code 如何運作](/zh-TW/how-claude-code-works)。