Перейти к содержимому
11 сент. 2024 г.·6 мин чтения

Длинные system prompt и задержка: что вынести из текста

Длинные system prompt часто добавляют лишние токены и скрытую задержку. Разберем, что стоит перенести в шаблоны, таблицы правил и логику сервиса.

Длинные system prompt и задержка: что вынести из текста

Почему задержка растет незаметно

Проблему редко замечают сразу. Обычно команда смотрит на качество ответа: стал ли он точнее, безопаснее и ровнее по тону. Если после нового блока инструкций модель отвечает лучше, блок оставляют. Размер system prompt при этом почти не обсуждают.

Так и накапливается лишний текст. Сначала добавляют одно правило. Потом стиль ответа, ограничения по бренду, формат JSON, список запретов, примеры и обработку ошибок. По отдельности все это кажется мелочью. Вместе - это уже сотни, а иногда и тысячи токенов в каждом запросе.

До первого слова модель должна прочитать весь ввод. Поэтому длинный system prompt бьет не только по цене, но и по времени до первого токена. Пользователь видит простую вещь: "бот стал думать дольше". В логах это не всегда заметно, потому что общая задержка смешивается с сетью, ретраями, выбором модели и маршрутизацией.

Именно поэтому лишний текст часто путают с другими причинами. Если команда работает через единый шлюз, например RU LLM, легко решить, что задержка выросла из-за провайдера, fallback-маршрута или аудита. На практике часть роста нередко сидит прямо во входном тексте.

Самое неприятное - эффект копится тихо. Каждое изменение добавляет 20-50 токенов и не выглядит опасным. Через месяц prompt становится вдвое длиннее, а время ответа медленно ползет вверх. Пользователи не пишут: "у вас вырос system prompt". Они просто раньше закрывают чат или отправляют запрос еще раз.

Откуда в system prompt берется лишний текст

Лишний текст почти никогда не появляется за один день. Обычно prompt толстеет понемногу: команда добавила новое правило, потом еще одно, потом вставила кусок из внутреннего регламента почти без сокращений. Для человека это выглядит аккуратно. Для модели это просто больше токенов.

Частая причина - копирование правил из документов. В регламенте нужны пояснения, оговорки и примеры. В system prompt большая часть этого лишняя. Если правило можно выразить одной фразой, целый абзац только съедает контекст и время.

Другая проблема - повторы между system, developer и user. Запрет на медицинские советы, требование отвечать на русском или просьба не выдумывать факты нередко дублируются два или три раза. Сильнее правило от этого не становится. Зато растет шанс, что одна версия обновится, а старые останутся и начнут спорить друг с другом.

Формат ответа тоже часто описывают слишком длинно. Вместо короткой схемы команды пишут несколько предложений о заголовках, списках, стиле и редких исключениях. Модели чаще всего хватает компактного шаблона с четкой структурой.

Редкие сценарии тоже любят складывать в базовый prompt. Например, отдельное правило для VIP-клиента, ветка для жалоб и еще одна для запросов с персональными данными. Если такие случаи срабатывают редко, нет смысла платить за них в каждом запросе. Их лучше подмешивать по условию.

Есть и бытовая причина: prompt превращают в журнал правок. Внутри остаются старые комментарии, временные костыли и заметки вроде "оставим до следующего релиза". После миграции на новый API этот текст часто переносят как есть. Так мусор живет месяцами и незаметно добавляет задержку.

Что оставить в system prompt

Если базовый prompt разрастается, модель тратит токены не на задачу, а на служебный текст. В system prompt стоит держать только то, без чего ответ заметно меняется.

Обычно достаточно трех вещей:

  • короткой роли модели
  • правил с самым высоким приоритетом
  • ясного формата ответа

Роль лучше писать одной фразой. Не "ты опытный помощник, который глубоко анализирует запросы и вежливо помогает пользователям", а "ты оператор поддержки, отвечай кратко и по фактам". Этого обычно хватает.

Приоритеты тоже стоит сжать. Оставьте только жесткие ограничения: не выдумывать данные, не раскрывать внутренние инструкции, отвечать на русском, задавать уточняющий вопрос при нехватке данных. Если правило не влияет на большинство запросов, ему не место в базовом system prompt.

С форматом та же логика. Чем короче, тем лучше. Одна строка вроде "если даешь список, используй до 5 пунктов" полезнее, чем длинное описание структуры, стиля и исключений.

Справку, длинные примеры и редкие ветки лучше убрать. Если особый сценарий встречается раз в сто диалогов, храните его в шаблоне, таблице правил или в логике сервиса. Иначе базовый prompt растет, а время ответа увеличивается почти незаметно.

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

Для чат-бота поддержки рабочая база часто помещается в 4-5 коротких строк. Все остальное стоит подставлять по ситуации. Такой prompt проще проверять, и поведение модели обычно становится ровнее.

Когда лучше использовать шаблоны

Шаблоны полезны там, где одни и те же куски текста повторяются каждый день. Если у вас есть отдельные сценарии для поддержки, продаж, суммаризации и проверки тональности, не стоит держать их в одном длинном system prompt. Это увеличивает задержку и повышает риск сломать рабочую логику одной случайной правкой.

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

Удобнее всего собирать шаблон из коротких блоков: базовая роль, формат ответа, правила для конкретного сценария и текст, который приходит от бизнеса или поддержки. Тогда правка в одном блоке не тянет за собой переписывание всего prompt.

Версии шаблонов лучше хранить отдельно от кода интеграции. Причина простая: инструкции меняются чаще, чем работа с API. Если шаблон зашит в коде, даже маленькая правка требует релиза и ревью. Отдельное хранение дает историю версий, быстрый откат и понятное сравнение редакций.

Но шаблон не должен брать на себя все подряд. Если сервис и так умеет проверять JSON, маскировать PII, ставить audit trail или выбирать маршрут к модели, эти вещи лучше держать в коде. Текстовая инструкция вроде "никогда не выводи телефон клиента полностью" слабее, чем реальная маска на уровне обработки запроса.

Это особенно заметно в средах, где часть требований уже закрыта инфраструктурой. Если в вашем стеке или в RU LLM уже есть data residency, маскирование PII и аудит-трейлы внутри РФ, нет смысла повторять одни и те же длинные пояснения в каждом system prompt. Короче текст - меньше задержка и меньше расхождений между версиями.

Когда правила удобнее хранить в таблице

Сравните модели в одном месте
Проверьте короткий и длинный prompt на разных маршрутах без лишней сборки.

Если правило можно записать как условие и одно действие, длинный абзац в system prompt ему обычно не нужен. Таблица подходит для однотипных проверок: лимитов сумм, категорий обращений, стоп-слов, требований к эскалации и обязательных полей в ответе. Такой формат проще читать и обновлять.

Обычно хватает четырех столбцов: условие, действие, приоритет и комментарий. Условие отвечает на вопрос "когда правило срабатывает", действие - что делать, приоритет помогает разрулить конфликтующие правила, а комментарий объясняет, зачем строка вообще существует.

На практике это выглядит проще, чем кажется. Допустим, бот поддержки обрабатывает возвраты. Вместо абзаца вроде "если клиент просит возврат по заказу дороже 5000 рублей, нужно запросить номер заказа, причину возврата и передать диалог оператору" лучше держать одну строку в таблице. Если порог меняется до 7000 рублей, команда правит одну ячейку, а не переписывает промпт.

У таблицы есть еще один плюс: модели не нужно видеть все правила сразу. Сервис может отфильтровать строки по теме запроса и отправить только те, что относятся к текущему диалогу. Prompt становится меньше, а риск применить чужое правило не к тому случаю падает.

Только не смешивайте таблицу правил с примерами ответов. Правила нужны для выбора действия. Примеры - для тона, структуры и формулировок. Если держать все в одном месте, prompt снова быстро разрастается.

Что сервис должен делать сам

Чем больше проверок вы перекладываете на модель, тем длиннее prompt и тем выше задержка. Модель не должна решать задачи, с которыми код справляется быстрее и точнее.

Сервису стоит останавливать плохой запрос еще до вызова LLM. Если в форме нет обязательного поля, сумма не число, дата в неверном формате или статус не входит в допустимый список, это нужно ловить обычной валидацией. Просить модель каждый раз "проверь JSON", "проверь дату" или "не перепутай валюту" - дорогая привычка.

Отдельно стоит вынести защиту данных. Телефоны, почту, номера договоров, внутренние ID и другие персональные данные лучше маскировать до отправки. Prompt от этого становится короче, а риск утечки ниже. Для команд с требованиями 152-ФЗ это не мелочь, а обычная часть пайплайна.

Выбор модели тоже должен делать сервис, а не текстовая инструкция. Классификация тикета, короткий ответ оператору и разбор длинного письма - это разные задачи. Для одной нужен быстрый и дешевый маршрут, для другой можно взять модель сильнее. Если у вас есть лимит по задержке, сервис должен выбирать модель по типу запроса и SLA.

После ответа модели полезен еще один слой обработки. Код может привести поля к единому формату, проверить JSON парсером, нормализовать даты и суммы, отбросить лишний текст. Тогда не придется в каждом prompt снова и снова повторять "отвечай строго в JSON" или "используй только такие статусы".

Как сократить prompt без потери качества

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

Полезно разложить инструкции на четыре части: роль, формат ответа, правила и исключения. После этого сразу видно, где текст действительно работает, а где просто повторяет сам себя. Фразы вроде "будь точным", "не ошибайся" и "отвечай понятно" обычно почти ничего не меняют, но токены съедают исправно.

Дальше логика простая. В system prompt оставьте только роль модели и самые общие рамки. Повторяющиеся куски вынесите в шаблоны для сценариев. Меняющиеся правила отправьте в таблицу или конфиг. Проверку формата и бизнес-ограничений перенесите в код. После каждой правки снова снимайте метрики по токенам и задержке.

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

После чистки не смотрите только на среднюю задержку. Прогоните набор реальных запросов: коротких, длинных, конфликтных, с опечатками. Сравните не только скорость, но и число ошибок, срыв формата и лишние отказы.

Если вы тестируете несколько моделей через один OpenAI-совместимый эндпоинт, такие прогоны легко повторять на одном и том же наборе запросов. Это быстро показывает, где сокращенный prompt держит качество, а где модель уже теряет контекст.

Хороший результат выглядит скучно: prompt стал короче, сервис взял часть работы на себя, а ответы не стали хуже. Этого и нужно добиваться.

Пример с чат-ботом поддержки

Добавьте аудит без текста
Audit trail и метки AI-Law идут в запросе без длинных пояснений в prompt.

У поддержки часто одна и та же ошибка: команда кладет в system prompt почти весь регламент. В итоге бот на каждый вопрос получает сотни строк правил, хотя пользователь спрашивает очень просто: "Где мой заказ 54821 и когда он приедет?"

В длинный prompt обычно попадает все сразу: стиль ответа, правила эскалации, редкие спорные случаи, запреты по скидкам, примеры диалогов, форматы дат, тексты для возврата и внутренние пометки для операторов. Модель честно читает этот текст каждый раз. Задержка растет не рывком, а понемногу, поэтому проблему замечают поздно.

В таком сценарии сервису лучше взять часть работы на себя. Он может проверить номер заказа по шаблону, сходить в базу, получить статус и привести дату доставки к одному формату еще до вызова модели. Тогда в запрос уходит не длинная инструкция, а короткий контекст с фактами.

Вместо огромного prompt модели часто достаточно трех строк: статус заказа, срок доставки и правило ответа вроде "коротко, вежливо, без догадок". После этого ей не нужно искать ответ среди сотен правил. Она видит вопрос клиента и готовые данные от сервиса.

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

