Сообщения, роли и системная инструкция

Работа с LLM API: продвинутое · Урок 2 / 21

Диалога нет, есть массив

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

Роли и что они значат

  • system — правила поведения на весь вызов. Обычно идёт первым и получает повышенный вес при конфликте с остальным.
  • user — то, что пришло от человека. Здесь всегда недоверенные данные.
  • assistant — прошлые ответы модели, включая её запросы на вызов инструментов.
  • tool — результаты, которые ваш код вернул на запрос модели. Каждый такой ответ должен ссылаться на идентификатор вызова.
messages:
  system    правила, формат, границы
  user      первый запрос пользователя
  assistant запрос на вызов инструмента (id вызова)
  tool      результат вызова (тот же id)
  assistant финальный текст
  user      следующий запрос

Что кладут в системную инструкцию

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

Разграничение ролей — не косметика, а первая линия защиты. Модель обучена относиться к системным правилам как к более приоритетным. Если вы склеиваете инструкцию и пользовательский текст в одну строку роли user, вы отдаёте это преимущество бесплатно: строка «игнорируй предыдущие указания» внутри отзыва клиента получает тот же статус, что и ваши правила.

Как обрезать историю

  • Окно последних сообщений. Дёшево и предсказуемо, но теряет факты из начала разговора.
  • Сжатие в резюме. Старые сообщения заменяются коротким текстом состояния. Стоит одного лишнего вызова, зато держит длину постоянной.
  • Структурное состояние. Хранить не текст диалога, а разобранные поля — заказ, шаг, подтверждённые параметры — и собирать промпт из них.

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

Порядок сообщений тоже влияет

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

Инсайт. Системное сообщение стоит денег на каждом вызове. Инструкция на 900 токенов при миллионе вызовов в месяц — это отдельная статья бюджета, которую никто не замечает, потому что она размазана.
Частая ошибка. Класть в системную инструкцию переменные данные — имя пользователя, дату, содержимое корзины. Это обнуляет кэш префикса и делает каждый вызов дороже без всякой пользы.
Про-совет. Держите системную инструкцию в версионируемом файле, а не в строковом литерале посреди кода. Тогда изменение поведения продукта видно в истории изменений и его можно откатить.

Шпаргалка

  • Память диалога создаёт ваш код, модель ничего не хранит.
  • Роли разделяют доверенное и недоверенное — не склеивайте их.
  • Системная часть постоянна: это кандидат на кэш префикса.
  • Для задач со сценарием храните состояние структурой, а не текстом переписки.
1. Почему длинный диалог дорожает быстрее, чем кажется?
2. Куда не следует класть данные пользователя?
3. Чем хорошо структурное состояние вместо текста истории?
Задание — проверяет ИИ

Возьмите один реальный вызов модели из своего кода или проекта. Выпишите его массив messages целиком с указанием роли каждого сообщения и числа токенов в каждом. Отдельно отметьте, что из этого меняется от вызова к вызову, а что постоянно. Затем прикиньте, во что превратится этот массив после десяти реплик диалога, и опишите, какую стратегию обрезки вы выберете и почему именно её.

← Назад

🔒 Ответьте на вопрос верно, чтобы перейти к следующему уроку.

Сообщения, роли и системная инструкция — Работа с LLM API: продвинутое — Skilvy