Bỏ qua để đến nội dung

Subagent trong SDK

Bài viết được dịch tự động từ bài viết gốc, chưa được kiểm tra lại bởi con người. Chỉ những bài viết có dấu tick xanh cạnh tiêu đề là đã được kiểm tra.

Subagent là các phiên bản agent riêng biệt mà agent chính của bạn có thể sinh ra để xử lý các tác vụ con tập trung. Dùng chúng để tách biệt context, chạy nhiều phân tích song song, và áp dụng chỉ dẫn chuyên biệt mà không làm phình to prompt của agent chính.

Trang này giải thích cách định nghĩa và dùng subagent trong SDK thông qua tham số agents.

Bạn có thể tạo subagent bằng ba cách:

  • Lập trình (programmatic): dùng tham số agents trong tùy chọn query().
  • Dựa trên filesystem: định nghĩa agent dưới dạng file markdown trong thư mục .claude/agents/. Xem định nghĩa subagent dưới dạng file.
  • Built-in general-purpose: Claude có thể gọi subagent built-in general-purpose bất cứ lúc nào qua Agent tool mà không cần bạn định nghĩa gì.

Trang này tập trung vào cách lập trình, được khuyến nghị cho ứng dụng SDK.

Khi bạn định nghĩa subagent, Claude quyết định có nên gọi chúng hay không dựa trên trường description của mỗi subagent. Hãy viết mô tả rõ ràng giải thích khi nào nên dùng subagent, và Claude sẽ tự động giao việc phù hợp. Bạn cũng có thể yêu cầu tường minh một subagent theo tên trong prompt, ví dụ “Use the code-reviewer agent to…”.

Mỗi subagent chạy trong hội thoại riêng, hoàn toàn mới. Các tool call trung gian và kết quả nằm bên trong subagent; chỉ message cuối cùng của nó trả về cho agent cha.

Ví dụ: một subagent research-assistant có thể khám phá hàng chục file mà không có nội dung nào trong số đó tích lũy vào hội thoại chính. Agent cha nhận một bản tóm tắt gọn gàng, không phải mọi file mà subagent đã đọc.

Nhiều subagent có thể chạy đồng thời, nên các tác vụ con độc lập hoàn thành trong thời gian của tác vụ chậm nhất thay vì tổng thời gian của tất cả.

Ví dụ: trong một buổi review code, bạn có thể chạy đồng thời các subagent style-checker, security-scanner, và test-coverage thay vì chạy tuần tự.

Mỗi subagent có thể có system prompt riêng với chuyên môn, best practice, và ràng buộc cụ thể.

Ví dụ: một subagent database-migration có thể có kiến thức chi tiết về best practice SQL, chiến lược rollback, và kiểm tra tính toàn vẹn dữ liệu - những thứ sẽ là nhiễu không cần thiết trong chỉ dẫn của agent chính.

Subagent có thể bị giới hạn chỉ dùng một số tool nhất định, giảm rủi ro hành động ngoài ý muốn.

Ví dụ: một subagent doc-reviewer chỉ có quyền dùng Read và Grep, đảm bảo nó có thể phân tích nhưng không bao giờ vô tình sửa file tài liệu của bạn.

Định nghĩa subagent trực tiếp trong code bằng tham số agents. Claude gọi subagent qua tool Agent, nên hãy đưa Agent vào allowedTools để tự động duyệt lệnh gọi subagent mà không cần prompt xin quyền.

