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 с 10-летним опытом.
Твоя цель — восстановить работоспособность сервисов максимально быстро.
Ограничения:
- Никогда не используй команды типа `rm -rf /`
- Всегда спрашивай подтверждение перед удалением данных
- Если не уверен в действии — спроси у пользователя
Формат ответа:
- Если нужно вызвать инструмент — используй Tool Calling
- Если нужно уточнить — отвечай текстом
SOP для инцидентов:
1. Проверь статус сервиса (check_http)
2. Если не 200 — читай логи (read_logs)
3. Анализируй ошибки
4. Применяй фикс (restart/rollback)
5. Верифицируй (check_http снова)
Пример для 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. Сгенерировать отчет
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"}}
Примечание: Это учебная демонстрация формата ответа в тексте промпта. При реальном использовании Function Calling (см. Главу 03: Инструменты) модель возвращает вызов инструмента в отдельном поле
tool_calls, а не как текст в ответе.
Когда использовать:
- Сложный формат ответа (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 := []openai.ChatCompletionMessage{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: "Проблема с доступом"},
}
// Модель видит примеры в 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: ...".
- CoT → SOP: SOP — это процесс, закрепленный инструкцией и/или примерами. CoT помогает модели следовать этому процессу шаг за шагом.
См. подробнее:
- Lab 01: Basics — работа с контекстом и памятью
- Lab 02: Tools — формат ответов через Function Calling
- Lab 06: Incident (SOP) — SOP как алгоритм действий
Сквозной пример: что именно отправляет агент в LLM¶
Для тех, кому нужно понимать протокол: Этот раздел показывает техническую структуру запросов к LLM API. Если вы только начинаете, можете пропустить и вернуться позже.
Когда мы разрабатываем агента, важно понимать, где именно находятся разные части промпта и как они попадают в запрос к LLM.
Структура запроса к LLM¶
graph LR
A[SystemPrompt] --> D[ChatCompletionRequest]
B[ToolsSchema] --> D
C[UserInput] --> D
D --> E[LLM API]
E --> F{Ответ}
F -->|Text| G[assistant content]
F -->|Tool Call| H[tool_calls]
H --> I[Runtime выполняет]
I --> J[tool result]
J --> K[Добавляет в messages]
K --> D
Где что находится?¶
1. System Prompt — в поле Messages[0].Role = "system":
- Инструкции (Role, Goal, Constraints)
- Few-shot примеры (если используются)
- SOP (алгоритм действий)
2. Tools Schema — в отдельном поле Tools (НЕ внутри промпта!):
- JSON Schema описания инструментов
- Отдельно от промпта, но модель видит их вместе
3. User Input — в поле Messages[N].Role = "user":
- Текущий запрос пользователя
- История диалога (предыдущие user/assistant сообщения)
4. Tool Results — добавляются runtime'ом в Messages:
- После выполнения инструмента
Role = "tool",ToolCallIDсвязывает с вызовом
Пример 1: Text-only ответ (без инструментов)¶
Request:
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "Ты DevOps инженер.\n\nПримеры:\nUser: \"Как дела?\"\nAssistant: \"Все хорошо, чем могу помочь?\""
},
{
"role": "user",
"content": "Привет!"
}
]
}
Где что находится:
- System Prompt (инструкции + few-shot примеры) →
messages[0].content - User Input →
messages[1].content - Tools → отсутствует
Response:
{
"choices": [{
"message": {
"role": "assistant",
"content": "Привет! Чем могу помочь?",
"tool_calls": null
}
}]
}
Пример 2: Tool-call ответ (с инструментами, 2 хода)¶
Ход 1: Request с tool call
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "Ты DevOps инженер. Используй инструменты для проверки сервисов."
},
{
"role": "user",
"content": "Проверь статус nginx"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "check_status",
"description": "Check service status",
"parameters": {
"type": "object",
"properties": {
"service": {
"type": "string",
"description": "Service name"
}
},
"required": ["service"]
}
}
}
]
}
Где что находится:
- System Prompt →
messages[0].content - User Input →
messages[1].content - Tools Schema → отдельное поле
tools[](НЕ внутри промпта!)
Response #1 (tool call):
{
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "check_status",
"arguments": "{\"service\": \"nginx\"}"
}
}
]
}
}]
}
Runtime выполняет инструмент:
- Парсит
tool_calls[0].function.arguments→{"service": "nginx"} - Вызывает
check_status("nginx")→ результат:"nginx is ONLINE"
Ход 2: Request с tool result
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "Ты DevOps инженер. Используй инструменты для проверки сервисов."
},
{
"role": "user",
"content": "Проверь статус nginx"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "check_status",
"arguments": "{\"service\": \"nginx\"}"
}
}
]
},
{
"role": "tool",
"content": "nginx is ONLINE",
"tool_call_id": "call_abc123"
}
],
"tools": [...]
}
Response #2 (финальный ответ):
{
"choices": [{
"message": {
"role": "assistant",
"content": "nginx работает нормально, сервис ONLINE",
"tool_calls": null
}
}]
}
Что происходит:
- System Prompt содержит инструкции (может содержать few-shot примеры выбора инструментов)
- Tools Schema передается отдельным полем
tools[](не внутри промпта!) - User Input — текущий запрос
- Модель видит все три части и генерирует tool_call (имя инструмента + аргументы)
- Runtime (ваш код агента) валидирует tool_call, выполняет инструмент и добавляет результат в
messagesсrole = "tool". Runtime — это код, который вы пишете на Go для управления циклом агента (см. Главу 00: Предисловие) - Второй запрос включает tool result, модель формулирует финальный ответ
Ключевые моменты¶
-
System Prompt — это текст в
Messages[0].Content. Может содержать инструкции, few-shot примеры, SOP. -
Tools Schema — это отдельное поле
Toolsв запросе. Не находится внутри промпта, но модель видит его вместе с промптом. -
Few-shot примеры — находятся внутри System Prompt (текст). Они показывают модели формат ответа или выбор инструментов.
-
User Input — это
Messages[N].Role = "user". Может быть несколько сообщений (история диалога). -
Tool Results — добавляются runtime'ом в
MessagesсRole = "tool"после выполнения инструмента.
Важно: Tools Schema и System Prompt — это разные вещи:
- System Prompt — текст для модели (инструкции, примеры)
- Tools Schema — структурированное описание инструментов (JSON Schema)
См. детальный протокол: Глава 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:
Пример рассуждения (это пример того, как агент работает в цикле):
Thought: Пользователь жалуется на медленную работу. Начну с проверки метрик.
Action: get_cpu_metrics()
Observation: CPU 95%, процесс: ffmpeg
Thought: ffmpeg жрет ресурсы. Проверю, что это за процесс.
Action: get_process_info(pid=12345)
Модель видит пример формата рассуждения и следует ему. На практике это происходит в цикле: каждый Observation добавляется Runtime'ом (вашим кодом) в историю, и модель видит его при следующей итерации.
CoT и Agent Loop¶
Формат "Thought-Action-Observation" — это формализация Agent Loop (итеративного процесса агента).
Как это работает:
- Thought — модель анализирует ситуацию и думает, что делать дальше
- Action — модель выбирает инструмент и параметры (генерирует
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[]) и генерирует следующий шаг на основе этого контекста.
CoT может быть post-hoc (после факта)
Цепочка рассуждений (CoT), которую генерирует модель, не обязательно отражает реальный процесс вывода. Модель может сначала "решить" задачу (на основе вероятностного механизма), а затем сгенерировать "красивое объяснение" этого решения.
Проблема: Красивое CoT не является доказательством корректности ответа. Модель может уверенно рационализировать неправильный вывод.
Решение: Не полагайтесь на CoT как на единственный источник истины. Проверяйте ответы через инструменты, evals, и runtime-валидацию. Для критических решений используйте Human-in-the-Loop независимо от качества объяснения.
См. подробнее: Глава 04: Автономность и Циклы — как работает ReAct Loop и итеративный процесс агента.
Примеры CoT в разных доменах¶
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
Мы направляем внимание модели по нужному руслу через явное указание шагов в промпте.
Chain-of-Thought в действии:
Обратите внимание на System Prompt с SOP:
"Think step by step following this SOP: 1. Check HTTP... 2. Check Logs..."
Зачем это нужно?
Без этого промпта модель видит: User: Fix it.
Ее вероятностный механизм может выдать: Call: restart_service. Это самое "популярное" действие.
С этим промптом модель вынуждена сгенерировать текст:
- "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 инженер.
Ограничения:
- Никогда не удаляй данные без подтверждения
- Всегда проверяй логи перед действием
Ошибка 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:
Ожидаемый результат:
- Добавлен формат рассуждения: "Thought: ... Action: ... Observation: ..."
- Примеры few-shot с CoT (если используете few-shot)
- Или инструкция "Думай по шагам" (если 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 — как агент взаимодействует с реальным миром
Навигация: ← Физика LLM | Оглавление | Инструменты →