TL;DR
Когда вы пишете LLM длинную инструкцию текстом — "сначала проверь X, потом если Y то сделай Z, иначе откажи" — модель пропускает шаги, путает условия, выполняет действие до проверки. Исследовательская группа обнаружила: переписать ту же инструкцию в виде псевдокода (с явными if/else, именованными подпроцедурами и явным возвратом доказательств) поднимает точность следования на 16 пунктов — при неизменном содержании, только другой формат.
Причина проблемы проста: модель держит всю инструкцию "в голове" одновременно, и длинная проза конкурирует с диалогом за внимание. Чем дальше правило от начала — тем реже применяется. Проза особенно плохо передаёт три вещи: альтернативный порядок шагов, условия "если не выполнено — отказать", и разницу между "что должно быть правдой" и "как это проверить".
Авторы предложили два слоя. Первый — компиляция: переписать инструкцию в структурированный псевдокод с явными условиями, подпрограммами-проверками и возвратом доказательств. Второй — пэйджинг: показывать модели только активный шаг, а не весь документ. Первый слой работает сам по себе и безопасен. Второй зависит от "дисциплины состояния" модели — слабым LLM он вредит.
Схема метода
ШАГ 1 — КОМПИЛЯЦИЯ (один раз, офлайн)
Берём инструкцию в виде текста
→ Переписываем в псевдокод:
· process_function — один на цель/задачу
· rule_subroutine — проверка + рецепт верификации + возврат {результат, доказательство}
· явные if/else для условий отказа
→ Получаем программу, живёт в системном промпте
ШАГ 2 — ПЭЙДЖИНГ (опционально, только для сильных моделей)
Вместо всей программы → показываем только активный фрейм
Каждый запрос = один шаг программы
→ При call/return — вставляем следующий фрейм
! Оба шага выполняются в обычном чате, без кода
! Шаг 1 работает отдельно — Шаг 2 без Шага 1 не имеет смысла
Пример применения
Задача: Вы — основатель небольшого SaaS для B2B в России. Хотите, чтобы Claude квалифицировал входящие заявки строго по вашей процедуре: проверил бюджет, сроки, ЛПР, и либо записал на демо, либо вежливо отказал. Обычно пишете это текстом — Claude иногда записывает всех подряд, иногда забывает проверить бюджет.
Промпт (псевдокод-формат):
Ты — квалификационный ассистент. Следуй программе строго.
function qualify_lead(company, contact):
# ШАГ 1: Проверка ЛПР
result1 = check_decision_maker(contact)
if result1.holds != true:
refuse("Нужно общаться с ЛПР. " + result1.evidence)
return
# ШАГ 2: Проверка бюджета
result2 = check_budget()
if result2.holds != true:
refuse("Бюджет не соответствует. " + result2.evidence)
return
# ШАГ 3: Проверка срочности
result3 = check_timeline()
if result3.holds != true:
refuse("Сроки не совпадают. " + result3.evidence)
return
# Только если все проверки пройдены:
schedule_demo(company, contact)
return {action: "demo_scheduled", evidence: [result1, result2, result3]}
subroutine check_decision_maker(contact):
# Задай вопрос: принимает ли контакт решение о покупке?
# Верни: {holds: true/false, evidence: цитата из ответа клиента}
subroutine check_budget():
# Задай вопрос: есть ли бюджет от 50 000 руб/мес?
# Верни: {holds: true/false, evidence: цитата из ответа клиента}
subroutine check_timeline():
# Задай вопрос: планируют ли внедрение в течение 3 месяцев?
# Верни: {holds: true/false, evidence: цитата из ответа клиента}
Начни с: "Здравствуйте! Расскажите о вашей задаче."
Веди диалог, собирая данные для каждой проверки по очереди.
ВАЖНО: не переходи к следующему шагу без завершения текущего.
ВАЖНО: при отказе — всегда цитируй конкретный ответ клиента как доказательство.
Результат:
Модель поведёт диалог строго по процедуре — сначала выяснит роль контакта, потом бюджет, потом сроки. При несоответствии любого критерия — откажет с явным объяснением и цитатой из разговора. До записи на демо дойдёт только если все три проверки вернули holds: true. Вы увидите в ответе не просто "записал/отказал", а структурированный вывод с доказательной базой.
Почему это работает
Слабость LLM: проза сжимает структуру. Когда вы пишете "сначала проверь X, потом если не выполнено — откажи, иначе проверь Y" — модель видит одно длинное предложение. Границы условий размыты. Порядок не закреплён. Чем длиннее инструкция, тем сильнее ранние правила давят на поздние. Модель "видит" всё сразу, но удерживает неравномерно.
Сильная сторона LLM: следовать явным структурам. Модель хорошо обучена на коде — исходников в её обучающих данных было много. Синтаксис if/else, call, return, именованные функции — это однозначный язык: нет двусмысленности в порядке, нет слияния "что" и "как", каждое условие — отдельная единица. Псевдокод не нужно исполнять технически. Он работает как структурная метка — помогает модели генерировать текст по нужному паттерну.
Как метод использует это: Компиляция переводит неоднозначную прозу в формат, где порядок зафиксирован явно, условия выхода (refuse + return) отделены от шагов выполнения, а проверки возвращают доказательство — не просто "да/нет". Это убирает главный источник ошибок: "додумывание" порядка и пропуск шагов.
Рычаги управления:
- return {holds, evidence} → убери evidence, если хочешь краткий ответ; добавь поля, если нужна подробная аудитория
- Глубина subroutines → для простых задач объедини в одну функцию; для сложных — выноси каждую проверку отдельно
- Явные refuse + return → замени на другое поведение: escalate, ask_more, suggest_alternative
- Количество шагов → чем больше критических шагов — тем сильнее выигрыш от псевдокода над прозой
Шаблон промпта
Ты — [роль]. Следуй программе строго.
function {название_процедуры}({параметры}):
result1 = {проверка_1}()
if result1.holds != true:
{действие_при_отказе_1}(result1.evidence)
return
result2 = {проверка_2}()
if result2.holds != true:
{действие_при_отказе_2}(result2.evidence)
return
# Все проверки пройдены:
{целевое_действие}({параметры})
return {result: "success", evidence: [result1, result2]}
subroutine {проверка_1}():
# Что спросить / что проверить
# Верни: {holds: true/false, evidence: [конкретная цитата или факт]}
subroutine {проверка_2}():
# Что спросить / что проверить
# Верни: {holds: true/false, evidence: [конкретная цитата или факт]}
ПРАВИЛА ВЫПОЛНЕНИЯ:
- Не переходи к следующему шагу без завершения текущего
- При отказе — всегда цитируй конкретное основание из evidence
- Не выполняй {целевое_действие} без прохождения всех проверок
Плейсхолдеры:
- {роль} — кто ведёт процедуру: "квалификационный менеджер", "редактор", "аналитик"
- {название_процедуры} — что делаем: qualify_lead, approve_content, review_request
- {проверка_N} — конкретная проверка: check_budget, verify_source, confirm_deadline
- {действие_при_отказе} — что делать при несоответствии: refuse, escalate, request_revision
- {целевое_действие} — финальный шаг, если всё ОК: schedule_demo, publish, approve
🚀 Быстрый старт — вставь в чат:
Вот шаблон для составления псевдокод-инструкции.
Адаптируй под мою задачу: {твоя задача}.
Задавай вопросы, чтобы заполнить все поля.
[вставить шаблон выше]
LLM спросит про шаги процедуры, условия отказа и что считать доказательством — потому что без этого псевдокод-структура не заполнится. Она возьмёт паттерн из шаблона и адаптирует под твою процедуру.
Ограничения
⚠️ Слабые модели: Пэйджинг (показ только активного фрейма) вредит моделям без "дисциплины состояния" — они теряются без глобального контекста. Компиляция в псевдокод при этом безопасна для всех. Если используете небольшую или менее мощную модель — применяйте только шаблон, без пошагового пэйджинга.
⚠️ Субъективные задачи: Метод создан для процедур с чёткими критериями "выполнено / не выполнено". Для творческих задач (оценка качества текста, генерация идей) псевдокод-формат даёт меньше прироста — там нет чётких
holds: true/false.
⚠️ Простые инструкции: Для одношаговых задач переусложнение структуры добавляет токены без пользы. Метод окупается при 3+ зависимых шагах с условной логикой.
⚠️ Нужна предварительная работа: Чтобы написать псевдокод, сначала нужно самому чётко знать процедуру. Если процесс размыт в голове — псевдокод это обнажит. Это плюс для качества процесса, но требует усилий на старте.
Как исследовали
Команда из Polytechnic University Hong Kong взяла SOPBench — специальный бенчмарк с задачами из банковской сферы, здравоохранения, библиотек, DMV и других доменов. Каждая задача — это сценарий: агент должен либо выполнить операцию (если все условия выполнены), либо корректно отказать (если нет). Оценщик проверяет не только финальное решение, но и порядок вызовов инструментов.
Три конфигурации сравнивали на одном наборе задач: официальный текст SOP (проза), тот же SOP в виде псевдокода без runtime, и псевдокод с пэйджинг-рантаймом. Шесть моделей разного уровня — от слабых (GPT-4o-mini, Qwen2.5-7B) до сильных (DeepSeek-V4-Flash, Qwen3.7-Plus). Это важная деталь дизайна: авторы специально хотели поймать порог способностей.
Результат оказался неожиданно чистым: компиляция в псевдокод помогла всем сильным моделям и не навредила никому. Пэйджинг разделил поле надвое — сильные модели улучшились ещё, слабые потеряли катастрофически (−26 пунктов для GPT-4o-mini). Авторы проверили механизм через "зонды": выяснилось, что слабые модели могли реконструировать глобальный контекст из памяти — проблема не в забывчивости. Проблема в том, что без полного текста перед глазами они теряли спонтанную дисциплину: начинали делать дополнительные вызовы после завершения задачи, путали порядок.
Самый практичный вывод: компилируй всегда, пэйджинг — только после проверки модели.
Адаптации и экстраполяции
🔧 Техника: вложенные subroutines → разбивка сложных проверок
Если одна проверка сама требует нескольких шагов — выноси её в отдельную подпрограмму. Так основная функция остаётся читаемой, а сложная логика изолирована:
subroutine verify_payment_capacity(): step1 = check_monthly_revenue() step2 = check_existing_debts() if step1.holds and not step2.holds: return {holds: false, evidence: "доход есть, но есть долги: " + step2.evidence} return {holds: step1.holds, evidence: step1.evidence}
🔧 Техника: "аудит-трейл" в финальном ответе
Добавьте в финальный
returnявный список всех пройденных проверок с доказательствами. Получаете структурированный протокол решения — удобно для согласования с командой или логирования:return { decision: "demo_scheduled", audit: [ {check: "ЛПР", result: true, evidence: "..цитата.."}, {check: "бюджет", result: true, evidence: "..цитата.."}, {check: "срочность", result: true, evidence: "..цитата.."} ] }
🔧 Комбинация с Chain-of-Thought: Псевдокод фиксирует что проверять и в каком порядке. CoT добавляет как рассуждать внутри каждого шага. Вставьте внутри subroutine явную инструкцию:
# Рассуждай вслух перед тем как вернуть результат— получите и структуру, и прозрачность рассуждений.
Ресурсы
Название: Compile, Then Page: Executable SOP Programs and a Capability-Gated Runtime for Procedural LLM Agents
Авторы: Chenglin Yu, Li Yin, Ying Yu, Hongxia Yang, Ming Li
Организации: The Hong Kong Polytechnic University, The University of Hong Kong, Zhejiang Normal University
Связанное: SOPBench [Li et al., 2025], InfiAgent runtime, DSPy, StateFlow
