自我精炼与 CRITIC:迭代改进输出 本节摘要:自我精炼(Self-Refine, Madaan 等人, 2023)用一个 LLM 扮演三个角色——生成、反馈、精炼——循环往复,7 个任务平均绝对提升 20 个百分点。CRITIC(Gou 等人, 2023)硬化了反馈这一步:把验证路由到外部工具(搜索、代码解释器、计算器、测试运行器)。在 2026 年,这个模式以「评估器-优化器」(Anthropic)或「输出护栏」(OpenAI Agents SDK)的名字出现在每一个框架里。本节讲透这两篇论文如何共同定义了 2026 年迭代改进的默认范式——生成、(尽可能外部地)验证、精炼、验证通过即停——并用标准库手写一个带历史和可选外部验证器的自我精炼循环。
本节摘要:自我精炼(Self-Refine, Madaan 等人, 2023)用一个 LLM 扮演三个角色——生成、反馈、精炼——循环往复,7 个任务平均绝对提升 20 个百分点。CRITIC(Gou 等人, 2023)硬化了反馈这一步:把验证路由到外部工具(搜索、代码解释器、计算器、测试运行器)。在 2026 年,这个模式以「评估器-优化器」(Anthropic)或「输出护栏」(OpenAI Agents SDK)的名字出现在每一个框架里。本节讲透这两篇论文如何共同定义了 2026 年迭代改进的默认范式——生成、(尽可能外部地)验证、精炼、验证通过即停——并用标准库手写一个带历史和可选外部验证器的自我精炼循环。
对应原课程:Phase 14 · Lesson 05 ·
self-refine-and-critic(原英文phases/14-agent-engineering/05-self-refine-and-critic/docs/en.md)。
阅读完本节,你应当能够:
一个 Agent 产出了一个几乎正确的答案。也许一行代码有语法错;也许一段总结太长;也许一个计划漏了边界情况。你想要的是:Agent 批判自己的输出,然后修掉它。
自我精炼证明了这件事用单个模型、不用训练数据、不用 RL 就能做成。但有个陷阱:LLM 在硬事实上不擅长自验证。CRITIC 给出了修复方案——把验证这一步路由到外部工具(搜索、代码解释器、计算器、测试运行器)。
这两篇论文合起来定义了 2026 年迭代改进的默认范式:生成、验证(能外部就外部)、精炼、验证通过即停。
一个 LLM,三个角色:
generate(task) -> output_0 feedback(task, output_0) -> critique_0 refine(task, output_0, critique_0, history) -> output_1 feedback(task, output_1) -> critique_1 refine(task, output_1, critique_1, history) -> output_2 ... 反馈说「没问题」或预算耗尽时停止。
关键细节:refine 看到的是完整历史——所有过往输出和批判——所以它不会重复同样的错误。论文做了消融:去掉历史,质量急剧下降。
头条结果:7 个任务(数学、代码、缩写、对话,含 GPT-4)平均绝对提升 20 个百分点。不用训练,不用外部工具,单模型。
自我精炼的弱点:反馈这一步是LLM 给自己打分。对于事实性陈述,这是不可靠的(一个幻觉出来的断言,在产出它的那个模型自己看来往往很有说服力)。CRITIC 把 feedback(task, output) 替换成 verify(task, output, tools),其中 tools 包括:
验证器产出一条锚定在工具结果上的结构化批判,精炼器再据此条件化。
头条结果:在事实性任务上 CRITIC 优于自我精炼,因为批判是有锚的。在没有外部验证器的任务上(创意写作、格式化),CRITIC 退化成自我精炼。
💡 一句话区分:自我精炼是「模型自己批评自己」,CRITIC 是「让工具来批评模型」。后者在有可机器检验标准的事实任务上严格更强;前者在没有外部裁判的软任务上仍是有价值的兜底。
两种常见形态:
2026 年默认:组合使用。「验证器通过 或(模型说没问题 且 迭代 ≥ 2)或 迭代 ≥ 最大迭代数」时停止。
Anthropic 2024 年 12 月的博文把这个命名为五种工作流模式之一。两个角色:
循环到评估器通过为止。这是 Anthropic 框架下的自我精炼/CRITIC。Anthropic 加的关键工程细节:评估器和优化器的提示应该结构上显著不同,这样模型才不会只是橡皮图章。
OpenAI Agents SDK 把这个模式作为「输出护栏」提供。一个护栏是一个跑在 Agent 最终输出上的验证器。如果护栏触发(抛出 OutputGuardrailTripwireTriggered),输出被拒,Agent 可以重试。护栏可以调工具(CRITIC 风格)或纯函数(自我精炼风格)。
⚠️ 反模式警示:最常见的坑是「同一个模型、同一种提示」做生成和批判。批判提示必须和生成提示结构上不同(不同的关注点、不同的输出格式、甚至不同的模型),否则批判只是在复述生成,循环永远在原地打转。
原课程 code/main.py 在一个玩具任务上实现自我精炼和 CRITIC:给定一个主题,产出一个简短的要点列表。验证器检查格式(3 个要点、每个不超过 60 字符)。CRITIC 额外加一个外部「事实验证器」,惩罚已知的幻觉。
核心组件如下,用伪代码展示骨架。
def generate(task): return llm.generate(f"为以下主题写 3 个要点:{task}")
def feedback(task, output): return llm.generate( f"检查这组要点是否满足:3 个、每个 ≤60 字符、无事实错。\n{output}")
def verify_external(task, output): issues = [] if not (count_bullets(output) == 3): issues.append("要点数不是 3") for b in bullets(output): if len(b) > 60: issues.append(f"过长:{b}") if is_known_hallucination(b): # 调外部事实库 / 搜索 issues.append(f"疑似幻觉:{b}") return issues # 空列表 = 通过
def refine(task, output, critique, history): prompt = (f"任务:{task}\n当前输出:{output}\n批判:{critique}\n" f"过往尝试与批判:{history}\n据此修订,别重复同样的错。") return llm.generate(prompt)
def self_refine(task, use_critic=True, max_iter=4): output = generate(task) history = [] for i in range(max_iter): critique = (verify_external(task, output) if use_critic else feedback(task, output)) if not critique: # 验证通过 / 无反馈 return output history.append((output, critique)) output = refine(task, output, critique, history) return output # 预算耗尽
运行 python3 code/main.py,对比自我精炼与 CRITIC 两次运行。CRITIC 抓住了自我精炼漏掉的一个事实错,因为外部验证器有自我批判所没有的锚。
💡 设计要点:
history是自我精炼的命脉。论文消融显示,丢掉历史后质量塌方——模型会反复犯同一个错,因为它不记得自己已经试过且失败过。把历史做成结构化记录(每次的输出 + 批判),而不是一锅文本。
| 框架 | 这个模式的形态 |
|---|---|
| Anthropic 评估器-优化器 | 用 Claude 友好的语言命名这个模式;强调评估器与优化器提示要结构不同 |
| OpenAI Agents SDK 输出护栏 | CRITIC 形状:护栏可以调工具;触发 OutputGuardrailTripwireTriggered 后可重试 |
| LangGraph 反思节点 | 读起来像自我精炼:一个节点给输出打分,需要时路由到精炼 |
| Google Gemini 2.5 Computer Use | 加了一个每步安全评估器,是 CRITIC 变体:每个行动提交前都验证 |
所有这些实现都遵循同一个三段结构:生成 → 验证 → 精炼,验证通过即停。差异在于验证器是「纯函数」还是「可调工具」,以及停止条件的严格程度。
本节产出一份可复用技能(原课程 outputs/skill-refine-loop.md):
skill-refine-loop.md:给定任务形状、验证器可用性、迭代预算,配置一个评估器-优化器循环。产出三段提示(生成器、评估器/验证器、优化器),外加一份停止策略。它包含一份验证器选择清单:有没有可机器检验的标准?有没有外部工具?批判提示和生成提示是否结构不同?Python 代码(code/main.py)是独立可运行的玩具,生成/反馈/外部验证/精炼/停止条件五件套都是厂商无关的;把脚本式组件换成真实 LLM 与真实工具调用即可投入生产。
max_iterations=1 跑玩具。CRITIC 还有帮助吗?output_guardrails 映射到 CRITIC 的验证器角色。SDK 哪里做对了,哪里做错了?refine 看到全部过往输出与批判,丢掉历史质量塌方。下一节,我们将进入「工具使用与函数调用」——这是 Agent 工程 P0 的最后一节。它把前五节的循环、规划、反思、搜索、精炼都落到一个共同基础上:Agent 如何安全、可靠地调用外部工具。