Ví dụ này tạo hai subagent: một code reviewer chỉ đọc và một test runner có thể thực thi lệnh.

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
async def main():
async for message in query(
prompt="Review the authentication module for security issues",
options=ClaudeAgentOptions(
# Tự động duyệt các tool này, bao gồm Agent để gọi subagent
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
"code-reviewer": AgentDefinition(
# description cho Claude biết khi nào dùng subagent này
description="Expert code review specialist. Use for quality, security, and maintainability reviews.",
# prompt định nghĩa hành vi và chuyên môn của subagent
prompt="""You are a code review specialist with expertise in security, performance, and best practices.
When reviewing code:
- Identify security vulnerabilities
- Check for performance issues
- Verify adherence to coding standards
- Suggest specific improvements
Be thorough but concise in your feedback.""",
# tools giới hạn những gì subagent có thể làm (chỉ đọc ở đây)
tools=["Read", "Grep", "Glob"],
# model ghi đè model mặc định cho subagent này
model="sonnet",
),
"test-runner": AgentDefinition(
description="Runs and analyzes test suites. Use for test execution and coverage analysis.",
prompt="""You are a test execution specialist. Run tests and provide clear analysis of results.
Focus on:
- Running test commands
- Analyzing test output
- Identifying failing tests
- Suggesting fixes for failures""",
# Quyền Bash cho phép subagent này chạy lệnh test
tools=["Bash", "Read", "Grep"],
),
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Review the authentication module for security issues",
options: {
// Tự động duyệt các tool này, bao gồm Agent để gọi subagent
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-reviewer": {
// description cho Claude biết khi nào dùng subagent này
description:
"Expert code review specialist. Use for quality, security, and maintainability reviews.",
// prompt định nghĩa hành vi và chuyên môn của subagent
prompt: `You are a code review specialist with expertise in security, performance, and best practices.
When reviewing code:
- Identify security vulnerabilities
- Check for performance issues
- Verify adherence to coding standards
- Suggest specific improvements
Be thorough but concise in your feedback.`,
// tools giới hạn những gì subagent có thể làm (chỉ đọc ở đây)
tools: ["Read", "Grep", "Glob"],
// model ghi đè model mặc định cho subagent này
model: "sonnet"
},
"test-runner": {
description:
"Runs and analyzes test suites. Use for test execution and coverage analysis.",
prompt: `You are a test execution specialist. Run tests and provide clear analysis of results.
Focus on:
- Running test commands
- Analyzing test output
- Identifying failing tests
- Suggesting fixes for failures`,
// Quyền Bash cho phép subagent này chạy lệnh test
tools: ["Bash", "Read", "Grep"]
}
}
}
})) {
if ("result" in message) console.log(message.result);
}
TrườngKiểuBắt buộcMô tả
descriptionstringMô tả bằng ngôn ngữ tự nhiên về khi nào nên dùng agent này
promptstringSystem prompt định nghĩa vai trò và hành vi của agent
toolsstring[]KhôngMảng tên tool được phép. Nếu bỏ trống, kế thừa mọi tool khả dụng cho subagent
disallowedToolsstring[]KhôngMảng tên tool loại khỏi bộ tool của agent. Cũng chấp nhận mẫu ở cấp MCP server: mcp__server hoặc mcp__server__* loại mọi tool từ server đó, và mcp__* loại mọi MCP tool từ mọi server
modelstringKhôngGhi đè model cho agent này. Chấp nhận alias như 'fable', 'opus', 'sonnet', 'haiku', 'inherit', hoặc một model ID đầy đủ. Mặc định dùng model chính nếu bỏ trống
skillsstring[]KhôngDanh sách tên skill được nạp trước vào context của agent khi khởi động. Skill không được liệt kê vẫn có thể gọi qua Skill tool
memory'user' | 'project' | 'local'KhôngNguồn bộ nhớ cho agent này
mcpServers(string | object)[]KhôngMCP server khả dụng cho agent này, theo tên hoặc cấu hình inline
initialPromptstringKhôngTự động gửi làm lượt user đầu tiên khi agent này chạy ở vai trò agent chính. Bị bỏ qua khi agent được gọi làm subagent
maxTurnsnumberKhôngSố lượt agentic tối đa trước khi agent dừng
backgroundbooleanKhôngChạy agent này như một tác vụ nền không chặn khi được gọi
effort'low' | 'medium' | 'high' | 'xhigh' | 'max' | numberKhôngMức độ nỗ lực suy luận cho agent này
permissionModePermissionModeKhôngPermission mode cho việc thực thi tool trong agent này

Trong Python SDK, các tên trường nhiều từ như disallowedToolsmcpServers giữ nguyên chính tả camelCase để khớp với định dạng wire, thay vì theo quy ước snake_case của Python.

