自我精炼与 CRITIC:迭代改进输出


文档摘要

自我精炼与 CRITIC:迭代改进输出 本节摘要:自我精炼(Self-Refine, Madaan 等人, 2023)用一个 LLM 扮演三个角色——生成、反馈、精炼——循环往复,7 个任务平均绝对提升 20 个百分点。CRITIC(Gou 等人, 2023)硬化了反馈这一步:把验证路由到外部工具(搜索、代码解释器、计算器、测试运行器)。在 2026 年,这个模式以「评估器-优化器」(Anthropic)或「输出护栏」(OpenAI Agents SDK)的名字出现在每一个框架里。本节讲透这两篇论文如何共同定义了 2026 年迭代改进的默认范式——生成、(尽可能外部地)验证、精炼、验证通过即停——并用标准库手写一个带历史和可选外部验证器的自我精炼循环。

自我精炼与 CRITIC:迭代改进输出

本节摘要:自我精炼(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)。

学习目标

阅读完本节,你应当能够:

  1. 说出自我精炼的三段提示(生成、反馈、精炼),并解释为什么历史对精炼提示是承重的。
  2. 解释 CRITIC 的关键洞察:LLM 在没有外部锚定的情况下,自验证是不可靠的
  3. 用标准库实现一个带历史的自我精炼循环,以及一个可选的外部验证器。
  4. 把这个模式映射到 Anthropic 的「评估器-优化器」工作流和 OpenAI Agents SDK 的输出护栏。

一、问题与直觉

一个 Agent 产出了一个几乎正确的答案。也许一行代码有语法错;也许一段总结太长;也许一个计划漏了边界情况。你想要的是:Agent 批判自己的输出,然后修掉它。

自我精炼证明了这件事用单个模型、不用训练数据、不用 RL 就能做成。但有个陷阱:LLM 在硬事实上不擅长自验证。CRITIC 给出了修复方案——把验证这一步路由到外部工具(搜索、代码解释器、计算器、测试运行器)。

这两篇论文合起来定义了 2026 年迭代改进的默认范式:生成、验证(能外部就外部)、精炼、验证通过即停

自我精炼(Madaan 等人,NeurIPS 2023)

一个 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 个百分点。不用训练,不用外部工具,单模型。

CRITIC(Gou 等人,arXiv:2305.11738,v4 2024 年 2 月)

自我精炼的弱点:反馈这一步是LLM 给自己打分。对于事实性陈述,这是不可靠的(一个幻觉出来的断言,在产出它的那个模型自己看来往往很有说服力)。CRITIC 把 feedback(task, output) 替换成 verify(task, output, tools),其中 tools 包括:

  • 查事实用的搜索引擎
  • 查代码正确性用的代码解释器
  • 查算术用的计算器
  • 领域特定的验证器(单测、类型检查器、linter)。

验证器产出一条锚定在工具结果上的结构化批判,精炼器再据此条件化。

头条结果:在事实性任务上 CRITIC 优于自我精炼,因为批判是有锚的。在没有外部验证器的任务上(创意写作、格式化),CRITIC 退化成自我精炼。

💡 一句话区分:自我精炼是「模型自己批评自己」,CRITIC 是「让工具来批评模型」。后者在有可机器检验标准的事实任务上严格更强;前者在没有外部裁判的软任务上仍是有价值的兜底。

停止条件

两种常见形态:

  1. 验证器通过 —— 外部测试返回成功。有就优先用(单测、类型检查器、护栏断言)。
  2. 没有反馈发出 —— 模型说「输出没问题」。更便宜但不可靠;要配一个最大迭代上限。

2026 年默认:组合使用。「验证器通过 (模型说没问题 迭代 ≥ 2) 迭代 ≥ 最大迭代数」时停止。

评估器-优化器(Anthropic,2024)

Anthropic 2024 年 12 月的博文把这个命名为五种工作流模式之一。两个角色:

  • 评估器:给输出打分,产出批判。
  • 优化器:给定批判,修订输出。

循环到评估器通过为止。这是 Anthropic 框架下的自我精炼/CRITIC。Anthropic 加的关键工程细节:评估器和优化器的提示应该结构上显著不同,这样模型才不会只是橡皮图章。

OpenAI Agents SDK 输出护栏

