Feedback Loop Prompting: Teach Your Agent to Critique and Retry Its Own Output

A single LLM call gets you a first draft. Sometimes that's good enough. Usually it isn't.
The feedback loop pattern fixes this without switching models, fine-tuning, or adding complexity you can't debug. You give the model three things: a generator prompt, a critic prompt, and exit criteria. Then you let it iterate until the output meets your standard or hits a retry limit.
This isn't the model "checking itself." Research from Google DeepMind and UIUC (Huang et al., "Large Language Models Cannot Self-Correct Reasoning Yet") found that pure self-correction -- asking a model to review its own reasoning with no external signal -- often makes things worse. A critical survey published in December 2024 in Transactions of the Association for Computational Linguistics found that LLM self-correction without external feedback can actually degrade performance. Models waver on correct answers and introduce new errors.
That's the whole point of the pattern. You're not asking the model to magically know it's wrong. You're giving it something concrete to evaluate against.
The Three Components
Every feedback loop has the same structure:
Generator -- produces the initial output. This is your normal prompt.
Critic -- evaluates the output against specific criteria. This is where the pattern gets its power. The critic can be a second LLM call with a rubric, a test suite, a linter, a diff against reference output, or any function that returns structured feedback.
Exit criteria -- decides when to stop. Either the critic says the output passes, or you hit a maximum retry count. Without this, you get infinite loops or diminishing returns.
The original Self-Refine paper (Madaan et al., 2023) demonstrated this with a single model playing all three roles -- generator, critic, refiner -- and showed roughly 20% improvement across code generation, math reasoning, and writing tasks. No training. No fine-tuning. Just structured iteration.
Why External Signal Matters
Here's what separates a working feedback loop from wishful thinking.
Self-Correction Bench (arXiv 2507.02778), which tested 14 open-source non-reasoning models, found a 64.5% "blind spot rate" -- models could correct identical errors when told they came from an external source, but failed to correct the same errors in their own output. The capability to fix the problem existed. The model just couldn't trigger it on its own work.
One interesting finding from that same study: appending the single word "Wait" after the model's initial answer reduced blind spots by 89.3%. One token. That's not a production strategy, but it tells you something important -- the model needs a signal to shift from generation mode to evaluation mode.
In a real feedback loop, that signal is your critic prompt returning specific, structured feedback.
Example 1: Code Generation with Test Feedback
This is the cleanest version of the pattern. Your critic is a test suite -- it either passes or it doesn't, and the error messages tell the model exactly what's wrong.
The Generator Prompt:
Write a Python function called `parse_duration` that converts
human-readable duration strings into total seconds.
Supported formats:
- "2h 30m" -> 9000
- "45s" -> 45
- "1h 15m 30s" -> 4530
- "3m" -> 180
Return an integer. Raise ValueError for invalid input.
The Critic (a test suite you run programmatically):
def test_parse_duration():
assert parse_duration("2h 30m") == 9000
assert parse_duration("45s") == 45
assert parse_duration("1h 15m 30s") == 4530
assert parse_duration("3m") == 180
assert parse_duration("0s") == 0
try:
parse_duration("abc")
assert False, "Should have raised ValueError"
except ValueError:
pass
The Retry Prompt (sent when tests fail):
Your function failed the following tests:
{critic_feedback}
Here is your previous implementation:
{previous_output}
Fix the function to pass all tests. Return only the corrected function.
Why This Works: The test suite is an oracle -- it gives the model unambiguous pass/fail signals with specific error messages. The model doesn't need to "know" it's wrong. The test output tells it exactly what's wrong and the retry prompt gives it the context to fix it.
Scott Logic demonstrated this pattern at scale in December 2025 when an engineer used an agentic loop to implement a complete flexbox layout algorithm -- 800 lines of code and 350 tests in about 3 hours. The reference implementation (browser rendering output) served as the critic. The same task took a Facebook engineer roughly two weeks in 2015.
Example 2: Writing with a Rubric Critic
Code has test suites. Writing needs a rubric.
The Generator Prompt:
Write a 200-word product description for a noise-canceling
headphone aimed at remote workers. Emphasize comfort for
all-day wear and microphone quality for video calls.
Tone: conversational, not salesy.
The Critic Prompt:
Score this product description on each criterion (1-5):
1. SPECIFICITY: Does it use concrete details, not vague claims?
2. TONE: Conversational without being unprofessional?
3. AUDIENCE FIT: Speaks to remote workers' actual pain points?
4. LENGTH: Within 180-220 words?
5. CTA: Ends with a clear next step?
For any criterion scoring 3 or below, explain exactly what's
wrong and suggest a specific fix.
Description to evaluate:
{output}
Respond in this format:
SCORES: [list scores]
PASS: [yes if all scores >= 4, otherwise no]
FEEDBACK: [specific fixes needed, if any]
The Retry Prompt:
Revise this product description based on the following feedback:
{critic_feedback}
Original description:
{previous_output}
Address each piece of feedback specifically. Keep what scored well.
Return only the revised description.
Why This Works: The rubric gives the critic structured dimensions to evaluate. "Score 1-5 on specificity" produces more useful feedback than "is this good?" The retry prompt passes the specific feedback, so the model knows which parts to fix and which to keep.
Expected Output (Critic Response):
SCORES: [4, 4, 3, 5, 2] PASS: no FEEDBACK: Audience fit -- mentions "long meetings" but doesn't address the #1 remote worker complaint: background noise from home environments (kids, dogs, construction). CTA -- the description just ends. Add a specific action: "available at [store]" or "try risk-free for 30 days."
That feedback is specific enough for the generator to fix exactly what's wrong on the next pass.
Example 3: Data Analysis with Validation Checks
For data work, your critic is a set of assertions.
The Generator Prompt:
Analyze this CSV of monthly sales data. Calculate:
1. Total revenue per quarter
2. Month-over-month growth rates
3. Top 3 products by revenue
Output as a Python script that reads 'sales.csv' and prints
results. Include the calculations, not just print statements.
The Critic (programmatic validation):
# Run the generated script, then validate:
assert abs(sum(quarterly_totals.values()) - df['revenue'].sum()) < 0.01, \
f"Quarterly totals ({sum(quarterly_totals.values())}) don't sum to " \
f"overall total ({df['revenue'].sum()})"
assert all(-1 <= g <= 10 for g in growth_rates), \
f"Growth rates outside reasonable range: {growth_rates}"
assert len(top_products) == 3, \
f"Expected 3 top products, got {len(top_products)}"
Why This Works: The validation catches the two most common LLM failures in data analysis -- arithmetic errors and off-by-one mistakes in aggregation. The assertions give specific error messages that tell the model what number it got vs. what was expected.
Building the Loop
The orchestration is straightforward. Here's the pattern in pseudocode:
def feedback_loop(generator_prompt, critic, retry_prompt_template,
max_retries=3):
output = llm_call(generator_prompt)
for attempt in range(max_retries):
feedback = critic(output)
if feedback.passes:
return output
retry_prompt = retry_prompt_template.format(
previous_output=output,
critic_feedback=feedback.details
)
output = llm_call(retry_prompt)
return output # best effort after max retries
Three design decisions matter:
Max retries. Two to three is the sweet spot for most tasks. The Reflexion paper showed significant improvement on the first retry, diminishing returns after the third. Beyond that, you're burning tokens for marginal gains.
Critic specificity. "This is wrong" is almost useless. "The quarterly totals don't match the annual total by $4,230" gives the model something to work with. The Reflexion authors found that richer feedback (specific instructions and explanations) consistently outperformed bare retry signals.
Separate critic context. If your critic is a second LLM call, give it a clean system prompt focused only on evaluation. Don't reuse the generator's context. This avoids the confirmation bias that single-agent loops are prone to -- the model anchoring to its own reasoning and defending it rather than evaluating it.
When Not to Use This
Not every LLM call needs a feedback loop. If the task is simple enough that a well-crafted single prompt gets it right 95% of the time, the loop is overhead. If you don't have a meaningful critic signal -- no tests, no rubric, no reference to compare against -- the model is just rewriting, not improving.
The pattern pays off when: the output has verifiable quality criteria, the task is complex enough that first-pass output is inconsistent, and you have a critic signal that's cheaper than the generation itself.
The feedback loop isn't about making the model smarter. It's about giving it the information it needs to use the capability it already has.
Training Your Team on Agent Patterns
Feedback loops are one of the foundational agentic patterns, and getting them right means understanding both the prompting and the orchestration. If your team is building agent workflows and wants structured training on patterns like this, connect with Kief Studio on Discord or schedule a session.
Rather have someone set it up for you?
That's a fair call. LTFI, the agentic business operating system from Kief Studio, can set up the work these guides describe and run it with you. No website yet? Kief Studio will build you one for free.

