引言

想象一下你正在参加一场高难度的数学考试。你解出了一道题,但不确定答案是否正确。你会怎么做?你可能会重读题目,或者尝试重新解一遍。但最高效的学生通常会使用不同的策略: 他们会将答案代回方程看是否成立,或者设计一套严格的检查清单来验证步骤。

大语言模型 (LLM,如 GPT-4 和 Llama-3) 在生成答案方面表现惊人,但在第二步——自我纠正 (Self-Correction) ——上却臭名昭著。当 LLM 犯错时——无论是传记中的幻觉,还是数学题中的计算错误——即使被要求“再次检查”,它往往也无法发现错误。更糟糕的是,当被提示进行自我纠正时,由于不确定性或糟糕的验证逻辑,模型经常会将正确的答案改成错误的。

这就引出了一篇引人入胜的新论文,题为 “ProgCo: Program Helps Self-Correction of Large Language Models” (ProgCo: 程序助力大语言模型自我纠正) 。研究人员提出,自然语言的歧义性是自我纠正的大敌。他们的解决方案是什么? 代码

在这篇文章中,我们将深入探讨 ProgCo (程序驱动的自我纠正) 。我们将探索强迫 LLM 用“伪代码”思考如何让它以比标准对话提示高得多的准确率验证自己的工作,从而有效地为 AI 解锁“系统 2”式的深思熟虑过程。

“内在”自我纠正的问题

在理解解决方案之前,我们必须先理解为什么 LLM 难以纠正自己。 内在自我纠正 (Intrinsic self-correction) 指的是模型在没有任何外部帮助 (没有人类反馈,没有谷歌搜索,没有计算器) 的情况下优化其输出的能力。

典型的工作流程如下:

  1. 生成初始回复。
  2. 验证回复 (自我验证) 。
  3. 根据反馈优化回复 (自我优化) 。

Figure 1: Illustration of a typical workflow of LLM’s intrinsic self-correction.

如图 1 所示,这是一个循环过程。如果验证失败,模型会生成反馈并再次尝试。

失败点通常在于自我验证 (Self-Verification) 阶段。目前的方法通常会问模型: “这正确吗?”或者“检查你的步骤”。问题在于 LLM 存在以下问题:

  • 过度自信: 它们倾向于相信自己的初始输出。
  • 逻辑缺陷: 如果模型使用错误的逻辑来解决问题,它通常也会使用同样的错误逻辑来验证它。
  • 歧义性: 自然语言检查清单 (如“检查语气是否专业”) 往往过于模糊,无法强制执行严格的逻辑一致性。

ProgCo 的作者们认为我们需要一种更严格、更结构化的媒介。我们需要程序。

核心方法: ProgCo

ProgCo 代表序驱动的自我正( Program-driven Self-Correction) 。该框架建立在这样一个见解之上: 代码比自然语言歧义更少,并且强制执行结构化的、逐步的评估。

ProgCo 包含两个主要组件:

  1. ProgVe (程序驱动验证) : 使用伪代码来验证答案。
  2. ProgRe (程序驱动优化) : 一个双轨系统,不仅优化答案,还优化验证代码本身。

Figure 3: The overall framework of ProgCo, achieving self-correction through iterative Prog Ve and ProgRe.

如图 3 所示,这是一个迭代过程。模型生成一个程序来测试其答案。它执行该程序。如果测试通过,任务完成。如果失败,模型进入优化循环,更新其答案及其测试代码。

组件 1: 程序驱动验证 (ProgVe)

标准的提示工程要求 LLM 用文字“验证”内容。ProgVe 则要求 LLM 编写一个函数 , 返回 TrueFalse

步骤 1: 验证程序生成

在 LLM 生成初始回复 (\(y_0\)) 后,ProgCo 提示模型生成一个验证函数 (\(f\)) 。至关重要的是,这种生成通常独立于初始答案进行,以避免偏见。

