Содержание
  1. Определение PAL по первичке: генерация и исполнение разделены
  2. Полный few-shot промпт с def solution и запретом операций
  3. Корректная solution и print(solution()): эталон 89
  4. Проверка входов и знаков: контроль used 44 → 88
  5. Промпт не равен sandbox: сначала просмотр, потом запуск
  6. Границы учебного примера
  7. Частые вопросы
Справочник

Что такое PAL (Program-Aided Language Models)?

5 ноября 2026 · 8 минут чтения

Что такое PAL (Program-Aided Language Models)? PAL (Program-Aided Language Models) — подход к рассуждению, в котором языковая модель читает задачу на естественном языке и генерирует программу как промежуточные шаги, а вычисление ответа берёт на себя отдельный интерпретатор Python. Авторы описывают это в статье Gao et al. на PMLR: модель декомпозирует условие в программные шаги, а решение делегируется среде исполнения. Генерация кода и его запуск — две разные операции, и это ядро техники.

Определение PAL по первичке: генерация и исполнение разделены

В первичной статье (Gao et al., PMLR 202) PAL описан как подход, где языковая модель читает задачу на естественном языке и генерирует программы в роли промежуточных шагов рассуждения, а шаг решения перекладывается на интерпретатор Python. Разложение условия на исполняемые шаги остаётся единственной задачей модели, вычисление уходит внешнему решателю. Авторы подчёркивают: цепочки рассуждений могут быть логически верными, но приводить к неверному ответу, и перенос вычисления закрывает этот разрыв.

Официальный README проекта reasoning-machines/pal формулирует то же: модель решает задачи со сложной арифметикой, генерируя цепочки из текста и кода, а исполнение кода передаётся программному runtime — в их случае интерпретатору Python. Реализация построена на few-shot prompting.

Для PAL нужны два отдельных шага: модель генерирует программу, затем интерпретатор исполняет её. В README показан интерфейс ProgramInterface, который связывает backend модели, backend Python и пользовательский промпт; параметр get_answer_expr задаёт выражение, вычисляемое после сгенерированного кода, чтобы получить ответ.

Разделение ролей объясняет, почему PAL устойчивее к большим числам. В статье на GSM-HARD, где числа в вопросах заменены на крупные, точность прямого ответа падает с 19.7% до 5.0%, а PAL держится на 61.5%. Причина в том, что арифметику выполняет интерпретатор.

Звено Что делает Где происходит
Языковая модель читает условие, пишет программу и промежуточные шаги генерация текста и кода
Runtime исполняет сгенерированный код, возвращает результат интерпретатор Python
Читатель проверяет код до запуска своя среда

Полный few-shot промпт с def solution и запретом операций

Ниже — готовый промпт для задачи на подсчёт остатка. Он требует от модели только определения функции solution() с полным телом и return, запрещает сетевые и файловые операции и не просит исполнять код. Обучающий пример и новая задача даны целиком.

ТЕКСТ9 строк
Ответь только определением Python-функции solution() без сетевых и файловых операций. Не исполняй код. Ниже пример и новая задача.
Пример: В ящике 3 набора по 8 болтов, израсходовано 5. Сколько осталось?
def solution():
    batches = 3
    per_batch = 8
    used = 5
    return batches * per_batch - used
Новая задача: Мастерская заказала 7 наборов по 18 заготовок, использовала 43, получила возврат 6. Сколько осталось?
Верни def solution(): с полным телом и return, не словесный ответ и не отдельный return вне функции.

Что менять под себя: числа и формулировку новой задачи, а также обучающий пример, если ваша задача другого типа. Требование верни def solution() с полным телом и return оставляйте — оно отсекает ответ в виде отдельного выражения или словесного числа.

Почему промпт устроен именно так. В статье PAL каждый пример в промпте — это пара «вход и программные шаги», финальные ответы в примерах не приводятся: решение делегируется интерпретатору. Авторы также отмечают, что осмысленные имена переменных важны для качества: в их абляции замена имён на однобуквенные снижала средний результат с 71.8% до 59%. Поэтому в промпте переменные названы по смыслу — batches, per_batch, used, returned.

Ограничение «без сетевых и файловых операций» — это инструкция модели. Условие задаёт желаемый вид кода; реальные ограничения при запуске определяются средой исполнения. Об этом — отдельный раздел ниже.

Корректная solution и print(solution()): эталон 89

Ожидаемый код для новой задачи выглядит так. Это ручной учебный эталон, составленный для проверки.

PYTHON8 строк
def solution():
    batches = 7
    per_batch = 18
    used = 43
    returned = 6
    return batches * per_batch - used + returned

print(solution())

Разберём по строкам. batches = 7 — число наборов, per_batch = 18 — заготовок в наборе, used = 43 — израсходовано, returned = 6 — возврат. Выражение batches * per_batch - used + returned считает остаток: расход вычитается, возврат прибавляется. Функция объявлена через def solution():, return находится внутри неё, а print(solution()) вызывает функцию после определения и печатает результат.

Арифметика: 7 × 18 = 126, затем 126 − 43 = 83, затем 83 + 6 = 89. Ожидаемый stdout — 89. Обучающий пример из промпта даёт 3 × 8 − 5 = 19; новая задача даёт 89. Оба значения — учебные, они показывают, как проверить знаки и порядок операций.

