Промптинг и структурный вывод
Промптинг в проде - инженерия, а не заклинания: структурный вывод, температура, регрессионные тесты. Вопрос-детектор: «как получить от модели надёжный JSON» - по ответу видно, падал ли твой парсер на „Вот ваш JSON:“.
// Промпт это код: версионируется, тестируется, имеет регрессии.
Few-shot и chain-of-thought
Few-shot: примеры «вход → выход» прямо в промпте задают формат надёжнее любых словесных описаний. Это in-context learning - веса не меняются, модель подхватывает паттерн из контекста.
Chain-of-thought - «рассуждай по шагам» - поднимает качество на задачах рассуждения; заметно работает у достаточно крупных моделей.
// Ловушка few-shot: модель копирует всё, включая перекос примеров. Все примеры позитивного класса, и классификатор внезапно «всегда позитивен».
- in-context learning
- обучение из примеров в промпте, без изменения весов
- self-consistency
- несколько цепочек рассуждения → мажоритарный ответ
Структурный вывод: JSON без слёз
Иерархия надёжности: просьба «верни JSON» < few-shot с примерами формата < JSON-схема с валидацией и ретраем < constrained decoding / функции API, где грамматика формата гарантирована генерацией.
На своей стороне всегда: валидатор схемы и ретрай с сообщением об ошибке. Прод, парсящий свободный текст без валидации, падает на первом же вежливом предисловии модели.
// Температура - под задачу: 0 для экстракции и классификации (детерминизм и стабильный формат), выше - для генерации идей. 0.8 на извлечении полей - «творческие» значения.
- constrained decoding
- генерация, ограниченная грамматикой/схемой формата
- температура
- разброс сэмплирования: 0 - детерминизм, выше - разнообразие
Промпт это код
Структура рабочего промпта: роль и задача, контекст, формат ответа, ограничения, примеры. Инструкции - явные и позитивные: «выведи только JSON» работает лучше «не пиши лишнего».
Промпт версионируется и тестируется: набор кейсов с ожидаемыми ответами, прогон на каждое изменение. «Поправил слово - сломал прод» без тестов не видно вообще.
// Дорогой приём для точности: self-consistency - сэмплировать несколько цепочек рассуждения и взять мажоритарный ответ; на математике и логике даёт ощутимый прирост.
Как отвечать: «Как получить от модели гарантированный JSON?»
Слоями, от гарантий к страховкам. Лучший вариант - constrained decoding или tool/function calling: формат гарантируется самой генерацией по схеме. Если API этого не даёт - жёсткая JSON-схема в промпте, few-shot пример и температура 0. И в любом случае на моей стороне валидатор схемы с ретраем: при невалидном ответе возвращаю модели ошибку валидации и прошу исправить. Плюс регрессионный набор кейсов на каждое изменение промпта - формат имеет свойство ломаться от невинных правок.
Иерархия от гарантированного к вероятностному и обвязка на своей стороне - инженерный ответ вместо «попросить получше».
На чём валят
- −Парсить JSON из свободного текста без валидатора и ретрая - прод падает на «Вот ваш JSON:».
- −Few-shot с однобокими примерами - модель копирует перекос.
- −Температура 0.8 на извлечении полей - плавающий формат и творческие значения.
- −Менять промпт в проде без регрессионных кейсов - улучшил один случай, сломал десять.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.
- Приложению нужен строго JSON от LLM для парсинга. Что надёжнее «попросить в промпте вернуть JSON»?A)Structured output / constrained decoding: генерировать строго по JSON-схеме на уровне декодированияB)Повысить температуру, чтобы JSON получался разнообразнееC)Просить модель писать весь ответ заглавными буквамиD)Ничего лучше нет, вежливая просьба в тексте промпта — это доступный способ добиться JSON а обеспечить валидный JSON от модели иным путём не получится
показать ответ и разбор
+A)Structured output / constrained decoding: генерировать строго по JSON-схеме на уровне декодирования// разбор: Просьба в промпте не гарантирует валидный JSON — модель может добавить текст, сломать кавычки, забыть поле. Structured output / constrained decoding ограничивает генерацию грамматикой/схемой на уровне выбора токенов (JSON mode, function calling, грамматики) — на выходе всегда синтаксически валидная структура. Это снимает хрупкий парсинг и ретраи. Схему всё равно валидируют на стороне приложения.
- Небольшая переформулировка промпта заметно меняет качество ответов. Что это говорит и что делать?A)Это сложно, формулировка промпта на результат не влияетB)Надо просто повысить температуру сэмплированияC)LLM чувствительна к формулировке: промпты надо тестировать на наборе кейсов и версионировать, а не подбирать на глазD)Модель сломана, её нужно немедленно заменить на другую
показать ответ и разбор
+C)LLM чувствительна к формулировке: промпты надо тестировать на наборе кейсов и версионировать, а не подбирать на глаз// разбор: Prompt sensitivity — реальное свойство: формулировка, порядок, разделители, формат примеров влияют на выход, потому что меняют условное распределение. Вывод не «модель сломана», а «промпт — это артефакт, который надо инженерить»: держать набор тест-кейсов, мерить изменения, версионировать промпты как код, не полагаться на разовый подбор. Температура тут ни при чём.
- Зачем в чат-моделях разделяют system-, user- и assistant-роли?A)Это чисто косметическое разделение ролей в интерфейсе, не имеющее вообще никакого эффекта на поведение моделиB)Чтобы модель отвечала пользователю ощутимо быстрееC)Чтобы экономить токены на разметке сообщенийD)System задаёт устойчивые правила/роль поверх диалога, user — запрос; модель обучена приоритезировать system
показать ответ и разбор
+D)System задаёт устойчивые правила/роль поверх диалога, user — запрос; модель обучена приоритезировать system// разбор: Роли структурируют контекст: system несёт устойчивые инструкции/персону/правила, user — конкретный запрос, assistant — прошлые ответы. Chat-модели дообучены трактовать system с более высоким приоритетом, поэтому туда кладут политику и формат. Это не косметика — рычаг управления поведением и (частичной) защиты от переопределения правил пользователем. Полной гарантии приоритета нет (см. джейлбрейки).
- В длинный промпт кладут инструкцию, потом много контекста. Где разместить ключевую инструкцию и почему?A)Это не важно, поскольку позиция инструкции в промпте на внимание модели не влияетB)Обязательно ровно в геометрическом центре всего контекстаC)В начале и/или в конце: модель хуже использует середину длинного контекста (lost in the middle)D)В самом конце промпта и не в начале
показать ответ и разбор
+C)В начале и/или в конце: модель хуже использует середину длинного контекста (lost in the middle)// разбор: «Lost in the middle»: модели надёжнее используют информацию в начале и конце длинного контекста, а помещённое в середину — теряют. Поэтому ключевую инструкцию и важные документы ставят с краёв, критичные факты дублируют/выносят в конец, а реранкинг располагает лучшие чанки по краям. Позиция реально влияет — суть не в центре буквально, а в «не хорони важное в середине».
- Один и тот же большой system-промпт шлётся в тысячах запросов. Как срезать стоимость/латентность?A)Никак, каждый запрос считается с нуляB)Prompt caching: движок кэширует KV-состояние общего префикса, и повторный префикс не пересчитываетсяC)Поднять температуру, чтобы ответы начали кэшироватьсяD)Уменьшить размер словаря токенизатора модели
показать ответ и разбор
+B)Prompt caching: движок кэширует KV-состояние общего префикса, и повторный префикс не пересчитывается// разбор: Если у многих запросов общий длинный префикс (system-промпт, инструкции, справочник), prompt caching переиспользует уже посчитанное KV-состояние этого префикса: prefill повторного префикса пропускается, платится только за новый хвост — дешевле и быстрее (меньше TTFT). Работает для стабильного префикса в начале; поэтому неизменное кладут в начало, переменное — в конец.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.