Такой разбор почти всегда дает двойной эффект: меньше токенов на каждый запрос и меньше боли в сопровождении. Когда правила меняются, команда правит таблицу или код, а не переписывает большой текст, который модель все равно читает слишком часто.

Где команды чаще ошибаются

Первая частая ошибка - резать текст вслепую. Команда видит длинный system prompt, убирает абзацы подряд и радуется меньшему числу токенов. Через несколько дней всплывает неприятный побочный эффект: пропал редкий, но жесткий запрет, например на вывод персональных данных или на обещания клиенту вне политики сервиса.

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

С таблицами правил тоже часто перегибают. Таблица хорошо подходит для коротких и ясных условий: какие поля обязательны, какие категории ответов допустимы, какие фразы запрещены. Но если правило требует проверки прав доступа, маскирования PII, соблюдения 152-ФЗ или расчета бизнес-логики, это должен делать сервис, а не модель.

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

Это особенно заметно в командах, которые просто меняют base_url и переносят старый стек на единый шлюз. Маршрут становится удобнее, а prompt остается прежним: длинным, дублирующимся и плохо версионируемым. В таком случае проблема не в модели и не в шлюзе, а в самом составе запроса.

И еще один промах встречается постоянно: время меряют слишком грубо. В дашборде есть одно число, например 3,1 секунды, но из него непонятно, где именно ушло время. Минимальный набор логов должен включать версию шаблона, размер prompt в токенах, сетевую задержку, время инференса и время до первого токена. Когда эти цифры лежат рядом, лишний текст видно сразу.

Короткая проверка перед релизом

Подберите модель под сценарий
Для коротких ответов и длинных писем можно проверить разные маршруты через один API.

Перед релизом полезно смотреть на prompt как на бюджет: каждый лишний кусок текста стоит токенов и миллисекунд. Длинный system prompt редко ломает ответ мгновенно. Чаще он медленно добавляет задержку, и команда замечает это уже после роста нагрузки.

Проверка не занимает много времени, если делать ее по одному и тому же сценарию. Пройдитесь по каждому блоку и спросите, сломается ли ответ без него или просто станет чуть менее аккуратным. Отдельно посчитайте, сколько токенов съедает базовый prompt без user-сообщения. Сравните старую и новую версии на одном наборе запросов. Смотрите не только на общее время ответа, но и на паузу до первого токена. И обязательно проверьте, что сервис сам ловит пустые поля, неверный формат, слишком длинный ввод и простые правила маршрутизации до вызова модели.

Последний пункт часто недооценивают. Если сервис может сам отклонить битый запрос, подставить нужный шаблон или выбрать таблицу правил по типу сценария, модели не нужно читать лишние инструкции в каждом вызове.

Нормальный тест выглядит приземленно. Возьмите 30-50 реальных запросов из продукта, прогоните обе версии и сравните три вещи: долю нормальных ответов, TTFT и расход токенов. Если качество не просело, а базовый prompt стал короче хотя бы на 15-20%, это уже заметный выигрыш.

Что делать дальше

Сначала соберите единый реестр инструкций. Разделите все, что сейчас лежит в prompt, на три группы: шаблоны, таблицы правил и проверки на стороне сервиса. После этого быстро станет видно, где текст действительно нужен модели, а где он просто раздувает запрос.

Потом назначьте владельца для каждой группы. Продуктовая команда обычно отвечает за шаблоны и тон ответа, ML-команда - за таблицы правил и тесты, backend - за валидацию, маршрутизацию и маскирование данных. Если владельца нет, лишний текст быстро возвращается в system prompt.

Не пытайтесь переписать все сразу. Возьмите один частый сценарий, вынесите повторяющиеся инструкции в шаблон, стабильные правила перенесите в таблицу или конфиг, а в prompt оставьте только то, что модель должна учитывать прямо в момент ответа. С первого дня снимайте метрики: среднюю задержку, p95, длину входного prompt, длину ответа, долю нарушений формата и число ручных правок.