Định nghĩa dựa trên filesystem (thay thế)

Phần tiêu đề “Định nghĩa dựa trên filesystem (thay thế)”

Bạn cũng có thể định nghĩa subagent dưới dạng file markdown trong thư mục .claude/agents/. Xem tài liệu subagent Claude Code để biết chi tiết cách này. Agent định nghĩa theo cách lập trình được ưu tiên hơn agent dựa trên filesystem có cùng tên.

Context window của một subagent bắt đầu hoàn toàn mới, không có hội thoại cha, nhưng không hề trống rỗng. Nội dung duy nhất bạn truyền từ agent cha sang subagent là chuỗi prompt của Agent tool, nên hãy đưa mọi đường dẫn file, thông báo lỗi, hoặc quyết định mà subagent cần trực tiếp vào prompt đó.

Subagent nhận đượcSubagent không nhận được
System prompt riêng (AgentDefinition.prompt) và prompt của Agent toolLịch sử hội thoại hoặc kết quả tool của agent cha
CLAUDE.md của dự án (nạp qua settingSources)Nội dung skill đã nạp trước, trừ khi được liệt kê trong AgentDefinition.skills
Định nghĩa tool (kế thừa từ cha hoặc tập con trong tools, có lọc riêng cho lượt chạy nền)System prompt của agent cha

Một lỗi API khiến subagent kết thúc sớm, ví dụ rate limit, không bao giờ được gửi lại như kết quả của nó. Nếu rate limit, quá tải, hoặc lỗi server làm gián đoạn một subagent chạy foreground đã tạo ra output văn bản, Agent tool trả về output từng phần đó kèm ghi chú rằng subagent chưa hoàn thành.

Claude tự động quyết định khi nào gọi subagent dựa trên tác vụ và trường description của mỗi subagent. Ví dụ, nếu bạn định nghĩa subagent performance-optimizer với mô tả “Performance optimization specialist for query tuning”, Claude sẽ gọi nó khi prompt của bạn đề cập đến việc tối ưu truy vấn.

Hãy viết mô tả rõ ràng, cụ thể để Claude có thể khớp tác vụ với đúng subagent.

Để đảm bảo Claude dùng một subagent cụ thể, nhắc tên nó trong prompt:

"Use the code-reviewer agent to check the authentication module"

Cách này bỏ qua việc khớp tự động và gọi trực tiếp subagent được nêu tên.

Bạn có thể tạo định nghĩa agent động dựa trên điều kiện thời gian chạy. Ví dụ này tạo một security reviewer với các mức độ nghiêm ngặt khác nhau, dùng model mạnh hơn cho các review nghiêm ngặt.

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
# Hàm factory trả về một AgentDefinition
# Mẫu này cho phép bạn tùy chỉnh agent dựa trên điều kiện thời gian chạy
def create_security_agent(security_level: str) -> AgentDefinition:
is_strict = security_level == "strict"
return AgentDefinition(
description="Security code reviewer",
# Tùy chỉnh prompt dựa trên mức độ nghiêm ngặt
prompt=f"You are a {'strict' if is_strict else 'balanced'} security reviewer...",
tools=["Read", "Grep", "Glob"],
# Điểm mấu chốt: dùng model mạnh hơn cho review có mức độ quan trọng cao
model="opus" if is_strict else "sonnet",
)
async def main():
# Agent được tạo tại thời điểm query, nên mỗi request có thể dùng cấu hình khác nhau
async for message in query(
prompt="Review this PR for security issues",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
# Gọi factory với cấu hình mong muốn
"security-reviewer": create_security_agent("strict")
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query, type AgentDefinition } from "@anthropic-ai/claude-agent-sdk";
// Hàm factory trả về một AgentDefinition
// Mẫu này cho phép bạn tùy chỉnh agent dựa trên điều kiện thời gian chạy
function createSecurityAgent(securityLevel: "basic" | "strict"): AgentDefinition {
const isStrict = securityLevel === "strict";
return {
description: "Security code reviewer",
// Tùy chỉnh prompt dựa trên mức độ nghiêm ngặt
prompt: `You are a ${isStrict ? "strict" : "balanced"} security reviewer...`,
tools: ["Read", "Grep", "Glob"],
// Điểm mấu chốt: dùng model mạnh hơn cho review có mức độ quan trọng cao
model: isStrict ? "opus" : "sonnet"
};
}
// Agent được tạo tại thời điểm query, nên mỗi request có thể dùng cấu hình khác nhau
for await (const message of query({
prompt: "Review this PR for security issues",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
// Gọi factory với cấu hình mong muốn
"security-reviewer": createSecurityAgent("strict")
}
}
})) {
if ("result" in message) console.log(message.result);
}

