39.3 Self-critique patterns (and when they backfire)

Overview and links for this section of the guide.

Self-Critique

Self-critique is asking the model to review and improve its own output. It can significantly improve quality—but it can also make things worse.

// Basic self-critique pattern
const initial = await model.generate(task);

const critique = await model.generate(`
Review this response for errors, missing information, or improvements:
${initial}

List specific issues and suggested fixes.
`);

const improved = await model.generate(`
Original response:
${initial}

Critique:
${critique}

Create an improved version addressing the critique.
`);

Patterns

Pattern 1: Separate Critic

// Use a different prompt persona for critique
const CREATOR_PROMPT = `You are a software architect. Design a solution.`;
const CRITIC_PROMPT = `You are a security auditor. Find flaws in this design.`;

const design = await model.generate({ system: CREATOR_PROMPT, user: task });
const critique = await model.generate({ system: CRITIC_PROMPT, user: design });

Pattern 2: Checklist Critique

// Structured critique against specific criteria
const CRITIQUE_CHECKLIST = `
Review the response against these criteria:
[ ] Answers the original question
[ ] No factual errors
[ ] Code compiles and runs
[ ] Handles edge cases
[ ] Security considerations addressed

For each failed check, explain what's wrong.`;

const critique = await model.generate({
  user: `Response:\n${response}\n\n${CRITIQUE_CHECKLIST}`
});

Pattern 3: Iterative Refinement

// Multiple rounds of critique
async function refineWithCritique(task: string, maxRounds = 3): Promise {
  let response = await model.generate(task);
  
  for (let i = 0; i < maxRounds; i++) {
    const critique = await model.generate(`
      Critique this response. If it's good, say "APPROVED".
      Otherwise, list specific improvements needed.
      
      Response: ${response}
    `);
    
    if (critique.includes('APPROVED')) {
      return response;
    }
    
    response = await model.generate(`
      Improve this response based on the critique:
      ${response}
      
      Critique: ${critique}
    `);
  }
  
  return response;
}

When It Backfires

Problem Symptom Solution
Over-confidence Model approves its own mistakes Use external validation or different model
Regression Critique makes correct answer wrong Validate against ground truth
Infinite loops Critique and response cycle endlessly Limit rounds, detect oscillation
Added errors "Improvements" introduce new bugs Run tests after each iteration
Hedging Model becomes overly cautious Be specific about what to critique
// Detecting regression
async function safeRefine(task: string, validator: (r: string) => boolean) {
  const original = await model.generate(task);
  const originalValid = validator(original);
  
  const refined = await refineWithCritique(task, original);
  const refinedValid = validator(refined);
  
  // If refinement broke something, prefer original
  if (originalValid && !refinedValid) {
    console.warn('Refinement caused regression, using original');
    return original;
  }
  
  return refined;
}

Guidelines

  • Don't use for simple tasks: Self-critique adds latency and cost. Skip it for straightforward queries.
  • Use for high-stakes decisions: When errors are costly, the extra validation is worth it.
  • Combine with external validation: Self-critique isn't a substitute for tests, type-checking, or human review.
  • Be specific: "Critique this" is worse than "Check for SQL injection vulnerabilities."
  • Watch for oscillation: If the model keeps flip-flopping, stop and return the best version.
Self-Critique ≠ Correctness

The model can "critique" and still be wrong. It might confidently approve subtly broken code. Always have external validation for critical paths.

Where to go next