Home/
Part XIII — Expert Mode: Systems, Agents, and Automation/39. Prompt Engineering for Experts (The Real Stuff)/39.3 Self-critique patterns (and when they backfire)
39.3 Self-critique patterns (and when they backfire)
Overview and links for this section of the guide.
On this page
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.