PAL (default)
All steps
Runs clean
Crashes, then repaired
Parts of this pattern
- Question Input / output
- A word problem with arithmetic: 'Roger has 5 tennis balls. He buys 2 cans of 3. How many does he have now?'
- Model LLM call
- Turns the problem into a short program, with its reasoning as comments and variables. It does no arithmetic itself.
- Interpreter Tool
- Runs the program in a sandbox and captures what it prints. Every calculation happens here.
- Answer Input / output
- What the program printed, '11', returned as the answer without passing back through the model.
- Question → Model
- The question goes to the model with worked examples that answer in code.
Question: Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many tennis balls does he have now?
- Model → Interpreterprogram
- The model's reply is a program; your code extracts it and sends it to the sandbox.
tennis_balls = 5; bought_balls = 2 * 3; print(tennis_balls + bought_balls)
- Interpreter → Answerprinted
- What the program prints is the answer. The model never restates it, so it cannot garble the number in the retelling.
stdout: 11
- Interpreter → Modelerror
- An extension, not in the original paper: if the program crashes, the error goes back for one repair.
NameError: name 'bought_ball' is not defined (line 3)
Program of Thoughts
The program is pure computation that stores its result in ans, which is the answer. For some tasks, the model reasons one step further from ans.
All steps
ans is the answer
ans as an intermediate step
Parts of this pattern
- Question Input / output
- A numerical question, such as Roger's tennis balls, or one whose options need one more step after the arithmetic.
- Model LLM call
- Writes a program of named variables that stores its result in ans; for some tasks, it later reasons from ans to the answer.
- Interpreter Tool
- Runs the program and reads the value of the variable ans. All the arithmetic happens here.
- Answer Input / output
- Either ans itself, such as 11, or the option the model reached from it, such as (B) 1:03 PM.
- Question → Model
- The question goes to the model with the instruction to compute it in code and store the result in ans.
Question: Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many does he have now?
- Model → Interpreterprogram
- The program: pure computation with meaningful variable names and no prose.
initial_balls = 5; cans = 2; balls_per_can = 3; ans = initial_balls + cans * balls_per_can
- Interpreter → Answerans
- On the main path, the value of ans is the answer, with no second model call.
ans = 11, returned as the answer.
- Interpreter → Modelans, reason
- When the task needs one more step, ans goes back to the model as an intermediate result.
ans = 2.05 (hours of travel)
- Model → Answeroption
- The model reasons from ans to the final answer, such as an option in a multiple-choice question.
2.05 h is 2 h 3 min; 11:00 AM + 2 h 3 min = 1:03 PM. Answer: (B)
← → neighboursesc atlas
Program-Aided Reasoning
Also known as PAL · Program of Thoughts · PoT · Code-as-reasoning · Code interpreter reasoning
The model writes a program that encodes its reasoning, an interpreter runs it, and the program's output is the answer.
PAL: Introduced by Gao et al. (2022) · Carnegie Mellon University & Inspired Cognition
Gao, Madaan and Zhou were equal first authors. Program of Thoughts (Chen et al., University of Waterloo, Vector Institute, UC Santa Barbara and Google Research) was introduced concurrently in November 2022: see its tab.
Program of Thoughts: Introduced by Chen et al. (2022) · University of Waterloo, Vector Institute and others
Published in TMLR 2023, concurrently with PAL. It separates computation (done by the interpreter) from reasoning (done by the model). For multiple-choice questions it also used ans as an intermediate step, reasoning from it to the final option.
Measured over one run
PAL
- Nodes
- 4. Boxes in the diagram: models, tools, stores, people and plain code.
- LLM calls
- 1. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
- Tool calls
- 1. Messages sent to a tool node in the first scenario.
- Steps
- 3. Steps in the first scenario, with repeated steps counted every time they run.
- Scenarios
- 2. Distinct example runs you can switch between on the diagram.
- Loop
- yes. Whether the flow cycles back on itself until a condition is met.
- Parallel
- no. Whether two or more messages are in flight at the same time.
- Branch
- yes. Whether the flow takes one path out of several, chosen at run time.
- Human in the loop
- no. Whether a person appears as a node, to approve, correct or answer.
- Autonomy
- low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
- Cost
- low. Relative token spend per request.
- Latency
- low. Relative wall-clock time per request.
Program of Thoughts
- Nodes
- 4. Boxes in the diagram: models, tools, stores, people and plain code.
- LLM calls
- 2. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
- Tool calls
- 1. Messages sent to a tool node in the first scenario.
- Steps
- 3. Steps in the first scenario, with repeated steps counted every time they run.
- Scenarios
- 2. Distinct example runs you can switch between on the diagram.
- Loop
- yes. Whether the flow cycles back on itself until a condition is met.
- Parallel
- no. Whether two or more messages are in flight at the same time.
- Branch
- yes. Whether the flow takes one path out of several, chosen at run time.
- Human in the loop
- no. Whether a person appears as a node, to approve, correct or answer.
- Autonomy
- low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
- Cost
- low. Relative token spend per request.
- Latency
- low. Relative wall-clock time per request.
Counted from the first scenario's timeline when the site is built.
Problem
“Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many does he have now?” Chain-of-thought gets models to break this down correctly, but the model still does the arithmetic itself, one token at a time. On bigger numbers, dates or long sums, the plan is often right and a single calculation is wrong. A language model is a poor calculator; a computer does arithmetic exactly.
How it works
Program-aided reasoning splits the job along that line. The question goes to the model with worked examples whose answers are short programs. So instead of writing “5 + 6 = 11”, the model writes:
tennis_balls = 5bought_balls = 2 * 3print(tennis_balls + bought_balls)Your code extracts the program and runs it in a sandboxed interpreter. What it prints, 11, is the answer. It does not go back through the model, so the model cannot garble the number when restating it. The model does the part it is good at, turning words into a plan; the interpreter does the part it is good at, computing.
In the original method that is the whole pattern: one model call and one run. The “Crashes, then repaired” scenario shows a common extension: if the program raises an error, the error goes back to the model once and the corrected program is run.
PAL (Gao, Madaan, Zhou et al., Carnegie Mellon, 2022) writes programs whose comments and variable names carry the reasoning. Program of Thoughts (Chen et al., 2022) appeared at the same time, aimed at numerical and financial questions. Its program is pure computation that stores the result in a variable, ans, and ans is the answer. For multiple-choice questions the paper also used ans as an intermediate step: the model reasons from it to the final option, for example from 2.05 hours of travel to an arrival time of 1:03 PM. That form is the second tab.
When to use
- The task involves arithmetic, dates, counting, unit conversion or symbolic manipulation, and wrong calculations are the main source of errors.
- The reasoning maps naturally onto code: quantities, formulas, loops over items.
- You can run code safely, in a sandbox with time and memory limits.
When to avoid
- You have no sandbox. Running model-written code with access to your network or files is not an option.
- The reasoning is qualitative, such as weighing arguments or interpreting text, and does not translate into code.
- The calculation is trivial. A single sum does not need an interpreter.
Trade-offs
You add an interpreter to your stack and a sandbox to maintain, plus one execution per question. In exchange, the arithmetic is exact, and the program is a precise record of how the answer was reached, which you can read, test and rerun. The model can still misread the problem, and then the computer calculates the wrong thing perfectly.
Failure modes
- Correct code for the wrong problem: the model misreads the question, and the program faithfully computes a wrong answer. Check the program’s variables against the question when the stakes are high.
- Crashes: a typo or an undefined name stops the run. Catch errors, and allow one repair if you need robustness.
- No output: the program computes the answer but never prints it. Treat empty output as a failure, or read a named result variable instead of stdout.
- Unsafe code: a program reads files, opens connections or loops forever. Sandbox every run, block the network and the file system, and set a time limit.
Build it with your AI
PAL
Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.
Implement the Program-Aided Reasoning pattern in this codebase, using the LLM client and language we already use.
## Goal
Answer a question that needs calculation by having the model write a short program for it, running that program in a sandbox, and returning what the program prints.
## How it works
1. Fill in the Program-aided prompt with worked examples and the user's question, and call the model once.
2. Extract the code block from the reply. If there is none, return no answer with a status saying the model wrote no program.
3. Run the code in a sandboxed interpreter with no network or file access, a time limit and a memory limit, and capture what it prints.
4. Return the printed output, trimmed, as the answer, and keep the program alongside it as the working.
5. If repair is enabled and the run raises an error, call the model once with the Repair prompt, passing the program and the error, and run the corrected program the same way.
## Prompts
### Program-aided prompt
````markdown
Solve the problem by writing a Python program. Use comments for your
reasoning and variables for every quantity, and print the final answer.
Return only the program, in one code block.
Question: Olivia has $23. She bought five bagels for $3 each.
How much money does she have left?
```python
# Olivia starts with $23
money_initial = 23
# she buys 5 bagels at $3 each
bagels = 5
bagel_cost = 3
money_spent = bagels * bagel_cost
print(money_initial - money_spent)
```
Question: {{question}}
````
### Repair prompt
```markdown
Your program for the question below failed when it ran.
<question>{{question}}</question>
<program>{{program}}</program>
<error>{{error}}</error>
Fix the program so it runs and prints the final answer.
Return only the corrected program, in one code block.
```
## Stop rule
Stop when a program runs and prints an answer. If the run fails and repair is off, return no answer with the program and the error. With repair on, stop after one attempt; if that also fails, return no answer with a status saying execution failed.
## Requirements
- Never run generated code outside a sandbox; block the network and the file system, and set a time limit (default 5 s) and a memory limit.
- Treat empty output as a failure, the same as an exception.
- Make the repair step optional and off by default, since it is an extension to the original method.
- Log the question, the program, the output or error, and whether a repair was used.
- Add a test with a stub LLM that returns a program printing 5 + 2 * 3 and a real sandbox; assert one model call and that the answer is exactly '11'.
Program of Thoughts
Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.
Implement the Program-Aided Reasoning pattern (Program of Thoughts variant) in this codebase, using the LLM client and language we already use.
## Goal
Answer a numerical question by having the model write a program that binds every quantity to a named variable and stores the result in ans, then returning ans, or reasoning one step further from it where the task needs that.
## How it works
1. Call the model with the Program of Thoughts prompt and the question. The program must bind every quantity to a meaningfully named variable and store the result in a variable called ans.
2. Run the program in a sandboxed interpreter with time and memory limits, and read the value of ans.
3. If the task needs no further step, return ans as the answer. This is the main path: one model call.
4. If the task needs a step the program does not take, such as choosing among multiple-choice options or converting units, call the model with the Finish from ans prompt, passing the question and ans.
5. Parse the finishing reply's 'Answer:' line and return it, keeping the program and ans alongside it as the working.
## Prompts
### Program of Thoughts prompt
```markdown
Write a Python program that computes the answer to the question.
Bind every quantity to a variable with a meaningful name, compute
step by step, and store the final result in a variable called ans.
Return only the program, in one code block.
Question: {{question}}
```
### Finish from ans prompt
```markdown
A program computed an intermediate result for the question below.
<question>{{question}}</question>
<ans>{{ans}}</ans>
Starting from ans, reason step by step to the final answer, for
example by converting units or matching it to one of the options.
End with one line that starts with "Answer:".
```
## Stop rule
Stop when ans has been read, or after the one finishing call when that step is enabled. If the program fails or never sets ans, return no answer with the program and the error.
## Requirements
- Never run generated code outside a sandbox; block the network and the file system, and set time and memory limits.
- Read the answer from the variable ans, not from printed output, and fail clearly if it is missing.
- Make the finishing step a per-task setting, off by default; the paper used it only for multiple-choice questions.
- Log the question, the program, ans and, when used, the finishing reply.
- Add a test with a stub LLM whose program sets ans = 5 + 2 * 3, with finishing off; assert exactly one model call and that the answer is exactly 11.
- Add a test with finishing on: the program sets ans = 123 / 60 and the stub finish replies 'Answer: (B)'; assert two calls, that the finish prompt contains '2.05', and the answer '(B)'.
Prompt templates
PAL
Solve the problem by writing a Python program. Use comments for yourreasoning and variables for every quantity, and print the final answer.Return only the program, in one code block.
Question: Olivia has $23. She bought five bagels for $3 each.How much money does she have left?```python# Olivia starts with $23money_initial = 23# she buys 5 bagels at $3 eachbagels = 5bagel_cost = 3money_spent = bagels * bagel_costprint(money_initial - money_spent)```
Question: {{question}}Your program for the question below failed when it ran.
<question>{{question}}</question><program>{{program}}</program><error>{{error}}</error>
Fix the program so it runs and prints the final answer.Return only the corrected program, in one code block.Program of Thoughts
Write a Python program that computes the answer to the question.Bind every quantity to a variable with a meaningful name, computestep by step, and store the final result in a variable called ans.Return only the program, in one code block.
Question: {{question}}A program computed an intermediate result for the question below.
<question>{{question}}</question><ans>{{ans}}</ans>
Starting from ans, reason step by step to the final answer, forexample by converting units or matching it to one of the options.End with one line that starts with "Answer:".Related patterns
Composes well with:
Sources
From the Agentic Atlas by Joran Kikke · Edit on GitHub · Suggest a correction