PAL
Program-Aided Language Models: use executable code as intermediate reasoning
Program-Aided Language Models: use executable code as intermediate reasoning
A reusable prompt, example set, evaluation record or safety rule with its task boundary preserved.
Run at least one representative case, inspect the result and record what still requires human review.
Gao et al. (2022) proposed a method where LLMs read natural language problems and generate programs as intermediate reasoning steps. Called Program-Aided Language Models (PAL), it differs from chain-of-thought prompting because instead of using free-form text to reach a solution, it offloads the solution steps to a programming runtime like a Python interpreter.

Image source: Gao et al. (2022)
Let's use LangChain and OpenAI GPT-3 as an example. We want to build a simple app that interprets questions and uses a Python interpreter to compute the answer.
Specifically, we'll create a function that uses an LLM to answer date-understanding questions. We'll provide a prompt with examples adopted from here.
Imports we need:
from datetime import datetime
from dateutil.relativedelta import relativedelta
from langchain.llms import OpenAI
from dotenv import load_dotenv
Set up the environment:
load_dotenv()
# API configuration
openai.api_key = os.getenv("OPENAI_API_KEY")
# for LangChain
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
Set up the model instance:
llm = OpenAI(model_name='text-davinci-003', temperature=0)
Set up the prompt + question:
question = "Today is 27 February 2023. I was born exactly 25 years ago. What is the date I was born in MM/DD/YYYY?"
DATE_UNDERSTANDING_PROMPT = """
# Q: 2015 is coming in 36 hours. What is the date one week from today in MM/DD/YYYY?
# If 2015 is coming in 36 hours, then today is 36 hours before.
today = datetime(2015, 1, 1) - relativedelta(hours=36)
# One week from today,
one_week_from_today = today + relativedelta(weeks=1)
# The answer formatted with %m/%d/%Y is
one_week_from_today.strftime('%m/%d/%Y')
# Q: The first day of 2019 is a Tuesday, and today is the first Monday of 2019. What is the date today in MM/DD/YYYY?
# If the first day of 2019 is a Tuesday, and today is the first Monday of 2019, then today is 6 days later.
today = datetime(2019, 1, 1) + relativedelta(days=6)
# The answer formatted with %m/%d/%Y is
today.strftime('%m/%d/%Y')
# Q: The concert was scheduled to be on 06/01/1943, but was delayed by one day to today. What is the date 10 days ago in MM/DD/YYYY?
# If the concert was scheduled to be on 06/01/1943, but was delayed by one day to today, then today is one day later.
today = datetime(1943, 6, 1) + relativedelta(days=1)
# 10 days ago,
ten_days_ago = today - relativedelta(days=10)
# The answer formatted with %m/%d/%Y is
ten_days_ago.strftime('%m/%d/%Y')
# Q: It is 4/19/1969 today. What is the date 24 hours later in MM/DD/YYYY?
# It is 4/19/1969 today.
today = datetime(1969, 4, 19)
# 24 hours later,
later = today + relativedelta(hours=24)
# The answer formatted with %m/%d/%Y is
today.strftime('%m/%d/%Y')
# Q: Jane thought today is 3/11/2002, but today is in fact Mar 12, which is 1 day later. What is the date 24 hours later in MM/DD/YYYY?
# If Jane thought today is 3/11/2002, but today is in fact Mar 12, then today is 3/12/2002.
today = datetime(2002, 3, 12)
# 24 hours later,
later = today + relativedelta(hours=24)
# The answer formatted with %m/%d/%Y is
later.strftime('%m/%d/%Y')
# Q: Jane was born on the last day of Feburary in 2001. Today is her 16-year-old birthday. What is the date yesterday in MM/DD/YYYY?
# If Jane was born on the last day of Feburary in 2001 and today is her 16-year-old birthday, then today is 16 years later.
today = datetime(2001, 2, 28) + relativedelta(years=16)
# Yesterday,
yesterday = today - relativedelta(days=1)
# The answer formatted with %m/%d/%Y is
yesterday.strftime('%m/%d/%Y')
# Q: {question}
""".strip() + '\n'
llm_out = llm(DATE_UNDERSTANDING_PROMPT.format(question=question))
print(llm_out)
This outputs:
# If today is 27 February 2023 and I was born exactly 25 years ago, then I was born 25 years before.
today = datetime(2023, 2, 27)
# I was born 25 years before,
born = today - relativedelta(years=25)
# The answer formatted with %m/%d/%Y is
born.strftime('%m/%d/%Y')
The llm_out is Python code, so we can execute it with exec:
exec(llm_out)
print(born)
This outputs: 02/27/1998
📚 Related resources
❓ Common questions
Open a question to review the practical answer.
What is PAL and how is it different from CoT?
PAL (Program-Aided Language Models, Gao et al. 2022) makes the LLM write its reasoning steps as code instead of free text — the LLM emits Python, then a real interpreter executes it for the answer. CoT reasons in natural language and trips on arithmetic; PAL offloads the computation to Python so the math is exact. Where CoT messes up basic add/subtract/multiply/divide, PAL sidesteps the failure mode entirely.
Does PAL replace the entire reasoning process with code?
It doesn't replace everything — it replaces the parts that need exact computation. The LLM still handles language understanding (what does the problem ask, which variables matter, how to decompose), then translates that into code that the interpreter runs. The split is clean: LLM does semantic parsing and planning, Python does exact execution.
What kinds of tasks suit PAL?
Math word problems, date arithmetic, unit conversion, statistical aggregation — anything where a program computes exactly. The paper's demo is date understanding: "today is 27 Feb 2023, I was born exactly 25 years ago, what's my birthday in MM/DD/YYYY?" — the LLM emits `today - relativedelta(years=25)`, exec runs it, out comes 02/27/1998. Also great for finance, stoichiometry, table aggregations.
How do you implement PAL — do you need a special interpreter?
Standard recipe: few-shot the examples in "comment + Python" format → let the LLM continue the code → run it with `exec(llm_out)` → read the result variable. The paper's demo uses LangChain + OpenAI + datetime / dateutil. In production, you must wrap exec in a sandbox (locked-down subprocess, wasm runtime) — running raw LLM output through `exec` is a remote-code-execution timebomb.
Is PAL the same as ReAct with a calculator tool?
Same family, but PAL goes further. ReAct + Calculator gets the LLM to call one-shot arithmetic; PAL has the LLM write a whole program — multiple variables, loops, library imports — under the model "LLM = code author, Python = executor". OpenAI Code Interpreter / ChatGPT Advanced Data Analysis is essentially the productised form of PAL.