Всем привет! У меня есть некоторый опыт в построении систем с использованием LLM под капотом и поэтому я хочу этим опытом поделиться, а в конечном итоге понетворкаться и получить еще больше опыта. Эту статью я написал неделю назад и решил запостить в Клуб немного отредактированную версию. Здесь мой Telegram канал, буду рад подписке, а так же обсуждению поста в комментах. И так, поехали..
Данное руководство сфокусировано на практических, готовых к использованию в production техниках промпт-инжиниринга, которые появились благодаря реальным внедрениям и тщательному тестированию. Вместо рассмотрения теоретических подходов, мы рассмотрим проверенные методы, обеспечивающие стабильные результаты в production.
Это руководство разработано для:
- AI Solutions архитекторов, внедряющих крупномасштабные LLM-системы
- Backend-разработчиков, переходящих к AI-ориентированным приложениям
- Инженерных команд, поддерживающих production AI приложения
- Технических лидеров, оценивающих стратегии промпт-инжиниринга
Мы рассмотрим:
- Современные архитектурные паттерны промпт-инжиниринга, которые масштабируются
- Практические методы повышения надежности и снижения галлюцинаций
- Стратегии реализации structured output, chain-of-thought
- Оптимизацию производительности через эффективное кэширование и управление температурой
Текущее состояние промпт-инжиниринга (2024-2025)
Область вышла за рамки простых подходов, основанных на инструкциях. Современные production системы требуют сложных промпт-архитектур, которые могут:
- Обеспечивать стабильные, надежные результаты в масштабе
- Справляться со сложными задачами рассуждения с минимальными галлюцинациями
- Оптимизировать как производительность, так и стоимость
- Легко интегрироваться с существующими практиками разработки программного обеспечения.
Мы наблюдали эту эволюцию через разработки ведущих моделей, такие как Claude 3.5 Sonnet и Llama 3.1, которые сделали высокопроизводительный AI более доступным, одновременно повышая планку для подходов к промышленной разработке.
Теперь, когда мы определили текущее состояние и направление развития промпт-инжиниринга, давайте рассмотрим фундаментальные архитектурные паттерны, которые формируют основу современных production-систем.
Архитектура современного промпт-инжиниринга
N-shot промптинг: основы построения надежных систем
N-shot prompting или по-другому — few-shot prompting это одна из самых эффективных техник промптинга, когда мы предоставляем примеры выполнения задачи в самом промпте, это существенно облегчает понимание задачи моделью. Важно соблюдать несколько правил:
- если ваша задача подразумевает довольно сильное разнообразие входных данных, то необходимо иметь хорошее количество примеров. При недостаточном количестве модель может зациклиться на них и качество генерации снизится. Applied-llms в качестве правила хорошего тона предлагают указывать более 5 разнообразных примеров. В академических вычисления используют 32 или 64 примеров в промпте;
- примеры должны представлять данные production версии вашего приложения. Например, если ваше приложение — краткое изложение книг, то включите в примеры книги из разных жанров в тех же пропорциях которые ожидаются на практике.
Пример использования
Analyze the sentiment of these reviews (Positive/Negative):
Example 1:
Input: "The food was cold and the service was terrible."
Output: Negative
Example 2:
Input: "Amazing experience! The staff went above and beyond."
Output: Positive
Example 3:
Input: "Average food, nothing special but decent prices."
Output: Neutral
Now analyze this:
Input: "I waited for an hour and they got my order wrong."
Построив основу с помощью N-shot промптинга, перейдем к более продвинутой технике структурирования данных, которая существенно повышает надежность и предсказуемость ответов моделей.
Structured Output
Так как я технарь по образованию, я очень люблю структурированную информацию и мне нравится перекладывать JSON`ы, и поэтому, когда появился structured output в openai sdk, я был очень рад!
Structured Output это фича некоторых моделей, которая гарантирует, что ответ будет построен согласно предоставленной схеме.
LLM тоже любят структурированную информацию, так что очень полезно использовать JSON, XML в своём промпте для того, чтобы отделять разную информацию друг от друга. Например, мы можем описать задачу в теге <task></task>, а вспомогательный контекст в теге <context></context>, что поможет модели лучше разобраться, что ей необходимо использовать для выполнения задачи.
На сегодняшний день, и OpenAI SDK и Anthropic SDK поддерживают structured output, но по разному – у Anthropic предлагается указывать пример structured output в самом промпте (поддерживает XML, JSON), а у OpenAI можно указывать response_format в виде JSON схемы.
Пример:
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
completion = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "Extract the event information."},
{"role": "user", "content": "Alice and Bob are going to a science fair on Friday."},
],
response_format=CalendarEvent,
)
event = completion.choices[0].message.parsed
В event будет:
{
"name": "science fair",
"date": "Friday",
"participants": ["Alice","Bob"]
}
Развивая тему структурированных данных, рассмотрим элегантный метод Pre-fill Response, который позволяет еще точнее контролировать формат вывода модели.
Pre-fill Response: контроль над форматом вывода
Ещё одна техника, которая заставляет LLM использовать определённую структуру в своём ответе называется Pre-fill response, о ней рассказали в Anthropic и суть её заключается в том, что перед тем, как отправить запрос в LLM, мы заполняем кусок поля content для роли assistant JSON’ом или XML’ом (например, просто добавляем символ "{"), а модель, думая что она начала уже генерировать какую-то структуру, просто продолжит её генерировать, и таким образом, создаст ответ в виде structured output.
User:
Extract the name, size, price, and color from this product description as a JSON object:
<description>
The SmartHome Mini is a compact smart home assistant available in black or white for only $49.99. At just 5 inches wide, it lets you control lights, thermostats, and other connected devices via voice or app—no matter where you place it in your home. This affordable little hub brings convenient hands-free control to your smart devices.
</description>
Assistant (prefill):
{
Assistant (Claude’s response):
"name": "SmartHome Mini",
"size": "5 inches wide",
"price": "$49.99",
"colors": [
"black",
"white"
]
}
Chain-of-Thought: прозрачность рассуждений в production
Chain-of-Thought это очень крутая техника промптинга, когда мы просим LLM объяснять ход своих мыслей перед тем как вернуть ответ. Можно представить это как дать модели черновик (sketchpad), таким образом, ей не нужно хранить это всё в памяти. Можно просто добавить фразу “Let’s think step by step”, но эффективнее будет сделать CoT более конкретным, поскольку добавление конкретики посредством одного или двух дополнительных предложений часто значительно снижает частоту галлюцинаций.
Например, когда мы просим модель сделать саммари текстовой версии звонка, мы можем конкретизировать шаги:
- Сначала перечисли ключевые решения, последующие пункты и связанных с ними владельцев в черновике.
- Затем проверь, что детали в черновике фактически соответствуют стенограмме.
- Наконец, сгенерируй ключевые моменты в краткое саммари.
Пример использования
Problem: A company has 3 product lines. Product A sells for $120 with a 40% margin, Product B sells for $85 with a 35% margin, and Product C sells for $200 with a 25% margin. If they want to generate $100,000 in profit with a product mix of 2:3:1 (A:B:C), how many total units do they need to sell?
Step-by-Step Reasoning:
1. Calculate profit per unit for each product:
Product A: $120 × 40% = $48 profit per unit
Product B: $85 × 35% = $29.75 profit per unit
Product C: $200 × 25% = $50 profit per unit
2. Consider the product mix ratio (2:3:1):
- For every 6 total units (2+3+1), we have:
2 units of A: 2 × $48 = $96
3 units of B: 3 × $29.75 = $89.25
1 unit of C: 1 × $50 = $50
3. Calculate profit per ratio set:
$96 + $89.25 + $50 = $235.25 per set of 6 units
4. Find number of sets needed:
$100,000 ÷ $235.25 = 425.08 sets
5. Calculate total units:
425.08 × 6 = 2,550.48 units
Round up to 2,551 units to achieve target profit
Answer: They need to sell 2,551 total units.
Chain-of-Thought очень полезен при дебаге, когда вы не понимаете, почему модель приняла то или иное решение. Так как я всегда использую structured output, то CoT я помещаю в отдельное поле в JSON схеме и смотрю на него только при дебаге.
Изучив способы улучшения качества отдельных запросов, рассмотрим архитектурный подход к оптимизации сложных задач через их декомпозицию.
Оптимизация и масштабирование
Декомпозиция сложных запросов
Так же как и в программировании, в промптинге необходимо разделять общие задачи на частные и конкретные для более эффективного результата. Вместо того, чтобы использовать большую модель и описывать в промпте все задачи, можно отправить несколько запросов с небольшим промптом в маленькую модель, убедиться в том, что эти задачи соответствуют вашим ожиданиям и полученные результаты отправить в большую модель для задач, подразумевающих рассуждения.
Например, если ваше приложение должно отвечать на вопросы пользователя, используя контекст (типичный чатбот с использованием RAG), разделите эту задачу на несколько подзадач:
- проверить что запрос пользователя действительно содержит вопрос и что запрос не нарушает ваши политики;
- выделить вопрос из запроса пользователя (отбросить ненужные приветствия пользователя, sensitive информацию и другое);
- сгенерировать специальные запросы в ваш keyword search (если такой есть), semantic search, etc;
- найти дополнительный контекст по пользователю (например, настройки его профиля);
- отправить полученную информацию в большую модель, которая будет отвечать на вопрос пользователя, используя контекст.
Вооружившись основными техническими подходами, обратимся к практическим рекомендациям, которые помогут повысить эффективность ваших промптов:
- используйте простые и понятные предложения, термины;
- если есть специальные термины, жаргоны, позаботьтесь о том, чтобы предоставить модели объяснение этих терминов или замените эти термины на понятные слова перед тем как добавлять их в промпт;
- не передавайте ненужную информацию в промпт;
- для промпта, обычно, нет необходимости в использовании какого то особенного форматирования, кроме отделения предоставленного контекста в рамках RAG, хотя я часто использую markdown в промпте для того чтобы это всё красиво отображалось в Langfuse при дебаге;
- вот примеры системных промптов для Claude и для ChatGPT;
- так же как и в программировании, при создании промпта придерживайтесь идеи, что этот промпт должен быть понятен и вам через 2-3 месяца, и любому другому человеку, который будет впоследствии обслуживать ваше приложение. Большинство LLM обучались на обычных текстах для людей, поэтому обычные инструкции они смогут понять лучше.
Поскольку надежность является критическим фактором в production-системах, рассмотрим специальные техники минимизации галлюцинаций в ответах моделей.
Стратегии борьбы с галлюцинациями
На сегодняшний день пока что нет 100% способа избежать галлюцинаций, но вот несколько советов, как снизить их к минимуму.
Для таких приложений как чатбот или других, где предусматривается использование RAG, включайте в промпт инструкцию, которая позволит LLM сказать “Я не знаю” или “Не релевантно”, чтобы модель не пыталась додумать ответ, если не знает, а вы смогли явно обработать такой кейс.
Для задач, которые предусматривают больше рассуждений, Chain-of-Thought может помочь снизить галлюцинации. Я видел примеры генераций, где модель рассуждала над задачей, и в chain-of-thought было явно видно, что она меняет своё решение на противоположное, верное.
Оптимизация производительности через кэширование
Кэширование является очень полезным для экономии токенов и времени генерации запросов. Кэширование может быть как на стороне вашего приложения, так и на стороне провайдера LLM. Например, для OpenAI и Anthropic кэширование работает так:
- Автоматически кэширует промпты длиннее 1024 токенов
- TTL – 5-10 минут с возможностью продления до 1 часа
- Чтение (output) будет на 50% дешевле
- Включается автоматически для всех запросов и для всех моделей
- Автоматически кэширует промпты длиннее 1024 токенов для Sonnet/Opus и 2048 для Haiku
- TTL – 5 минут, обновляется при каждом использовании
- Чтение (output) будет на 90% дешевле, запись на 25% дороже
- Кэширование на данный момент в бете и необходимо явно указать использование
Таким образом, важно помнить, что статическую информацию (инструкции) необходимо помещать в начало промпта, а динамическую (информация о пользователе, контекст вопроса) в конец.
На стороне приложения я, обычно, тоже использую кэширование в Redis. В качестве ключа я использую хэш запроса пользователя и отдаю ответ сразу, не передавая в LLM провайдер. Это очень удобно во время разработки приложения и при однотипных запросах от пользователей (в контексте чатбота).
Продолжая тему оптимизации, обсудим тонкую настройку параметра temperature, который существенно влияет на баланс между креативностью и предсказуемостью ответов.
Тонкая настройка параметров генерации
Параметр temperature в LLM отвечает за “креативность” ответа. Это диапазон от 0.0 до 1.0, где более высокое значение означает что ответ будет более разнообразным. При высокой температуре, во время генерации, следующие токены, которые обычно менее вероятны, выбираются чаще. При низкой, ответы будут менее разнообразными и более однородными.
Обычно, для задач с рассуждениями я начинаю с температуры 0.6 – 0.7 и далее корректирую, а для более атомарных и конкретных задач я использую температуру поменьше. Но важно помнить, что низкая температура может “отуплять” некоторые модели. Вот пример для gpt-4, но для fine-tuned llama3-8b не применимо.
Изучив работающие подходы, важно также понимать, какие популярные техники на практике оказываются малоэффективными.
Техники, не оправдавшие себя в production
Я не проводил тесты, но вот мнение Yan, Ziyou:
Вежливость: Добавление фраз типа «пожалуйста» и «спасибо» не сильно влияет на качество вывода, даже если это может принести нам некоторую благосклонность со стороны наших будущих AI overlords.
Советы и угрозы: Последние модели, как правило, хорошо выполняют инструкции без необходимости предлагать «200 долларов чаевых» или угрожать, что мы «потеряем работу».
Конечно, не помешает быть вежливыми или игривыми в наших подсказках. Тем не менее, полезно знать, что они не так уж и важны для получения хороших результатов.
Рассмотрев весь спектр современных техник промпт-инжиниринга, от базовых принципов до продвинутых стратегий оптимизации, подведем итоги.
Заключение
Промпт-инжиниринг к 2025 году стал комплексной инженерной дисциплиной, где успех зависит от системной интеграции различных техник в production. Основные принципы включают: структурированный модульный подход к разработке промптов, комбинирование методов (Chain-of-Thought, Structured Output) для баланса качества и производительности, и оптимизацию через кэширование и настройку температуры для экономической эффективности. При внедрении рекомендуется начинать с базовой структуризации и постепенно усложнять систему, опираясь на конкретные метрики и комбинируя автоматизированное и ручное тестирование качества ответов.
Используемые источники
Yan, Eugene, Bryan Bischof, Charles Frye, Hamel Husain, Jason Liu, and Shreya Shankar. 2024. ‘Applied LLMs - What We’ve Learned From A Year of Building with LLMs’. Applied LLMs. 8 June 2024. https://applied-llms.org/.
Yan, Ziyou. (May 2024). Prompting Fundamentals and How to Apply them Effectively. eugeneyan.com. https://eugeneyan.com/writing/prompting/.
Спасибо за внимание! Повторю ссылку на мой Telegram канал
Без обид, но почти вся инфа по промтингу появилась почти сразу с релизом chatGPT в 2022.
Хотелось бы почитать про конкретные бизнес-кейсы вам приходилось успешно решать
Прикрепляю один из самых старых и полных гайдов по промтингу
https://www.promptingguide.ai/
Нет, не стал. Как был так и остался буллшиттингом.
Тыканье палочкой в черную недетерминированную коробку рандомными попытками с целью реверс-инжинирнуть поведение модели и ограничения, наложенные на нее разработчиками.
«Лучшие практики тибетских магов-членов академий магии и предсказаний позолоти ручку», не более.
Все «сложные промпт-архитектуры» сводятся к заклинаниям, подсмотренным у других «архитекторов» и судорожным дерганьям предоставленных разработчиками параметров типа «температура».
Спасибо за отличную статью.
Я бы ещё подчеркнул что работающие приемы промтинга могут заметно отличаться от модели к модели. Например тот же Клод часто нужно явно просить что нужно делать и что НЕ нужно сделать.
Спасибо за статью!
А есть у этого шаманства какая-то теоретическая база, исследования, хотя бы на уровне "это работает, это не работает" или только эмпирический опыт?
Так же интересно узнать, какой стек используете? Langchain или что-то более высокоуровневое? Делали ли агентные системы? Я трогал веточкой autogpt, но не смог заставить работать.
Я тоже в этом немного поварился и по моему опыту одна из сложных задач ещё находить баланс между размером n в n-shot learning и verbosity в chain of thoughts и стоимостью одного запроса в плане денег и времени ответа. Я в своих прототипах добился высокой точности, но потом выяснилось что клиенту важно ещё получить ответ в течении 5-10 секунд и чтобы запрос не стоил 2$ и пришлось уменьшить n и убрать chain of thoughts.
Как наверное уже замечали в интернетах в подобных случаях, статью можно чуток подредактировать и выпускать под названием "Руководство для менеджеров как ставить задачи стажёрам и сотрудникам и общаться с гуманитариями в ИТ" :)
Круто, спасибо за статью! Как раз сам уже некоторое время копаю в сторону внедрения RAG и LLM в процессы и продукты заказчиков и параллельно ищу энтузиастов и профи в этой области, чтоб занетворкаться.)
А касательно внедрения - ты это делаешь для каких-то российских/СНГ клиентов или аутсорс на Европу и глобальный рынок?)
Было бы очень интересно послушать про реальные кейсы и задачи в каждом случае: требования от заказчиков, как ты их реализовывал, а также некие общие паттерны решений и подходов не только в промптинге, но и в декомпозиции кейсов, создании самих систем и солюшенов, и выборе софта (например, встречал заказы, где хотят конкретные инструменты: например, n8n, Botpress, Promptflow и аналогичные).
Классная практическая статья! Спасибо за более конкретную информацию по улучшению промптов. Так-то вроде да, все как бы знают, что надо просить решать задачу поэтапно, но опыт человека, который поделал это с множеством моделей, сравнил результаты и откинул нерабочее - это ценно. Лично я до сих пор добавляю в промпт фразу про «это важно для меня», хотя по ходу уже она не улучшает результаты.
Супер, спасибо за статью!
Есть вопрос немного сбоку: как лучше для LLM скармливать табличные данные из каталогов оборудования? Картинками или можно страницу pdf целиком давать?
Задача - получать для каждого типа оборудования краткое текстовое описание на основе тех. характеристик в таблице.
Пока идея скармливать скриншоты + давать пример описания для аналогичного оборудования.
Вот пример исходника:
Спасибо за статью, прочитал с интересом. Сразу возникло пару идей как можно использовать у себя в бизнесе.
А у меня, возможно, нубский вопрос. Вот эти все инструкции, few shots и прочее, их лучше указывать в системном или юзер промпте? Есть ли какие-то материалы на эту тему?
Вот читаю я все это и вспоминаю начало ИИ-хайпа.
Программисты не нужны, AI всех заменит. Помните?
А тут что-то неуловимо напоминающее конференцию по программированию времен 90х (когда книг было мало, доступа к документации тоже и в итоге программирование напоминало шаманство). А в комментах обсуждают в каких форматах сетке эффективнее скармливать данные и как экономить
такты и байты оперативкитокены.А счастье было так близко :(
Спасибо за материал. Хотелось бы узнать о текущих тенденциях/решениях экономии токенов.
Few Shot Prompting — хорош, пока не оценивается с позиции трат на десятках и сотнях тысяч запросов.
Лично для себя выявил подход с файнтюнингом вместо FSP. Из крутого, обучаться можно на реальных данных и появляется даже ROC-AUC / RMSE на тестовых выборках.
Взамен, все фью шот образцы удаляются из запросов, что сильно экономит токены.
Хотелось бы почитать еще идей и мнений по разработке систем.
Тоже было интересно, но данных весьма мало.
Лично я под системным понимаю общие инструкции модели. Такие, которые фактически не отличаются между вводами.
Вот например для автоматического анализа фраз Яндекс.Директа у меня там описано, что важно находить кратчайшую минус фразу, ставить восклицательные знаки возле местоимений и предлогов и т д.
Не важно какую фразу передаст пользовательская инструкция, системная всегда одинаковая.