OpenAI Agents SDK 把这个模式作为「输出护栏」提供。一个护栏是一个跑在 Agent 最终输出上的验证器。如果护栏触发(抛出 OutputGuardrailTripwireTriggered),输出被拒,Agent 可以重试。护栏可以调工具(CRITIC 风格)或纯函数(自我精炼风格)。

2026 年陷阱

  • 橡皮图章循环 —— 同一个模型、同一种提示风格做生成和批判,会收敛到「我觉得没问题」。用结构不同的提示,或用一个更小更便宜的模型做批判。
  • 过度精炼 —— 每次精炼都加延迟和 token。预算 1~3 轮;之后升级到人工评审。
  • CRITIC 用在平凡任务上 —— 如果没有外部验证器,CRITIC 退化成自我精炼;别为一个桩验证器付延迟。

⚠️ 反模式警示:最常见的坑是「同一个模型、同一种提示」做生成和批判。批判提示必须和生成提示结构上不同(不同的关注点、不同的输出格式、甚至不同的模型),否则批判只是在复述生成,循环永远在原地打转。

二、从零实现

原课程 code/main.py 在一个玩具任务上实现自我精炼和 CRITIC:给定一个主题,产出一个简短的要点列表。验证器检查格式(3 个要点、每个不超过 60 字符)。CRITIC 额外加一个外部「事实验证器」,惩罚已知的幻觉。

核心组件如下,用伪代码展示骨架。

Step 1:生成

def generate(task): return llm.generate(f"为以下主题写 3 个要点:{task}")

Step 2:反馈(自我批判)

def feedback(task, output): return llm.generate( f"检查这组要点是否满足:3 个、每个 ≤60 字符、无事实错。\n{output}")

Step 3:外部验证(CRITIC 风格,有锚)

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 # 空列表 = 通过

Step 4:精炼(看历史)

def refine(task, output, critique, history): prompt = (f"任务:{task}\n当前输出:{output}\n批判:{critique}\n" f"过往尝试与批判:{history}\n据此修订,别重复同样的错。") return llm.generate(prompt)

Step 5:主循环

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 与真实工具调用即可投入生产。

五、练习

  1. (Easy)max_iterations=1 跑玩具。CRITIC 还有帮助吗?
  2. (Easy) 把外部验证器换成一个有噪声的(随机 30% 误报)。循环会怎么表现?这正是 2026 年大多数护栏栈的现实。
  3. (Medium) 实现一个「生成在大模型、批判在小模型」的变体。它比同模型更好吗?
  4. (Hard) 读 CRITIC 论文第 3 节(arXiv:2305.11738 v4)。说出三类验证工具,每类给一个例子。
  5. (Hard) 把 OpenAI Agents SDK 的 output_guardrails 映射到 CRITIC 的验证器角色。SDK 哪里做对了,哪里做错了?

本节要点回顾

  1. 自我精炼 = 一个模型扮三个角色:生成、反馈、精炼,循环往复;7 任务平均绝对提升 20 个百分点,不用训练、不用外部工具。
  2. 历史是精炼的命脉:refine 看到全部过往输出与批判,丢掉历史质量塌方。
  3. CRITIC 的关键洞察:LLM 自验证不可靠,把反馈路由到外部工具(搜索、代码、计算器、测试)。
  4. CRITIC 在事实任务上严格更强:因为有锚;在无外部验证器的软任务上退化成自我精炼。
  5. 停止条件不要单条件:验证器通过 模型说没问题(且迭代 ≥ 2) 达到最大迭代。
  6. Anthropic 的命名是评估器-优化器:强调评估器与优化器提示要结构不同,防止橡皮图章。
  7. OpenAI Agents SDK 用输出护栏实现:护栏可调工具(CRITIC 风格)或纯函数(自我精炼风格),触发后可重试。
  8. 三大 2026 陷阱:橡皮图章循环、过度精炼(预算 1~3 轮)、CRITIC 用在平凡任务上。
  9. 批判提示必须结构不同:不同关注点、不同输出格式、甚至不同模型,否则批判只是复述生成。
  10. 历史要结构化:每次的输出 + 批判做成记录,而不是一锅文本。

下一节,我们将进入「工具使用与函数调用」——这是 Agent 工程 P0 的最后一节。它把前五节的循环、规划、反思、搜索、精炼都落到一个共同基础上:Agent 如何安全、可靠地调用外部工具。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U