Прямой ответ
System prompt — инструкция, которая задаёт роль модели, границы поведения и формат ответа. Он применяется к каждому запросу и потому определяет поведение сервиса сильнее, чем любой отдельный пользовательский ввод. Практическая цель — получить стабильное поведение, а не «красивый» текст инструкции.
Рабочая структура:
- Роль и контекст. Кто модель, для какого продукта работает, на каком языке отвечает.
- Задача. Что именно нужно делать, в одном-двух предложениях.
- Правила. Ограничения: что запрещено, как отвечать на запросы вне компетенции, как ссылаться на источники.
- Формат вывода. Схема JSON, структура ответа, допустимые значения полей.
- Примеры. Один-два коротких примера «вход → выход»; для формата они работают лучше длинных объяснений.
Что делает инструкцию соблюдаемой:
- Короткие утвердительные правила. «Отвечай только на основании предоставленных данных» работает лучше, чем абзац рассуждений о важности точности.
- Одно правило — одна строка. Списки воспринимаются лучше связного текста.
- Явное поведение в отказе. Если не указано, что делать при нехватке данных, модель выдумает. Формулировка «Если данных недостаточно, верни
not_enough_data» устраняет целый класс галлюцинаций. - Формат описан схемой, а не только примером. Примеры дополняют схему, но не заменяют её.
Ограничения, о которых нужно помнить:
- System prompt — не защита от инъекций. Пользовательский ввод может содержать инструкции, которые модель попытается выполнить. Меры — в статье про prompt injection.
- Длинная инструкция конкурирует за контекст. Каждый запрос несёт её полностью, поэтому раздувание промпта стоит токенов и снижает внимание к остальным данным — см. контекстное окно.
- Правила в середине объёмного промпта соблюдаются хуже. Критичные ограничения стоит держать в начале и повторять перед выводом.
Практика: шаблон и организация работы
Пример рабочего системного промпта:
Ты — ассистент классификации обращений поддержки интернет-магазина.
Задача: определить категорию обращения и срочность.
Правила:
- Используй только текст обращения; не додумывай факты.
- Категория — строго из списка: delivery, payment, return, tech, other.
- Срочность — строго из списка: low, normal, high.
- Если данных недостаточно, верни {"error": "not_enough_data"}.
- Не добавляй пояснений вне JSON.
Формат вывода:
{"category": "<значение>", "severity": "<значение>", "reason": "<не более 15 слов>"}
Пример:
Вход: «Заказ не пришёл, деньги списали неделю назад»
Вывод: {"category": "delivery", "severity": "high", "reason": "задержка доставки и списание средств"}
Организация в коде:
- Храните промпт как данные, а не как строку в коде. Файл шаблона с версией позволяет менять поведение без правок логики и упрощает ревью.
- Версионируйте. Каждая версия промпта — это изменение поведения; привязывайте номер версии к логам запросов, чтобы можно было сопоставить регресс с правкой.
- Разделяйте профили. Один промпт на сценарий: классификация, извлечение, свободный ответ. Универсальный промпт «на всё» почти всегда работает хуже.
- Тестируйте как код. Набор эталонных входов с ожидаемыми признаками ответа и прогон в CI; методика — в статье про eval для LLM.
Проверка соблюдения формата:
def check_format(answer: str) -> bool:
import json
try:
d = json.loads(answer)
except json.JSONDecodeError:
return False
return (d.get("category") in {"delivery","payment","return","tech","other","error"}
and d.get("severity") in {"low","normal","high"} or "error" in d)
Как безопасно менять промпт. Правка инструкции — это изменение поведения сервиса, поэтому применяется так же, как изменение кода: через ревью, с прогоном эталонного набора и с возможностью быстрого отката к предыдущей версии. Полезная практика — хранить рядом две версии и сравнивать их на одном наборе входов перед переключением: расхождение видно сразу, а не по жалобам пользователей через неделю.
Что не стоит писать в системный промпт. Секреты и токены доступа, внутренние правила авторизации, данные клиентов и длинные справочники. Промпт можно попытаться извлечь, а объёмные данные снижают внимание к правилам; справочную информацию лучше передавать отдельным контекстом с явной разметкой, где заканчивается инструкция и начинаются данные.
Практический сценарий: модель игнорирует запрет на пояснения
Контекст: сервис извлечения данных возвращает JSON с предшествующим текстом «Хорошо, вот результат:», из-за чего парсер падает.
- Диагностика. В системном промпте было одно общее предложение про формат и длинный абзац про стиль общения. Запрет на пояснения отсутствовал явно, а единственный пример демонстрировал только JSON.
- Изменение. Переписали промпт по структуре: роль — задача — правила списком — схема — пример. Добавили явное правило «Выводи только JSON, без текста до и после».
- Проверка параметров. Дополнительно снизили температуру до 0.1 — при 0.7 модель чаще добавляла вводные фразы. Взаимосвязь параметров и формата разобрана в статье про sampling.
- Результат. На 300 обращениях доля ответов, начинающихся с
{, выросла с 82 % до 100 %; парсер перестал падать. - Профилактика. Промпт вынесен в шаблон с версией, добавлен тест формата в CI и ограничение вывода на стороне движка, где это поддерживается.
Вывод: инструкции соблюдают не «умные», а структурно ясные. Правила списком, явное поведение при отказе и пример формата решают большинство проблем.
FAQ
Насколько длинным должен быть системный промпт? Ориентир — 150–600 токенов для типового сервиса. Если промпт растёт, обычно это признак того, что правила не структурированы или в него перенесли данные, которые должны приходить отдельно.
Помогает ли добавление «ты эксперт мирового уровня»? Как правило, нет: такие формулировки не изменяют поведение измеримо, но расходуют токены. Работают конкретные правила, ограничения и примеры.
Как защищать системный промпт от извлечения пользователем? Полной защиты нет: промпт можно попытаться выпросить или вывести косвенно. Практика: не класть в промпт секреты и внутренние правила доступа, а авторизацию и фильтрацию данных делать вне модели. Подробнее — в статье про prompt injection.
Нужно ли менять системный промпт под разные модели? Да. Модели по-разному реагируют на формулировки и на шаблон чата: то, что стабильно работает на одной, может нарушаться на другой. При смене модели промпт проходит тот же набор тестов, что и при изменении кода.
Источники: Transformers docs (chat templating), OWASP Top 10 for LLM apps, llama.cpp — ссылки в шапке.