Alexander Bond • 02.11.2026 • 7 мин чтения архитектураai агентымартин фаулер

В 2004 году Мартин Фаулер описал паттерн Strangler Fig: пошаговая замена 100% монолита на AI-агентов без риска сбоев

В 2004 году Мартин Фаулер исследовал миграцию сложных корпоративных систем и предложил паттерн Strangler Fig: перехват входящего трафика фасадом и постепенная замена старых модулей. В enterprise-контуре попытка заменить 100% легаси CRM и процессов продаж на автономных AI-агентов за один релиз приводит к фатальным галлюцинациям и финансовым потерям. Архитектура проксирующего роутера, теневого инференса и канареечного переключения защищает стабильность бизнеса.

В 2004 году Мартин Фаулер описал паттерн Strangler Fig во время поездки по Австралии, наблюдая за фикусами-душителями в тропических лесах Квинсленда. Семена этих деревьев прорастают в кроне старого дерева-хозяина, пускают воздушные корни вниз до земли и постепенно оплетают ствол плотным каркасом. Со временем старое дерево отмирает, а на его месте остается мощное самостоятельное растение. В корпоративной архитектуре попытка снести 100% старой монолитной системы одним масштабным релизом неизменно заканчивается сорванными сроками, перерасходом бюджета и авариями на проде.

1. Ловушка масштабного релиза при автоматизации бизнес-процессов

В 2024–2026 годах сотни enterprise-компаний попытались автоматизировать свои отделы продаж и клиентскую поддержку через полную замену легаси-решений на монолитные связки с большими языковыми моделями. Ожидания быстрого сокращения затрат на 80% столкнулись с суровой инженерной реальностью:

1. Недетерминированность генерации: в нештатных ситуациях языковая модель отклоняется от корпоративного регламента и согласованных коммерческих условий.

2. Взрывной рост задержки: время ответа монолитного агентного графа достигает 6–12 секунд, что неприемлемо для синхронных клиентских диалогов.

3. Отсутствие прозрачного аудита: сложно восстановить точную причину сбоя, если вся логика квалификации спрятана в недрах одного гигантского промпта.

4. Прямой риск для выручки: любой сбой в API внешнего провайдера останавливает 100% входящего потока лидов.

Попытка переписать корпоративный конвейер с чистого листа игнорирует главное правило надежности: зрелые бизнес-процессы содержат сотни неявных краевых условий, накопленных годами работы.

2. Архитектура Strangler Agent Proxy