()\nf = M ( P _ { f u c } ^ { g e n } | | x )\n[

这个验证程序是什么样子的?

  • 对于指令遵循任务: 如果用户要求一首全大写且具有特定标题格式的诗,程序会显式检查 response.is_upper() 并验证标题的正则表达式。
  • 对于数学任务 (逆向推理) : 这正是 ProgVe 大放异彩的地方。代码不是重新解决问题,而是实施逆向推理 (Reverse Reasoning) 。 如果问题是在给定折扣的情况下询问原价,验证代码会获取答案,应用折扣,并检查它是否与提示中给出的最终价格匹配。

Figure 2: Illustration of generating verification pseudoprogram for input tasks.

图 2 展示了这种多功能性。注意关于折扣计算的底部示例。代码不仅仅是问“这不仅对吗?”,而是进行数学计算: calculated_discounted_price = original_price - discount。如果这与已知的折后价格 ($19.50) 不匹配,验证将返回 False

步骤 2: 验证程序执行

这里的转折点在于: 代码不一定需要在计算机上运行。

虽然 ProgCo 可以使用 Python 解释器,但其默认模式是使用 LLM 本身作为程序执行器 。 LLM 阅读代码并在其“脑海” (上下文) 中逐步“执行”它。

]\nr _ { i } = M ( P _ { f u c } ^ { e x e c } | | x | | y _ { i } ) , f b _ { i } = M ( P _ { f b } | | x | | y _ { i } | | r _ { i } )\n[

为什么要用 LLM 作为执行器?

  1. 伪代码的灵活性: 有时验证需要抽象逻辑,比如 is_structured_as_letter() (结构像信件) 。真正的 Python 编译器会抛出 NameError。而 LLM 理解该函数的意图并基于世界知识执行它。
  2. 因果追踪: 通过强迫 LLM 逐行模拟执行轨迹,我们强迫它慢下来并遵守代码结构的因果逻辑,从而减少幻觉。

组件 2: 程序驱动优化 (ProgRe)

如果 ProgVe 返回“False”,模型必须修正错误。然而,自我纠正的一个主要问题是误导性反馈 。 有时验证代码是错的,或者反馈很模糊,导致模型毁掉了一个完美的答案。

为了解决这个问题,ProgRe 引入了双重优化 (Dual Refinement) : 它不仅优化回复,还优化验证程序。

反思回复

ProgRe 不会盲目地应用反馈,而是采用“对比与重新生成”策略。

  1. 反思: 模型根据反馈生成一个临时的回复 (\(y_{temp}\)) 。
  2. 对比: 模型将旧答案 (\(y_i\)) 与新临时答案 (\(y_{temp}\)) 进行对比,识别核心差异。
  3. 生成洞察: 这些差异被合成为“洞察” (\(ins\)) 。
  4. 重新生成: 利用这些具体洞察生成最终的优化答案。

]\ny _ { i + 1 } ^ { t e m p } = M ( P _ { r e f l e x } | | x | | y _ { i } | | f b _ { i } )\n[

]\ni n s = M ( P _ { c o n t } | | y _ { i } | | y _ { i + 1 } ^ { t e m p } ) , y _ { i + 1 } = M ( i n s | | x )\n[

这一额外的“对比”步骤帮助模型理解变化发生的原因,防止它在错误答案之间反复横跳。

反思程序

如果答案是正确的,但测试代码是错的怎么办? (例如,提示要求“超过 100 字”,代码却检查“少于 100 字”) 。

ProgRe 包含一个优化验证程序的步骤。利用当前的回复和反馈,模型重新评估其测试代码。如果代码逻辑有缺陷,它会更新函数 (\(f_{i+1}\)) 以用于下一轮。

]\nf _ { i + 1 } = M ( P _ { r e f l e x } ^ { c o d e } | | x | | f _ { i } | | y _ { i } | | f b _ { i } )\n()

这确保了“裁判” (程序) 与“选手” (回复) 一同进步。

实验与结果

研究人员在三个基准上评估了 ProgCo:

  • IFEval: 指令遵循 (例如,“写一个超过 400 字的故事”) 。
  • GSM8K: 小学生水平的数学应用题。
  • MATH: 具有挑战性的竞赛级数学题。

