서브에이전트는 메인 에이전트가 집중된 하위 작업을 처리하기 위해 생성할 수 있는 별도의 에이전트 인스턴스입니다. 서브에이전트를 사용하여 집중된 하위 작업을 위한 컨텍스트를 격리하고, 여러 분석을 병렬로 실행하며, 메인 에이전트의 프롬프트를 비대하게 만들지 않고 전문화된 지침을 적용할 수 있습니다.
이 가이드에서는 agents 매개변수를 사용하여 SDK에서 서브에이전트를 정의하고 사용하는 방법을 설명합니다.
서브에이전트를 세 가지 방법으로 생성할 수 있습니다:
query() 옵션에서 agents 매개변수를 사용합니다 (TypeScript, Python).claude/agents/ 디렉토리에 마크다운 파일로 에이전트를 정의합니다 (파일로 서브에이전트 정의하기 참조)general-purpose 서브에이전트를 호출할 수 있습니다이 가이드는 SDK 애플리케이션에 권장되는 프로그래밍 방식에 초점을 맞춥니다.
서브에이전트를 정의하면 Claude는 각 서브에이전트의 description 필드를 기반으로 호출 여부를 결정합니다. 서브에이전트가 언제 사용되어야 하는지 설명하는 명확한 설명을 작성하면 Claude가 자동으로 적절한 작업을 위임합니다. 프롬프트에서 이름으로 서브에이전트를 명시적으로 요청할 수도 있습니다 (예: "code-reviewer 에이전트를 사용하여...").
서브에이전트는 메인 에이전트와 별도의 컨텍스트를 유지하여 정보 과부하를 방지하고 상호작용을 집중적으로 유지합니다. 이러한 격리는 전문화된 작업이 관련 없는 세부 사항으로 메인 대화 컨텍스트를 오염시키지 않도록 보장합니다.
예시: research-assistant 서브에이전트는 수십 개의 파일과 문서 페이지를 탐색하면서도 모든 중간 검색 결과로 메인 대화를 어지럽히지 않고 관련 결과만 반환할 수 있습니다.
여러 서브에이전트가 동시에 실행될 수 있어 복잡한 워크플로우의 속도를 극적으로 향상시킵니다.
예시: 코드 리뷰 중에 style-checker, security-scanner, test-coverage 서브에이전트를 동시에 실행하여 리뷰 시간을 몇 분에서 몇 초로 줄일 수 있습니다.
각 서브에이전트는 특정 전문 지식, 모범 사례 및 제약 조건이 포함된 맞춤형 시스템 프롬프트를 가질 수 있습니다.
예시: database-migration 서브에이전트는 SQL 모범 사례, 롤백 전략 및 데이터 무결성 검사에 대한 상세한 지식을 가질 수 있으며, 이는 메인 에이전트의 지침에서는 불필요한 노이즈가 될 수 있습니다.
서브에이전트는 특정 도구로 제한될 수 있어 의도하지 않은 작업의 위험을 줄입니다.
예시: doc-reviewer 서브에이전트는 Read 및 Grep 도구에만 접근할 수 있어 문서 파일을 분석할 수는 있지만 실수로 수정하는 것을 방지합니다.
코드에서 agents 매개변수를 사용하여 서브에이전트를 직접 정의합니다. 이 예시는 읽기 전용 접근 권한을 가진 코드 리뷰어와 명령을 실행할 수 있는 테스트 러너, 두 개의 서브에이전트를 생성합니다. Claude는 Task 도구를 통해 서브에이전트를 호출하므로 allowedTools에 Task 도구가 포함되어야 합니다.
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(
# Task tool is required for subagent invocation
allowed_tools=["Read", "Grep", "Glob", "Task"],
agents={
"code-reviewer": AgentDefinition(
# description tells Claude when to use this subagent
description="Expert code review specialist. Use for quality, security, and maintainability reviews.",
# prompt defines the subagent's behavior and expertise
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 restricts what the subagent can do (read-only here)
tools=["Read", "Grep", "Glob"],
# model overrides the default model for this subagent
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""",
# Bash access lets this subagent run test commands
tools=["Bash", "Read", "Grep"]
)
}
)
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
description | string | 예 | 이 에이전트를 언제 사용할지에 대한 자연어 설명 |
prompt | string | 예 | 에이전트의 역할과 동작을 정의하는 시스템 프롬프트 |
tools | string[] | 아니오 | 허용된 도구 이름 배열. 생략하면 모든 도구를 상속합니다 |
model | 'sonnet' | 'opus' | 'haiku' | 'inherit' | 아니오 | 이 에이전트의 모델 오버라이드. 생략하면 메인 모델이 기본값입니다 |
서브에이전트는 자체 서브에이전트를 생성할 수 없습니다. 서브에이전트의 tools 배열에 Task를 포함하지 마세요.
.claude/agents/ 디렉토리에 마크다운 파일로 서브에이전트를 정의할 수도 있습니다. 이 접근 방식에 대한 자세한 내용은 Claude Code 서브에이전트 문서를 참조하세요. 프로그래밍 방식으로 정의된 에이전트는 동일한 이름의 파일 시스템 기반 에이전트보다 우선합니다.
커스텀 서브에이전트를 정의하지 않더라도 allowedTools에 Task가 있으면 Claude는 내장 general-purpose 서브에이전트를 생성할 수 있습니다. 이는 전문화된 에이전트를 만들지 않고도 연구나 탐색 작업을 위임하는 데 유용합니다.
Claude는 작업과 각 서브에이전트의 description을 기반으로 서브에이전트를 호출할 시기를 자동으로 결정합니다. 예를 들어, "쿼리 튜닝을 위한 성능 최적화 전문가"라는 설명으로 performance-optimizer 서브에이전트를 정의하면, 프롬프트에서 쿼리 최적화를 언급할 때 Claude가 이를 호출합니다.
Claude가 작업을 올바른 서브에이전트에 매칭할 수 있도록 명확하고 구체적인 설명을 작성하세요.
Claude가 특정 서브에이전트를 사용하도록 보장하려면 프롬프트에서 이름으로 언급하세요:
"code-reviewer 에이전트를 사용하여 인증 모듈을 검사하세요"이렇게 하면 자동 매칭을 우회하고 지정된 서브에이전트를 직접 호출합니다.
런타임 조건에 따라 에이전트 정의를 동적으로 생성할 수 있습니다. 이 예시는 다양한 엄격도 수준의 보안 리뷰어를 생성하며, 엄격한 리뷰에는 더 강력한 모델을 사용합니다.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
# Factory function that returns an AgentDefinition
# This pattern lets you customize agents based on runtime conditions
def create_security_agent(security_level: str) -> AgentDefinition:
is_strict = security_level == "strict"
return AgentDefinition(
description="Security code reviewer",
# Customize the prompt based on strictness level
prompt=f"You are a {'strict' if is_strict else 'balanced'} security reviewer...",
tools=["Read", "Grep", "Glob"],
# Key insight: use a more capable model for high-stakes reviews
model="opus" if is_strict else "sonnet"
)
async def main():
# The agent is created at query time, so each request can use different settings
async for message in query(
prompt="Review this PR for security issues",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Task"],
agents={
# Call the factory with your desired configuration
"security-reviewer": create_security_agent("strict")
}
)
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())서브에이전트는 Task 도구를 통해 호출됩니다. 서브에이전트가 호출되는 시점을 감지하려면 name: "Task"인 tool_use 블록을 확인하세요. 서브에이전트의 컨텍스트 내에서 온 메시지에는 parent_tool_use_id 필드가 포함됩니다.
이 예시는 스트리밍된 메시지를 순회하면서 서브에이전트가 호출될 때와 후속 메시지가 해당 서브에이전트의 실행 컨텍스트 내에서 발생할 때를 로깅합니다.
메시지 구조는 SDK마다 다릅니다. Python에서는 message.content를 통해 콘텐츠 블록에 직접 접근합니다. TypeScript에서는 SDKAssistantMessage가 Claude API 메시지를 래핑하므로 message.message.content를 통해 콘텐츠에 접근합니다.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
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", "Task"],
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer.",
prompt="Analyze code quality and suggest improvements.",
tools=["Read", "Glob", "Grep"]
)
}
)
):
# Check for subagent invocation in message content
if hasattr(message, 'content') and message.content:
for block in message.content:
if getattr(block, 'type', None) == 'tool_use' and block.name == 'Task':
print(f"Subagent invoked: {block.input.get('subagent_type')}")
# Check if this message is from within a subagent's context
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())서브에이전트는 중단된 지점에서 계속하도록 재개할 수 있습니다. 재개된 서브에이전트는 이전의 모든 도구 호출, 결과 및 추론을 포함한 전체 대화 기록을 유지합니다. 서브에이전트는 처음부터 시작하는 것이 아니라 정확히 중단된 지점에서 다시 시작합니다.
서브에이전트가 완료되면 Claude는 Task 도구 결과에서 에이전트 ID를 받습니다. 프로그래밍 방식으로 서브에이전트를 재개하려면:
session_id를 추출합니다agentId를 파싱합니다resume: sessionId를 전달하고, 프롬프트에 에이전트 ID를 포함합니다서브에이전트의 트랜스크립트에 접근하려면 동일한 세션을 재개해야 합니다. 각 query() 호출은 기본적으로 새 세션을 시작하므로, 동일한 세션에서 계속하려면 resume: sessionId를 전달하세요.
커스텀 에이전트(내장 에이전트가 아닌)를 사용하는 경우, 두 쿼리 모두에서 agents 매개변수에 동일한 에이전트 정의를 전달해야 합니다.
아래 예시는 이 흐름을 보여줍니다: 첫 번째 쿼리는 서브에이전트를 실행하고 세션 ID와 에이전트 ID를 캡처한 다음, 두 번째 쿼리는 첫 번째 분석의 컨텍스트가 필요한 후속 질문을 하기 위해 세션을 재개합니다.
import { query, type SDKMessage } from '@anthropic-ai/claude-agent-sdk';
// Helper to extract agentId from message content
// Stringify to avoid traversing different block types (TextBlock, ToolResultBlock, etc.)
function extractAgentId(message: SDKMessage): string | undefined {
if (!('message' in message)) return undefined;
// Stringify the content so we can search it without traversing nested blocks
const content = JSON.stringify(message.message.content);
const match = content.match(/agentId:\s*([a-f0-9-]+)/);
return match?.[1];
}
let agentId: string | undefined;
let sessionId: string | undefined;
// First invocation - use the Explore agent to find API endpoints
for await (const message of query({
prompt: "Use the Explore agent to find all API endpoints in this codebase",
options: { allowedTools: ['Read', 'Grep', 'Glob', 'Task'] }
})) {
// Capture session_id from ResultMessage (needed to resume this session)
if ('session_id' in message) sessionId = message.session_id;
// Search message content for the agentId (appears in Task tool results)
const extractedId = extractAgentId(message);
if (extractedId) agentId = extractedId;
// Print the final result
if ('result' in message) console.log(message.result);
}
// Second invocation - resume and ask follow-up
if (agentId && sessionId) {
for await (const message of query({
prompt: `Resume agent ${agentId} and list the top 3 most complex endpoints`,
options: { allowedTools: ['Read', 'Grep', 'Glob', 'Task'], resume: sessionId }
})) {
if ('result' in message) console.log(message.result);
}
}서브에이전트 트랜스크립트는 메인 대화와 독립적으로 유지됩니다:
cleanupPeriodDays 설정(기본값: 30일)에 따라 정리됩니다.서브에이전트는 tools 필드를 통해 제한된 도구 접근 권한을 가질 수 있습니다:
이 예시는 코드를 검사할 수 있지만 파일을 수정하거나 명령을 실행할 수 없는 읽기 전용 분석 에이전트를 생성합니다.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
async def main():
async for message in query(
prompt="Analyze the architecture of this codebase",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Task"],
agents={
"code-analyzer": AgentDefinition(
description="Static code analysis and architecture review",
prompt="""You are a code architecture analyst. Analyze code structure,
identify patterns, and suggest improvements without making changes.""",
# Read-only tools: no Edit, Write, or Bash access
tools=["Read", "Grep", "Glob"]
)
}
)
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())| 사용 사례 | 도구 | 설명 |
|---|---|---|
| 읽기 전용 분석 | Read, Grep, Glob | 코드를 검사할 수 있지만 수정하거나 실행할 수 없음 |
| 테스트 실행 | Bash, Read, Grep | 명령을 실행하고 출력을 분석할 수 있음 |
| 코드 수정 | Read, Edit, Write, Grep, Glob | 명령 실행 없이 전체 읽기/쓰기 접근 |
| 전체 접근 | 모든 도구 | 부모로부터 모든 도구를 상속 (tools 필드 생략) |
Claude가 서브에이전트에 위임하지 않고 직접 작업을 완료하는 경우:
allowedTools에 포함되어야 합니다.claude/agents/에 정의된 에이전트는 시작 시에만 로드됩니다. Claude Code가 실행 중일 때 새 에이전트 파일을 생성한 경우, 세션을 재시작하여 로드하세요.
Windows에서는 매우 긴 프롬프트를 가진 서브에이전트가 명령줄 길이 제한(8191자)으로 인해 실패할 수 있습니다. 프롬프트를 간결하게 유지하거나 복잡한 지침에는 파일 시스템 기반 에이전트를 사용하세요.
Was this page helpful?