中文翻译暂不可用,显示俄语原文。
Что такое «circuit breaker» на уровне меж-агентских вызовов?
Краткий тезис
Circuit breaker (автоматический выключатель) — это паттерн отказоустойчивости, предотвращающий каскадные отказы в распределённых системах. На уровне меж-агентских вызовов он отслеживает ошибки при обращении одного агента к другому и при превышении порога временно блокирует вызовы, давая целевому агенту время на восстановление. Без такого механизма один упавший агент может вызвать лавину таймаутов и исчерпание ресурсов во всей цепочке.
1. Термин: Circuit breaker (автоматический выключатель)
Circuit breaker — это паттерн, заимствованный из электротехники. В программных системах он оборачивает вызов удалённого сервиса (или агента) и переключается между тремя состояниями:
- Closed (замкнут) — обычный режим: вызовы проходят, ошибки учитываются.
- Open (разомкнут) — вызовы немедленно завершаются с исключением (или fallback-ответом), не доходя до целевого сервиса.
- Half-Open (полуоткрыт) — после заданной паузы пропускается ограниченное число пробных запросов, чтобы проверить, восстановился ли сервис.
Цель — не тратить ресурсы на заведомо неудачные вызовы и дать системе стабилизироваться.
Контекст RAG|agentic RAG: агенты вызывают друг друга (например, агент-планировщик вызывает агента-исполнителя). Если агент-исполнитель перегружен или упал, breaker|circuit breaker не даёт планировщику бесконечно ждать и позволяет сразу переключиться на другой агент или вернуть кэшированный ответ.
2. Состояния circuit breaker и их поведение
| Состояние | Что происходит | Переход |
|---|---|---|
| Closed | Все вызовы выполняются. Счётчик неудач (или доля ошибок) сбрасывается, если вызов успешен. | При превышении порога ошибок → Open |
| Open | Вызовы блокируются (ошибка «circuit breaker open»). Через sleep window (время сна) переходит в Half-Open. | По истечении sleep window → Half-Open |
| Half-Open | Пропускается ограниченное число пробных запросов. Если все успешны → Closed, иначе → Open. | Успех → Closed; неудача → Open |
Пример с настройками:
- Порог ошибок: 5 неудач за 10 секунд.
- Sleep window: 30 секунд.
- Пробных запросов в Half-Open: 3.
3. Триггеры, пороги и параметры
breaker|Circuit breaker реагирует на наблюдаемые сбои. Основные триггеры:
- Процент ошибок — например, >50% запросов завершились с ошибкой за последнюю минуту.
- Абсолютное число ошибок — более N ошибок подряд.
- Таймауты — если запрос не укладывается в заданное время, он засчитывается как ошибка.
- Исключения — только определённые типы (например,
ServiceUnavailable), а не все ошибки (логические ошибки не должны открывать breaker).
Параметры конфигурации:
- failureThreshold — количество или процент ошибок для открытия.
successThreshold— количество успешных вызовов в Half-Open для закрытия.- timeout — максимальное время ожидания ответа (превышение = ошибка).
sleepWindow— время, в течение которого breaker остаётся открытым перед переходом в Half-Open.
4. Реализации circuit breaker
4.1 Готовые библиотеки
| Инструмент | Язык/Платформа | Особенности |
|---|---|---|
| Resilience4j | Java | Легковесная, модульная, поддержка реактивного программирования. |
| Hystrix (Netflix, устарел) | Java | Был стандартом, но в maintenance mode. |
| pybreaker | Python | Простая реализация для Python-приложений. |
| Polly | .NET | Богатая функциональность, поддержка политик retry, timeout, circuit breaker. |
| Istio (Envoy) | Service Mesh | circuit breaker на уровне сети, без изменения кода. |
4.2 Пример на Python с pybreaker
import pybreaker
import requests
breaker = pybreaker.CircuitBreaker(
fail_max=3, # 3 ошибки подряд -> Open
reset_timeout=30, # 30 секунд в Open -> Half-Open
exclude=[requests.exceptions.Timeout] # не учитывать таймауты
)
@breaker
def call_agent_b(payload):
resp = requests.post("http://agent-b:8080/process", json=payload, timeout=5)
resp.raise_for_status()
return resp.json()
# Использование
try:
result = call_agent_b({"query": "как настроить VPN?"})
except pybreaker.CircuitBreakerError:
# fallback — вернуть кэшированный ответ или обратиться к другому агенту
result = {"answer": "Агент B временно недоступен. Попробуйте позже."}
4.3 Custom implementation (прототип)
В микросервисной архитектуре можно реализовать на основе redis или in-memory:
import time
class CircuitBreaker:
def __init__(self, threshold=5, timeout=30):
self.threshold = threshold
self.timeout = timeout
self.failures = 0
self.last_failure_time = 0
self.state = "closed"
def call(self, func, *args, **kwargs):
if self.state == "open":
if time.time() - self.last_failure_time >= self.timeout:
self.state = "half-open"
else:
raise CircuitBreakerOpenError
try:
result = func(*args, **kwargs)
if self.state == "half-open":
self.state = "closed"
self.failures = 0
return result
except Exception:
self.failures += 1
self.last_failure_time = time.time()
if self.failures >= self.threshold:
self.state = "open"
raise
5. Применение на уровне меж-агентских вызовов
В агентной системе (Agentic RAG) несколько агентов обмениваются сообщениями. Например:
- Роутер → направляет запрос к нужному агенту.
- Агент-планировщик → разбивает задачу на шаги.
- Агент-исполнитель → вызывает LLM, ищет в базе знаний.
- Агент-валидатор → проверяет ответ.
Если один из агентов (допустим, поисковый) перегружен, circuit breaker на вызове agent_search.call() мгновенно переключит планировщик на fallback — либо использовать кэш, либо другого поискового агента (если есть реплика), либо вернуть сообщение о недоступности.
Особенности для агентов:
- Каждый вызов — это, как правило, HTTP/gRPC запрос или вызов очереди сообщений.
- Idempotency (идемпотентность) важна: повторная отправка запроса после открытия Half-Open не должна приводить к дублированию действия.
- Circuit breaker должен учитывать не только ошибки сети, но и логические ошибки (например, агент вернул пустой ответ) — по желанию.
6. Fallback и комбинирование с другими паттернами
Circuit breaker редко работает один. Стандартный стек отказоустойчивости включает:
| Паттерн | Назначение | Сочетание |
|---|---|---|
| Timeout | Ограничить время ожидания | Без таймаута circuit breaker может не сработать (зависшие запросы не учитываются) |
| Retry | Повторить вызов при временной ошибке | Retry ставится перед circuit breaker; после нескольких retry breaker открывается |
| Bulkhead | Ограничить число одновременных вызовов | Предотвращает истощение пулов потоков при каскаде |
| Fallback | Вернуть запасной ответ при открытом breaker | Например, кэш, статические данные, ответ от другого агента |
Пример цепочки:
- Вызвать агента с таймаутом 5 с.
- Если таймаут или ошибка — retry до 2 раз.
- Если retry не помогли — circuit breaker считает ошибку.
- При открытом breaker → fallback: вернуть ответ из кэша, помеченного как «возможно устаревший».
7. Преимущества и риски
| Плюсы | Минусы |
|---|---|
| Быстрый отказ (fail-fast) | Дополнительная сложность конфигурации |
| Защита от каскадных отказов | Возможно ложное открытие при кратковременных скачках |
| Уменьшение нагрузки на упавший сервис | Требует мониторинга состояний |
| Возможность graceful degradation | Не решает проблему идемпотентности повторных вызовов |
8. Тонкости настройки для агентов
- Порог ошибок должен быть адаптивным: для критичных агентов (например, оплата) можно делать более чувствительным.
- Sleep window — не слишком короткий (иначе breaker будет часто срабатывать), не слишком длинный (агент может быть готов раньше).
- Пробные запросы в Half-Open должны быть идемпотентными и лёгкими (можно отправлять heartbeats).
- Мониторинг: состояния circuit breaker нужно логировать и показывать в дашбордах (например, Prometheus + Grafana).
Пет-проект для закрепления
Задача: Реализовать простую имитацию агентной системы с circuit breaker на Python, где два агента общаются через HTTP.
Инструменты:
- Python с библиотеками
requests,pybreaker,flask(для имитации второго агента).
Шаги:
- Создать Flask-сервер
agent_b.py, который иногда отвечает с ошибкой 500 (например, 50% запросов). - Создать
agent_a.py, который вызывает agent_b с circuit breaker (pybreaker). - Настроить: fail_max=2, reset_timeout=10, exclude=[].
- Написать fallback-функцию, возвращающую сообщение "Agent B busy, using cached data".
- Запустить оба процесса, послать 20 запросов подряд, наблюдать логи.
Ожидаемый результат:
- После первых двух ошибок breaker переходит в Open.
- Следующие запросы (пока не прошло 10 с) сразу получают fallback.
- Через 10 с breaker переходит в Half-Open, отправляется пробный запрос.
- Если сервер снова отвечает ошибкой -> breaker снова Open, если успехом -> Closed.
Расширение: добавить ещё одного агента-дублёра и реализовать переключение при открытом breaker.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 818 | Timeout и retry для агентских вызовов |
| 820 | Backpressure в распределённых AI-системах |
| 822 | Idempotency в меж-агентской коммуникации |
| 817 | Bulkhead для изоляции ресурсов агентов |
| 825 | Graceful degradation и fallback-стратегии |
| 832 | Мониторинг отказоустойчивости агентной системы |
Навигация
- Предыдущий: 818
- Следующий: 820
- Индекс: 00. Индекс разборов