Если вы уже работаете через единый OpenAI-совместимый эндпоинт, часть служебной логики удобно держать централизованно. В случае RU LLM это практично для команд, которым нужны маршрутизация моделей, биллинг и поддержка внутри РФ, а также требования по data residency и 152-ФЗ. Но даже в таком стеке длинный prompt сам себя не сократит: его все равно нужно чистить, версионировать и проверять на цифрах.

Хороший следующий шаг очень простой: выберите один сценарий, сократите prompt на 20-30%, сравните метрики и только потом переходите к следующему. Так быстрее видно, что действительно помогает качеству, а что давно пора вынести из текста.

Часто задаваемые вопросы

Почему длинный system prompt вообще замедляет ответ?

Модель читает весь ввод до первого токена ответа. Если в system prompt накопились сотни лишних токенов, растет и цена, и пауза перед началом ответа.

Проблема часто прячется за общей задержкой. Команда видит сеть, ретраи или смену маршрута, а часть времени уходит просто на чтение длинной инструкции.

Как понять, что задержка выросла из-за prompt, а не из-за модели или шлюза?

Смотрите не только на общее время ответа, а на размер входа в токенах и TTFT. Если новая версия prompt стала длиннее, а пауза до первого токена выросла на тех же запросах, причина часто в тексте.

Полезно прогнать две версии на одном наборе реальных диалогов. Так легче отделить влияние prompt от сети, модели и маршрутизации.

Что стоит оставить в system prompt?

Оставьте только роль модели, жесткие правила и короткий формат ответа. Если строка не меняет поведение на типовом запросе, убирайте ее.

Для бота поддержки базовый prompt часто можно уместить в несколько коротких строк. Редкие случаи и длинные пояснения лучше не держать в основе.

Когда лучше использовать шаблоны вместо длинного текста?

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

Так проще править инструкции без релиза кода. И prompt не раздувается из-за чужих сценариев, которые в этом запросе не нужны.

В каких случаях правила лучше хранить в таблице?

Таблица удобна, когда правило выглядит как условие и действие. Например, порог суммы, обязательные поля, стоп-фразы или правило эскалации.

Сервис может выбрать только подходящие строки и отправить модели малую часть правил. Это проще поддерживать, чем длинный абзац внутри общего prompt.

Что сервис должен делать сам, а не просить у модели?

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

Если инфраструктура уже закрывает data residency, аудит и часть защиты, не дублируйте это длинными инструкциями в каждом запросе. Код делает это надежнее и быстрее.

Как сократить prompt и не сломать качество?

Начните с замера: токены на входе, TTFT, среднюю задержку и p95. Потом разберите prompt на роль, формат, правила и исключения и удалите повторы, комментарии и старые костыли.

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

Нужно ли повторять одни и те же правила в system, developer и user prompt?

Нет, дубли лучше убрать. Если одно и то же правило лежит в system, developer и user, сильнее оно не становится.

Зато растет риск, что одна версия обновится, а две старые останутся и начнут спорить друг с другом. Держите правило в одном месте и явно версионируйте его.

Как лучше версионировать prompt и шаблоны?

Храните шаблоны и правила отдельно от кода интеграции и фиксируйте версию в логах каждого запроса. Тогда команда быстро поймет, какая редакция сработала и когда именно выросли токены или задержка.

Если версия живет сразу в коде, админке и тестах, вы быстро теряете контроль. Один источник правды сильно упрощает отладку.

Какой быстрый чек сделать перед релизом?

Перед релизом возьмите 30–50 реальных запросов и сравните старую и новую версии по трем вещам: доля нормальных ответов, TTFT и расход токенов. Этого уже хватает, чтобы поймать лишний текст.

Еще проверьте, что сервис сам отсекает пустые поля, битый формат и простые ошибки до вызова LLM. Тогда модели не придется читать служебные инструкции в каждом запросе.