02. Промптинг как инженерная дисциплина¶
Зачем это нужно?¶
Промпт — это код для нейросети. Только, в отличие от обычного кода, он работает через управление вероятностями.
Без правильного промптинга агент будет:
- Выполнять действия случайно, без логики
- Пропускать важные шаги анализа
- Делать опасные действия без подтверждения
- Отвечать в неправильном формате
В этой главе разберём, как писать промпты так, чтобы они реально управляли поведением агента.
Реальный кейс¶
Ситуация: Вы создали агента для обработки инцидентов. Пользователь пишет: "Упал сервис, почини"
Проблема: Агент сразу рестартит сервис, не проверив логи. Или наоборот, будет долго анализировать, не применяя фикс.
Решение: Нормальный System Prompt с SOP (Standard Operating Procedure) задаёт порядок действий: статус → логи → анализ → фикс → верификация.
TL;DR: Что нужно запомнить¶
- System Prompt — это спецификация поведения агента. Состоит из: Role, Goal, Constraints, Format, SOP.
- In-Context Learning (ICL): Zero-shot (instruction-only) — компактно, гибко, но модель может неправильно интерпретировать формат. Few-shot (demonstration) — инструкция + примеры, точнее для сложных форматов. На практике — комбинация.
- CoT (Chain-of-Thought): заставляет модель думать по шагам. Критичен для агентов.
- SOP: алгоритм действий, закодированный в промпте. Задает процесс, CoT помогает следовать ему.
- Task Decomposition: сложные задачи разбиваем на подзадачи.
- Tools Schema передается отдельным полем
tools[], не внутри System Prompt. - Few-shot примеры должны быть согласованными — один формат, иначе модель запутается.
Структура System Prompt¶
Хороший System Prompt состоит из пяти блоков:
1. Role (Persona) — кто ты
2. Goal (Цель) — что нужно достичь
3. Constraints — что нельзя делать
4. Format — в каком формате отвечать
5. SOP — алгоритм действий
Шаблон System Prompt¶
Ты [Role] с [опыт/квалификация].
Твоя цель — [Goal].
Ограничения:
- [Constraint 1]
- [Constraint 2]
Формат ответа:
- [Format rule 1]
- [Format rule 2]
SOP для [тип задачи]:
1. [Шаг 1]
2. [Шаг 2]
3. [Шаг 3]
Пример для DevOps¶
Ты Senior DevOps Engineer. Твоя цель — восстановить работоспособность
сервиса, не сломав то, что ещё работает.
Инварианты:
- Деструктивные действия (restart, rollback, удаление данных) — только
после подтверждения: система может быть живой, а алерт — ложным,
и перезапуск усугубит проблему.
- Не запускай команды, стирающие данные за пределами зоны инцидента:
восстановление после них дороже самого инцидента.
Обычный путь расследования инцидента (не жёсткий порядок — если данных
мало, собирай ещё; главное — не применяй фикс до анализа):
- проверь статус сервиса (check_http)
- если статус не 200 — прочитай последние логи (read_logs)
- по логам определи вероятную причину (деплой, БД, ресурсы)
- примени минимальный фикс (restart/rollback)
- проверь статус снова (check_http)
Важно: строки-ограничители в промпте — это подсказка модели, а не защита. Модель может их проигнорировать или интерпретировать иначе. Реальную границу держит код: allowlist инструментов, права доступа, обязательное подтверждение опасных действий через механизм кода (Confirm-коллбек или обязательный аргумент инструмента). Промпт объясняет модели, почему инвариант такой — это снижает вероятность спонтанных нарушений, но не заменяет enforcement. Как это устроено — в Главе 05: Безопасность и HITL и Главе 17: Безопасность и управление.
Пример для Support¶
Ты Customer Support Agent уровня Tier 2.
Твоя цель — решить проблему пользователя быстро и вежливо.
Ограничения:
- Всегда будь вежлив
- Если проблема сложная — эскалируй
- Не давай технических деталей, если пользователь не технарь
Формат ответа:
- Используй структурированный формат: {"action": "...", "user_id": "..."}
SOP для обработки тикета:
1. Прочитай тикет полностью (get_ticket)
2. Собери контекст (версия ПО, ОС, браузер)
3. Поищи в базе знаний (search_kb)
4. Если решение найдено — сформулируй ответ
5. Если нет — эскалируй (escalate_ticket)
Пример для Data Analytics¶
Ты Data Analyst с опытом работы с SQL и BI-инструментами.
Твоя цель — предоставить точные данные и аналитику.
Ограничения:
- Работай только с read-only SQL (SELECT): запрос на изменение может испортить прод-данные, а восстановить их из аналитической сессии нельзя
- Проверяй качество данных перед анализом: на грязных данных выводы введут в заблуждение
- Если данные некорректны — сообщи об этом, а не «дорисовывай» выводы
Формат ответа:
- Сначала покажи SQL-запрос
- Затем результаты и анализ
SOP для анализа:
1. Понять вопрос пользователя
2. Сформулировать SQL-запрос
3. Проверить схему таблицы (describe_table)
4. Выполнить запрос (sql_select)
5. Проанализировать результаты
6. Сгенерировать отчет
Системный промпт — это кэшируемый префикс¶
У LLM API есть prompt cache: неизменный префикс запроса кэшируется и стоит заметно дешевле и быстрее. Отсюда практические правила:
- System prompt должен быть неизменяемым от запроса к запросу. Любое изменение — timestamp, счётчик, «персонализированная» вставка — ломает кэш и удорожает все запросы.
- Вся динамика (текущее время, результаты инструментов, новые факты) попадает в конец истории
messages— через tool results и добавление сообщений. Никогда не мутируйтеmessages[0]. time.Now()и другие меняющиеся значения в system prompt — антипаттерн.- Объёмные знания не копятся в промпте: большие инструкции выносятся в файлы-скилы, которые модель читает сама по мере надобности (progressive disclosure) — 10 скилов занимают ~10 строк в промпте, а не 10 страниц.
Подробнее — Глава 12: Память агента и Глава 13: Инженерия контекста.
In-Context Learning (ICL): Zero-shot и Few-shot¶
После того, как мы определили структуру System Prompt, возникает вопрос: как лучше передать модели нужное поведение?
In-Context Learning (ICL) — это способность модели адаптировать поведение на основе примеров внутри промпта, без изменения весов модели.
ICL работает в двух режимах:
Zero-Shot (только инструкция)¶
Даем модели только инструкцию, без примеров:
System Prompt: "Ты DevOps инженер. Когда пользователь просит проверить логи, используй инструмент read_logs."
User: "Проверь логи nginx"
Assistant: [Модель выполняет задачу на основе инструкции]
Когда использовать:
- Простые задачи, где модель хорошо понимает инструкции
- Ограниченный контекст (нужно экономить токены)
- Модель уже обучена на похожих задачах
Few-Shot (инструкция + примеры)¶
Даем модели инструкцию + примеры желаемого поведения:
System Prompt: "Ты DevOps инженер. Примеры:
Пример 1:
User: "Проверь логи nginx"
Assistant: {"tool": "read_logs", "args": {"service": "nginx"}}
Пример 2:
User: "Перезапусти сервер web-01"
Assistant: {"tool": "restart", "args": {"name": "web-01"}}
User: "Проверь статус сервера"
Assistant: {"tool": "check_status", "args": {"hostname": "web-01"}}
Важно: обучать модель формату tool-call текстом в промпте — это исторический приём (recovery). Основной путь сегодня — native tool-calling: модель обучена вызовам инструментов заранее, и достаточно передать JSON Schema в отдельном поле
tools[](см. Главу 03: Инструменты) — вызов вернётся в отдельном полеtool_calls, а не как текст. Few-shot с текстовыми{"tool": ...}примерами остаётся полезен в двух случаях: нестандартные текстовые форматы ответа (не tool-calls) и восстановление работы, когда модель или среда не поддерживают native tool-calling.
Когда использовать:
- Сложный формат ответа (JSON, структурированные данные)
- Нужна высокая точность следования формату
- Модель может неправильно интерпретировать инструкцию
Терминология: Инструкция vs Демонстрация¶
Термины Instruction-only (только инструкция) и Demonstration (демонстрация) или Few-shot — это альтернативные способы описания тех же режимов ICL:
- Instruction-only = Zero-shot: Мы описываем модели, что делать (компактно, гибко, но модель может неправильно интерпретировать формат)
- Demonstration/Few-shot = Few-shot: Мы показываем модели примеры желаемого поведения (модель точно копирует формат, но занимает больше токенов)
Правило по умолчанию: Используйте комбинацию — инструкция + 1-2 примера для сложных форматов или краевых случаев.
Таблица выбора режима ICL¶
| Режим | Что передаем модели | Когда использовать | Пример |
|---|---|---|---|
| Zero-shot (Instruction-only) | Только инструкция | Простые задачи, модель хорошо понимает инструкции, ограниченный контекст, экономия токенов | "Ты DevOps инженер. Проверяй логи через read_logs." |
| Few-shot (Demonstration) | Инструкция + примеры | Сложный формат ответа (JSON, структурированные данные), нужна высокая точность следования формату | Инструкция + 2-3 примера формата ответа |
Практический пример: Few-Shot для Support¶
// System Prompt с Few-Shot примерами
systemPrompt := `Ты Support агент.
Примеры формата ответа:
Пример 1:
User: "Мой аккаунт заблокирован"
Assistant: {"action": "check_account", "user_id": "extract_from_ticket"}
Пример 2:
User: "Не могу войти в систему"
Assistant: {"action": "check_login", "user_id": "extract_from_ticket"}`
messages := []Message{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: "Проблема с доступом"},
}
// Message — нейтральная структура из Главы 03:
// type Message struct {
// Role string
// Content string
// ToolCalls []ToolCall
// }
// Модель видит примеры в System Prompt и генерирует ответ в том же формате:
// {"action": "check_account", "user_id": "..."}
Антипример: Несогласованные Few-Shot примеры¶
Плохо: Примеры в разных форматах
Пример 1:
User: "Проверь логи"
Assistant: {"tool": "read_logs", "service": "nginx"}
Пример 2:
User: "Перезапусти сервер"
Assistant: {"action": "restart", "target": "web-01"} // Разный формат!
Пример 3:
User: "Статус"
Assistant: check_status("web-01") // Еще один формат!
Проблема: Модель видит три разных формата и не понимает, какой использовать. Результат непредсказуем.
Хорошо: Все примеры в одном формате
Пример 1:
User: "Проверь логи"
Assistant: {"tool": "read_logs", "args": {"service": "nginx"}}
Пример 2:
User: "Перезапусти сервер"
Assistant: {"tool": "restart", "args": {"name": "web-01"}} // Тот же формат
Пример 3:
User: "Статус"
Assistant: {"tool": "check_status", "args": {"hostname": "web-01"}} // Тот же формат
Результат: Модель четко понимает паттерн и следует ему.
Важно: Few-shot задаёт не только формат, но и скрытые подсказки. Примеры в few-shot могут не только показывать формат ответа, но и неявно подсказывать желаемый вывод. Модель может "подхватить" паттерн из примеров и сместить ответ в сторону того, что показано в демонстрациях, даже если это не соответствует реальным данным или задаче.
Проблема: Если в примерах правильный ответ всегда в позиции "A", или все примеры ведут к одному типу решения, модель может перенять этот позиционный или тематический биас.
Решение: Используйте разнообразные примеры, перемешивайте позиции правильных ответов, включайте контрпримеры. См. раздел "Как не подсказывать модели ответ" ниже.
Связь ICL с другими техниками¶
- ICL → CoT: Демонстрации могут задавать не только формат ответа, но и формат рассуждения. Например, примеры с "Thought: ... Action: ... Observation: ..." (исторический формат ReAct — подробнее в разделе CoT ниже).
- CoT → SOP: SOP — это процесс, закрепленный инструкцией и/или примерами. CoT помогает модели следовать этому процессу шаг за шагом.
См. подробнее:
- Lab 01: Basics — работа с контекстом и памятью
- Lab 02: Tools — формат ответов через Function Calling
- Lab 06: Incident (SOP) — SOP как алгоритм действий
Сквозной пример: что именно отправляет агент в LLM¶
Коротко — что где находится в запросе к LLM API:
- System Prompt — текст в
messages[0]сrole = "system": инструкции (Role, Goal, Constraints), SOP и few-shot примеры, если используются. - Tools Schema — отдельное поле
tools[](НЕ внутри промпта): JSON Schema-описания инструментов. Модель видит их вместе с промптом. - User Input — сообщения
role = "user"в историиmessages: текущий запрос плюс предыдущие user/assistant сообщения. - Tool Results — ваш runtime добавляет в конец истории сообщение
role = "tool"сtool_call_id, связывающим результат с вызовом.
Компактный скелет запроса в середине цикла (уже был один tool-call). Форма — как у нейтральных Go-структур курса (Request/Message/ToolCall, гл. 04); точный wire-формат HTTP-запроса ("type": "function" + обёртка function) — в Главе 03:
{
"model": "glm-5.3",
"messages": [
{ "role": "system", "content": "Ты DevOps инженер..." },
{ "role": "user", "content": "Проверь статус nginx" },
{ "role": "assistant", "content": "",
"tool_calls": [
{ "id": "call_1", "name": "check_status", "arguments": "{\"service\": \"nginx\"}" }
] },
{ "role": "tool", "tool_call_id": "call_1", "content": "nginx is ONLINE" }
],
"tools": [
{ "name": "check_status", "description": "Check service status",
"parameters": {
"type": "object",
"properties": { "service": { "type": "string" } },
"required": ["service"]
} }
]
}
Цикл: модель возвращает tool_calls → ваш код (runtime) валидирует вызов, выполняет инструмент и добавляет результат в конец messages → отправляется новый запрос с расширенной историей. Никакой магии: модель просто видит результаты предыдущих инструментов в контексте и генерирует следующий шаг на его основе.
Полный разбор протокола tool-calling — форматы, валидация аргументов, обработка ошибок — в Главе 03: Инструменты и Function Calling.
Chain-of-Thought (CoT): Думай по шагам¶
Chain-of-Thought (CoT) — это техника "Думай по шагам". Для агентов CoT критичен.
Когда CoT нужен?¶
Плохо: "Почини сервер" (один шаг)
Хорошо: "Проанализируй ситуацию, выдвини гипотезу, проверь её, предложи решение" (цепочка)
CoT нужен для:
- Сложных задач, требующих анализа
- Задач с несколькими шагами
- Задач, где нужно проверить гипотезу перед действием
CoT не нужен для:
- Простых одношаговых задач
- Задач, где формат ответа важнее процесса
Как задавать CoT?¶
CoT можно задавать через инструкцию (Zero-shot) или через примеры (Few-shot):
Zero-shot CoT:
Думай по шагам:
1. Проанализируй ситуацию
2. Выдвини гипотезу
3. Проверь гипотезу
4. Примени решение
Few-shot CoT (исторический формат ReAct):
Пример рассуждения (это пример того, как агент работает в цикле):
Thought: Пользователь жалуется на медленную работу. Начну с проверки метрик.
Action: get_cpu_metrics()
Observation: CPU 95%, процесс: ffmpeg
Thought: ffmpeg жрет ресурсы. Проверю, что это за процесс.
Action: get_process_info(pid=12345)
Модель видит пример формата рассуждения и следует ему. На практике это происходит в цикле: каждый Observation добавляется Runtime'ом (вашим кодом) в историю, и модель видит его при следующей итерации.
Контекст: откуда этот формат. «Thought / Action / Observation» — это текстовый протокол ReAct (2022): в то время модели не умели вызывать инструменты нативно, и весь цикл агента приходилось выражать текстом в промпте. Сегодня отдельный текстовый формат для этого не нужен: «Thought» — это просто
contentответа модели рядом сtool_calls, «Observation» — сообщениеrole = "tool". Знать ReAct полезно как происхождение agent loop и как приём восстановления (recovery), если модель или среда не поддерживают native tool-calling — но не как основной протокол.
CoT и Agent Loop¶
Формат "Thought-Action-Observation" — это формализация Agent Loop (итеративного процесса агента), предложенная в работе ReAct. Тогда весь цикл жил в тексте; сегодня тот же цикл выражается нативными полями API.
Как это работает (соответствие формату ReAct):
- Thought — это
contentответа модели: краткий анализ ситуации и план следующего шага, который модель пишет рядом сtool_calls - Action — это
tool_calls: модель выбирает инструмент и параметры (генерируетtool_call) - Observation — Runtime (ваш код) выполняет инструмент и добавляет результат в историю (
role = "tool") - Цикл повторяется: модель видит Observation в контексте, снова думает (Thought), выбирает следующий Action
Пример итерации:
Итерация 1:
Thought: "Нужно проверить метрики CPU"
Action: get_cpu_metrics()
Observation: "CPU 95%, процесс: ffmpeg" ← runtime добавил в историю
Итерация 2 (модель видит Observation в контексте):
Thought: "ffmpeg жрет ресурсы. Проверю детали процесса"
Action: get_process_info(pid=12345)
Observation: "Это видео-конвертация" ← runtime добавил в историю
Итерация 3:
Thought: "Легитимный процесс, но блокирует систему. Предложу ограничить приоритет"
Action: [финальный ответ пользователю]
Важно: Никакой магии тут нет — модель просто видит результаты предыдущих инструментов в контексте (messages[]) и генерирует следующий шаг на основе этого контекста. (Запись выше — учебная псевдонотация ReAct; в реальном ответе те же шаги выглядят как content + tool_calls.)
Важно: CoT может быть post-hoc (после факта). Цепочка рассуждений (CoT), которую генерирует модель, не обязательно отражает реальный процесс вывода. Модель может сначала "решить" задачу (на основе вероятностного механизма), а затем сгенерировать "красивое объяснение" этого решения.
Проблема: Красивое CoT не является доказательством корректности ответа. Модель может уверенно рационализировать неправильный вывод.
Решение: Не полагайтесь на CoT как на единственный источник истины. Проверяйте ответы через инструменты, evals, и runtime-валидацию. Для критических решений используйте Human-in-the-Loop независимо от качества объяснения.
См. подробнее: Глава 04: Автономность и Циклы — как работает ReAct Loop и итеративный процесс агента.
Примеры CoT в разных доменах¶
Ниже — учебные траектории рассуждения в нотации ReAct. Читать их стоит как иллюстрацию хода мысли агента; в реальном цикле с native tool-calling те же шаги — это content (рассуждение) и tool_calls (действие) в ответах модели.
DevOps¶
Thought: Пользователь жалуется на медленную работу. Начну с проверки метрик.
Action: get_cpu_metrics()
Observation: CPU 95%, процесс: ffmpeg
Thought: ffmpeg жрет ресурсы. Проверю, что это за процесс.
Action: get_process_info(pid=12345)
Observation: Это видео-конвертация, запущенная пользователем
Thought: Это легитимный процесс, но он блокирует систему. Предложу пользователю ограничить приоритет.
Security¶
Thought: Получен алерт о подозрительной активности. Начну с триажа.
Action: query_siem(query="host=192.168.1.10 AND time>now-1h")
Observation: Множество failed login attempts
Thought: Это похоже на brute-force. Проверю источник.
Action: get_source_ip()
Observation: IP из незнакомой страны
Thought: Высокий риск. Изолирую хост, но сначала запрошу подтверждение.
Data Analytics¶
Thought: Пользователь спрашивает про продажи. Нужно понять, какие данные есть.
Action: describe_table("sales")
Observation: Таблица содержит поля: date, region, amount
Thought: Теперь сформулирую SQL-запрос для получения продаж за последний месяц.
Action: sql_select("SELECT region, SUM(amount) FROM sales WHERE date > NOW() - INTERVAL '1 month' GROUP BY region")
Observation: Результаты: Region A: 100k, Region B: 150k
Thought: Проанализирую результаты и сформулирую выводы.
SOP и декомпозиция задач: процесс агента¶
SOP (Standard Operating Procedure) — это алгоритм действий, закодированный в промпте. Задает процесс, CoT помогает следовать ему шаг за шагом.
Связь: Goal → Constraints → SOP → CoT¶
- Goal/Constraints задают рамки (что нужно достичь, что нельзя делать)
- SOP задает процесс (какие шаги выполнять)
- CoT помогает идти по шагам (думать на каждом этапе)
Зачем это нужно?¶
Без SOP агент может "метаться": сразу рестартить, потом читать логи, потом опять рестартить.
Почему SOP важен: направление внимания модели
Без SOP модель видит: User: Fix it. Ее вероятностный механизм может выдать: Call: restart_service. Это самое "популярное" действие.
С SOP модель вынуждена сгенерировать текст:
- "Step 1: I need to check HTTP status." → Это повышает вероятность вызова
check_http - "HTTP is 502. Step 2: I need to check logs." → Это повышает вероятность вызова
read_logs
Мы направляем внимание модели по нужному руслу через явное указание шагов в промпте.
Пример SOP для инцидента (DevOps)¶
SOP для падения сервиса:
1. Check Status: Проверь HTTP код ответа
2. Check Logs: Если 500/502 — читай последние 20 строк логов
3. Analyze: Найди ключевые слова:
- "Syntax error" → Rollback
- "Connection refused" → Check Database
- "Out of memory" → Restart
4. Action: Примени фикс согласно анализу
5. Verify: Проверь HTTP статус снова
Пример SOP для Support¶
SOP для обработки тикета:
1. Read: Прочитай тикет полностью
2. Context: Собери контекст (версия, ОС, браузер)
3. Search: Поищи в базе знаний похожие случаи
4. Decide:
- Если решение найдено → Draft reply
- Если сложная проблема → Escalate
5. Respond: Отправь ответ пользователю
Пример SOP для Security¶
SOP для триажа алерта:
1. Severity: Определи критичность (Low/Medium/High/Critical)
2. Evidence: Собери доказательства (логи, метрики, сетевой трафик)
3. Triage:
- Если False Positive → Close alert
- Если True Positive → Containment (с подтверждением!)
4. Report: Сгенерируй отчет для SOC
Структурирование задач (Task Decomposition)¶
Сложные задачи нужно разбивать на подзадачи.
Без декомпозиции:
С декомпозицией:
User: "Разберись с проблемой базы"
Assistant:
1. Проверю доступность БД (ping_db)
2. Проверю метрики (cpu, memory, connections)
3. Прочитаю логи (read_db_logs)
4. Проанализирую ошибки
5. Предложу решение
Типовые ошибки промптинга¶
Ошибка 1: Слишком общий промпт¶
Симптом: Модель не понимает, что делать, отвечает общими фразами.
Причина: Промпт не задает конкретную роль, цель и процесс действий.
Решение:
// ПЛОХО
Ты помощник.
// ХОРОШО
Ты Senior DevOps Engineer с 10-летним опытом.
Твоя цель — восстановить работоспособность сервисов.
Следуй SOP: 1. Check Status 2. Check Logs 3. Analyze 4. Fix 5. Verify
Ошибка 2: Отсутствие CoT¶
Симптом: Модель пытается сделать всё сразу, пропускает шаги анализа.
Причина: Промпт не задает формат рассуждения (Chain-of-Thought), модель не "думает" по шагам.
Решение:
// ПЛОХО
Почини сервер.
// ХОРОШО
Думай по шагам:
1. Проанализируй ситуацию
2. Выдвини гипотезу
3. Проверь гипотезу
4. Примени решение
Ошибка 3: Отсутствие ограничений¶
Симптом: Модель может выполнить опасные действия без подтверждения.
Причина: Промпт не задает ограничения на действия агента — и модель действует по принципу «быстрее починить».
Решение:
// ПЛОХО
Ты DevOps инженер. Делай что нужно.
// ХОРОШО
Ты DevOps инженер. Твоя цель — восстановить сервис, не создав новый ущерб.
Ограничения:
- Удаляй данные только после подтверждения: система может быть живой,
а алерт — ложным, и откат данных невозможен
- Собери факты (статус, логи) до любого действия: действие без диагноза
чаще вредит, чем помогает
Помните: эти строки — подсказка модели, снижающая вероятность ошибки. Гарантию даёт код: allowlist инструментов и подтверждение опасных действий как механизм runtime (гл. 05).
Ошибка 4: Подсказанный ответ (Anchoring Bias)¶
Симптом: Модель смещает ответ в сторону того, что явно предложено в промпте или запросе пользователя, даже если это неверно.
Причина: Промпт или запрос содержит явные подсказки о желаемом ответе ("я думаю правильный ответ — A", "скорее всего это X"). Модель, обученная на максимизации человеческих предпочтений (RLHF), может "льстить" и соглашаться.
Решение:
// ПЛОХО
User: "Я думаю, что проблема в базе данных. Проверь логи."
System Prompt: "Пользователь считает, что проблема в БД. Проверь логи."
// ХОРОШО
User: "Я думаю, что проблема в базе данных. Проверь логи."
System Prompt: "Проверь логи и проанализируй все возможные причины. Не ограничивайся только предположениями пользователя."
Практика: Разделяйте факты (данные, логи, метрики) и предпочтения/гипотезы пользователя. Не включайте предпочтения в контекст как факты.
Ошибка 5: Биас в few-shot ("ответ всегда A")¶
Симптом: Модель перенимает позиционный паттерн из примеров: если правильный ответ в few-shot всегда в позиции "A", модель начинает выбирать "A" чаще, чем должно быть.
Причина: Few-shot примеры не разнообразны, правильные ответы всегда в одной позиции или следуют одному паттерну.
Решение:
// ПЛОХО
Пример 1: Вопрос → Ответ A (правильный)
Пример 2: Вопрос → Ответ A (правильный)
Пример 3: Вопрос → Ответ A (правильный)
// ХОРОШО
Пример 1: Вопрос → Ответ A (правильный)
Пример 2: Вопрос → Ответ B (правильный)
Пример 3: Вопрос → Ответ C (правильный)
// Или перемешивайте позиции, добавляйте контрпримеры
Практика: Перемешивайте позиции правильных ответов, включайте разнообразные примеры, добавляйте контрпримеры (неправильные ответы с объяснением, почему они неправильные).
Ошибка 6: Слепая вера в CoT¶
Симптом: Разработчик полагается на "красивое объяснение" модели как на доказательство корректности ответа, не проверяя сам ответ.
Причина: CoT выглядит логичным и убедительным, но может быть post-hoc рационализацией неправильного вывода.
Решение:
// ПЛОХО
Модель: "Thought: Проблема в БД. Action: restart_database()"
Разработчик: "Отлично, логично!" → Выполняет действие без проверки
// ХОРОШО
Модель: "Thought: Проблема в БД. Action: restart_database()"
Разработчик: Проверяет через инструменты (check_db_status, read_logs),
валидирует через evals, запрашивает подтверждение для критических действий
Практика: CoT — это инструмент для улучшения рассуждений модели, но не источник истины. Всегда проверяйте ответы через инструменты и evals, особенно для критических действий.
Как не подсказывать модели ответ¶
Few-shot и CoT могут невольно "подсказывать" модели желаемый вывод. Вот чеклист, как избежать этого:
Чеклист: Нейтральные формулировки¶
Хорошо:
- Используйте нейтральные формулировки запросов
- Разделяйте факты и предпочтения пользователя
- Не включайте предположения как факты в контекст
Плохо:
- "Я думаю правильный ответ — A, проверь"
- "Пользователь считает X, используй это как факт"
- "Скорее всего проблема в Y, проверь только Y"
Чеклист: Разнообразие few-shot примеров¶
Хорошо:
- Перемешивайте позиции правильных ответов (A, B, C, D)
- Включайте разнообразные типы задач
- Добавляйте контрпримеры (неправильные ответы с объяснением)
Плохо:
- Все правильные ответы в позиции "A"
- Все примеры одного типа
- Только положительные примеры
Чеклист: Разделение предпочтений и фактов¶
Хорошо:
Факты (включаем в контекст):
- Логи показывают ошибку 500
- Метрики CPU: 95%
Предпочтения/гипотезы (отдельно, не как факты):
- Пользователь предполагает проблему в БД
- Гипотеза: проблема в сети
Плохо:
Чеклист: Подтверждение через инструменты¶
Хорошо:
- Проверяйте ответы через инструменты (read_logs, check_status)
- Используйте evals для проверки устойчивости к подсказкам
- Не полагайтесь только на CoT как на доказательство
Плохо:
- Принимать ответ модели только потому, что CoT выглядит логично
- Не проверять ответы инструментами
- Нет evals на устойчивость к anchoring
Пример: Анти-промпт и исправленная версия¶
Плохо (подсказывает ответ):
Ты DevOps инженер. Пользователь считает, что проблема в базе данных.
Проверь логи и подтверди, что проблема в БД.
Проблемы:
- Включает предположение пользователя как факт
- Подсказывает желаемый вывод ("подтверди, что проблема в БД")
- Модель может согласиться, даже если проблема не в БД
Хорошо (нейтрально):
Ты DevOps инженер. Пользователь сообщил о проблеме.
Проверь логи, метрики и все возможные причины.
Проанализируй данные объективно, не ограничиваясь предположениями.
Улучшения:
- Не включает предположение как факт
- Не подсказывает желаемый вывод
- Требует объективного анализа всех причин
Критерии сдачи / Чек-лист¶
Сдано:
- Роль (Persona) четко определена
- Цель (Goal) конкретна и измерима
- Ограничения (Constraints) явно указаны
- Формат ответа (Format) описан
- SOP (если применимо) детально расписан
- CoT включен для сложных задач
- Few-Shot примеры добавлены (если нужен сложный формат)
- Few-Shot примеры согласованы (один формат)
- Few-Shot примеры разнообразны (нет позиционного биаса)
- Промпт не подсказывает желаемый ответ (нейтральные формулировки)
- Предпочтения пользователя отделены от фактов
- Ответы проверяются через инструменты и evals, не только через CoT
Не сдано:
- Промпт слишком общий (нет конкретной роли и цели)
- Отсутствует CoT для сложных задач
- Нет ограничений на опасные действия
- Few-Shot примеры в разных форматах
- Few-Shot примеры имеют позиционный биас (все ответы в позиции "A")
- Промпт подсказывает желаемый ответ ("подтверди, что X")
- Предпочтения пользователя включены как факты
- Слепая вера в CoT без проверки через инструменты
Мини-упражнения¶
Упражнение 1: Создайте System Prompt¶
Создайте System Prompt для агента, который обрабатывает тикеты поддержки:
Ожидаемый результат:
- Роль: Support Agent
- Цель: решить проблему пользователя
- Ограничения: вежливость, эскалация сложных случаев
- Формат: структурированный JSON с полями
actionиuser_id - SOP: Read → Context → Search → Decide → Respond
Упражнение 2: Добавьте CoT¶
Улучшите промпт из упражнения 1, добавив Chain-of-Thought:
Ожидаемый результат:
- Добавлен формат рассуждения: модель сначала анализирует и формулирует гипотезу, потом действует
- В native tool-calling рассуждение живёт в
contentответа рядом сtool_calls— отдельный текстовый формат (Thought/Action/Observation) не нужен - Или инструкция "Думай по шагам" (если zero-shot)
Для любопытных¶
Этот раздел объясняет механику работы few-shot и CoT на уровне модели. Можно пропустить, если вас интересует только практика.
Почему Few-Shot работает?¶
Механизм Self-Attention¶
Механизм Self-Attention в трансформере позволяет модели "видеть" связи между токенами в контексте. Когда модель видит примеры:
- Интуитивно: Модель "подстраивается" под шаблон, который видит в контексте
- Механически: Векторное представление токенов смещается в сторону нужного формата, потому что предыдущие токены (примеры) задали этот контекст
- Практически: Качество результата резко зависит от качества примеров и их согласованности
Почему CoT работает?¶
Представьте задачу: "Сколько будет 23 * 41 + 12?"
Без CoT:
- Модель должна выдать ответ "955" сразу
- Это требует огромной вычислительной мощности в одном шаге
- Вероятность ошибки высока (модель может "угадать" неправильно)
С CoT:
- Модель генерирует: "23 * 40 = 920... 23 * 1 = 23... сумма 943... плюс 12... ответ 955"
- Генерируя промежуточные токены ("920", "943"), модель выгружает вычисления в контекст
- Следующий токен предсказывается на основе расширенного контекста, содержащего промежуточные результаты
- Это превращает сложную задачу в серию простых задач
Для агентов CoT критичен, потому что агенты решают сложные многошаговые задачи, где каждый шаг зависит от предыдущего.
Связь с другими главами¶
- Физика LLM: Понимание вероятностной природы LLM помогает создавать эффективные промпты, см. Главу 01: Физика LLM
- Инструменты: Как промпт влияет на выбор инструментов, см. Главу 03: Инструменты
- Автономность: Как SOP и CoT работают в цикле агента, см. Главу 04: Автономность
Что дальше?¶
После изучения промптинга переходите к:
- 03. Инструменты и Function Calling — как агент взаимодействует с реальным миром