Обратите внимание на форму. Если модель вернёт return вне функции или отдельное выражение без def, код не выполнится как задумано: print(solution()) не найдёт функцию. Требование полного тела с return внутри def — это то, что делает результат запускаемым.

Проверка Что смотрим Ожидание
Входы 7, 18, 43, 6 на месте все четыре значения сохранены
Знаки расход вычитается, возврат прибавляется - used + returned
Синтаксис return внутри def solution() функция объявлена целиком
Вывод print(solution()) после определения stdout 89

Проверка входов и знаков: контроль used 44 → 88

Перед запуском стоит сверить числа и знаки с условием. Четыре входа — 7, 18, 43, 6 — должны совпадать с текстом задачи. Знак перед used — минус, перед returned — плюс. Если перепутать, ответ изменится предсказуемым образом, и это удобный контроль.

Возьмём ту же задачу и заменим used на 44 при остальных равных. Тогда 7 × 18 = 126, 126 − 44 = 82, 82 + 6 = 88. Ручной эталон даёт 88. Разница с 89 ровно на единицу — это и есть след забытого или лишнего расхода. Такой контрольный прогон показывает, что формула чувствительна именно к тому входу, который вы меняете, и что знак вычитания стоит на нужном месте.

Этот эталон — учебный. Он не является измеренным ответом языковой модели и не доказывает, что модель выдаст именно его. Его роль — дать вам точку сравнения: вы знаете, какой результат должен получиться при данных входах, и можете сверить с ним то, что вернёт интерпретатор.

Порядок проверки для читателя:

  1. Получите текст кода от модели.
  2. Прочитайте каждую строку и сопоставьте четыре входа со значениями в условии.
  3. Проверьте знаки: расход вычитается, возврат прибавляется.
  4. Убедитесь, что в коде нет файловых, сетевых и процессных операций.
  5. Выполните именно проверенный малый код в своей отдельно подготовленной среде Python.

Если на шаге 4 обнаружился неожиданный импорт или операция, остановитесь и разберите код заново. Запускать непроверенный сгенерированный код не стоит.

Промпт не равен sandbox: сначала просмотр, потом запуск

Инструкция в промпте — «без сетевых и файловых операций» — управляет тем, что модель напишет, и не является изолированной средой. Указание в промпте не обезвреживает произвольный выход: если модель всё же вставит вызов, он окажется в тексте кода, и его запуск будет зависеть от вашей среды. Разграничение простое: промпт влияет на генерацию, изоляция — на исполнение.

В README проекта показано, что ProgramInterface запускает сгенерированный фрагмент и затем вычисляет get_answer_expr, чтобы получить финальный ответ. То есть исполнение кода — штатная часть маршрута, и оно происходит в среде, которую вы контролируете. В статье авторы используют стандартный интерпретатор Python и отмечают, что решателем может быть любой интерпретатор или компилятор.

Практический порядок: сначала просмотр кода, затем запуск малого проверенного фрагмента. Перед запуском определите реальные ограничения выбранной среды на файлы, сеть и процессы. Приведённый пример не содержит готовой настройки таких ограничений.

Отдельно про ошибки исполнения. В статье авторы сообщают, что весь сгенерированный Python-код был синтаксически корректным, менее 1% примеров вызвали исключение во время выполнения, а самая частая ошибка — обращение к переменной, которая не была определена раньше (NameError). Это наблюдение из их экспериментов, и оно полезно как ориентир: чаще всего проблема не в синтаксисе, а в неопределённой переменной.

Границы учебного примера

В LearnPrompting и PromptingGuide уже есть полные учебные маршруты few-shot, генерации и исполнения кода. Здесь проверяется собственный набор: 7 наборов по 18 заготовок, расход 43 и возврат 6, с контрольной заменой расхода на 44.

Качество PAL зависит от того, насколько верно модель составила программу. В первичной статье при слабой способности модели к коду результат PAL мог уступать chain-of-thought; применимость выбранного генератора требуется проверять отдельно.

Частые вопросы

Что такое PAL простыми словами?
PAL — это способ решения задач, где языковая модель пишет программу, а отдельный интерпретатор Python выполняет её и выдаёт ответ. Модель занимается разбором условия и составлением кода, а вычисление уходит среде исполнения. Так арифметика выполняется точно, если программа составлена верно.

Чем PAL отличается от chain-of-thought?
В цепочке рассуждений модель ведёт шаги в виде текста и сама называет ответ. В PAL шаги записаны как программные конструкции, а финальный результат получается запуском кода в интерпретаторе. Авторы статьи связывают устойчивость PAL именно с этим переносом вычисления.

Почему в промпте нужен def solution и return?
Требование полного тела функции с return внутри def делает результат запускаемым: print(solution()) вызовет объявленную функцию. Отдельный return вне функции или словесное число не дадут исполнить код. Это же требование отсекает ответы в неудобной форме.

Можно ли запускать сгенерированный код сразу?
Сначала стоит прочитать код построчно, сверить входы и знаки и убедиться в отсутствии файловых, сетевых и процессных операций. Инструкция в промпте не является изолированной средой. Только после проверки запускайте малый фрагмент в своей отдельно подготовленной среде Python.

Что даёт контрольная замена used на 44?
При остальных равных входах ручной эталон даёт 88 вместо 89. Разница в единицу показывает, что формула чувствительна именно к расходу и что знак вычитания стоит верно. Это учебная проверка знаков и порядка операций.

Читайте также

3 материала