Paper · 2023-04-11 · cs.CL, cs.AI
Teaching Large Language Models to Self-Debug
Self-Debugging teaches a frozen LLM to debug its own code with few-shot prompts: run the program, explain it line by line, judge it from the run or the explanation, and fix it, for up to 10 turns. Author-reported: Codex on Spider 81.3 to 84.1; on TransCoder with unit tests 80.4 to 92.5; GPT-4 on MBPP 72.8 to 80.6.
Self-refinement (draft, critique, rewrite loop)LLM self-evaluationProgram repair (LLM self-debugging)In-context learningpromptingcode-generationself-correction
AI-compiled by claude-haiku-5-5 on 2026-10-18, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Language models often get a program wrong on the first try, especially a long or tricky one. A common fix is to ask for many programs and keep the best one, which costs many model calls. This paper takes a different route: it shows the model its own program, what the program printed when it ran, and asks it to explain the code step by step, as a programmer might explain it to a rubber duck. The model then decides for itself whether the code is right, and if not, writes a new version. No model weights are changed; the whole approach is in the prompt.
The idea works best when the program can be run. Where there are example tests, the test results drive the feedback. Where there are no tests, as with text-to-SQL, the model has to judge its own explanation against the question. Either way, a handful of rounds of this loop lift accuracy over a single attempt, and it can beat a method that draws many more samples.
TL;DR
- Self-Debugging is a prompting-only loop: generate, explain, give feedback, and fix, repeated until the feedback says the code is right or 10 turns pass §3 §5.
- Feedback can be a bare verdict, a verdict with unit-test results, or a model-written explanation or trace §3.
- Author-reported gains: Spider (no tests) +2.8 points for Codex with explanation; TransCoder and MBPP (tests visible) up to about +12 points tab. 2.
- The code-explanation variant is the one that helps without tests; running the program is what drives the big gains when tests exist §5.1 §5.2.2.
- Pick it when you can run code and have a budget for a few extra calls per program. Not stated: token cost or latency per turn.
Problem
Single-attempt code generation fails often on complex tasks. Reranking many samples works but needs tens of samples §1. Learned repair models need training §1. Earlier prompt-only feedback on code was reported as weak without outside feedback such as tests or human hints §1 §6. The paper asks whether a frozen model can find its own bugs when it has only its own explanation or the result of running its code §1 §3.
Method
Setting. A pretrained LLM is used with few-shot prompts only; no weights are trained §1 §3. The task has a problem description, and for some tasks visible unit tests (input-output pairs) §2.
One turn has three steps §3:
- Generation: the model predicts a candidate program from the problem.
- Explanation: the model explains the program in natural language, or writes an execution trace for a sample input §3.
- Feedback: a message says whether the program is correct. The verdict comes from the model or from running unit tests §3.
The loop stops when the feedback says the program is correct, or after the maximum number of turns §3 §5.
Feedback variants §3:
- Simple: only a sentence saying correct or wrong, with no explanation step.
- UT (unit-test feedback): adds the results of the failed unit tests to the message.
- Expl (code explanation): the model explains the code line by line, then judges it.
- Trace: the model writes a line-by-line execution trace. It is generated text, not real intermediate state, so it needs no more access than Expl §3.
Text-to-SQL (Spider) has no unit tests §4.1. The prompt has three parts §4.1:
- The model restates the question and infers how many columns the answer needs.
- The SQL is executed. The returned table, cut to its first 2 rows, goes into the explanation prompt. The explanation covers each clause, the column count and the query's meaning.
- The model compares its explanation with the question and says whether the SQL is correct. If not, it writes a fixed SQL §4.1 app. E.3.
Code translation (TransCoder, C++ to Python) has 10 unit tests per problem, all shown in the problem §4.2. The loop runs only when the Python fails at least one test, and continues until it passes all tests or the turn limit is reached §4.2.
Text-to-Python (MBPP) shows only the first of 3 tests §4.3. The other 2 are hidden. The model must judge correctness even when the visible test passes. The feedback still reports the visible test result §4.3 app. G.3 app. G.4.
Initial candidates and selection §2. Sample several programs. If unit tests exist, drop the programs that fail them. Then take the most frequent execution output among programs without runtime errors, and debug that program §2. When only one program is used, it is generated greedily §5.
# Self-Debugging loop [§3] [§5]
# Input: problem (text, optional unit tests), llm
# Output: final program
def self_debug(problem, unit_tests, llm):
# 1. Generate the initial program, greedily when only one [§5]
program = llm.generate(problem)
for turn in range(10): # maximum of 10 debugging turns [§5]
# 2. Run the program on tests or sample inputs [§3] [§4.1]
result = run_program(program, unit_tests)
# 3. Explain the program; the explanation can include the result [§3]
explanation = llm.explain(problem, program, result)
# 4. Judge correctness from the run, or from the explanation [§3]
feedback = llm.judge(problem, program, explanation, result)
if feedback_says_correct(feedback):
break
# 5. Ask for a fixed program, using the feedback [§3]
program = llm.fix(problem, program, feedback)
return programUnit-test pass criterion, for reference. A program P passes when its output matches the expected output on every test input §2:
P(i_k) = o_k \quad \text{for all } k \in \{1, \dots, K\} §2
Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| Models | code-davinci-002 (Codex), gpt-3.5-turbo, gpt-4, StarCoder (15.5B) | §5 | GPT model versions and access dates not stated |
| Decoding, single initial program | greedy, temperature 0 | §5 | |
| Decoding, multiple initial samples | temperature 0.7 | §5 | See Pitfalls for the 0.8 in app. F.1 |
| Decoding, explanations, feedback, fixes | greedy | §5 | |
| Max debugging turns | 10 | §5 | Successful runs mostly end within 3 turns §5 |
| Top-p, max tokens, stop sequences | not stated | ||
| Spider exemplars: baseline / simple / explanation | 5 / 9 / 9 (few-shot) | app. E.1 app. E.2 app. E.3 | Chat models: 0-shot app. E.6 app. E.7 |
| Spider returned rows in prompt | first 2 rows | §4.1 | |
| TransCoder problems / tests | 560 problems, 10 tests each | §4.2 | |
| TransCoder baseline prompt | 3-shot, temperature 0.8 (from PaLM) | app. F.1 | Taken from Chowdhery et al. |
| TransCoder exemplars: simple / UT / UT+Expl / UT+Trace | 2 / 2 / 2 / 2 (few-shot) | app. F.3 app. F.4 app. F.5 app. F.6 | Chat models: 0-shot app. F.7 to app. F.10 |
| MBPP problems / tests | 500 problems, 3 tests; 1 shown, 2 hidden | §4.3 | |
| MBPP exemplars: baseline / simple / UT / UT+Expl | 3 / 6 / 6 / 3 (few-shot) | app. G.1 app. G.2 app. G.3 app. G.4 | Chat models: 0-shot app. G.5 to app. G.8 |
| Sample counts for efficiency study (Spider) | 8, 16, 32 initial samples | §5.2.1 fig. 6 | |
| Selection for multi-sample runs | filter by unit tests, then majority vote on execution output | §2 | Tie-breaking not stated |
| Ablation feedback without test execution | Expl and Trace variants only | §5.2.2 tab. 3 |
Results
Author-reported. Accuracy on each benchmark's test split §5 tab. 2. Spider uses the dev split. Prompting baselines use Codex.
Table 2 (feedback formats, greedy decoding) tab. 2:
| Benchmark | Feedback | Codex | GPT-3.5 | GPT-4 | StarCoder |
|---|---|---|---|---|---|
| Spider | Baseline | 81.3 | 71.1 | 73.2 | 64.7 |
| Spider | Simple | 81.3 | 72.2 | 73.4 | 64.9 |
| Spider | + Expl. | 84.1 | 72.2 | 73.6 | 64.9 |
| TransCoder | Baseline | 80.4 | 89.1 | 77.3 | 70.0 |
| TransCoder | Simple | 89.3 | 91.6 | 80.9 | 72.9 |
| TransCoder | UT | 91.6 | 92.7 | 88.8 | 76.4 |
| TransCoder | + Expl. | 92.5 | 92.7 | 90.4 | 76.6 |
| TransCoder | + Trace | 87.9 | 92.3 | 89.5 | 73.6 |
| MBPP | Baseline | 61.4 | 67.6 | 72.8 | 47.2 |
| MBPP | Simple | 68.2 | 70.8 | 78.8 | 50.6 |
| MBPP | UT | 69.4 | 72.2 | 80.6 | 52.2 |
| MBPP | + Expl. | 69.8 | 74.2 | 80.4 | 52.2 |
| MBPP | + Trace | 70.8 | 72.8 | 80.2 | 53.2 |
Table 1 (comparison with reranking and prompting baselines) tab. 1:
| Setting | Method | Metric | Baseline | This paper | Source |
|---|---|---|---|---|---|
| Spider dev | T5-3B + N-best reranking (trained) | accuracy | — | 80.6 | tab. 1 |
| Spider dev | LEVER (trained verifier, Codex) | accuracy | — | 81.9 | tab. 1 |
| Spider dev | Coder-Reviewer (prompting only) | accuracy | — | 74.5 | tab. 1 |
| Spider dev | MBR-Exec (prompting only) | accuracy | — | 75.2 | tab. 1 |
| Spider dev | Self-Debugging, Codex, + Expl. | accuracy | 81.3 | 84.1 | tab. 1 tab. 2 |
| MBPP | MBR-Exec, n=25 | accuracy | — | 63.0 | tab. 1 |
| MBPP | Reviewer, n=25 | accuracy | — | 66.9 | tab. 1 |
| MBPP | LEVER, n=100 | accuracy | — | 68.9 | tab. 1 |
| MBPP | Self-Debugging, Codex, n=10 initial samples, UT + Expl. | accuracy | 72.2 | 75.6 | tab. 1 |
Table 3 (without unit-test execution, so the model judges all programs) tab. 3:
| Benchmark | Feedback | Codex | GPT-3.5 | GPT-4 |
|---|---|---|---|---|
| TransCoder | Baseline | 80.4 | 89.1 | 77.3 |
| TransCoder | Simple | 83.4 | 89.1 | 78.2 |
| TransCoder | + Expl. | 83.9 | 89.1 | 78.0 |
| TransCoder | + Trace | 83.9 | 89.1 | 78.4 |
| MBPP | Baseline | 61.4 | 67.6 | 72.8 |
| MBPP | Simple | 57.6 | 68.2 | 76.0 |
| MBPP | + Expl. | 64.4 | 68.2 | 76.0 |
| MBPP | + Trace | 66.2 | 69.2 | 76.4 |
Table 4 (error types fixed, percent of fixed cases) tab. 4.
| Error type | Spider (Codex) | TransCoder (GPT-3.5) | MBPP (GPT-4) |
|---|---|---|---|
| Wrong WHERE conditions | 25.7 | — | — |
| Missing the DISTINCT keyword | 17.1 | — | — |
| Wrong JOIN clauses | 14.3 | — | — |
| Wrong number of SELECT columns | 11.4 | — | — |
| Wrong INTERSECT/UNION clauses | 8.6 | — | — |
| Wrong aggregate functions and keywords | 5.8 | — | — |
| Wrong COUNT columns | 5.7 | — | — |
| Wrong column selection | 5.7 | — | — |
| Missing nested conditions | 5.7 | — | — |
| Output mismatch | — | 61.9 | 69.2 |
| Runtime errors | — | 38.1 | 30.8 |
Other headline results:
- Sample efficiency (Spider, Codex): greedy decoding plus Self-Debugging matches the baseline with 16 samples, and starting from 8 samples beats the 32-sample baseline §5.2.1 fig. 6.
- Difficulty (Spider, Codex): the gain is largest on extra-hard problems, +9 points §5.2.3 fig. 6.
- Turns: one turn gives most of the gain; the extra accuracy after one turn is within 0.1% on Spider §5.2.1.
- Explanation alone, no Self-Debugging loop, TransCoder: a consistent gain of 2 to 3 points across sample counts app. C.
Paper vs code
No official code. The paper gives no repository link. The GitHub searches
(WebFetch, not gh) were self-debugging (no results from the authors' group),
self-debug with org:google-research (no results) and self-debugging+llm
(only third-party projects). None belong to the authors, so none is used.
Pitfalls
- Spider judges correctness with no tests. Simple feedback alone barely helps there; the gain comes from the explanation step §5.1. The explanation step runs the SQL and passes the returned table to the model, so the loop is not purely self-contained §4.1.
- Some MBPP exemplar feedback contradicts itself. Several exemplars say the code passes the assertion and then conclude "The code above is wrong" app. G.3 app. G.4. The paper does not say whether this is intended. When you write prompts, use the consistent version.
- Temperature conflict. Section 5 sets temperature 0.7 for multi-sample runs, but the TransCoder baseline prompt uses 0.8, copied from PaLM §5 app. F.1. Which run uses which value is not stated.
- TransCoder tests are not held out. All 10 tests are in the problem and drive the feedback. The text describes no separate hidden test set for TransCoder, so its gains measure repair against visible tests. MBPP is different: 2 of 3 tests are hidden §4.2 §4.3.
- Without execution, simple feedback can hurt. On MBPP with Codex, simple feedback without tests scores 57.6, below the 61.4 baseline tab. 3. Without tests, the model is overconfident about its first answer for GPT-3.5 and GPT-4 §5.2.2.
- Trace is not execution. The trace is generated text. It does not expose real intermediate values §3.
- Fewer exemplars when explanations are added. Prompts with both feedback and explanation have fewer exemplars to fit the context limit: 3 instead of 6 on MBPP app. C app. G.4.
- Cost is not stated. Each turn adds an explanation call and a feedback call on top of the fix call. The paper compares against methods that draw 10 times more samples, but gives no token, latency or dollar cost.
- Model versions. The GPT model versions and API access dates are not stated. Results from different snapshots may not reproduce.
- Chat prompts differ. Chat models get 0-shot prompts with the instructions rewritten for a conversation format app. A.
- Reference numbers are from the LaTeX source. Section, table and figure numbers follow the order in the source (this card uses arXiv v2, updated 2023-10-05); they were not checked against a compiled PDF. Appendix letters follow the order of the appendix sections.
Lineage
- Builds on: few-shot prompting §2, execution-based selection and majority voting over samples §2. The rubber-duck idea comes from human debugging practice §1.
- Related methods: prompt-based self-critique and refinement for text tasks, such as Self-Refine, Reflexion and RCI §6. The line-by-line explanation is said to be similar in spirit to chain-of-thought prompting §6.
- Compared against: T5-3B N-best reranking, LEVER, MBR-Exec and Coder-Reviewer §5 tab. 1.
- Superseded by: not stated.
Source and license
Adapted from “Teaching Large Language Models to Self-Debug” by Xinyun Chen, Maxwell Lin, Nathanael Schärli, Denny Zhou (arXiv:2304.05128), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors.