Мой блог
Разделение reasoning и side effects в production-пайплайнах с LLM
Привет! Я Сергей Багров. В этой статье мы разберем архитектурный подход к проектированию систем на базе искусственного интеллекта, где языковая модель формирует лишь гипотезы и предложения (reasoning), а выполнение реальных изменений и внешних эффектов (side effects) полностью контролируется детерминированным программным кодом.
Когда вся логика работы приложения завязана на один единственный prompt и бесконечный agent loop, разработчики неизбежно сталкиваются с проблемами при обработке таймаутов и ошибок. В качестве примера можно рассмотреть ситуацию с оформлением возврата средств, когда слепой повтор запроса способен привести к дублированию транзакции.





Выбор архитектуры по форме задачи
Соблазнительный шаг — отдать весь процесс под управление одного агента. Это экономит время на старте разработки, но смешивает интерпретацию входных данных, проверку прав и отправку запросов во внешние сервисы. Согласно рекомендациям из инженерного руководства Anthropic, полезно четко разделять заранее запрограммированный workflow и динамический agent loop, где модель самостоятельно выбирает инструменты.

Оценка неопределенности и цены ошибки
Перед тем как проектировать контур взаимодействия с LLM, я рекомендую ответить на четыре ключевых вопроса: насколько неопределен входной текст, можно ли формально проверить результат, известен ли маршрут выполнения заранее и какова цена возможной ошибки. Исходя из этих параметров, задачи распределяются между моделью, кодом и человеком.
Классификацию свободного текста лучше доверить языковой модели, так как граница классов зависит от контекста. При этом расчет лимитов, проверку прав и выполнение записей должен осуществлять исключительно код, опираясь на доверенные источники данных, а не на внутренние рассуждения нейросети.
Пусть модель вернет proposal, а не выполнит действие
Удобная граница ответственности проходит по объекту-предложению (proposal). Модель преобразует неструктурированный пользовательский контекст в ограниченную структуру данных, которая сама по себе еще не инициирует никаких изменений в системе.
После формирования такого объекта детерминированный модуль загружает актуальные данные из базы, проверяет бизнес-правила, сверяет суммы и права вызывающей стороны. Такой подход позволяет тестировать каждый компонент по отдельности: логику модели — на датасетах, правила валидации — с помощью стандартных юнит-тестов, а интеграционные сценарии — в условиях искусственных сбоев сети.
Retry начинается с вопроса «что успело произойти?»
Базовое правило «повторить операцию три раза при сбое» хорошо работает для чтения, но представляет серьезную опасность для операций записи. Сетевой таймаут не гарантирует, что запрос не дошел до целевого API; он может означать утерю ответа или зависание процесса после частичной записи.
Поэтому таймауты требуют разделения на несколько сценариев исхода:
- Запрос физически не был отправлен, что допускает автоматический повтор.
- Удаленная система вернула подтвержденный отказ.
- Запрос ушел, но ответ потерян, из-за чего требуется предварительный read-back или процедура reconciliation.
- Частичный ответ уже передан клиенту, в связи с чем повторные попытки запрещены даже при наличии ключа идемпотентности.
Управление состоянием и трассировка
Операционный журнал системы должен четко разделять два понятия: «что решила модель» и «что сделала система». Для каждого запуска критически важно сохранять идентификаторы попыток, версии используемых промптов, конфигурации политик, результаты прохождения гейтов и искомый статус операции.

Сырые персональные данные и токены доступа нельзя передавать в системы мониторинга в открытом виде. Журналы должны содержать лишь маскированные превью или зашифрованные метаданные, помогающие дежурному инженеру восстановить реальную картину инцидента без помощи самой языковой модели.
Разделение контуров проверки и мониторинга
Для обеспечения стабильности работы приложения я советую разделять офлайн-оценку (offline eval), релизные гейты (release gates), проверки в рантайме (runtime gates) и общий мониторинг. Каждая из этих систем решает собственные задачи на разных этапах жизненного цикла продукта.

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

Внедряя подобные архитектурные принципы поэтапно — начиная с выделения рискованных операций в отдельные функции, ввода типизированных предложений и настройки жестких гейтов, — можно построить прозрачный и надежный production-пайплайн, в котором LLM отвечает за творческую интерпретацию неопределенностей, а код гарантирует безопасность и предсказуемость бизнес-логики.
