Как работает цикл агента
Поймите жизненный цикл сообщений, выполнение инструментов, контекстное окно и архитектуру, которые питают ваших агентов SDK.
Agent SDK позволяет встроить автономный цикл агента Claude Code в ваши собственные приложения. SDK — это отдельный пакет, который дает вам программный контроль над инструментами, разрешениями, ограничениями затрат и выводом.
Оба SDK (TypeScript и Python) включают собственный бинарный файл Claude Code, поэтому большинству установок не требуется отдельная установка Claude Code. Примечание об установке см. в quickstart.
Когда вы запускаете агента, SDK запускает тот же цикл выполнения, который питает Claude Code: Claude оценивает ваш запрос, вызывает инструменты для выполнения действий, получает результаты и повторяет до завершения задачи. На этой странице объясняется, что происходит внутри этого цикла, чтобы вы могли эффективно создавать, отлаживать и оптимизировать своих агентов.
Цикл с первого взгляда
Каждая сессия агента следует одному и тому же циклу:
- Получить запрос. Claude получает ваш запрос вместе с системным запросом, определениями инструментов и историей разговора. SDK выдает
SystemMessageс подтипом"init", содержащий метаданные сессии. - Оценить и ответить. Claude оценивает текущее состояние и определяет, как действовать дальше. Он может ответить текстом, запросить один или несколько вызовов инструментов или оба варианта. SDK выдает один или несколько объектов
AssistantMessage, по одному для каждого блока содержимого, такого как текстовый блок или запрос вызова инструмента. - Выполнить инструменты. SDK запускает каждый запрошенный инструмент и собирает результаты. Каждый набор результатов инструментов возвращается Claude для следующего решения. Вы можете использовать hooks для перехвата, изменения или блокировки вызовов инструментов перед их выполнением.
- Повторить. Шаги 2 и 3 повторяются как цикл. Claude продолжает вызывать инструменты и обрабатывать результаты до тех пор, пока не выдаст ответ без вызовов инструментов.
- Вернуть результат. SDK выдает финальное
AssistantMessageс текстовым ответом (без вызовов инструментов), за которым следуетResultMessageс финальным текстом, использованием токенов, стоимостью и ID сессии.
Быстрый вопрос, например «какие файлы здесь?», может занять два или три хода: один или два с вызовом Glob, затем один с ответом, содержащим результаты. Сложная задача, например «выполни рефакторинг модуля аутентификации и обнови тесты», может связать десятки вызовов инструментов на протяжении многих ходов, поскольку Claude корректирует свои действия после каждого результата.
Ходы и сообщения
Ход — это один проход цикла: Claude выдает выход, и если он включает вызовы инструментов, SDK выполняет их, а результаты автоматически возвращаются Claude. Это происходит без возврата управления вашему коду. Ходы продолжаются до тех пор, пока Claude не выдаст выход без вызовов инструментов, после чего цикл заканчивается и доставляется финальный результат.
Рассмотрим, как может выглядеть полная сессия для запроса «Исправить неудачные тесты в auth.ts».
Сначала SDK отправляет ваш запрос Claude и выдает SystemMessage с метаданными сессии. Затем начинается цикл:
- Ход 1: Claude вызывает
Bashдля запускаnpm test. SDK выдаетAssistantMessageс вызовом инструмента, выполняет команду, затем выдаетUserMessageс выводом (три ошибки). - Ход 2: Claude вызывает
Readнаauth.tsиauth.test.ts. SDK выдаетAssistantMessageдля каждого вызова и возвращает содержимое файлов. - Ход 3: Claude вызывает
Editдля исправленияauth.ts, затем вызываетBashдля повторного запускаnpm test. Все три теста проходят. SDK выдаетAssistantMessageдля каждого вызова. - Финальный ход: Claude выдает текстовый ответ без вызовов инструментов: «Исправлена ошибка аутентификации, все три теста теперь проходят.» SDK выдает финальное
AssistantMessageс этим текстом, затемResultMessageс тем же текстом плюс стоимость и использование.
Это было четыре хода: три с вызовами инструментов, один финальный текстовый ответ.
Вы можете ограничить цикл с помощью max_turns / maxTurns. Считайте каждый ход с вызовами инструментов плюс один для финального текстового ответа. Без этого дополнительного хода выполнение завершится сообщением ResultMessage с подтипом error_max_turns и без финального ответа. Например, max_turns=2 в цикле выше остановился бы перед шагом редактирования. Вы также можете использовать max_budget_usd / maxBudgetUsd для ограничения ходов на основе порога расходов.
Без ограничений цикл работает до тех пор, пока Claude не закончит самостоятельно, что хорошо для хорошо определенных задач, но может работать долго на открытых запросах («улучшить этот кодовую базу»). Установка бюджета — хороший стандарт для производственных агентов. См. Ходы и бюджет ниже для справки по опциям.
Типы сообщений
По мере выполнения цикла SDK выдает поток сообщений. Каждое сообщение имеет тип, который говорит вам, на каком этапе цикла оно пришло. Пять основных типов:
-
SystemMessage: события жизненного цикла сессии. Полеsubtypeих различает:"init": метаданные сессии для запуска. Когда hookSessionStartилиSetupзапускается при инициализации сессии, его сообщения жизненного цикла hook прибывают перед сообщениемinit"compact_boundary": срабатывает после компактирования"informational": простые текстовые баннеры статуса из цикла"worker_shutting_down": хост выходит или Remote Control отключился
В TypeScript каждый подтип, кроме
"init", является собственным типом в объединенииSDKMessage, а не подтипомSDKSystemMessage. -
AssistantMessage: выдается для каждого блока содержимого в ответах Claude, включая финальный текстовый. Каждое содержит один блок содержимого, такой как текст или вызов инструмента, и сообщения из одного ответа имеют общий ID сообщения. -
UserMessage: выдается после каждого выполнения инструмента с результатом инструмента, отправленным обратно Claude. Также выдается для любых пользовательских входов, которые вы транслируете в середине цикла. -
StreamEvent: выдается только при включении частичных сообщений. Содержит необработанные события потоковой передачи API (дельты текста, фрагменты входных данных инструмента). См. Потоковые ответы. -
ResultMessage: отмечает конец цикла агента. Содержит финальный текстовый результат, использование токенов, стоимость и ID сессии. Проверьте полеsubtype, чтобы определить, успешна ли задача или достигнут ли лимит. Небольшое количество завершающих системных событий, таких какprompt_suggestion, может прибыть после него, поэтому итерируйте поток до завершения, а не прерывайте на результате. См. Обработать результат.
Эти пять типов охватывают полный жизненный цикл цикла агента. Оба SDK также выдают события наблюдаемости, такие как статус ограничения скорости и уведомления задач, которые не требуются для управления циклом. См. справку по типам сообщений Python и справку по типам сообщений TypeScript для полных списков.
Обработать сообщения
Какие сообщения вы обрабатываете, зависит от того, что вы создаете:
- Только финальные результаты: обработайте
ResultMessage, чтобы получить выход, стоимость и то, успешна ли задача или достигнут ли лимит. - Обновления прогресса: обработайте
AssistantMessage, чтобы увидеть, что делает Claude на каждом ходу, включая какие инструменты он вызвал. - Прямая потоковая передача: включите частичные сообщения (
include_partial_messagesв Python,includePartialMessagesв TypeScript), чтобы получить сообщенияStreamEventв реальном времени. См. Потоковые ответы в реальном времени.
Как вы проверяете типы сообщений, зависит от SDK:
- Python: проверьте типы сообщений с помощью
isinstance()для классов, импортированных изclaude_agent_sdk(например,isinstance(message, ResultMessage)). - TypeScript: проверьте строковое поле
type(например,message.type === "result").AssistantMessageиUserMessageоборачивают необработанное сообщение API в поле.message, поэтому блоки содержимого находятся вmessage.message.content, а не вmessage.content.
[accordion] Пример: Проверить типы сообщений и обработать результаты
import asyncio from claude_agent_sdk import query, AssistantMessage, ResultMessage, TextBlock, ToolUseBlock async def main(): try: async for message in query(prompt="Summarize this project"): if isinstance(message, AssistantMessage): # Each AssistantMessage carries one content block for block in message.content: if isinstance(block, TextBlock): print(f"Claude: {block.text}") elif isinstance(block, ToolUseBlock): print(f"Tool call: {block.name}") if isinstance(message, ResultMessage): if message.subtype == "success": print(message.result) else: print(f"Stopped: {message.subtype}") except Exception as error: # A single-shot query() raises after yielding an error result. If the # failure was an error result, the error subtype branches above have # already run; connection or process failures yield no result message. 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") { // Each assistant message carries one content block for (const block of message.message.content) { if (block.type === "text") { console.log(`Claude: ${block.text}`); } else if (block.type === "tool_use") { console.log(`Tool call: ${block.name}`); } } } if (message.type === "result") { if (message.subtype === "success") { console.log(message.result); } else { console.log(`Stopped: ${message.subtype}`); } } } } catch (error) { // A single-shot query() throws after yielding an error result. If the // failure was an error result, the error subtype branches above have // already run; connection or process failures yield no result message. console.log(`Session ended with an error: ${error}`); }
Выполнение инструментов
Инструменты дают вашему агенту возможность действовать. Без инструментов Claude может только отвечать текстом. С инструментами Claude может читать файлы, запускать команды, искать код и взаимодействовать с внешними сервисами.
Встроенные инструменты
SDK включает те же инструменты, которые питают Claude Code:
| Категория | Инструменты | Что они делают |
|---|---|---|
| Операции с файлами | Read, Edit, Write |
Читать, изменять и создавать файлы |
| Поиск | Glob, Grep |
Найти файлы по шаблону, искать содержимое с помощью regex |
| Выполнение | Bash |
Запускать команды оболочки, скрипты, операции git |
| Веб | WebSearch, WebFetch |
Искать в веб, получать и анализировать страницы |
| Обнаружение | ToolSearch |
Динамически находить и загружать инструменты по требованию вместо предварительной загрузки всех |
| Оркестрация | Agent, Skill, AskUserQuestion, TaskCreate, TaskUpdate |
Порождать подагентов, вызывать skills, спрашивать пользователя, отслеживать задачи |
На моделях, которые не получают инструменты отслеживания задач, Claude Code предоставляет TaskCreate и TaskUpdate только когда вы согласитесь.
Помимо встроенных инструментов, вы можете:
- Подключить внешние сервисы с помощью MCP servers (базы данных, браузеры, API)
- Определить пользовательские инструменты с помощью пользовательских обработчиков инструментов
- Загрузить skills проекта через источники настроек для повторно используемых рабочих процессов
Разрешения инструментов
Claude определяет, какие инструменты вызывать на основе задачи, но вы контролируете, разрешено ли выполнение этих вызовов. Вы можете автоматически одобрить определенные инструменты, полностью заблокировать другие или требовать одобрения для всего. Три опции работают вместе, чтобы определить, что работает:
allowed_tools/allowedToolsавтоматически подтверждает перечисленные инструменты. Агент только для чтения с["Read", "Glob", "Grep"]в списке разрешенных инструментов запускает эти инструменты без запросов, за исключением чтения из сетевых путей. Инструменты, не указанные в списке, все еще доступны, и вызовы к ним, которые требуют подтверждения, переходят к режиму разрешений иcanUseTool.disallowed_tools/disallowedToolsблокирует перечисленные инструменты, независимо от других настроек. См. Разрешения для порядка, в котором правила проверяются перед запуском инструмента.permission_mode/permissionModeконтролирует, сколько человеческого надзора вы хотите. SDK оценивает активный режим вместе с вашими правилами разрешения и запрета в фиксированном порядке, описанном в Как оцениваются разрешения. См. Режим разрешения для доступных режимов.
Вы также можете ограничить отдельные инструменты правилами, такими как "Bash(npm *)", чтобы разрешить только определенные команды. См. Разрешения для полного синтаксиса правил.
Когда инструмент отклоняется, Claude получает сообщение об отклонении как результат инструмента и обычно пытается использовать другой подход или сообщает, что не может продолжить.
Параллельное выполнение инструментов
Когда Claude запрашивает несколько вызовов инструментов в одном ходе, оба SDK могут запускать их одновременно или последовательно в зависимости от инструмента. Инструменты только для чтения (такие как Read, Glob, Grep и MCP инструменты, отмеченные как только для чтения) могут работать одновременно. Инструменты, которые изменяют состояние (такие как Edit, Write и Bash), работают последовательно, чтобы избежать конфликтов.
Пользовательские инструменты по умолчанию работают последовательно. Чтобы включить параллельное выполнение для пользовательского инструмента, установите readOnlyHint в его аннотациях. Оба SDK TypeScript и Python используют это имя поля из MCP SDK.
Управление выполнением цикла
Вы можете ограничить количество ходов цикла, его стоимость, глубину рассуждений Claude, а также указать, требуют ли инструменты подтверждения перед запуском. Все это — поля ClaudeAgentOptions (Python) / Options (TypeScript).
Ходы и бюджет
| Параметр | Что он контролирует | По умолчанию |
|---|---|---|
Максимум ходов (max_turns / maxTurns) |
Максимальное количество ходов | Без ограничений |
Максимальный бюджет (max_budget_usd / maxBudgetUsd) |
Оценочные расходы, при достижении которых цикл останавливается | Без ограничений |
При достижении любого из ограничений SDK возвращает ResultMessage с соответствующим подтипом ошибки (error_max_turns или error_max_budget_usd). О том, как проверять эти подтипы, см. Обработка результата, а синтаксис — в ClaudeAgentOptions / Options.
Ограничение бюджета распространяется на субагентов: их расходы учитываются в общей сумме. Как только расходы достигают лимита, запуск очередного субагента завершается ошибкой Budget limit reached, а Claude Code останавливает все еще работающих фоновых субагентов. Для такого соблюдения лимита требуется Claude Code v2.1.217 или новее.
При потоковом вводе сообщение, которое все еще находится в очереди, когда ход завершается по лимиту максимального количества ходов, остается в очереди. Claude Code не добавляет его в последний вызов модели этого хода. Он начинает для сообщения новый ход, и счетчик максимального количества ходов для этого хода начинается заново. Общая сумма бюджета продолжает накапливаться между сообщениями, и как только расходы достигают maxBudgetUsd, последующие сообщения в том же диалоге завершаются результатом error_max_budget_usd. Команда /clear сбрасывает бюджет.
Запас бюджета
Claude Code сравнивает расходы с лимитом max_budget_usd / maxBudgetUsd после получения ответов модели, поскольку стоимость каждого ответа вычисляется по данным об использовании токенов, которые API возвращает вместе с ним. Ответ, при котором достигается лимит, все равно завершается и учитывается в total_cost_usd. Поэтому расходы могут превысить лимит не более чем на стоимость этого одного ответа плюс все, что потратят субагенты, еще работающие в этот момент, до своей остановки. Учитывайте этот запас при установке лимита.
Уровень effort
Параметр effort определяет, насколько глубоко рассуждает Claude. Более низкие уровни effort расходуют меньше токенов за ход и снижают стоимость. Не все модели поддерживают параметр effort. Список поддерживающих его моделей см. в разделе Effort.
| Уровень | Поведение | Подходит для |
|---|---|---|
"low" |
Минимальные рассуждения, быстрые ответы | Поиск файлов, вывод содержимого каталогов |
"medium" |
Сбалансированные рассуждения | Рутинные правки, стандартные задачи |
"high" |
Тщательный анализ | Рефакторинг, отладка |
"xhigh" |
Расширенная глубина рассуждений | Задачи программирования и агентные задачи на моделях, которые это поддерживают |
"max" |
Максимальная глубина рассуждений | Многошаговые задачи, требующие глубокого анализа |
Если вы не задаете effort, Claude Code определяет уровень effort самостоятельно в порядке, описанном в разделе Настройка уровня effort.
[!NOTE]
effortпозволяет обменять задержку и стоимость токенов на глубину рассуждений в рамках каждого ответа. Расширенное мышление — это отдельная функция, которая создает блокиthinkingв выводе, а полеdisplayвThinkingConfigдля Python или TypeScript определяет, получаете ли вы их текст. Они независимы: можно задатьeffort: "low"с включенным расширенным мышлением илиeffort: "max"без него.
Используйте более низкий уровень effort для агентов, выполняющих простые, четко очерченные задачи (например, вывод списка файлов или запуск одного grep), чтобы снизить стоимость и задержку. Задайте effort в параметрах query() верхнего уровня для всей сессии или для отдельного субагента с помощью поля effort в AgentDefinition, чтобы переопределить уровень сессии.
Режим разрешений
Параметр режима разрешений (permission_mode в Python, permissionMode в TypeScript) определяет, запрашивает ли агент подтверждение перед использованием инструментов:
| Режим | Поведение | Сценарий использования |
|---|---|---|
"default" |
Вызовы инструментов, которым требуется подтверждение и которые не покрываются разрешающими правилами, вызывают ваш callback canUseTool; при отсутствии callback вызов отклоняется |
Интерактивные приложения с собственным callback для подтверждения |
"acceptEdits" |
Автоматически подтверждает правки файлов и распространенные команды файловой системы (mkdir, touch, mv, cp и т. д.); остальные команды Bash следуют правилам по умолчанию |
Вы доверяете правкам Claude и хотите ускорить итерации, например при прототипировании или работе в изолированном каталоге |
"plan" |
Claude исследует и планирует, не редактируя ваши исходные файлы; правки файлов никогда не подтверждаются автоматически и запрашиваются через ваш callback canUseTool |
Вы хотите, чтобы Claude предлагал изменения, не выполняя их, например во время код-ревью или когда нужно подтверждать изменения до их внесения |
"dontAsk" |
Никогда не запрашивает подтверждение. Выполняются инструменты, заранее разрешенные правилами разрешений, а также вызовы, которым в режиме default подтверждение не требуется, например чтение файлов внутри ваших рабочих каталогов. Все вызовы, которые в ином случае потребовали бы подтверждения, отклоняются, хотя установленный вами мод все же может подтвердить некоторые из этих вызовов. Некоторые вызовы, например чтение по сетевым путям, отклоняются, даже если вы их разрешили. Список см. в разделе Режим Don't ask |
Агенты без интерфейса, когда некому подтверждать вызовы |
"auto" |
Использует классификатор на основе модели для проверки действий, таких как shell-команды и сетевые запросы, разрешая или блокируя каждое проверяемое действие. Доступность и порядок принятия решений см. в разделе Авторежим | Автономные агенты, которым все же нужны защитные ограничения при использовании инструментов |
"bypassPermissions" |
Выполняет вызовы инструментов без запроса подтверждения, включая вызовы инструментов, которые вы не указали в allowedTools. Некоторые вызовы все равно передаются в ваш callback canUseTool — они перечислены в разделе Режим Bypass permissions. В TypeScript SDK также требуется allowDangerouslySkipPermissions: true в options. Нельзя использовать при запуске от имени root в Unix. Используйте только в изолированных средах, где действия агента не могут повлиять на важные для вас системы |
CI, контейнеры или другие изолированные среды |
Для интерактивных приложений используйте "default" с callback подтверждения инструментов, чтобы показывать запросы подтверждения. Для автономных агентов на машине разработчика "acceptEdits" автоматически подтверждает правки файлов и распространенные команды файловой системы (mkdir, touch, mv, cp и т. д.), при этом остальные команды Bash по-прежнему требуют разрешающих правил. Оставьте "bypassPermissions" для CI, контейнеров или других изолированных сред. Подробнее см. в разделе Разрешения.
Модель
Задайте параметр model, чтобы выбрать модель, которая будет выполнять сессию. Подробнее см. в разделе Выбор модели.
Контекстное окно
Контекстное окно — это общее количество информации, доступной Claude во время сессии. Оно не сбрасывается между ходами в пределах сессии. Все накапливается: системный промпт, определения инструментов, история диалога, входные данные инструментов и выходные данные инструментов. Содержимое, которое остается неизменным на протяжении ходов (системный промпт, определения инструментов, CLAUDE.md), автоматически кэшируется с помощью кэширования промптов, что снижает стоимость и задержку для повторяющихся префиксов. Информацию о том, как пользовательский системный промпт или текст append влияет на повторное использование кэша между сессиями, см. в разделе Изменение системных промптов.
Что потребляет контекст
Вот как каждый компонент влияет на контекст в SDK:
| Источник | Когда он загружается | Влияние |
|---|---|---|
| Системный промпт | Каждый запрос | Небольшая фиксированная стоимость, всегда присутствует |
| Файлы CLAUDE.md | Начало сессии, через settingSources |
Полное содержимое в каждом запросе (но с кэшированием промптов, поэтому полную стоимость оплачивает только первый запрос) |
| Определения инструментов | Каждый запрос для основных встроенных инструментов, таких как Bash, Read и Edit; по требованию для инструментов MCP и других встроенных инструментов, загрузку которых поиск инструментов по умолчанию откладывает | Все схемы загружаются заранее в случаях, описанных в разделе Настройка поиска инструментов |
| История диалога | Накапливается на протяжении ходов | Растет с каждым ходом: промпты, ответы, входные данные инструментов, выходные данные инструментов |
| Описания скиллов | Начало сессии, через источники настроек | Краткие описания; полное содержимое загружается только при вызове |
Большие выходные данные инструментов потребляют значительный объем контекста. Чтение большого файла или запуск команды с подробным выводом может использовать тысячи токенов за один ход. Контекст накапливается на протяжении ходов, поэтому более длительные сессии с множеством вызовов инструментов накапливают значительно больше контекста, чем короткие.
Автоматическое сжатие контекста
Когда контекстное окно приближается к своему лимиту, SDK автоматически сжимает диалог: он кратко резюмирует более старую историю, чтобы освободить место, сохраняя нетронутыми ваши самые последние обмены сообщениями и ключевые решения. Когда это происходит, SDK выдает в поток сообщение с type: "system" и subtype: "compact_boundary" (в Python это SystemMessage; в TypeScript это отдельный тип SDKCompactBoundaryMessage).
Сжатие контекста заменяет более старые сообщения резюме, поэтому конкретные инструкции из начала диалога могут не сохраниться. Постоянные правила следует размещать в CLAUDE.md (загружаемом через settingSources), а не в начальном промпте, потому что содержимое CLAUDE.md повторно добавляется в каждый запрос.
Вы можете настроить поведение сжатия контекста несколькими способами:
- Инструкции по резюмированию в CLAUDE.md: механизм сжатия читает ваш CLAUDE.md как любой другой контекст, поэтому вы можете добавить раздел, указывающий, что сохранять при резюмировании. Механизм сжатия ориентируется на смысл, поэтому заголовок раздела может быть произвольным.
- Хук
PreCompact: запускайте пользовательскую логику перед сжатием контекста, например для архивирования полного транскрипта. Хук получает полеtrigger(manualилиauto). См. хуки. - Ручное сжатие контекста: отправьте
/compactв качестве строки промпта, чтобы запустить сжатие по требованию. Команды, отправленные таким образом, — это обычные входные данные SDK. См. отправка команд по имени.
[accordion] Пример: инструкции по резюмированию в CLAUDE.md
Добавьте в CLAUDE.md вашего проекта раздел, указывающий механизму сжатия, что сохранять. Название заголовка не имеет особого значения; используйте любую понятную метку.
# 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 them
Эффективное использование контекста
Несколько стратегий для долго работающих агентов:
- Используйте субагентов для подзадач. Субагент возвращает только свой финальный ответ, поэтому контекст основного агента увеличивается на резюме, а не на транскрипт подзадачи.
- Тщательно выбирайте инструменты. Каждое определение инструмента занимает место в контексте. Используйте поле
toolsвAgentDefinition, чтобы ограничить субагентов минимальным необходимым набором инструментов. - Следите за затратами на MCP-серверы. MCP Tool Search по умолчанию откладывает загрузку схем инструментов MCP и загружает их по требованию. Когда поиск инструментов отключен или переключился на предварительную загрузку, каждый MCP-сервер добавляет все свои схемы инструментов в каждый запрос, поэтому несколько серверов с множеством инструментов могут потребить значительный объем контекста еще до того, как агент выполнит какую-либо работу. Конфигурации, в которых применяется этот резервный вариант, см. в разделе Настройка поиска инструментов.
- Используйте более низкий уровень effort для рутинных задач. Установите effort в значение
"low"для агентов, которым нужно только читать файлы или выводить списки каталогов. Это снижает расход токенов и стоимость.
Подробную разбивку затрат контекста по функциям см. в разделе Понимание затрат контекста.
Сессии и непрерывность
Каждое взаимодействие с SDK создает или продолжает сессию. Захватите ID сессии из ResultMessage.session_id (доступно в обоих SDK) для возобновления позже. TypeScript SDK также выставляет его как прямое поле на инициализирующем SystemMessage; в Python он вложен в SystemMessage.data.
Когда вы возобновляете, полный контекст из предыдущих ходов восстанавливается: файлы, которые были прочитаны, анализ, который был выполнен, и действия, которые были предприняты. Вы также можете разветвить сессию, чтобы ветвиться в другой подход без изменения оригинала.
См. Управление сессией для полного руководства по возобновлению, продолжению и разветвлению паттернов. Для возобновления сессий в контейнерах без состояния или бессерверных хостах передайте адаптер session_store / sessionStore, чтобы SDK зеркалировал стенограммы на ваш собственный бэкенд и другой хост мог их возобновить. Подпроцесс Claude Code по-прежнему сначала записывает на локальный диск. См. Архитектура двойной записи для того, какая копия пережидает свежую сессию в сравнении с запуском, возобновленным из хранилища, и как сохранить локальную копию эфемерной.
[!NOTE]
В Python
ClaudeSDKClientавтоматически обрабатывает ID сессий на протяжении нескольких вызовов. См. справку Python SDK для деталей.
Обработать результат
Когда цикл заканчивается, ResultMessage говорит вам, что произошло, и дает вам выход. Поле subtype (доступно в обоих SDK) — это основной способ проверить состояние завершения.
| Подтип результата | Что произошло | Поле result доступно? |
|---|---|---|
success |
Claude нормально завершил задачу | Да |
error_max_turns |
Достигнут лимит maxTurns перед завершением |
Нет |
error_max_budget_usd |
Достигнут лимит maxBudgetUsd перед завершением |
Нет |
error_during_execution |
Ошибка прервала цикл (например, отмененный запрос) | Нет |
error_max_structured_output_retries |
Валидация структурированного выхода не прошла после настроенного лимита повторов | Нет |
Поле result содержит финальный текстовый выход и присутствует только в варианте success, поэтому всегда проверяйте подтип перед его чтением.
Все подтипы результатов содержат total_cost_usd, usage, num_turns и session_id, поэтому вы можете отслеживать стоимость и возобновлять даже после ошибок. Обратите внимание на эти случаи:
- После сбоя сеанса финальный результат — это
error_during_execution, чьи поля стоимости могут быть обнулены и чейstop_reasonравенnull, и процесс завершается после его выдачи. См. Восстановление итогов после сбоя сеанса. - В Python
total_cost_usd,usageиmodel_usageтипизированы как опциональные, поэтому проверьте, что они не равныNoneперед их чтением.
Поле usage охватывает только основной цикл агента. Используйте modelUsage или model_usage в Python для полного учета токенов и стоимости дерева. См. Отслеживание затрат и использования для деталей по интерпретации полей usage.
[!NOTE]
Когда запрос заканчивается на результате ошибки:
- Одиночный вызов
query()выдает финальное сообщение результата, затем вызывает ошибку, которая включает текст отказа, такой какReached maximum number of turns. Вызов ошибки намеренный. Оберните цикл в блок try, если вашему коду нужно продолжить работу после него. Базовый процесс Claude Code также завершается с ненулевым кодом.- Сеанс потоковой передачи входных данных остается активным, и вы можете продолжать отправлять сообщения, кроме случаев после сбоя сеанса, который выдает финальный результат
error_during_executionи завершает процесс.
Результат также включает поле stop_reason (string | null в TypeScript, str | None в Python), указывающее, почему модель остановила генерацию на своем финальном ходе. Общие значения — end_turn (модель закончила нормально), max_tokens (достигнут лимит выходных токенов) и refusal (модель отклонила запрос). На результатах ошибок, которые произвел цикл, stop_reason содержит значение из последнего ответа помощника перед завершением цикла; результат, который Claude Code синтезирует после сбоя сеанса, содержит null.
Для обнаружения отклонений проверьте stop_reason === "refusal" (TypeScript) или stop_reason == "refusal" (Python). См. SDKResultMessage (TypeScript) или ResultMessage (Python) для полного типа.
Hooks
Hooks — это обратные вызовы, которые срабатывают в определенных точках цикла: перед запуском инструмента, после его возврата, когда агент заканчивает, и так далее. Некоторые часто используемые hooks:
| Hook | Когда он срабатывает | Общие использования |
|---|---|---|
PreToolUse |
Перед выполнением инструмента | Валидировать входные данные, блокировать опасные команды |
PostToolUse |
После возврата инструмента | Аудировать выходные данные, запускать побочные эффекты |
UserPromptSubmit |
Когда запрос отправляется | Вводить дополнительный контекст в запросы |
Stop |
Когда агент заканчивает | Валидировать результат, сохранять состояние сессии |
SubagentStart / SubagentStop |
Когда подагент порождается или завершается | Отслеживать и агрегировать результаты параллельных задач |
PreCompact |
Перед компактированием контекста | Архивировать полную транскрипцию перед суммированием |
Hooks работают в процессе вашего приложения, а не внутри контекстного окна агента, поэтому они не потребляют контекст. Hooks также могут короткозамкнуть цикл: hook PreToolUse, который отклоняет вызов инструмента, предотвращает его выполнение, и Claude получает сообщение об отклонении вместо этого.
Оба SDK поддерживают все события выше. TypeScript SDK включает дополнительные события, которые Python еще не поддерживает. См. Контролировать выполнение с помощью hooks для полного списка событий, доступности для каждого SDK и полного API обратного вызова.
Собрать все вместе
Этот пример объединяет ключевые концепции с этой страницы в одного агента, который исправляет неудачные тесты. Он конфигурирует агента с разрешенными инструментами (автоматически одобренными, поэтому агент работает автономно), настройками проекта и ограничениями безопасности на ходы и усилия рассуждения. По мере выполнения цикла он захватывает ID сессии для потенциального возобновления, обрабатывает финальный результат и выводит общую стоимость.
Поскольку один вызов query() вызывает исключение после выдачи результата ошибки, цикл обернут в блок try, чтобы скрипт корректно завершился при достижении лимита.
import asyncio
from 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",
], # Listing tools here auto-approves them (no prompting)
setting_sources=[
"project"
], # Load CLAUDE.md, skills, hooks from current directory
max_turns=30, # Prevent runaway sessions
effort="high", # Thorough reasoning for complex debugging
),
):
# Handle the final result
if isinstance(message, ResultMessage):
session_id = message.session_id # Save for potential resumption
if message.subtype == "success":
print(f"Done: {message.result}")
elif message.subtype == "error_max_turns":
# Agent ran out of turns. Resume with a higher limit.
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:
# A single-shot query() raises after yielding an error result. If the
# failure was an error result, the error subtype branches above have
# already run; connection or process failures yield no result message.
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"], // Listing tools here auto-approves them (no prompting)
settingSources: ["project"], // Load CLAUDE.md, skills, hooks from current directory
maxTurns: 30, // Prevent runaway sessions
effort: "high" // Thorough reasoning for complex debugging
}
})) {
// Save the session ID to resume later if needed
if (message.type === "system" && message.subtype === "init") {
sessionId = message.session_id;
}
// Handle the final result
if (message.type === "result") {
if (message.subtype === "success") {
console.log(`Done: ${message.result}`);
} else if (message.subtype === "error_max_turns") {
// Agent ran out of turns. Resume with a higher limit.
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) {
// A single-shot query() throws after yielding an error result. If the
// failure was an error result, the error subtype branches above have
// already run; connection or process failures yield no result message.
console.log(`Session ended with an error: ${error}`);
}
Когда агент успешно завершает работу, пример выводит строку Done: с резюме исправления агента, а затем строку вроде Cost: $0.0312.
Следующие шаги
Теперь, когда вы понимаете цикл, вот куда идти в зависимости от того, что вы создаете:
- Еще не запустили агента? Начните с quickstart, чтобы установить SDK и увидеть полный пример, работающий от начала до конца.
- Готовы подключиться к вашему проекту? Загрузите CLAUDE.md, skills и hooks файловой системы, чтобы агент автоматически следовал соглашениям вашего проекта.
- Создаете интерактивный UI? Включите потоковую передачу, чтобы показать живой текст и вызовы инструментов по мере выполнения цикла.
- Нужен более плотный контроль над тем, что может делать агент? Заблокируйте доступ к инструментам с помощью разрешений и используйте hooks для аудита, блокировки или преобразования вызовов инструментов перед их выполнением.
- Запускаете долгие или дорогие задачи? Перенесите изолированную работу на подагентов, чтобы держать ваш основной контекст стройным.
- Развертываете как сервис? См. Размещение Agent SDK для руководства по контейнерам и бессерверным решениям, и Хранилище сессий для сохранения сессий в вашем собственном бэкенде.
Для более широкой концептуальной картины цикла агента (не специфичной для SDK) см. Как работает Claude Code. Для практического руководства по проектированию циклов в Claude Code, от циклов на основе ходов к циклам на основе целей и проактивным циклам, см. Loop engineering: getting started with loops в блоге.