Agent SDK cho phép bạn nhúng agent loop tự động của Claude Code vào ứng dụng của riêng bạn. SDK là một package độc lập, cho bạn quyền kiểm soát lập trình đối với tool, permission, giới hạn chi phí, và output. Bạn không cần cài Claude Code CLI để dùng nó.
Khi bạn khởi động một agent, SDK chạy cùng execution loop đang vận hành Claude Code: Claude đánh giá prompt của bạn, gọi tool để hành động, nhận kết quả, và lặp lại cho tới khi tác vụ hoàn thành. Trang này giải thích điều gì xảy ra bên trong vòng lặp đó để bạn có thể xây dựng, debug, và tối ưu agent của mình hiệu quả.
Vòng lặp nhìn tổng quan
Phần tiêu đề “Vòng lặp nhìn tổng quan”Mỗi phiên agent đều theo cùng một chu trình:
- Nhận prompt. Claude nhận prompt của bạn, cùng với system prompt, định nghĩa tool, và lịch sử hội thoại. SDK yield một
SystemMessagevới subtype"init"chứa metadata của session. - Đánh giá và phản hồi. Claude đánh giá trạng thái hiện tại và quyết định cách tiến hành. Nó có thể phản hồi bằng text, yêu cầu một hoặc nhiều lời gọi tool, hoặc cả hai. SDK yield một
AssistantMessagechứa text và các yêu cầu gọi tool. - Thực thi tool. SDK chạy từng tool được yêu cầu và thu thập kết quả. Mỗi bộ kết quả tool được đưa lại cho Claude để ra quyết định tiếp theo. Bạn có thể dùng hooks để chặn, sửa, hoặc block lời gọi tool trước khi nó chạy.
- Lặp lại. Bước 2 và 3 lặp lại thành một chu trình. Mỗi chu trình đầy đủ là một turn. Claude tiếp tục gọi tool và xử lý kết quả cho tới khi nó tạo ra phản hồi không có lời gọi tool nào.
- Trả kết quả. SDK yield một
AssistantMessagecuối cùng với phản hồi text (không có lời gọi tool), theo sau bởi mộtResultMessagechứa text cuối cùng, token usage, chi phí, và session ID.
Một câu hỏi nhanh (“có những file gì ở đây?”) có thể chỉ mất một hoặc hai turn gọi Glob rồi phản hồi kết quả. Một tác vụ phức tạp (“refactor module auth và update test”) có thể chuỗi hàng chục lời gọi tool qua nhiều turn - đọc file, sửa code, chạy test - với Claude điều chỉnh cách tiếp cận dựa trên từng kết quả.
Turn và message
Phần tiêu đề “Turn và message”Một turn là một lượt đi-về bên trong vòng lặp: Claude tạo ra output bao gồm lời gọi tool, SDK thực thi các tool đó, và kết quả được đưa lại cho Claude tự động. Điều này xảy ra mà không trả quyền điều khiển lại cho code của bạn. Turn tiếp tục cho tới khi Claude tạo ra output không có lời gọi tool, lúc đó vòng lặp kết thúc và kết quả cuối cùng được trả về.
Xem thử một phiên đầy đủ trông như thế nào với prompt “Fix the failing tests in auth.ts”.
Đầu tiên, SDK gửi prompt của bạn cho Claude và yield một SystemMessage với metadata session. Sau đó vòng lặp bắt đầu:
- Turn 1: Claude gọi
Bashđể chạynpm test. SDK yield mộtAssistantMessagevới lời gọi tool, thực thi lệnh, rồi yield mộtUserMessagevới output (ba lỗi). - Turn 2: Claude gọi
Readtrênauth.tsvàauth.test.ts. SDK trả về nội dung file và yield mộtAssistantMessage. - Turn 3: Claude gọi
Editđể sửaauth.ts, rồi gọiBashđể chạy lạinpm test. Cả ba test đều pass. SDK yield mộtAssistantMessage. - Turn cuối: Claude tạo ra phản hồi chỉ có text, không có lời gọi tool: “Fixed the auth bug, all three tests pass now.” SDK yield một
AssistantMessagecuối cùng với text này, rồi mộtResultMessagevới cùng text cộng thêm chi phí và usage.
Đó là bốn turn: ba turn có lời gọi tool, một turn phản hồi chỉ text.
Bạn có thể giới hạn vòng lặp với max_turns / maxTurns, thứ chỉ đếm các turn có dùng tool. Ví dụ, max_turns=2 trong vòng lặp trên sẽ dừng trước bước sửa file. Bạn cũng có thể dùng max_budget_usd / maxBudgetUsd để giới hạn turn dựa trên ngưỡng chi tiêu.
Không có giới hạn, vòng lặp chạy cho tới khi Claude tự hoàn thành - ổn với các tác vụ được scope tốt, nhưng có thể chạy lâu với prompt mở (“improve this codebase”). Đặt một budget là mặc định hợp lý cho agent production. Xem Turn và budget bên dưới để biết tham số cụ thể.
Các loại message
Phần tiêu đề “Các loại message”Khi vòng lặp chạy, SDK yield một luồng message. Mỗi message mang một type cho biết nó đến từ giai đoạn nào của vòng lặp. Năm type cốt lõi là:
-
SystemMessage: các sự kiện vòng đời session. Trườngsubtypephân biệt chúng:"init": metadata session cho lần chạy. Khi hookSessionStarthoặcSetupchạy trong lúc khởi động session, các message vòng đời hook của nó đến trước messageinit"compact_boundary": xuất hiện sau khi compaction"informational": banner trạng thái dạng text thuần từ vòng lặp"worker_shutting_down": vòng lặp sẽ kết thúc sau turn hiện tại vì host đang thoát hoặc Remote Control ngắt kết nối
Trong TypeScript, mỗi subtype khác
"init"là một type riêng trong unionSDKMessagethay vì một subtype củaSDKSystemMessage. -
AssistantMessage: phát ra sau mỗi phản hồi của Claude, kể cả phản hồi chỉ-text cuối cùng. Chứa các content block text và block gọi tool từ turn đó. -
UserMessage: phát ra sau mỗi lần thực thi tool với nội dung kết quả tool gửi lại cho Claude. Cũng phát ra cho bất kỳ input nào bạn stream giữa chừng vòng lặp. -
StreamEvent: chỉ phát ra khi partial message được bật. Chứa raw streaming event thô từ API. Xem Stream responses. -
ResultMessage: đánh dấu kết thúc agent loop. Chứa kết quả text cuối cùng, token usage, chi phí, và session ID. Kiểm tra trườngsubtypeđể xác định tác vụ thành công hay chạm giới hạn. Một số ít sự kiện hệ thống theo sau, nhưprompt_suggestion, có thể xuất hiện sau nó, nên lặp stream tới khi hoàn tất thay vì break ngay khi thấy result. Xem Xử lý kết quả.
Năm type này bao phủ toàn bộ vòng đời agent loop. Cả hai SDK đều yield thêm các sự kiện observability như trạng thái rate-limit và thông báo task, không bắt buộc để vận hành vòng lặp.
Xử lý message
Phần tiêu đề “Xử lý message”Bạn cần xử lý message nào tuỳ thuộc vào thứ bạn đang xây:
- Chỉ cần kết quả cuối: xử lý
ResultMessageđể lấy output, chi phí, và tác vụ thành công hay chạm giới hạn. - Cập nhật tiến trình: xử lý
AssistantMessageđể xem Claude đang làm gì mỗi turn, kể cả tool nào nó gọi. - Streaming trực tiếp: bật partial message (
include_partial_messagestrong Python,includePartialMessagestrong TypeScript) để nhậnStreamEventtheo thời gian thực. Xem Stream response theo thời gian thực.
Cách kiểm tra type của message tuỳ theo SDK:
- Python: kiểm tra type message bằng
isinstance()với các class import từclaude_agent_sdk(ví dụ,isinstance(message, ResultMessage)). - TypeScript: kiểm tra trường string
type(ví dụ,message.type === "result").AssistantMessagevàUserMessagebọc message API thô trong trường.message, nên content block nằm ởmessage.message.content, không phảimessage.content.
Ví dụ: kiểm tra type message và xử lý kết quả
import asynciofrom claude_agent_sdk import query, AssistantMessage, ResultMessage
async def main(): try: async for message in query(prompt="Summarize this project"): if isinstance(message, AssistantMessage): print(f"Turn completed: {len(message.content)} content blocks") if isinstance(message, ResultMessage): if message.subtype == "success": print(message.result) else: print(f"Stopped: {message.subtype}") except Exception as error: # Một lời gọi query() single-shot raise lỗi sau khi yield result lỗi. Nếu # lỗi đến từ result lỗi, các nhánh subtype ở trên đã chạy rồi; # lỗi kết nối hoặc process không yield result message nào cả. print(f"Session ended with an error: {error}")
asyncio.run(main())import { query } from "@anthropic-ai/claude-agent-sdk";
try { for await (const message of query({ prompt: "Summarize this project" })) { if (message.type === "assistant") { console.log(`Turn completed: ${message.message.content.length} content blocks`); } if (message.type === "result") { if (message.subtype === "success") { console.log(message.result); } else { console.log(`Stopped: ${message.subtype}`); } } }} catch (error) { // Một lời gọi query() single-shot throw lỗi sau khi yield result lỗi. Nếu // lỗi đến từ result lỗi, các nhánh subtype ở trên đã chạy rồi; // lỗi kết nối hoặc process không yield result message nào cả. console.log(`Session ended with an error: ${error}`);}Thực thi tool
Phần tiêu đề “Thực thi tool”Tool cho agent của bạn khả năng hành động. Không có tool, Claude chỉ có thể phản hồi bằng text. Có tool, Claude có thể đọc file, chạy lệnh, tìm kiếm code, và tương tác với dịch vụ bên ngoài.
Built-in tools
Phần tiêu đề “Built-in tools”SDK bao gồm cùng bộ tool đang vận hành Claude Code:
| Nhóm | Tools | Chúng làm gì |
|---|---|---|
| File operations | Read, Edit, Write | Đọc, sửa, và tạo file |
| Search | Glob, Grep | Tìm file theo pattern, tìm nội dung bằng regex |
| Execution | Bash | Chạy shell command, script, thao tác git |
| Web | WebSearch, WebFetch | Tìm kiếm trên web, fetch và parse trang |
| Discovery | ToolSearch | Tìm và load tool động khi cần, thay vì preload hết |
| Orchestration | Agent, Skill, AskUserQuestion, TaskCreate, TaskUpdate | Sinh subagent, gọi skill, hỏi người dùng, theo dõi task |
Ngoài built-in tool, bạn có thể:
- Kết nối dịch vụ bên ngoài với MCP servers (database, browser, API)
- Định nghĩa tool tuỳ biến với custom tool handlers
- Load skill của project qua setting sources cho workflow tái sử dụng
Tool permission
Phần tiêu đề “Tool permission”Claude quyết định gọi tool nào dựa trên tác vụ, nhưng bạn kiểm soát liệu các lời gọi đó có được phép thực thi hay không. Bạn có thể tự động phê duyệt tool cụ thể, chặn tool khác hoàn toàn, hoặc yêu cầu phê duyệt cho mọi thứ. Ba option phối hợp với nhau để quyết định điều gì chạy:
allowed_tools/allowedToolstự động phê duyệt các tool trong danh sách. Một agent chỉ-đọc với["Read", "Glob", "Grep"]trong allowed tools list chạy các tool đó mà không cần hỏi. Tool không nằm trong danh sách vẫn khả dụng nhưng cần phê duyệt.disallowed_tools/disallowedToolschặn tool trong danh sách, bất kể cấu hình khác.permission_mode/permissionModekiểm soát điều gì xảy ra với tool không nằm trong allow hay deny rule. Xem Permission mode để biết các mode khả dụng.
Bạn cũng có thể scope tool cụ thể với rule như "Bash(npm *)" để chỉ cho phép một số lệnh nhất định.
Khi một tool bị từ chối, Claude nhận được thông báo từ chối làm kết quả tool và thường thử cách tiếp cận khác hoặc báo rằng nó không thể tiếp tục.
Thực thi tool song song
Phần tiêu đề “Thực thi tool song song”Khi Claude yêu cầu nhiều lời gọi tool trong một turn, cả hai SDK có thể chạy chúng đồng thời hoặc tuần tự tuỳ tool. Tool chỉ-đọc (như Read, Glob, Grep, và MCP tool được đánh dấu read-only) có thể chạy đồng thời. Tool làm thay đổi trạng thái (như Edit, Write, và Bash) chạy tuần tự để tránh xung đột.
Custom tool mặc định chạy tuần tự. Để bật thực thi song song cho một custom tool, đặt readOnlyHint trong annotation của nó.
Kiểm soát vòng lặp chạy như thế nào
Phần tiêu đề “Kiểm soát vòng lặp chạy như thế nào”Bạn có thể giới hạn số turn vòng lặp thực hiện, chi phí bao nhiêu, Claude suy luận sâu tới đâu, và tool có cần phê duyệt trước khi chạy hay không. Tất cả đều là trường trên ClaudeAgentOptions (Python) / Options (TypeScript).
Turn và budget
Phần tiêu đề “Turn và budget”| Option | Nó kiểm soát gì | Mặc định |
|---|---|---|
Max turns (max_turns / maxTurns) | Số round trip có dùng tool tối đa | Không giới hạn |
Max budget (max_budget_usd / maxBudgetUsd) | Chi phí tối đa trước khi dừng | Không giới hạn |
Khi chạm một trong hai giới hạn, SDK trả về ResultMessage với subtype lỗi tương ứng (error_max_turns hoặc error_max_budget_usd). Xem Xử lý kết quả để biết cách kiểm tra các subtype này.
Giới hạn budget bao gồm cả subagent: chi tiêu của chúng tính vào tổng. Khi đã chạm giới hạn, việc sinh subagent mới thất bại với Budget limit reached, và Claude Code dừng mọi subagent chạy nền còn lại.
Với streaming input, một message bạn gửi khi một turn vẫn đang chạy sẽ được xếp hàng chờ khi turn đó kết thúc do chạm giới hạn max-turns, và nó bắt đầu turn riêng với giới hạn max-turns riêng.
Effort level
Phần tiêu đề “Effort level”Option effort kiểm soát mức độ suy luận Claude áp dụng. Effort level thấp hơn dùng ít token hơn mỗi turn và giảm chi phí. Không phải model nào cũng hỗ trợ tham số effort.
| Level | Hành vi | Phù hợp cho |
|---|---|---|
"low" | Suy luận tối thiểu, phản hồi nhanh | Tra cứu file, liệt kê thư mục |
"medium" | Suy luận cân bằng | Sửa đổi thông thường, tác vụ tiêu chuẩn |
"high" | Phân tích kỹ lưỡng | Refactor, debug |
"xhigh" | Suy luận sâu mở rộng | Task coding và agentic; khuyến nghị trên Fable 5, Opus 4.7+, và Sonnet 5 |
"max" | Suy luận sâu tối đa | Bài toán nhiều bước cần phân tích sâu |
Nếu bạn không đặt effort, cả hai SDK để tham số này trống và giao cho hành vi mặc định của model.
Dùng effort thấp hơn cho agent làm tác vụ đơn giản, được scope rõ (như liệt kê file hay chạy một grep) để giảm chi phí và độ trễ. Đặt effort trong option top-level của query() cho cả session, hoặc theo từng subagent với trường effort trên AgentDefinition để override cấp session.
Permission mode
Phần tiêu đề “Permission mode”Option permission mode (permission_mode trong Python, permissionMode trong TypeScript) kiểm soát agent có hỏi phê duyệt trước khi dùng tool hay không:
| Mode | Hành vi | Use case |
|---|---|---|
"default" | Tool không được cover bởi allow rule sẽ trigger callback canUseTool của bạn; không có callback nghĩa là từ chối | Ứng dụng tương tác với callback phê duyệt tuỳ biến |
"acceptEdits" | Tự động phê duyệt sửa file và các lệnh filesystem thông thường (mkdir, touch, mv, cp, v.v.); các lệnh Bash khác theo rule mặc định | Bạn tin tưởng thay đổi của Claude và muốn lặp nhanh hơn, ví dụ khi prototype hoặc làm việc trong thư mục cô lập |
"plan" | Claude khám phá và lên kế hoạch mà không sửa file nguồn của bạn; sửa file không bao giờ được tự động phê duyệt và luôn hỏi qua callback canUseTool | Bạn muốn Claude đề xuất thay đổi mà không thực thi, ví dụ khi review code hoặc cần phê duyệt thay đổi trước khi thực hiện |
"dontAsk" | Không bao giờ hỏi. Tool được phê duyệt trước bởi permission rule sẽ chạy; mọi thứ khác bị từ chối. AskUserQuestion, connector tool được tổ chức của bạn đặt là ask, và MCP tool đánh dấu requiresUserInteraction bị từ chối ngay cả khi bạn đã allow | Bạn muốn một môi trường tool cố định, rõ ràng cho headless agent và thích từ chối cứng hơn là phụ thuộc ngầm vào canUseTool bị thiếu |
"auto" | Dùng một model classifier để phê duyệt hoặc từ chối permission prompt | Agent tự động vẫn muốn có guardrail an toàn cho việc dùng tool |
"bypassPermissions" | Chạy mọi tool được phép mà không hỏi, trừ tool khớp một ask rule tường minh, connector tool được tổ chức của bạn đặt là ask, và tool cần tương tác người dùng. Trong TypeScript SDK, cũng cần allowDangerouslySkipPermissions: true trong options. Không thể dùng khi chạy với quyền root trên Unix. Chỉ dùng trong môi trường cô lập mà hành động của agent không ảnh hưởng tới hệ thống bạn quan tâm | CI, container, hoặc môi trường cô lập khác |
Với ứng dụng tương tác, dùng "default" cùng callback phê duyệt tool để hiện prompt phê duyệt. Với agent tự động trên máy dev, "acceptEdits" tự động phê duyệt sửa file và lệnh filesystem thông thường trong khi vẫn gate các lệnh Bash khác sau allow rule. Dành "bypassPermissions" cho CI, container, hoặc môi trường cô lập khác.
Model
Phần tiêu đề “Model”Nếu bạn không đặt model, SDK dùng mặc định của Claude Code, tuỳ thuộc vào phương thức xác thực và gói đăng ký của bạn. Đặt nó tường minh (ví dụ, model="claude-sonnet-5") để ghim một model cụ thể hoặc dùng model nhỏ hơn cho agent nhanh, rẻ hơn.
Context window
Phần tiêu đề “Context window”Context window là tổng lượng thông tin khả dụng cho Claude trong một session. Nó không reset giữa các turn trong cùng một session. Mọi thứ đều tích luỹ: system prompt, định nghĩa tool, lịch sử hội thoại, input tool, và output tool. Nội dung không đổi qua các turn (system prompt, định nghĩa tool, CLAUDE.md) được tự động prompt cached, giúp giảm chi phí và độ trễ cho các prefix lặp lại.
Điều gì tiêu tốn context
Phần tiêu đề “Điều gì tiêu tốn context”Đây là cách mỗi thành phần ảnh hưởng tới context trong SDK:
| Nguồn | Khi nào load | Ảnh hưởng |
|---|---|---|
| System prompt | Mọi request | Chi phí cố định nhỏ, luôn hiện diện |
| File CLAUDE.md | Khi bắt đầu session, qua settingSources | Nội dung đầy đủ trong mỗi request (nhưng được prompt-cached, nên chỉ request đầu tiên trả chi phí đầy đủ) |
| Định nghĩa tool | Mọi request; MCP schema mặc định deferred | Schema built-in tool load mỗi request. Tool search hoãn schema MCP tool theo mặc định, fallback về load trước trên Google Cloud’s Agent Platform, một ANTHROPIC_BASE_URL không phải first-party, hoặc một deployment Microsoft Foundry host trên Azure |
| Lịch sử hội thoại | Tích luỹ theo turn | Tăng theo mỗi turn: prompt, phản hồi, input tool, output tool |
| Mô tả skill | Khi bắt đầu session, qua setting sources | Tóm tắt ngắn; nội dung đầy đủ chỉ load khi được gọi |
Output tool lớn tiêu tốn context đáng kể. Đọc một file lớn hay chạy lệnh với output dài dòng có thể dùng hàng nghìn token chỉ trong một turn. Context tích luỹ qua các turn, nên session dài với nhiều lời gọi tool xây dựng nhiều context hơn đáng kể so với session ngắn.
Compaction tự động
Phần tiêu đề “Compaction tự động”Khi context window gần chạm giới hạn, SDK tự động nén hội thoại: nó tóm tắt lịch sử cũ hơn để giải phóng không gian, giữ nguyên các trao đổi gần đây nhất và quyết định quan trọng. SDK phát ra một message với type: "system" và subtype: "compact_boundary" trong stream khi điều này xảy ra.
Compaction thay thế message cũ bằng một bản tóm tắt, nên các chỉ dẫn cụ thể từ đầu hội thoại có thể không được giữ lại. Các quy tắc lâu dài nên nằm trong CLAUDE.md (load qua settingSources) thay vì trong prompt ban đầu, vì nội dung CLAUDE.md được đưa lại vào mỗi request.
Bạn có thể tuỳ biến hành vi compaction theo vài cách:
- Chỉ dẫn tóm tắt trong CLAUDE.md: Bộ nén đọc CLAUDE.md của bạn như mọi context khác, nên bạn có thể thêm một phần nói cho nó biết cần giữ gì khi tóm tắt. Tiêu đề phần là tự do (không phải magic string); bộ nén khớp theo ý định.
- Hook
PreCompact: Chạy logic tuỳ biến trước khi compaction xảy ra, ví dụ để lưu trữ toàn bộ transcript. Hook nhận trườngtrigger(manualhoặcauto). - Compaction thủ công: Gửi
/compactnhư một chuỗi prompt để trigger compaction theo yêu cầu. Lệnh gửi theo cách này là SDK input, không phải shortcut chỉ dành cho CLI.
Ví dụ: chỉ dẫn tóm tắt trong CLAUDE.md
Thêm một phần vào CLAUDE.md của project nói cho bộ nén biết cần giữ gì. Tên tiêu đề không đặc biệt; dùng bất kỳ nhãn rõ ràng nào.
# Summary instructions
When summarizing this conversation, always preserve:- The current task objective and acceptance criteria- File paths that have been read or modified- Test results and error messages- Decisions made and the reasoning behind themGiữ context hiệu quả
Phần tiêu đề “Giữ context hiệu quả”Vài chiến lược cho agent chạy dài:
- Dùng subagent cho subtask. Mỗi subagent bắt đầu với hội thoại mới hoàn toàn (không có lịch sử message trước, dù nó vẫn load system prompt riêng và context cấp project như CLAUDE.md). Nó không thấy các turn của parent, và chỉ phản hồi cuối cùng trả về parent như kết quả tool. Context của agent chính tăng theo bản tóm tắt đó, không phải toàn bộ transcript subtask.
- Chọn lọc tool. Mỗi định nghĩa tool chiếm không gian context. Dùng trường
toolstrênAgentDefinitionđể scope subagent về tập tối thiểu chúng cần. - Theo dõi chi phí MCP server. Tool search MCP hoãn schema MCP tool theo mặc định và load theo yêu cầu. Khi tool search tắt hoặc đã fallback về load trước, mỗi MCP server thêm toàn bộ schema tool của nó vào mỗi request, nên vài server với nhiều tool có thể tiêu tốn context đáng kể trước khi agent làm bất kỳ việc gì.
- Dùng effort thấp hơn cho tác vụ thường ngày. Đặt effort thành
"low"cho agent chỉ cần đọc file hay liệt kê thư mục. Điều này giảm token usage và chi phí.
Session và tính liên tục
Phần tiêu đề “Session và tính liên tục”Mỗi tương tác với SDK tạo hoặc tiếp tục một session. Lấy session ID từ ResultMessage.session_id (có ở cả hai SDK) để resume sau này. TypeScript SDK cũng expose nó như một trường trực tiếp trên SystemMessage init; trong Python nó nằm lồng trong SystemMessage.data.
Khi bạn resume, toàn bộ context từ các turn trước được khôi phục: file đã đọc, phân tích đã thực hiện, và hành động đã làm. Bạn cũng có thể fork một session để rẽ nhánh sang cách tiếp cận khác mà không sửa bản gốc.
Xem Quản lý session để biết hướng dẫn đầy đủ về resume, continue, và fork. Để resume session xuyên các container stateless hay serverless host, truyền một session_store / sessionStore adapter để transcript được mirror sang backend riêng của bạn và bất kỳ host nào cũng resume được. Subprocess Claude Code vẫn ghi vào đĩa local trước; đặt CLAUDE_CONFIG_DIR trỏ tới một thư mục tạm trong options.env nếu bản copy local cần là ephemeral.
Xử lý kết quả
Phần tiêu đề “Xử lý kết quả”Khi vòng lặp kết thúc, ResultMessage cho bạn biết điều gì đã xảy ra và trả kết quả. Trường subtype (có ở cả hai SDK) là cách chính để kiểm tra trạng thái kết thúc.
| Result subtype | Điều gì đã xảy ra | Có trường result? |
|---|---|---|
success | Claude hoàn thành tác vụ bình thường | Có |
error_max_turns | Chạm giới hạn maxTurns trước khi hoàn thành | Không |
error_max_budget_usd | Chạm giới hạn maxBudgetUsd trước khi hoàn thành | Không |
error_during_execution | Một lỗi làm gián đoạn vòng lặp (ví dụ, lỗi API hoặc request bị huỷ) | Không |
error_max_structured_output_retries | Không có structured output hợp lệ nào được tạo trong giới hạn retry cấu hình: mọi lần thử đều lỗi validation, hoặc model fallback rút lại output đã hoàn thành mà không có retry thành công | Không |
Trường result (output text cuối cùng) chỉ có ở variant success, nên luôn kiểm tra subtype trước khi đọc nó. Mọi result subtype đều mang total_cost_usd, usage, num_turns, và session_id để bạn theo dõi chi phí và resume ngay cả sau lỗi. Trong Python, total_cost_usd và usage được đánh kiểu optional và có thể là None trên một số path lỗi, nên hãy guard trước khi format chúng.
Kết quả cũng bao gồm trường stop_reason (string | null trong TypeScript, str | None trong Python) cho biết vì sao model dừng tạo output ở turn cuối. Giá trị phổ biến gồm end_turn (model hoàn thành bình thường), max_tokens (chạm giới hạn token output), và refusal (model từ chối yêu cầu). Trên result subtype lỗi, stop_reason mang giá trị từ phản hồi assistant cuối cùng trước khi vòng lặp kết thúc. Để phát hiện refusal, kiểm tra stop_reason === "refusal" (TypeScript) hoặc stop_reason == "refusal" (Python).
Hooks
Phần tiêu đề “Hooks”Hooks là callback chạy tại các điểm cụ thể trong vòng lặp: trước khi tool chạy, sau khi nó trả về, khi agent hoàn thành, v.v. Một số hook thường dùng:
| Hook | Khi nó chạy | Dùng phổ biến |
|---|---|---|
PreToolUse | Trước khi tool thực thi | Validate input, chặn lệnh nguy hiểm |
PostToolUse | Sau khi tool trả về | Audit output, trigger side effect |
UserPromptSubmit | Khi một prompt được gửi | Chèn thêm context vào prompt |
Stop | Khi agent hoàn thành | Validate kết quả, lưu trạng thái session |
SubagentStart / SubagentStop | Khi một subagent sinh ra hoặc hoàn tất | Theo dõi và tổng hợp kết quả task song song |
PreCompact | Trước khi context compaction | Lưu trữ toàn bộ transcript trước khi tóm tắt |
Hooks chạy trong process ứng dụng của bạn, không phải bên trong context window của agent, nên chúng không tiêu tốn context. Hooks cũng có thể short-circuit vòng lặp: một hook PreToolUse từ chối một lời gọi tool ngăn nó thực thi, và Claude nhận được thông báo từ chối thay vào đó.
Cả hai SDK hỗ trợ mọi sự kiện ở trên. TypeScript SDK bao gồm thêm các sự kiện mà Python chưa hỗ trợ.
Kết hợp lại
Phần tiêu đề “Kết hợp lại”Ví dụ này kết hợp các khái niệm chính từ trang này thành một agent duy nhất sửa test thất bại. Nó cấu hình agent với allowed tools (tự động phê duyệt để agent chạy tự động), project settings, và giới hạn an toàn về turn và effort suy luận. Khi vòng lặp chạy, nó lưu session ID để có thể resume sau, xử lý kết quả cuối cùng, và in tổng chi phí.
Vì một lời gọi query() single-shot raise lỗi sau khi yield result lỗi, vòng lặp được bọc trong try block để script thoát gọn gàng khi chạm giới hạn.
import asynciofrom claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def run_agent(): session_id = None
try: async for message in query( prompt="Find and fix the bug causing test failures in the auth module", options=ClaudeAgentOptions( allowed_tools=[ "Read", "Edit", "Bash", "Glob", "Grep", ], # Liệt kê tool ở đây sẽ tự động phê duyệt (không hỏi) setting_sources=[ "project" ], # Load CLAUDE.md, skill, hook từ thư mục hiện tại max_turns=30, # Ngăn session chạy vô tận effort="high", # Suy luận kỹ lưỡng cho debug phức tạp ), ): # Xử lý kết quả cuối cùng if isinstance(message, ResultMessage): session_id = message.session_id # Lưu để có thể resume sau
if message.subtype == "success": print(f"Done: {message.result}") elif message.subtype == "error_max_turns": # Agent hết turn. Resume với giới hạn cao hơn. print(f"Hit turn limit. Resume session {session_id} to continue.") elif message.subtype == "error_max_budget_usd": print("Hit budget limit.") else: print(f"Stopped: {message.subtype}") if message.total_cost_usd is not None: print(f"Cost: ${message.total_cost_usd:.4f}") except Exception as error: # Một lời gọi query() single-shot raise lỗi sau khi yield result lỗi. Nếu # lỗi đến từ result lỗi, các nhánh subtype ở trên đã chạy rồi; # lỗi kết nối hoặc process không yield result message nào cả. print(f"Session ended with an error: {error}")
asyncio.run(run_agent())import { query } from "@anthropic-ai/claude-agent-sdk";
let sessionId: string | undefined;
try { for await (const message of query({ prompt: "Find and fix the bug causing test failures in the auth module", options: { allowedTools: ["Read", "Edit", "Bash", "Glob", "Grep"], // Liệt kê tool ở đây sẽ tự động phê duyệt (không hỏi) settingSources: ["project"], // Load CLAUDE.md, skill, hook từ thư mục hiện tại maxTurns: 30, // Ngăn session chạy vô tận effort: "high" // Suy luận kỹ lưỡng cho debug phức tạp } })) { // Lưu session ID để resume sau nếu cần if (message.type === "system" && message.subtype === "init") { sessionId = message.session_id; }
// Xử lý kết quả cuối cùng if (message.type === "result") { if (message.subtype === "success") { console.log(`Done: ${message.result}`); } else if (message.subtype === "error_max_turns") { // Agent hết turn. Resume với giới hạn cao hơn. console.log(`Hit turn limit. Resume session ${sessionId} to continue.`); } else if (message.subtype === "error_max_budget_usd") { console.log("Hit budget limit."); } else { console.log(`Stopped: ${message.subtype}`); } console.log(`Cost: $${message.total_cost_usd.toFixed(4)}`); } }} catch (error) { // Một lời gọi query() single-shot throw lỗi sau khi yield result lỗi. Nếu // lỗi đến từ result lỗi, các nhánh subtype ở trên đã chạy rồi; // lỗi kết nối hoặc process không yield result message nào cả. console.log(`Session ended with an error: ${error}`);}Khi agent hoàn thành thành công, ví dụ in ra một dòng Done: với bản tóm tắt sửa lỗi của agent, sau đó là một dòng như Cost: $0.0312.
Bước tiếp theo
Phần tiêu đề “Bước tiếp theo”Giờ bạn đã hiểu vòng lặp, đây là nơi để đi tiếp tuỳ vào bạn đang xây gì:
- Chưa chạy agent nào? Bắt đầu với quickstart để cài SDK và xem một ví dụ đầy đủ chạy từ đầu đến cuối.
- Sẵn sàng tích hợp vào project? Load CLAUDE.md, skill, và filesystem hook để agent tự động theo quy ước project của bạn - xem Dùng tính năng Claude Code trong SDK.
- Xây UI tương tác? Bật streaming để hiện text và lời gọi tool trực tiếp khi vòng lặp chạy.
- Cần kiểm soát chặt chẽ hơn agent được làm gì? Khoá quyền truy cập tool bằng permissions, và dùng hooks để audit, block, hoặc transform lời gọi tool trước khi thực thi.
- Chạy tác vụ dài hoặc tốn kém? Đẩy công việc độc lập sang subagent để giữ context chính gọn nhẹ.
- Triển khai như một dịch vụ? Xem hướng dẫn hosting Agent SDK cho container và serverless, và Session storage để lưu session vào backend riêng.
lượt xem