Подагенты в SDK
Определяйте и вызывайте подагентов для изоляции контекста, параллельного выполнения задач и применения специализированных инструкций в приложениях Claude Agent SDK.
Подагенты — это отдельные экземпляры агентов, которые ваш основной агент может создавать для обработки сосредоточенных подзадач. Используйте подагентов для изоляции контекста при выполнении сосредоточенных подзадач, параллельного запуска нескольких анализов и применения специализированных инструкций без перегрузки основного промпта агента.
В этом руководстве объясняется, как определять и использовать подагентов в SDK с помощью параметра agents.
Обзор
Вы можете создавать подагентов тремя способами:
- Программно: используйте параметр
agentsв параметрахquery()(TypeScript, Python) - На основе файловой системы: определяйте агентов как файлы markdown в директориях
.claude/agents/(см. определение подагентов как файлов) - Встроенный универсальный: Claude может вызывать встроенного подагента
general-purposeв любое время через инструмент Agent без необходимости что-либо определять
Это руководство сосредоточено на программном подходе, который рекомендуется для приложений SDK.
Когда вы определяете подагентов, Claude определяет, следует ли их вызывать, на основе поля description каждого подагента. Напишите четкие описания, которые объясняют, когда следует использовать подагента, и Claude автоматически делегирует соответствующие задачи. Вы также можете явно запросить подагента по имени в своем промпте (например, "Используйте агента code-reviewer для...").
Преимущества использования подагентов
Изоляция контекста
Каждый подагент работает в своей собственной свежей беседе. Промежуточные вызовы инструментов и результаты остаются внутри подагента; только его финальное сообщение возвращается к родительскому агенту. См. Что наследуют подагенты для точного понимания того, что находится в контексте подагента.
Пример: подагент research-assistant может исследовать десятки файлов без накопления этого содержимого в основной беседе. Родительский агент получает краткое резюме, а не каждый файл, который прочитал подагент.
Параллелизация
Несколько подагентов могут работать одновременно, поэтому независимые подзадачи завершаются за время самого медленного из них, а не за сумму всех времён.
Пример: во время проверки кода вы можете одновременно запустить подагентов style-checker, security-scanner и test-coverage вместо последовательного запуска.
Специализированные инструкции и знания
Каждый подагент может иметь адаптированные системные промпты со специфической экспертизой, лучшими практиками и ограничениями.
Пример: подагент database-migration может иметь подробные знания о лучших практиках SQL, стратегиях отката и проверках целостности данных, которые были бы ненужным шумом в инструкциях основного агента.
Ограничения инструментов
Подагенты могут быть ограничены определенными инструментами, снижая риск непредвиденных действий.
Пример: подагент doc-reviewer может иметь доступ только к инструментам Read и Grep, обеспечивая анализ, но никогда случайно не модифицируя файлы документации.
Создание подагентов
Программное определение (рекомендуется)
Определяйте подагентов непосредственно в коде, используя параметр agents. Этот пример создает двух подагентов: рецензента кода с доступом только для чтения и средство запуска тестов, которое может выполнять команды. Claude вызывает подагентов через инструмент Agent, поэтому включите Agent в allowedTools для автоматического одобрения вызовов подагентов без запроса разрешения.
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(
# Auto-approve these tools, including Agent for subagent invocation
allowed_tools=["Read", "Grep", "Glob", "Agent"],
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())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Review the authentication module for security issues",
options: {
// Auto-approve these tools, including Agent for subagent invocation
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-reviewer": {
// 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": {
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 ("result" in message) console.log(message.result);
}
Конфигурация AgentDefinition
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
description |
string |
Да | Описание на естественном языке того, когда использовать этого агента |
prompt |
string |
Да | Системный промпт агента, определяющий его роль и поведение |
tools |
string[] |
Нет | Массив разрешенных имен инструментов. Если опущено, наследует все инструменты |
disallowedTools |
string[] |
Нет | Массив имен инструментов для удаления из набора инструментов агента. Также принимаются шаблоны уровня MCP сервера: mcp__server или mcp__server__* удаляет каждый инструмент с этого сервера, а mcp__* удаляет каждый инструмент MCP с любого сервера |
model |
string |
Нет | Переопределение модели для этого агента. Принимает псевдоним, такой как 'fable', 'opus', 'sonnet', 'haiku', 'inherit', или полный ID модели. По умолчанию используется основная модель, если опущено |
skills |
string[] |
Нет | Список имен skills для предварительной загрузки в контекст агента при запуске. Неперечисленные skills остаются вызываемыми через инструмент Skill |
memory |
'user' | 'project' | 'local' |
Нет | Источник памяти для этого агента |
mcpServers |
(string | object)[] |
Нет | MCP серверы, доступные этому агенту, по имени или встроенной конфигурации |
initialPrompt |
string |
Нет | Автоматически отправляется как первый ход пользователя, когда этот агент работает как основной потоковый агент. Игнорируется, когда агент вызывается как подагент |
maxTurns |
number |
Нет | Максимальное количество ходов агента перед остановкой |
background |
boolean |
Нет | Запустить этого агента как неблокирующую фоновую задачу при вызове |
effort |
'low' | 'medium' | 'high' | 'xhigh' | 'max' | number |
Нет | Уровень усилий рассуждения для этого агента |
permissionMode |
PermissionMode |
Нет | Режим разрешений для выполнения инструментов в этом агенте |
В Python SDK эти имена полей используют camelCase для соответствия формату передачи. Подробности см. в справочнике AgentDefinition.
{/* min-version: 2.1.172 */}Начиная с Claude Code v2.1.172, подагенты могут создавать своих собственных подагентов. Фоновый подагент на пять уровней ниже основного агента не может создавать дополнительных подагентов; основные подагенты могут создавать на любой глубине. Чтобы предотвратить создание подагентом других подагентов, опустите Agent из его массива tools или добавьте его в disallowedTools. Полные правила глубины см. в разделе вложенные подагенты.
Определение на основе файловой системы (альтернатива)
Вы также можете определять подагентов как файлы markdown в директориях .claude/agents/. Подробности об этом подходе см. в документации подагентов Claude Code. Программно определенные агенты имеют приоритет над агентами на основе файловой системы с тем же именем.
Даже без определения пользовательских подагентов, Claude может создавать встроенного подагента general-purpose. Это полезно для делегирования задач исследования или исследования без создания специализированных агентов. Включите Agent в allowedTools, чтобы эти вызовы автоматически одобрялись без запроса разрешения.
Что наследуют подагенты
Окно контекста подагента начинается свежим (без истории родительской беседы), но не пусто. Единственный канал от родителя к подагенту — это строка промпта инструмента Agent, поэтому включайте любые пути файлов, сообщения об ошибках или решения, которые нужны подагенту, непосредственно в этот промпт.
| Подагент получает | Подагент не получает |
|---|---|
Его собственный системный промпт (AgentDefinition.prompt) и промпт инструмента Agent |
История беседы родителя или результаты инструментов |
Проект CLAUDE.md (загруженный через settingSources) |
Предварительно загруженное содержимое skills, если не указано в AgentDefinition.skills |
Определения инструментов (унаследованные от родителя или подмножество в tools) |
Системный промпт родителя |
Родитель получает финальное сообщение подагента дословно как результат инструмента Agent, но может суммировать его в своем собственном ответе. Чтобы сохранить выходные данные подагента дословно в ответе, обращенном к пользователю, включите инструкцию об этом в промпт или опцию systemPrompt, которую вы передаете основному вызову query().
Вызов подагентов
Автоматический вызов
Claude автоматически решает, когда вызывать подагентов, на основе задачи и поля description каждого подагента. Например, если вы определяете подагента performance-optimizer с описанием "Performance optimization specialist for query tuning", Claude вызовет его, когда ваш промпт упоминает оптимизацию запросов.
Напишите четкие, конкретные описания, чтобы Claude мог сопоставить задачи с правильным подагентом.
Явный вызов
Чтобы гарантировать, что Claude использует определенного подагента, упомяните его по имени в своем промпте:
"Use the code-reviewer agent to check the authentication module"
Это обходит автоматическое сопоставление и напрямую вызывает названного подагента.
Динамическая конфигурация агента
Вы можете создавать определения агентов динамически на основе условий во время выполнения. Этот пример создает рецензента безопасности с разными уровнями строгости, используя более мощную модель для строгих проверок.
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", "Agent"],
agents={
# Call the factory with your desired configuration
"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";
// Factory function that returns an AgentDefinition
// This pattern lets you customize agents based on runtime conditions
function createSecurityAgent(securityLevel: "basic" | "strict"): AgentDefinition {
const isStrict = securityLevel === "strict";
return {
description: "Security code reviewer",
// Customize the prompt based on strictness level
prompt: `You are a ${isStrict ? "strict" : "balanced"} security reviewer...`,
tools: ["Read", "Grep", "Glob"],
// Key insight: use a more capable model for high-stakes reviews
model: isStrict ? "opus" : "sonnet"
};
}
// The agent is created at query time, so each request can use different settings
for await (const message of query({
prompt: "Review this PR for security issues",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
// Call the factory with your desired configuration
"security-reviewer": createSecurityAgent("strict")
}
}
})) {
if ("result" in message) console.log(message.result);
}
Обнаружение вызова подагента
Подагенты вызываются через инструмент Agent. Чтобы обнаружить, когда вызывается подагент, проверьте блоки tool_use, где name — это "Agent". Сообщения из контекста подагента включают поле parent_tool_use_id.
Имя инструмента было переименовано с "Task" на "Agent" в Claude Code v2.1.63. Текущие выпуски SDK выдают "Agent" в блоках tool_use, но все еще используют "Task" в списке инструментов system:init и в result.permission_denials[].tool_name. Проверка обоих значений в block.name обеспечивает совместимость между версиями SDK.
Структура сообщения отличается между SDK. В Python блоки содержимого доступны непосредственно через message.content. В TypeScript SDKAssistantMessage оборачивает сообщение Claude API, поэтому содержимое доступно через 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"],
)
},
),
):
# Check for subagent invocation. Match both names: older SDK
# versions emitted "Task", current versions emit "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')}")
# 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())
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;
// Check for subagent invocation. Match both names: older SDK versions
// emitted "Task", current versions emit "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}`);
}
}
// Check if this message is from within a subagent's context
if (msg.parent_tool_use_id) {
console.log(" (running inside subagent)");
}
if ("result" in message) {
console.log(message.result);
}
}
Возобновление подагентов
Подагенты можно возобновить, чтобы продолжить с того места, где они остановились. Возобновленные подагенты сохраняют полную историю беседы, включая все предыдущие вызовы инструментов, результаты и рассуждения. Подагент продолжает работу ровно с того места, где он остановился, а не начинает заново.
Когда подагент завершается, результат инструмента Agent включает текстовый блок, содержащий agentId: <id>. Встроенные агенты Explore и Plan работают в один проход и не возвращают agentId, поэтому используйте пользовательского агента или general-purpose, когда вам нужно возобновить. Чтобы программно возобновить подагента:
- Захватите ID сессии: извлеките
session_idиз сообщений во время первого запроса - Извлеките ID агента: разберите
agentIdиз текста результата инструмента Agent - Возобновите сессию: передайте
resume: sessionIdв параметрах второго запроса и включите ID агента в ваш промпт
Вы должны возобновить ту же сессию, чтобы получить доступ к стенограмме подагента. Каждый вызов query() по умолчанию начинает новую сессию, поэтому передайте resume: sessionId, чтобы продолжить в той же сессии.
При использовании пользовательского агента передайте то же определение агента в параметр agents для обоих запросов.
Пример ниже определяет пользовательского агента endpoint-finder. Первый запрос запускает его и захватывает ID сессии и ID агента из результата инструмента Agent, затем второй запрос возобновляет сессию, чтобы задать вопрос для уточнения, требующий контекста из первого анализа.
import asyncio
import re
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ToolResultBlock
AGENTS = {
"endpoint-finder": AgentDefinition(
description="Locates and catalogs API endpoints in a codebase.",
prompt="You find and document API endpoints. Report each endpoint's path, method, and handler.",
tools=["Read", "Grep", "Glob"],
)
}
def extract_agent_id(block: ToolResultBlock) -> str | None:
"""Extract agentId from an Agent tool result's text content."""
parts = block.content if isinstance(block.content, list) else [{"text": block.content}]
for part in parts:
if match := re.search(r"agentId:\s*([\w-]+)", part.get("text") or ""):
return match.group(1)
return None
async def main():
agent_id = None
session_id = None
# First invocation - run the endpoint-finder subagent
async for message in query(
prompt="Use the endpoint-finder agent to find all API endpoints in this codebase",
options=ClaudeAgentOptions(allowed_tools=["Read", "Grep", "Glob", "Agent"], agents=AGENTS),
):
# Capture session_id from ResultMessage (needed to resume this session)
if hasattr(message, "session_id"):
session_id = message.session_id
# Search tool results for the agentId trailer
for block in getattr(message, "content", None) or []:
if isinstance(block, ToolResultBlock):
agent_id = extract_agent_id(block) or agent_id
# Print the final result
if hasattr(message, "result"):
print(message.result)
# Second invocation - resume and ask follow-up
if agent_id and session_id:
async for message in query(
prompt=f"Resume agent {agent_id} and list the top 3 most complex endpoints",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"], agents=AGENTS, resume=session_id
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
const agents = {
"endpoint-finder": {
description: "Locates and catalogs API endpoints in a codebase.",
prompt: "You find and document API endpoints. Report each endpoint's path, method, and handler.",
tools: ["Read", "Grep", "Glob"]
}
};
// Stringify content to search for agentId without traversing nested block types
function extractAgentId(message: SDKMessage): string | undefined {
if (message.type !== "assistant" && message.type !== "user") return undefined;
const content = JSON.stringify(message.message.content);
const match = content.match(/agentId:\s*([\w-]+)/);
return match?.[1];
}
let agentId: string | undefined;
let sessionId: string | undefined;
// First invocation - run the endpoint-finder subagent
for await (const message of query({
prompt: "Use the endpoint-finder agent to find all API endpoints in this codebase",
options: { allowedTools: ["Read", "Grep", "Glob", "Agent"], agents }
})) {
// 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 Agent 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", "Agent"], agents, resume: sessionId }
})) {
if ("result" in message) console.log(message.result);
}
}
Стенограммы подагентов сохраняются независимо от основной беседы:
- Компактирование основной беседы: когда основная беседа компактируется, стенограммы подагентов не затрагиваются. Они хранятся в отдельных файлах.
- Сохранение сессии: стенограммы подагентов сохраняются в пределах их сессии. Вы можете возобновить подагента после перезагрузки Claude Code, возобновив ту же сессию.
- Автоматическая очистка: стенограммы очищаются на основе параметра
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", "Agent"],
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())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Analyze the architecture of this codebase",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-analyzer": {
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 ("result" in message) console.log(message.result);
}
Распространенные комбинации инструментов
| Вариант использования | Инструменты | Описание |
|---|---|---|
| Анализ только для чтения | Read, Grep, Glob |
Может изучать код, но не может изменять или выполнять |
| Выполнение тестов | Bash, Read, Grep |
Может запускать команды и анализировать выходные данные |
| Модификация кода | Read, Edit, Write, Grep, Glob |
Полный доступ на чтение/запись без выполнения команд |
| Полный доступ | Все инструменты | Наследует все инструменты от родителя (опустите поле tools) |
Масштабирование с помощью динамических рабочих процессов
Подагенты хорошо работают для нескольких делегированных задач за ход. Для запусков, которые координируют десятки или сотни агентов, используйте инструмент Workflow, который перемещает оркестровку в скрипт, который среда выполнения выполняет вне контекста беседы. Подробнее о том, чем рабочие процессы отличаются от делегирования подагентов по ходам, см. в динамических рабочих процессах.
Инструмент Workflow доступен в TypeScript Agent SDK v0.3.149 и позже. Включите Workflow в allowedTools для автоматического одобрения запусков рабочих процессов. Схемы входных и выходных данных инструмента указаны в справочнике TypeScript.
Troubleshooting
Claude не делегирует подагентам
Если Claude выполняет задачи напрямую вместо делегирования вашему подагенту:
- Проверьте, что вызовы Agent одобрены: включите
AgentвallowedToolsдля автоматического одобрения вызовов подагента. Без этого вызовы Agent переходят к вашему обратному вызовуcanUseToolили в режимеdontAskотклоняются - Используйте явное указание: упомяните подагента по имени в своем промпте (например, "Use the code-reviewer agent to...")
- Напишите четкое описание: объясните ровно, когда следует использовать подагента, чтобы Claude мог правильно сопоставить задачи
Агенты на основе файловой системы не загружаются
Агенты, определенные в .claude/agents/, загружаются только при запуске. Если вы создаете новый файл агента во время работы Claude Code, перезагрузите сессию, чтобы загрузить его.
Windows: сбои при длинных промптах
В Windows подагенты с очень длинными промптами могут не работать из-за ограничений длины командной строки (8191 символов). Держите промпты краткими или используйте агентов на основе файловой системы для сложных инструкций.
Связанная документация
- Подагенты Claude Code: полная документация подагентов, включая определения на основе файловой системы
- Динамические рабочие процессы: оркестрируйте множество подагентов из скрипта для работ, слишком больших для одной беседы
- Обзор SDK: начало работы с Claude Agent SDK