他们将 ProgCo 与标准基线进行了比较,如 Self-Refine (要求模型根据反馈进行优化) 、Self-Reflection (自我反思) 和 CheckList (生成问题清单进行检查) 。

主要表现

如下表 1 所示,结果令人瞩目。ProgCo 在所有数据集和模型 (Llama 3, GPT-3.5, GPT-4o) 上均始终优于所有其他自我纠正方法。

Table 1: The result of different self-correction methods.

看看 GPT-3.5 在 MATH 数据集上的结果。

  • 初始分数 (Initial Score) 为 36.2%。
  • 标准的 Self-Refine 实际上损害了性能 (降至 34.8%) ,这是模型自我怀疑时的常见现象。
  • ProgCo 在三轮后将准确率提高到了 44.2%——实现了 8.0% 的巨大提升

这凸显了虽然标准提示在复杂推理上经常失败,但程序驱动的方法提供了实现真正改进所需的支撑。

为什么有效?更高的召回率

要改进答案,首先必须意识到它是错的。这个指标称为错误回复的召回率 (Recall of Incorrect Responses)

Figure 4:Recall and F1 scores of self-verification methods for incorrect responses on GPT-3.5.

图 4 比较了不同方法识别错误的能力。

  • Checklist (灰色) : 召回率非常低。它很少发现错误。
  • CoT-Check (蓝灰色) : 稍好,但仍漏掉许多错误。
  • ProgVe (蓝色) : 召回率显著更高。通过强迫模型运行验证算法,它发现了原本会忽略的不一致之处。

迭代的力量

最有趣的发现之一是性能如何随时间 (迭代次数) 变化。

Figure 5: Score variation with the maximum number of self-correction rounds on GPT-3.5.

在图 5 (右侧,GSM8K) 中,看看橙色线 (Self-Reflection)红色线 (ProgCo) 的区别。

  • Self-Reflection 的性能最初下降,且难以获得增长势头。
  • ProgCo 显示出稳定、持续的攀升。随着轮次的推进,双重优化同时改进了答案和验证代码,创造了一个正反馈循环。

伪代码 vs. 真实代码

虽然 ProgCo 旨在让 LLM 充当计算机 (伪代码) ,但研究人员也测试了如果接入一个真正的 Python 解释器 (ProgVe + Python) 会发生什么。

Table 3: Performance of ProgCo in integrating the Python executor tool during the ProgVe process.

表 3 显示,虽然纯 LLM 方法很强,但添加真正的 Python 工具进一步提升了性能 (例如,GPT-4o 在 IFEval 上提升了 +3.51%) 。这证实了程序的结构是关键的活性成分,而 (Python 提供的) 精确执行精度则是锦上添花。

结论

ProgCo 论文提出了一个令人信服的观点: 如果我们希望大语言模型能够纠正自己的错误,我们需要改变它们对验证的思考方式。

对话式的自我验证 (“这正确吗?”) 容易受到导致最初错误的同样偏见的影响。通过将范式转变为程序驱动验证 , 我们迫使模型进入一种不同的推理模式——一种结构化的、逻辑的、严谨的模式。

给学生和开发者的关键要点:

  1. 验证需要结构: 伪代码是一种强大的提示工程工具,因为它强制执行自然语言所缺乏的严格逻辑步骤。
  2. 逆向推理是关键: 检查答案通常需要与寻找答案不同的逻辑路径 (例如,倒推) 。程序非常擅长封装这种逆向逻辑。
  3. 双重优化: 当 AI 未通过测试时,你必须同时质疑答案测试。ProgCo 优化验证代码的能力防止了模型陷入“错误失败”的循环。

随着 LLM 的不断进化,像 ProgCo 这样的方法充当了“系统 2”认知层——一种缓慢、深思熟虑的检查,确保“系统 1”闪电般的生成结果实际上是正确的。


本文中使用的图片和数据源自 Song 等人的研究论文 “ProgCo: Program Helps Self-Correction of Large Language Models” (2024)。