Claude gọi subagent qua Agent tool. Để phát hiện khi một subagent được gọi, kiểm tra block tool_usename"Agent". Message bên trong context của một subagent có trường parent_tool_use_id.

Cấu trúc message khác nhau giữa hai SDK. Trong Python, bạn truy cập block nội dung trực tiếp qua message.content. Trong TypeScript, SDKAssistantMessage bọc message API của Claude, nên bạn truy cập nội dung qua message.message.content.

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ToolUseBlock
async def main():
async for message in query(
prompt="Use the code-reviewer agent to review this codebase",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep", "Agent"],
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer.",
prompt="Analyze code quality and suggest improvements.",
tools=["Read", "Glob", "Grep"],
)
},
),
):
# Kiểm tra lệnh gọi subagent. Khớp cả hai tên: phiên bản SDK cũ
# phát ra "Task", phiên bản hiện tại phát ra "Agent".
if hasattr(message, "content") and message.content:
for block in message.content:
if isinstance(block, ToolUseBlock) and block.name in (
"Task",
"Agent",
):
print(f"Subagent invoked: {block.input.get('subagent_type')}")
# Kiểm tra xem message này có đến từ context của subagent không
if hasattr(message, "parent_tool_use_id") and message.parent_tool_use_id:
print(" (running inside subagent)")
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Use the code-reviewer agent to review this codebase",
options: {
allowedTools: ["Read", "Glob", "Grep", "Agent"],
agents: {
"code-reviewer": {
description: "Expert code reviewer.",
prompt: "Analyze code quality and suggest improvements.",
tools: ["Read", "Glob", "Grep"]
}
}
}
})) {
const msg = message as any;
// Kiểm tra lệnh gọi subagent. Khớp cả hai tên: phiên bản SDK cũ
// phát ra "Task", phiên bản hiện tại phát ra "Agent".
for (const block of msg.message?.content ?? []) {
if (block.type === "tool_use" && (block.name === "Task" || block.name === "Agent")) {
console.log(`Subagent invoked: ${block.input.subagent_type}`);
}
}
// Kiểm tra xem message này có đến từ context của subagent không
if (msg.parent_tool_use_id) {
console.log(" (running inside subagent)");
}
if ("result" in message) {
console.log(message.result);
}
}

Bạn có thể tiếp tục một subagent để chạy tiếp từ chỗ dừng lại thay vì bắt đầu lại từ đầu. Một subagent được resume giữ nguyên toàn bộ lịch sử hội thoại, bao gồm mọi tool call, kết quả, và lý luận trước đó.

Khi một subagent hoàn tất, kết quả Agent tool bao gồm một block văn bản chứa agentId: <id>. Các agent built-in ExplorePlan chỉ chạy một lần và không trả về agentId, nên hãy dùng một agent tùy chỉnh hoặc general-purpose khi bạn cần resume. Để resume một subagent theo cách lập trình:

  1. Ghi lại session ID: trích xuất session_id từ message trong lần query đầu tiên
  2. Trích xuất agent ID: phân tích agentId từ văn bản kết quả Agent tool
  3. Resume phiên: truyền resume: sessionId vào tùy chọn của query thứ hai, và bao gồm agent ID trong prompt của bạn

