Обычный способ собрать чат-агента на LLM — написать большой системный промпт, приложить к нему базу знаний и надеяться, что модель разберётся, какое из правил применимо к текущему собеседнику. Пока сценарий один, это работает. Как только выясняется, что собеседники приходят в принципиально разных ситуациях, а часть правил регулируется законом и внутренними регламентами заказчика, монолитный промпт начинает мешать: модель видит инструкции, которые к этому клиенту не относятся, и рано или поздно применяет их.
В проекте агента досудебного взыскания для микрофинансовой организации мы приняли одно ключевое решение: системный промпт не написан заранее, а собирается из данных — заново для каждого заёмщика. Отсюда три уровня. Всё, что можно вывести из данных по займу, вычисляется до первой реплики и попадает в промпт. Процедуры, которые могут понадобиться любому собеседнику, но по данным непредсказуемы, вынесены в дополнительные инструкции и подгружаются по ходу разговора. Фактические знания живут в базе знаний и достаются поиском.
Уровень 1. Данные по займу, из которых собирается промпт
Вместе с первым сообщением канал передаёт данные по договору. Их много и они разные по характеру: сколько дней просрочки, какой продукт и на какой срок, какие суммы и дедлайн, доступна ли пролонгация, включена ли акция, что было в предыдущих диалогах собеседника.
Прежде чем агент начнёт разговор, промпт собирает детерминированный сценарий. Сначала данные превращаются в флаги: есть ли просрочка, доступна ли пролонгация, включена ли акция, был ли повторный отказ, в какое окно по дням просрочки попадает заёмщик. Затем из флагов выводится содержание, на которое агент будет опираться в разговоре: какие варианты погашения доступны и в каком порядке их предлагать, какое последствие неоплаты актуально для этого срока просрочки, какой шаг каскада следующий. И только в конце промпт склеивается из фрагментов-разделов, часть которых включается по условию.
Диапазон поведения получается широкий. Если просрочки нет, агент работает в режиме консультации — отвечает на вопросы по договору и базе знаний и не напоминает о долге настойчиво. Если же просрочка есть, собирается промпт-взыскание: доступные варианты в нужном порядке, работа с возражениями, доведение последствий, выставление требования. Между этими вариантами сборки промпта — множество промежуточных сборок, потому что состав инструкций зависит не только от факта просрочки.
Раздел про акцию попадает в промпт только если акция этому клиенту доступна и включена. Раздел про рассрочку — аналогично. Правила про выставление требования включаются в мягком или в более настойчивом варианте в зависимости от того, отказывался ли клиент платить ранее. Последствия неоплаты по мере роста просрочки разные, и в промпт попадает то, которое актуально для этого заёмщика сегодня.
Уровень 2. Инструкции, которые подгружаются по ходу диалога
Часть тем возникает редко, но требует объёмных и точных процедур. Кредитные каникулы — процедура с несколькими ветвями и своими требованиями в каждой. Заявление «это не мой займ» — своя процедура проверки. До начала разговора мы не знаем, возникнет ли необходимость в такой процедуре — по данным займа это не предскажешь. А всегда держать в базовом промпте процедуру вредно: подробная редкая процедура конкурирует за внимание модели с основным каскадом.
Поэтому такие процедуры вынесены в дополнительные инструкции, которые агент подгружает сам через вызов инструмента. В базовом промпте остаётся только триггер: если клиент заговорил о кредитных каникулах, агент запрашивает нужную процедуру и дальше действует строго по ней. Сценарий на такой вызов отвечает не данными, а текстом инструкции, который остаётся в контексте до конца диалога. Модель сама сигнализирует, что тема возникла, и получает ровно ту процедуру, которая для этой темы написана.
Уровень 3. Знания — поиск по базе (RAG)
Факты живут не в промпте, а в базе знаний, и достаются через RAG: агент вызывает поиск, сценарий обращается к векторному хранилищу, найденные фрагменты возвращаются как результат инструмента.
В промпте — линия поведения: порядок каскада, что делать при отказе, когда доводить последствия. В базе знаний — фактура: способы оплаты, реквизиты, порядок начисления процентов, сроки зачисления платежа.
Что это даёт — и чего требует
Модель видит только релевантные правила. Инструкция, которой нет в промпте, не может сработать не вовремя — а это самый частый источник неуместных ответов в сложных сценариях. Взамен агента приходится проверять на большом количестве примеров собеседников: чем больше у промпта возможных конфигураций, тем больше вариантов нужно прогнать, прежде чем считать поведение проверенным.
Правила разложены по смысловым блокам. Замечание заказчика почти всегда локализуется в один фрагмент или один флаг: правка «последствие подбираем по дню просрочки» — это одна переменная и один раздел, а не переписывание монолита. Обратная сторона — цельного промпта, который можно открыть и прочитать, не существует: он появляется только в диалоге, под конкретного заёмщика. Работая с таким промптом, нужно держать в голове, в каком блоке лежит какое правило.
Поведение агента предсказуемо до диалога. Промпт вычисляется из данных, поэтому по выгрузке портфеля видно заранее, какие инструкции и какие варианты получит каждая группа заёмщиков: разговор о качестве работы агента становится разговором о данных и правилах.
Контекст расходуется на то, что нужно. Все три уровня работают в одну сторону: в промпт не попадает ничего, что этому собеседнику не пригодится, редкие процедуры подгружаются по факту возникшей темы, фактура достаётся поиском вместо того, чтобы лежать в контексте целиком.
Когда так стоит делать
Подход оправдан, когда собеседники приходят в существенно разных ситуациях, эти ситуации известны из данных до начала разговора, а цена неверно применённого правила высока. Для FAQ-бота с однородной аудиторией один промпт и RAG будут проще в поддержке и развитии.