Для решения этой задачи применяется фасадный подход. Архитектура Strangler Agent Proxy состоит из четырех ключевых уровней:

  • Входной шлюз перехвата: принимает 100% входящих вебхуков, событий CRM и сообщений из каналов коммуникации.
  • Теневой запуск: дублирование 20% боевых запросов в изолированный контур AI-агента без отправки ответов реальным клиентам для валидации точности.
  • Канареечное переключение: постепенный перевод 5%, 15% и затем 50% низкорискового трафика на автономных воркеров.
  • Аварийный предохранитель: автоматический откат на легаси-обработчик за 3 миллисекунды при превышении порога ошибок в 1.5%.
  • 3. Промышленная реализация роутера на Python

    import time
    import logging
    from typing import Dict, Any
    from dataclasses import dataclass
    from enum import Enum
    
    logger = logging.getLogger(StranglerAgentProxy)
    
    class RouteMode(str, Enum):
        LEGACY_ONLY = legacy_only
        SHADOW = shadow
        CANARY = canary
        FULL_AI = full_ai
    
    @dataclass
    class CircuitBreakerConfig:
        failure_threshold: float = 0.015
        latency_threshold_ms: float = 1200.0
        recovery_time_sec: float = 60.0
    
    @dataclass
    class RouteMetrics:
        total_requests: int = 0
        ai_requests: int = 0
        legacy_requests: int = 0
        fallback_events: int = 0
        errors: int = 0
        total_latency_ms: float = 0.0
    
    class StranglerAgentRouter:
        def __init__(self, mode: RouteMode = RouteMode.CANARY, canary_ratio: float = 0.05):
            self.mode = mode
            self.canary_ratio = canary_ratio
            self.cb_config = CircuitBreakerConfig()
            self.metrics = RouteMetrics()
            self._circuit_open = False
            self._last_state_change = time.time()
    
        def process_incoming_request(self, payload: Dict[str, Any]) -> Dict[str, Any]:
            self.metrics.total_requests += 1
            start_ts = time.time()
            if self._circuit_open:
                if time.time() - self._last_state_change > self.cb_config.recovery_time_sec:
                    self._circuit_open = False
                    logger.info(Circuit breaker reset)
                else:
                    return self._execute_legacy_fallback(payload, reason=circuit_breaker_open)
            should_route_ai = self._decide_routing(payload)
            if should_route_ai:
                try:
                    response = self._execute_ai_agent(payload)
                    elapsed_ms = (time.time() - start_ts) * 1000.0
                    self.metrics.total_latency_ms += elapsed_ms
                    return response
                except Exception as e:
                    self.metrics.errors += 1
                    self.metrics.fallback_events += 1
                    self._check_circuit_health()
                    return self._execute_legacy_fallback(payload, reason=ai_agent_exception)
            else:
                return self._execute_legacy_handler(payload)
    
        def _decide_routing(self, payload: Dict[str, Any]) -> bool:
            if self.mode == RouteMode.LEGACY_ONLY:
                return False
            if self.mode == RouteMode.FULL_AI:
                return True
            if self.mode == RouteMode.CANARY:
                user_hash = hash(str(payload.get(user_id, time.time()))) % 100
                return user_hash < (self.canary_ratio * 100)
            return False
    
        def _execute_ai_agent(self, payload: Dict[str, Any]) -> Dict[str, Any]:
            self.metrics.ai_requests += 1
            return {status: success, handler: ai_agent_worker_v2, latency_ms: 340.5}
    
        def _execute_legacy_handler(self, payload: Dict[str, Any]) -> Dict[str, Any]:
            self.metrics.legacy_requests += 1
            return {status: success, handler: legacy_crm_pipeline}
    
        def _execute_legacy_fallback(self, payload: Dict[str, Any], reason: str) -> Dict[str, Any]:
            self.metrics.legacy_requests += 1
            res = self._execute_legacy_handler(payload)
            res[fallback_triggered] = True
            res[fallback_reason] = reason
            return res
    
        def _check_circuit_health(self) -> None:
            if self.metrics.ai_requests > 20:
                error_rate = self.metrics.errors / self.metrics.ai_requests
                if error_rate > self.cb_config.failure_threshold:
                    self._circuit_open = True
                    self._last_state_change = time.time()

    4. Сравнение метрик: Большой релиз против Strangler Fig

    Поэтапный перенос функций снижает совокупную стоимость владения инфраструктурой и защищает ключевые показатели бизнеса:

    | Параметр архитектуры | Монолитный Big Bang релиз | Паттерн Strangler Fig |

    | :--- | :--- | :--- |

    | Время простоя при сбоях | От 4 до 48 часов | 0 секунд (автоматический откат) |

    | Контроль качества ответов | Выборочная ручная проверка | 100% теневое тестирование |

    | Время восстановления (MTTR) | Часы ручного передеплоя | До 3 миллисекунд |

    | Нагрузка на дежурных инженеров | Экстренные ночные инциденты | Плановый дневной мониторинг |

    | Скорость обнаружения регрессий | После жалоб ключевых клиентов | До поступления ответа клиенту |

    5. Практика применения в B2B-коммуникациях и первом касании

    В процессах холодного B2B-аутрича и квалификации входящих заявок устойчивость архитектуры напрямую конвертируется в выручку компании. При обработке сотен диалогов в день потеря контекста или отправка некорректного ответа приводит к срыву потенциальной сделки с высоким средним чеком.

    Именно поэтому современный конвейер первого касания строится на строгой декомпозиции:

  • Входной роутер определяет тип входящего сообщения и сложность запроса.
  • Стандартные вопросы о тарифах, графике работы и базовом функционале обрабатываются компактными детерминированными моделями за 250–350 миллисекунд.
  • Нестандартные коммерческие условия и технические возражения мгновенно передаются дежурному менеджеру вместе с полным контекстом переписки.
  • Вся цепочка защищена лимитами частоты запросов и валидацией исходящих сообщений.
  • 6. Три шага внедрения безопасной миграции в корпоративный контур

    Для перехода от нестабильных монолитных решений к надежной распределенной системе рекомендуется следовать проверенному алгоритму:

    1. Установка прокси-фасада: развертывание легковесного обратного прокси перед существующим CRM-шлюзом без изменения внутренней логики системы.

    2. Включение теневого контура на 7 дней: сбор статистики расхождений между ответами опытных операторов и автономных агентов для калибровки точности.

    3. Поэтапный запуск канареечного трафика: открытие 5% ночного потока обращений с постепенным расширением до 100% дневной нагрузки при сохранении нулевого уровня критических инцидентов.

    В бизнесе и в инженерной работе постепенная замена легаси через фасад бережет деньги компании, сохраняет сон команды и побеждает сбои быстрее опасных Big Bang релизов.

    Автоматизируйте привлечение B2B-клиентов

    Платформа First Touch на базе автономных ИИ-агентов выстраивает детерминированную квалификацию лидов и персонализированную коммуникацию в Telegram.

    Попробовать First Touch