Transcript của subagent tồn tại độc lập với hội thoại chính:

  • Nén hội thoại chính: khi hội thoại chính bị nén, transcript của subagent không bị ảnh hưởng. Chúng được lưu trong các file riêng.
  • Lưu trữ phiên: transcript của subagent tồn tại trong phạm vi phiên của nó. Bạn có thể resume một subagent sau khi khởi động lại Claude Code bằng cách resume cùng phiên.
  • Dọn dẹp tự động: Claude Code xóa transcript subagent sau thời gian lưu giữ cleanupPeriodDays, mặc định 30 ngày.

Dùng trường tools để giới hạn những gì một subagent có thể làm:

  • Bỏ trống tools: subagent được cấp mọi tool khả dụng cho subagent
  • Liệt kê tool: subagent chỉ nhận những tool đó. Ví dụ, một code reviewer không bao giờ nên sửa file sẽ nhận ["Read", "Grep", "Glob"]

Một tool bạn bỏ ra ngoài sẽ không có trong phiên của subagent chút nào: Claude làm việc mà không có nó, không có prompt xin quyền hay lỗi.

Trường hợp dùngToolMô tả
Phân tích chỉ đọcRead, Grep, GlobCó thể xem code nhưng không sửa hay thực thi
Chạy testBash, Read, GrepCó thể chạy lệnh và phân tích output
Sửa codeRead, Edit, Write, Grep, GlobToàn quyền đọc/ghi mà không thực thi lệnh
Toàn quyềnMọi toolKế thừa mọi tool khả dụng cho subagent (bỏ trống trường tools)

Subagent phù hợp với vài tác vụ giao việc mỗi lượt. Với các lần chạy điều phối hàng chục đến hàng trăm agent, hãy dùng Workflow tool, chuyển việc điều phối vào một script được runtime thực thi bên ngoài context hội thoại. Xem workflow động để biết workflow khác gì với giao việc subagent theo từng lượt.

Nếu Claude tự hoàn thành tác vụ thay vì giao cho subagent của bạn:

  • Kiểm tra lệnh gọi Agent đã được duyệt chưa: đưa Agent vào allowedTools để tự động duyệt lệnh gọi subagent. Nếu không, lệnh gọi Agent sẽ rơi vào callback canUseTool của bạn hoặc, trong chế độ dontAsk, bị từ chối
  • Dùng prompt tường minh: nhắc tên subagent trong prompt, ví dụ “Use the code-reviewer agent to…”
  • Viết mô tả rõ ràng: giải thích chính xác khi nào nên dùng subagent để Claude khớp tác vụ phù hợp

Agent dựa trên filesystem không được nạp

Phần tiêu đề “Agent dựa trên filesystem không được nạp”

Claude Code theo dõi ~/.claude/agents/.claude/agents/ và nhận diện file agent mới hoặc đã sửa trong vài giây, không cần khởi động lại. Nếu một định nghĩa không bao giờ xuất hiện, hãy kiểm tra các nguyên nhân sau:

  • Thư mục agents mới: bộ theo dõi chỉ bao phủ các thư mục đã tồn tại khi phiên bắt đầu, nên file đầu tiên trong một thư mục mới cần khởi động lại phiên. Đây là nguyên nhân phổ biến nhất.
  • Frontmatter không hợp lệ hoặc name trùng lặp: kiểm tra YAML của file, và xem đã có agent nào dùng name đó chưa.
  • --disable-slash-commands: các phiên khởi động với cờ này không theo dõi các thư mục này và luôn cần khởi động lại để nạp file mới.
  • Một agent lập trình có cùng tên: agents truyền vào query() sẽ ghi đè agent filesystem có cùng tên.

Trên Windows, subagent với prompt rất dài có thể thất bại do giới hạn độ dài dòng lệnh 8191 ký tự. Hãy giữ prompt ngắn gọn hoặc dùng agent dựa trên filesystem cho chỉ dẫn phức tạp.

  • Subagent Claude Code: tài liệu subagent đầy đủ bao gồm định nghĩa dựa trên filesystem
  • Workflow động: điều phối nhiều subagent từ một script cho các công việc quá lớn cho một hội thoại
  • Tổng quan SDK: bắt đầu với Claude Agent SDK