Обработка субагентов
Что вы освоите после этого урока
- Поймёте, почему DCP автоматически отключается в сессиях субагентов
- Узнаете о различиях в стратегиях использования токенов между субагентами и основным агентом
- Научитесь избегать проблем при использовании функций DCP в субагентах
Ваша текущая проблема
Вы могли заметить: в некоторых диалогах OpenCode функция обрезки DCP как будто «перестаёт работать» — вызовы инструментов не очищаются, статистика экономии токенов не меняется. Это может происходить при использовании определённых функций OpenCode, таких как проверка кода, глубокий анализ и других.
Это не означает, что DCP сломался. Просто эти функции используют механизм субагентов (Subagent), и DCP имеет особую обработку для них.
Что такое субагент
Что такое субагент (Subagent)?
Субагент — это внутренний механизм AI-агента OpenCode. Основной агент делегирует сложные задачи субагенту, который после завершения возвращает результат в виде краткой сводки.
Типичные сценарии использования:
- Проверка кода: Основной агент запускает субагент, который внимательно читает несколько файлов, анализирует проблемы и возвращает краткий список найденных ошибок
- Глубокий анализ: Основной агент запускает субагента, который выполняет множество вызовов инструментов и логических рассуждений, а затем возвращает ключевые находки
С технической точки зрения, сессия субагента имеет свойство parentID, указывающее на родительскую сессию.
Поведение DCP в отношении субагентов
DCP автоматически отключает все функции обрезки в сессиях субагентов.
Почему DCP не обрезает субагентов?
За этим стоит важная концепция дизайна:
| Роль | Стратегия использования токенов | Основная цель |
|---|---|---|
| Основной агент | Эффективное использование токенов | Поддержание контекста в длинных диалогах, снижение затрат |
| Субагент | Свободное использование токенов | Создание богатой информации для сводки основного агента |
Ценность субагента заключается в его способности «тратить токены ради качества информации» — через многочисленные вызовы инструментов и детальный анализ он предоставляет основному агенту высококачественную сводку. Если DCP начнёт обрезать вызовы инструментов в субагенте, это может привести к:
- Потере информации: Детальный процесс анализа субагента будет удалён, и невозможно будет создать полную сводку
- Снижению качества сводки: Основной агент получит неполную сводку, что повлияет на качество итоговых решений
- Нарушению исходного замысла: Субагент специально разработан для принципа «не жалеть токены ради качества»
Вывод: Субагентам не нужна обрезка, поскольку они в конечном итоге возвращают только краткую сводку родительскому агенту.
Как DCP обнаруживает субагент
DCP определяет, является ли текущая сессия субагентом, следующим образом:
// lib/state/utils.ts:1-8
export async function isSubAgentSession(client: any, sessionID: string): Promise<boolean> {
try {
const result = await client.session.get({ path: { id: sessionID } })
return !!result.data?.parentID // Если есть parentID, значит это субагент
} catch (error: any) {
return false
}
}Моменты обнаружения:
- При инициализации сессии (
ensureSessionInitialized()) - Перед каждым преобразованием сообщения (
createChatMessageTransformHandler())
Поведение DCP в сессиях субагента
Обнаружив субагента, DCP пропускает следующие функции:
| Функция | Обычная сессия | Сессия субагента | Место пропуска |
|---|---|---|---|
| Внедрение системного промпта | ✅ Выполняется | ❌ Пропускается | hooks.ts:26-28 |
| Стратегия автоматической обрезки | ✅ Выполняется | ❌ Пропускается | hooks.ts:64-66 |
| Внедрение списка инструментов | ✅ Выполняется | ❌ Пропускается | hooks.ts:64-66 |
Реализация кода (lib/hooks.ts):
// Обработчик системного промпта
export function createSystemPromptHandler(state: SessionState, ...) {
return async (_input: unknown, output: { system: string[] }) => {
if (state.isSubAgent) { // ← Обнаружение субагента
return // ← Возврат без внедрения описания инструментов обрезки
}
// ... обычная логика
}
}
// Обработчик преобразования сообщений
export function createChatMessageTransformHandler(...) {
return async (input: {}, output: { messages: WithParts[] }) => {
await checkSession(client, state, logger, output.messages)
if (state.isSubAgent) { // ← Обнаружение субагента
return // ← Возврат без выполнения любой обрезки
}
// ... обычная логика: дедупликация, перезапись, очистка ошибок, внедрение списка инструментов и т.д.
}
}Практическое сравнение случаев
Случай 1: Сессия основного агента
Сценарий: Вы общаетесь с основным агентом и просите его проанализировать код
Поведение DCP:
Пользователь: "Проанализируй утилитарные функции в src/utils.ts"
↓
[Основной агент] читает src/utils.ts
↓
[Основной агент] анализирует код
↓
Пользователь: "Теперь проверь src/helpers.ts"
↓
DCP обнаруживает паттерн повторного чтения
↓
DCP помечает первое чтение src/utils.ts как подлежащее обрезке ✅
↓
При отправке контекста в LLM содержимое первого чтения заменяется плейсхолдером
↓
✅ Экономия токеновСлучай 2: Сессия субагента
Сценарий: Основной агент запускает субагента для глубокой проверки кода
Поведение DCP:
Пользователь: "Глубоко проверь все файлы в src/"
↓
[Основной агент] обнаруживает сложную задачу, запускает субагента
↓
[Субагент] читает src/utils.ts
↓
[Субагент] читает src/helpers.ts
↓
[Субагент] читает src/config.ts
↓
[Субагент] читает больше файлов...
↓
DCP обнаруживает сессию субагента
↓
DCP пропускает все операции обрезки ❌
↓
[Субагент] создаёт детальный результат проверки
↓
[Субагент] возвращает краткую сводку основному агенту
↓
[Основной агент] генерирует итоговый ответ на основе сводкиЧасто задаваемые вопросы
Q: Как подтвердить, что текущая сессия является сессией субагента?
A: Вы можете подтвердить это следующими способами:
Посмотрите логи DCP (если включён режим отладки):
2026-01-23T10:30:45.123Z INFO state: session ID = abc-123 2026-01-23T10:30:45.124Z INFO state: isSubAgent = trueНаблюдайте за характеристиками диалога:
- Субагенты обычно запускаются при обработке сложных задач (например, глубокий анализ, проверка кода)
- Основной агент может показывать сообщение «Запускается субагент» или аналогичное
Используйте команду /dcp stats:
- В сессии субагента вызовы инструментов не обрезаются
- В статистике токенов количество «обрезанных» элементов равно 0
Q: Не приведёт ли полный отказ от обрезки в субагентах к большому расходу токенов?
A: Нет. Причины следующие:
- Субагенты недолговечны: Субагент завершает работу после выполнения задачи, в отличие от основного агента, который ведёт длинные диалоги
- Субагент возвращает сводку: Основному агенту передаётся краткая сводка, которая не увеличивает нагрузку на контекст основного агента
- Разные цели дизайна: Цель субагента — «тратить токены ради качества», а не «экономить токены»
Q: Можно ли принудительно заставить DCP обрезать субагента?
A: Нет, и не следует. DCP специально разработан, чтобы позволить субагентам полностью сохранять контекст для создания качественных сводок. Принудительная обрезка может:
- Привести к неполноте информации в сводке
- Повлиять на качество решений основного агента
- Нарушить концепцию дизайна субагентов в OpenCode
Q: Учитывается ли использование токенов в сессиях субагента в статистике?
A: Сессии субагентов сами по себе не учитываются в статистике DCP. DCP отслеживает экономию токенов только в сессиях основного агента.
Итоги урока
- Обнаружение субагента: DCP определяет сессии субагента через проверку
session.parentID - Автоматическое отключение: В сессиях субагента DCP автоматически пропускает все функции обрезки
- Причина дизайна: Субагентам нужен полный контекст для создания качественных сводок, а обрезка может нарушить этот процесс
- Границы использования: Субагенты не стремятся к эффективности токенов, а стремятся к качеству информации — это отличается от целей основного агента
Анонс следующего урока
В следующем уроке мы изучим Часто задаваемые вопросы и устранение неполадок.
Вы узнаете:
- Как исправить ошибки конфигурации
- Как включить отладочные логи
- Частые причины, почему токены не уменьшаются
- Ограничения сессий субагентов
Приложение: Ссылка на исходный код
Нажмите, чтобы развернуть расположение исходного кода
Время обновления: 2026-01-23
| Функция | Путь к файлу | Номера строк |
|---|---|---|
| Функция обнаружения субагента | lib/state/utils.ts | 1-8 |
| Инициализация состояния сессии | lib/state/state.ts | 80-116 |
| Обработчик системного промпта (пропуск субагента) | lib/hooks.ts | 26-28 |
| Обработчик преобразования сообщений (пропуск субагента) | lib/hooks.ts | 64-66 |
| Определение типа SessionState | lib/state/types.ts | 27-38 |
Ключевые функции:
isSubAgentSession(): Обнаружение субагента черезsession.parentIDensureSessionInitialized(): Обнаружение субагента при инициализации состояния сессииcreateSystemPromptHandler(): Пропуск внедрения системного промпта в сессиях субагентаcreateChatMessageTransformHandler(): Пропуск всех операций обрезки в сессиях субагента
Ключевые константы:
state.isSubAgent: Флаг субагента в состоянии сессии