Мультиагентная система - не цель, а дорогой способ декомпозиции
Несколько агентов добавляют новые модельные вызовы, сетевые переходы, состояние, права доступа и точки отказа. Они оправданы не потому, что роли выглядят правдоподобно, а когда декомпозиция улучшает измеримый результат. Сначала соберите сильный single-agent baseline с качественными tools, инструкциями и eval-набором.
Если один агент решает задачу в допустимом контексте, времени и бюджете, многоагентность обычно усложнит эксплуатацию. Если же отдельные домены требуют разных данных, политик, моделей или могут безопасно выполняться параллельно, разбиение становится инженерным инструментом.
Когда несколько агентов действительно нужны
| Сигнал | Польза разделения | Проверка |
|---|---|---|
| Разные домены | Узкие инструкции и tools | Меньше ошибок routing и tool selection |
| Чувствительные данные | Изоляция контекста и прав | Специалист не видит лишние данные |
| Независимые подзадачи | Параллельное выполнение | Снижается end-to-end latency |
| Разные команды-владельцы | Версионирование по доменам | Изменения имеют независимый rollout |
| Разные модели | Цена и качество под подзадачу | Ниже стоимость успешного результата |
Формулировка «исследователь, критик и автор» сама по себе ничего не доказывает. Проверьте, обладает ли каждая роль уникальными данными, инструментами, политикой или критерием качества.
Два базовых паттерна: supervisor и handoff
OpenAI Agents SDK выделяет два распространённых варианта. В manager-паттерне главный агент вызывает специалистов как tools и сохраняет контроль над разговором и финальным ответом. При handoff маршрутизатор передаёт управление специалисту, который становится активным агентом. Эти варианты можно сочетать.
Supervisor
Планирует, делегирует, проверяет и собирает один ответ.
Handoff
Меняет активного владельца задачи и его инструкции.
Hybrid
Маршрутизация между доменами плюс локальные подагенты.
Выбор паттерна по владению результатом
| Вопрос | Supervisor | Handoff |
|---|---|---|
| Кто отвечает пользователю | Один manager | Активный специалист |
| Кто объединяет выводы | Manager | Не требуется либо отдельный шаг |
| Единая политика | Проще централизовать | Нужна на каждом переходе |
| Изоляция инструкций | Специалист вызывается как подзадача | Полная смена активного контекста |
| Риск bottleneck | Выше у manager | Выше риск потерять общий контроль |
Если финальный ответ должен объединять расчёты, юридические ограничения и факты, удобнее manager. Если пользователь после первичной классификации должен работать напрямую с отделом возвратов, handoff естественнее.
Детерминированный workflow часто надёжнее свободного роутинга
Не каждое решение о следующем шаге нужно отдавать модели. Код может классифицировать структурированный результат, запустить независимые задачи параллельно, дождаться обязательных зависимостей и завершить workflow по явным условиям. Официальный гайд OpenAI прямо допускает сочетание orchestration через LLM и через код.
- Жёсткие compliance-переходы задавайте state machine.
- Независимые read-only исследования запускайте fan-out/fan-in.
- Свободное планирование оставляйте внутри безопасного участка.
- Для evaluator loop задайте максимальное число итераций.
- Недопустимый переход отклоняет runtime.
Карта агентов начинается с доменных границ
Опишите каждого агента как сервисный контракт, а не как характер. Нужны цель, входы, выходы, источники истины, разрешённые tools, запрещённые действия, владелец и SLO. Пересекающиеся обязанности приводят к гонкам и спору о том, кто должен завершить работу.
Agent ID: billing_refund_v2 Goal: prepare a refund eligibility decision, not execute payment. Accepts: case_id, reason_code, requested_amount. Reads: order ledger, refund policy. Writes: immutable decision proposal. Tools: get_order, get_policy, propose_refund. Forbidden: direct payment, policy editing, cross-tenant search. Output schema: RefundDecisionV2. Owner: Billing Platform. Timeout: 20 s. Max tool calls: 6.
Handoff должен быть типизированным конвертом
Передача полного диалога без пояснения заставляет следующего агента заново угадывать задачу. Создайте явный envelope: идентификаторы, цель, проверенные факты, ссылки на артефакты, критерии готовности, ограничения, бюджет и причину маршрутизации. Свободный текст можно приложить, но не использовать как единственный контракт.
{
"task_id": "t_...",
"parent_id": "t_...",
"from_agent": "triage_v3",
"to_agent": "billing_refund_v2",
"objective": "Decide refund eligibility",
"verified_facts": [{"field": "order_id", "value": "...", "source": "ledger://..."}],
"artifact_refs": [],
"definition_of_done": ["valid RefundDecisionV2", "policy clause cited"],
"remaining_budget": {"deadline_ms": 15000, "tool_calls": 6},
"trace_id": "tr_..."
}Не смешивайте транскрипт, рабочее состояние и память
| Слой | Что хранит | Срок и контроль |
|---|---|---|
| Transcript | Сообщения и tool events | Сессия, фильтрация перед передачей |
| Workflow state | Статусы, зависимости, бюджеты, approvals | Транзакционно до завершения |
| Artifacts | Отчёты, таблицы, документы | Версии и immutable references |
| Long-term memory | Разрешённые устойчивые факты | TTL, provenance, удаление и consent |
Shared state не означает, что каждый агент получает всё. Runtime формирует минимальное представление по роли, tenant и data classification. Изменение критичного состояния проходит через compare-and-set или транзакцию.
Источник истины не должен жить в ответе модели
Статус заказа, баланс, права и решение об approval читаются из authoritative systems. Сообщение агента является предложением или ссылкой на проверенный артефакт. В shared state сохраняйте не только значение, но и источник, время, версию и уровень доверия.
- Не копируйте большие документы между агентами - передавайте immutable reference.
- Не повышайте непроверенный вывод до verified fact.
- При конфликте повторно читайте источник истины.
- Логируйте, какой агент создал каждое утверждение.
- Персональные данные редактируйте до передачи.
Бюджет наследуется вниз, но не расширяется
Родительская задача задаёт общий deadline, лимит токенов, денег, tool calls, глубины и числа параллельных ветвей. Дочерний агент получает часть остатка. Он не может сам увеличить лимит или запустить неограниченное количество потомков.
global deadline = 60 s max depth = 3 max fan-out = 4 max total model calls = 12 max total tool calls = 30 max retries per operation = 2 child budget <= unallocated parent remainder stop on: deadline, exhausted budget, repeated state, cancellation, policy denial return: partial_result + missing_items + reason
Права делегируются уже выданного scope
Handoff не должен превращаться в повышение привилегий. Специалист получает пересечение прав пользователя, workflow, вызывающего агента, политики tenant и текущего состояния. Credentials модели не видны; runtime выдаёт короткоживущий capability token для конкретной операции.
Prompt injection распространяется по цепочке
Если исследователь прочитал вредоносную инструкцию на странице и передал её как «вывод», supervisor может довериться ей. Tool output, документы, память и сообщения других агентов остаются недоверенными данными. Они не могут менять system policy или выдавать права.
- Отделяйте инструкции от данных структурой сообщения.
- Передавайте цитату и provenance, а не скрытую команду.
- Фильтруйте историю при handoff.
- Повторно авторизуйте каждый side effect.
- Сканируйте артефакты до записи в общую память.
- Тестируйте indirect injection через каждого специалиста.
Deadlock, livelock и ping-pong - разные сбои
| Сбой | Пример | Защита |
|---|---|---|
| Deadlock | А ждёт B, B ждёт A | DAG зависимостей, timeout, запрет циклического wait |
| Livelock | Агенты меняют план, но не приближаются к цели | Progress invariant и max iterations |
| Ping-pong | Два специалиста возвращают задачу друг другу | Handoff history и запрет повторного ребра |
| Duplicate work | Две ветви создают один объект | Dedup key, lease, idempotency |
| Fan-out explosion | Каждый агент создаёт несколько детей | Глобальный лимит ветвей и depth |
Определите прогресс как проверяемое изменение
Фраза агента «продолжаю анализ» не является прогрессом. Оркестратор сравнивает состояние: появился новый подтверждённый факт, закрыта зависимость, создан валидный артефакт или уменьшился список неизвестного. Повтор того же состояния фиксируется fingerprint и останавливает ветвь.
- Сохранить fingerprint входа и состояния.
- Проверить повторный маршрут.
- Ограничить глубину и итерации.
- Проверить изменение progress metric.
- Остановить ветвь по deadline.
- Вернуть partial result вместо бесконечного retry.
- Поднять alert при систематическом цикле.
Параллельность требует политики слияния
Fan-out ускоряет независимые задачи, но fan-in должен понимать, какие результаты обязательны, как разрешать конфликт и что делать с опоздавшей ветвью. Не просите модель произвольно «усреднить» противоречия.
- Для факта выберите authoritative source.
- Для расчёта сравните входы и версию формулы.
- Для текста сохраните замечания как отдельные proposals.
- Для записи используйте optimistic locking.
- Для обязательной ветви завершайте с явным incomplete.
- После cancel запрещайте поздний side effect.
Ошибки, отмена и частичный результат проектируются заранее
Каждый агент возвращает typed status: completed, incomplete, denied, failed или cancelled. Ошибка содержит code, retryability, безопасное описание и ссылки на уже созданные артефакты. Оркестратор решает retry, fallback, human escalation или завершение с неполным результатом.
| Событие | Реакция | Запрет |
|---|---|---|
| Transient timeout | Ограниченный retry в общем deadline | Бесконечный локальный retry |
| Policy denied | Объяснение и эскалация | Обход другим агентом |
| Child failed | Fallback или partial result | Скрывать незавершённость |
| User cancelled | Распространить cancel token | Новые side effects |
Human-in-the-loop ставится перед необратимым действием
Подтверждение относится не к «работе агента вообще», а к неизменяемому proposal: получатели, сумма, ресурсы, diff, риск и срок. После любого изменения proposal approval теряет силу. Проверяющий видит происхождение данных и альтернативы.
Preview
Точный diff и последствия.
Approve
Scope, actor, expiry и hash.
Execute
Idempotency и audit event.
Trace должен показывать граф, а не только чат
Один trace_id связывает запрос пользователя, решение маршрутизатора, handoffs, model calls, tools, approvals, артефакты и итог. Для каждого span записывайте agent/version, prompt/config version, модель, входные references, токены, стоимость, latency, status и policy decisions. Чувствительные payload храните отдельно или редактируйте.
trace_id, task_id, parent_task_id agent_id, agent_version, route_reason model, prompt_version, tool_schema_version input_refs, output_refs, handoff_target start_time, latency, tokens, estimated_cost policy_decisions, approval_id status, error_code, retry_count progress_before, progress_after
Метрики координации важнее числа сообщений
| Метрика | Что показывает | Плохой сигнал |
|---|---|---|
| Task success | Выполнен критерий готовности | Красивый ответ без результата |
| Cost per success | Цена успешной задачи | Средняя цена без учёта провалов |
| Unnecessary handoff rate | Лишняя маршрутизация | Рост переходов без качества |
| Loop rate | Повторные состояния и ребра | Ping-pong |
| Coordination overhead | Доля времени и токенов на передачу | Специалисты дешевле, система дороже |
| Human escalation | Где автономность заканчивается | Скрытые ручные исправления |
Evals сравнивают архитектуры на одинаковых задачах
Соберите датасет из обычных, пограничных, неоднозначных и враждебных сценариев. На одинаковых входах сравните один агент, supervisor и handoff-вариант. Проверяйте не только финальный текст, но и маршрут, права, вызовы tools, side effects, стоимость и восстановление после сбоя.
- Правильный выбор владельца.
- Отказ от ненужного handoff.
- Валидный envelope.
- Сохранение provenance.
- Запрет повышения прав.
- Остановка циклов и fan-out.
- Корректная отмена.
- Partial result при отказе ветви.
- Injection через tool output.
- Сравнение cost per success с baseline.
План внедрения без big bang
- Зафиксируйте baseline. Один агент, датасет, качество, p95 latency и стоимость успешной задачи.
- Выделите одну границу. Например, отдельный read-only специалист по политике.
- Введите контракт. Typed inputs, output, provenance и error taxonomy.
- Добавьте runtime limits. Depth, fan-out, deadline, токены и tools.
- Запустите shadow. Новый граф не выполняет side effects.
- Сравните evals. Выигрыш должен покрывать coordination overhead.
- Откройте малый трафик. Canary с kill switch.
- Расширяйте по одной границе. Не добавляйте сразу сеть из десятков ролей.
Production-чек-лист мультиагентной системы
- Есть измеримый single-agent baseline.
- Каждый агент имеет непересекающийся контракт и владельца.
- Граф допустимых переходов задан runtime.
- Handoff envelope типизирован и версионируется.
- Transcript, state, artifacts и memory разделены.
- Права только сужаются при делегировании.
- Настроены depth, fan-out, deadline, token и cost limits.
- Есть loop detection, deduplication и idempotency.
- Cancel распространяется на все дочерние операции.
- Prompt injection не может менять policy.
- Trace связывает весь граф и версии.
- Evals проверяют маршруты, side effects и отказоустойчивость.
- Есть canary, kill switch и single-agent fallback.
Что такое мультиагентная система?
Чем supervisor отличается от handoff?
Всегда ли несколько агентов лучше одного?
Как передавать контекст между агентами?
Как остановить бесконечные циклы агентов?
Можно ли делиться одной памятью между всеми агентами?
Какие метрики нужны для мультиагентной системы?
Как безопасно запустить мультиагентную архитектуру?
- OpenAI Agents SDK - Agent orchestration
- OpenAI Agents SDK - Handoffs
- OpenAI Agents SDK - Context management
- OpenAI Agents SDK - Usage tracking
- Google Agent Development Kit - Multi-agent systems
- Amazon Bedrock - Multi-agent collaboration
- Microsoft Azure Architecture Center - AI agent orchestration patterns
- OWASP - Agentic AI threats and mitigations