Exploring Prompt Optimization

探索 Prompt 优化

16 分钟阅读

作者:Krish Maniar 和 William Fu-Hinthorn

如果您有兴趣参与更多 prompt 优化技术的 Beta 测试,请填写兴趣表此处

当我们编写 prompt 时,我们试图传达我们的意图,让 LLM 应用于混乱的数据,但很难一次有效地传达每个细微之处。Prompt 通常通过手动试错、测试和调整来完成,直到事情变得更好;另一方面,像 DSPypromptim 这样的工具已经展示了 prompt “编程”和系统性 prompt 优化的有效性,通过测量和在真实数据上进行测试来弥合意图与指令之间的差距。在本文中,我们

  • 策划五个不同的数据集,其中包含可验证的结果,用于基准测试 prompt 优化
  • 实施并基准测试五种系统性改进 prompt 的不同方法
  • 基准测试三种不同模型(gpt-4oclaude-sonneto1)在 prompt 优化方面的表现

我们的结论

  • 我们推荐的 prompt 优化模型是 claude-sonnet(优于 o1
  • Prompt 优化在底层模型缺乏领域知识的任务上最有效
  • 在上述情况下,prompt 优化可以使准确率比朴素基线 prompt 提高约 200%
  • 在这些情况下,prompt 优化也可以被视为一种长期记忆的形式:直接从您的数据中学习适应

我们测试了什么

我们基准测试了五种流行的 prompt 优化方法(更详细的解释稍后介绍)

  1. Few-shot prompting:使用训练示例作为预期行为的演示
  2. Meta-prompting:使用 LLM 分析和改进 prompt
  3. Meta-prompting with reflection:让 LLM 在提交更新后的 prompt 之前思考并批判其分析
  4. Prompt 梯度:为每个示例生成有针对性的改进建议作为“文本梯度”,然后在单独的 LLM 调用中应用这些梯度
  5. 进化优化:通过受控突变探索 prompt 空间

我们在三个模型(O1、GPT-4 和 Claude-3.5-Sonnet)上,在代表常见任务的五个数据集上运行了这些方法,旨在回答以下主要问题

  • Prompt 优化在何时效果最佳?
  • 哪些前沿模型在 prompt 优化方面表现良好?
  • 哪些算法最可靠?

算法

我们测试了五种不同的 prompt 优化方法,每种方法都有自己关于如何改进 prompt 的理论

Few-shot prompting

对于最简单的测试技术,我们从训练集中选择了最多 50 个示例(在几个 epoch 中采样),并将它们包含在 prompt 中,作为预期行为的演示。这可以有效地学习(因为不需要 LLM 调用来提出更改),尽管它会导致测试时更高的 token 成本(因为典型的演示包含的内容比直接的单个指令更多)。

Meta-prompting
这是最简单的指令调优方法。我们首先在示例上运行目标 LLM。然后,我们计算输出的分数。注意:这需要设置评估器。然后,我们向 meta-prompting LLM 展示输入、输出、参考输出(如果可用)以及当前 prompt 在这些输出上的分数示例。基于这些变量,我们然后要求 LLM 编写更好的 prompt。我们在小批量中重复此过程,定期在保留的开发(dev)集上进行评估。保留具有最高 dev 集分数的 prompt。

Meta-prompting with reflection

我们重复使用第一步的 meta-prompting 技术,但让 LLM 可以选择使用“思考”和“批判”工具。这些工具的作用仅仅是让 LLM 有机会在提交特定的 prompt 更新之前,在草稿纸上写下想法。这有助于 LLM 使用更多的测试时计算来分析之前的 prompt,并在提交下一个 prompt 更新之前,寻找底层数据分布中更隐藏的模式。

Prompt 梯度
这种方法由 Pryzant 等人的论文《Automatic Prompt Optimization》推广,将优化分解为更小的步骤

  1. 对当前 prompt 的输出进行评分
  2. 使用 LLM,为 prompt 失败的每个示例生成具体反馈(这些是“梯度”)
  3. 基于收集到的“梯度”提出 prompt 更新

想法是,在进行更改之前收集细粒度的反馈,比 meta-prompting 方法能带来更有针对性的改进。

进化优化
这些算法在“代”中运行,多代被组织成更大课程的一个阶段。对于每一代,算法应用半随机的“突变”(在我们的例子中,是在 LLM 的帮助下创建的不同类型的 prompt 更新)来创建候选 prompt。每代之后保留性能最佳的 prompt。

在这些实验中,我们采用了 PhaseEvo,这是 Cui 等人最近提出的一种技术,它结合了直接的“文本梯度”方法(如上所述)和更“全局”或横向的更新,指示 LLM 基于现有群体中的共享模式创建新的 prompt。理论上,这有助于算法通过更大程度地探索 prompt 群体中的变化来克服局部最优。PhaseEvo 分阶段工作

  1. 生成多样化的初始 prompt(通过猜测会为一组训练示例创建预期输出的指令,然后释义这些 prompt 以获得更大的多样性)
  2. 将 prompt 梯度应用于表现最佳者(有关更多信息,请参阅 prompt 梯度部分)
  3. 通过释义创建前 5 个表现最佳 prompt 的新变体
  4. 结合成功的 prompt 以捕捉其最佳元素。这会从两个或多个最不相似的现有 prompt 中生成新的 prompt。由于这专注于提炼或扩展现有 prompt,因此避免陷入局部错误并鼓励进一步探索。
  5. 对获胜者重复梯度优化以完成。

这些类型方法的假设是,LLM 倾向于根据观察到的错误进行肤浅的修正,而没有充分分析整体数据,也没有充分探索其他 prompt 技术。理论上,结构化的 prompt 进化可以帮助该过程找到比更直接的爬山方法更全局最优的解决方案。

数据集

我们创建了五个数据集来对此进行基准测试。

  1. 支持邮件路由 3:对于每封收件邮件,将其路由到正确的受让人(3 个受让人之一)。
  2. 支持邮件路由 10:与 (1) 相同,但有 10 个可能的受让人。这更具挑战性,因为每个受让人的“领域专业知识”不太明显。
  3. 多语言数学:LLM 会收到一道数学文字题,并且必须用 5 种语言之一拼写出正确答案。语言由文字题的主题或主题决定(体育->韩语,外太空->阿拉伯语,烹饪->德语,音乐->英语,野生动物->俄语)。prompt 和优化器都不知道为什么选择目标语言,因此优化器必须能够发现隐藏在数据集中的潜在模式。
  4. 电子邮件助手简单:这是一个合成数据集,旨在测试 prompt 优化对于 LLM 领域知识良好覆盖的任务是否有用。LLM 的任务是分类给定电子邮件是忽略、回复还是通知用户。
  5. 电子邮件助手古怪:这与上面的数据集类似,但基于更隐藏的偏好规则。注意:这些偏好规则是古怪的,这意味着即使响应标签在 LLM 的领域知识范围内,偏好规则也不在。我们制作了一个忙碌、古怪的科技大亨的角色,为响应提供地面实况标签。

结果

我们在五个数据集上进行了实验,使用 OpenAI 的 GPT-4o 和 O1 模型,以及 Anthropic 的 Claude-3.5-sonnet 作为 meta-prompting LLM 来驱动优化算法。目标 LLM 是 GPT-4o-mini(意味着我们正在使用其他模型来为 GPT-4o-mini 优化 prompt)。

对于每种算法,我们选择在 dev 集上得分最高的 prompt 作为优化运行的最终输出。对于该 prompt,我们绘制了在测试拆分上三次运行的平均分数(在条形图中)。还显示了 95% 的置信区间,使用二元通过/失败指标的 Wilson 分数区间计算得出。在附录中,我们还绘制了每个 epoch(或进化算法情况下的阶段)的 dev 集分数,以更好地展示每个实验的训练动态。

作为基线,我们将结果与每个任务的 starter prompt 的 GPT-4o-mini 分数进行比较。我们还包括了其他基于模型的模型(Claude-3.5-sonnet、O1、O1-mini 和 GPT-4o)在基线 prompt 上的表现结果。以下是我们发现的。

注意:由于在进化 prompt 算法期间 O1 端点零星地标记内容违规,我们省略了几个无法完成的 o1 实验。

支持邮件路由 (3)

优化器始终如一地优于基线 prompt,梯度方法和进化方法都显示出类似的增益。Claude 在所有方法中都明显优于 GPT-4o。即使在使用 meta-prompting 方法的 dev 集上,Claude 和 4o 也未能取得太大改进。

以下是测试拆分的结果。Few-shot prompting 始终如一地带来改进,但性能次优,4o-mini 设置仅略微优于最差的 meta-prompting 技术。更复杂的进化算法也略微优于其他算法。与 O1 相比,Claude 在优化底层模型方面做得稍好,而 GPT-4o 则落后。

支持邮件路由 (3) 数据集实验的测试集性能。如果 prompt + 模型组合将电子邮件分配给正确的人员,则答案被认为是正确的 (1)。对于每个实验设置,选择 dev 拆分通过率最高的 prompt 并在测试拆分上进行评估。按模型和算法进行的聚合使用算术平均值完成。

支持邮件路由 (10)

这是一个稍微困难的 10 路分类问题,风格与之前的数据集类似。正如您可以从下面的曲线中看到的那样,当使用简单的 meta-prompting 和 meta-prompting + reflection 算法时,GPT-4o 未能在开发集上收敛,这预示了在测试拆分中表现不佳。

最终测试结果如下。与第一个数据集类似,few-shot prompting 提供了持续的改进,尽管它仍然落后于大多数其他 prompt 优化器技术。

支持邮件路由 (10) 数据集实验的测试集性能。如果 prompt + 模型组合将电子邮件分配给正确的人员,则答案被认为是正确的(得分为 1)。对于每个实验设置,选择 dev 拆分通过率最高的 prompt 并在测试拆分上进行评估。按模型和算法进行的聚合使用算术平均值完成。

O1 在此数据集上表现出色,在类似配置下优于 Claude。除了进化算法和梯度算法之外,Gpt-4o 在所有算法中再次受到影响。令人惊讶的是,GPT-4o 在使用 meta-prompt + reflect 配置时会导致 prompt 退化,这可能是由于过度拟合到训练拆分中的具体细节。

多语言数学

此数据集可能是最不连续的,正如 dev 集性能在 epoch 3 或 4 左右的单个 epoch 中获得大部分改进所表明的那样(参见附录)。这是因为数据包含一个简单的隐藏模式:目标语言由文字题的主题决定。以下是测试拆分结果。

多语言数学数据集实验的测试集性能。如果值以正确的形式和正确的目标语言表达,则答案被认为是正确的 (1)。对于每个实验设置,选择 dev 拆分通过率最高的 prompt 并在测试拆分上进行评估。按模型和算法进行的聚合使用算术平均值完成。

由于所述的不连续性,大多数模型<>算法组合未能提供比基线更大的改进。

推理模型(O1 和 O1-mini)最擅长有效地利用 few-shot 示例,击败了所有未能收敛到正确解决方案的技术。然而,令人惊讶的是,尽管 O1 能够利用 few-shot,但它在优化 prompt 指令方面做得不好。O1 无法发现任何算法的技巧。

Claude 和(有点令人惊讶的)GPT-4o 都能够使用进化算法(该算法通过课程运行优化器,以捕获局部和全局信息,而不是反复关注特定错误)发现解决方案。同样,Claude 也能够在 metaprompt + reflection 设置下发现正确的解决方案。

电子邮件助手简单

此数据集提示模型决定电子邮件助手是否应通知用户、忽略电子邮件或直接回复电子邮件。它遵循相当明显的规则,这意味着我们期望基本 prompt 配置能够很好地工作。以下是训练曲线。

以下是测试结果。正如您一眼就能看出的那样,结果在模型<>算法组合中相当一致。

电子邮件助手(简单)数据集的测试拆分性能(通过率)。对于每个实验设置,选择 dev 拆分通过率最高的 prompt 并在测试拆分上进行评估。按模型和算法进行的聚合使用算术平均值完成。

在这种情况下,few-shot 示例产生了最可靠的改进。该任务不需要优化器揭示任何远离目标模型现有行为的隐藏模式。这些模式几乎没有隐藏。因此,few-shot 在传达预期行为方面做得最好。

直接 prompt 优化方法(梯度、metaprompt)很难捕捉到合理的指令来指导模型,使其超出其已知范围。我们注意到,meta-prompting 倾向于包含一些不必要的指令,即使指示优化器仅关注添加明确解决失败的指令。O1 和 GPT-4o 都难以在此任务上提供帮助。

电子邮件助手古怪

此任务揭示了算法之间的有趣差异。进化方法在整个训练过程中显示出稳定的改进,尽管从未达到完美的分数。更重要的是,它的改进更可靠地转化为 3 种组合中的 2 种的测试集性能。

在这里,Claude 仍然优于 GPT-4o 和 O1。进化算法通常优于其他两种技术,尽管 O1 在该设置中似乎表现不佳。

总体结果

下面我们绘制了所有测试数据集中每个实验设置的平均百分比变化。我们使用 bootstrap 抽样来绘制每个指标的 95% 置信区间。我们还将结果按优化器模型和算法分组。百分比变化表示优化器对目标模型的影响,相对于 GPT-4o-mini 基线。100% 意味着分数相对于影响翻了一番,因此如果原始 prompt 在任务中获得 20%,则优化后的 prompt 为 40% 等。

高于基线的平均相对改进,100% 表示通过率翻倍,200% 表示三倍等。

正如您所见,结果具有较大的误差幅度!虽然我们确实看到这些数据集的许多算法<>模型设置都取得了持续的改进,但大多数实验的下限是负数 - 当前设置有时会导致 prompt 过度拟合训练示例,而不是导致稳健的系统。当应用这些技术时,继续保持单独的测试拆分非常重要,以确认您在训练和开发拆分中看到的改进实际上转化为现实中更一致的行为。

如图所示,Claude 和 O1 的平均性能相当,但 O1 的方差非常高。如果您只关心正面交锋的胜率,那么一致性就更明显了:在测试设置下,Claude 是更可靠的优化器模型。

考虑到 O1 较慢的处理时间、更高的成本和不太可靠的 API(OpenAI 偶尔会错误地将我们的完成标记为违反 ToS),我们现在可以放心地推荐 Sonnet 3.5 作为首选的优化器模型。我们很高兴在 O3 和其他模型发布后更新我们的建议。

我们学到了什么

上述结果普遍支持 LLM 是有效的 prompt 工程师的现有文献。这些实验还揭示了它们何时会(无效)。

  1. Meta-prompting 对于发现规则或偏好以及 LLM 领域知识中可能不存在的其他清晰模式尤其有用。这意味着您可以通过示例定义您想要的行为,并依靠优化器将这些行为转化为其他 LLM,只要它们是合理的指令遵循者。这使得声明式 prompt 编程模型成为可能。
  2. Meta-prompting(通过指令调优)在传达偏好的细微差别方面不太有用,如简单的电子邮件分类数据集所示。对于简单的电子邮件数据集,所有 prompt 调优方法都逊色于 few-shot prompting 方法,其中区别更多地在于明确的规则和条件。
  3. 我们从 (1) 和 (2) 怀疑,结合 few-shot prompting 和指令调优可以提供互补的改进。这支持了 Opsahl Ong, et. al.Wan, et. al 等人的现有结论。Few-shot 示例比简单的指令传达更多信息,但不捕获复杂的条件和规则,这些条件和规则很可能是您自己企业代理的一部分。另一方面,通过 reflection、“文本梯度”或进化算法进行的 prompt 优化可以根据现有性能和数据集特征进行更有针对性的改进,并以更节省 token 的方式进行。
  4. Meta-prompting 不会赋予模型新的能力。对于多语言数学数据集,GPT-4o-mini 在任何优化配置中的通过率仍然没有超过 65%,这主要是由于推理错误。虽然优化器能够指示它如何表现(有时可以通过示例推理轨迹诱导出更好的思考方式),但它们不会解锁更强大的推理能力或特定领域的复杂知识。

超越评估

我们一直在构建 LangSmith,以帮助团队系统地评估其 LLM 应用程序。良好的评估让您能够检测到何时出现问题并了解系统的行为。但是,您为评估构建的数据集和指标解锁了更具价值的东西:通过优化系统地改进系统的能力。

我们实验中的数据集在优化方面效果良好,因为它们具有清晰的、可验证的结果

  • 具有地面实况标签的路由决策
  • 可以验证的数学答案
  • 可以通过编程方式检查的语言约束

这很重要,因为针对模糊或不可靠的指标进行优化通常会使 prompt 变得更糟,而不是更好。LLM 根据模糊的标准判断输出将优化其自身的偏差,而不是您的实际要求。

如果您正在 LangSmith 中跟踪应用程序的性能,那么您已经构建了有效 prompt 优化所需的基础。帮助您了解失败原因的相同数据集可以推动系统性的改进。数据、指标和学习形成闭环。

Prompt 优化作为长期记忆

优化是学习,因此,可以认为 prompt 优化是长期记忆的一种特殊情况,它捕获“始终在线”的行为模式。

虽然传统的记忆系统将信息存储在数据库中(向量、图或其他形式),但 prompt 优化将其直接存储在代理的 prompt 中,以便它们始终在上下文中可用。这样做可确保它们影响每个决策。这对于存储核心模式(如行为规则、风格偏好和关键的性格特征)非常有用。

记忆的“学习和改进”过程与传统的 prompt 优化非常相似,只是更新的计划方式和更新的存储位置略有不同。通常适用于 prompt 优化和学习算法的相同技术也可能适用于记忆。这是我们正在积极调查的角度。

为什么这很重要

这些结果支持我们(以及其他像 DSPy 这样的公司)观察到的情况:LLM 驱动的 prompt 优化可以系统地改进 prompt,并自动化当今主导 prompt 工程的大部分手动猜测和检查过程。使所有利益相关者都能访问这种方法,可以帮助我们所有人构建更好、更强大的系统。

但这不是万能药。我们优化的 prompt 都未饱和测试集,并且改进因任务而异。这表明 prompt 优化最好被视为改进 LLM 应用程序的更广泛工具包中的一种工具。

我们计划将这些见解直接整合到 LangSmith 中,以帮助团队超越手动 prompt 工程。目标不是消除人为判断,而是使其更系统化和数据驱动。

复现

您可以通过运行 https://github.com/hinthornw/promptimizer/tree/wfh/blog_experiments 中的 all_sweeps.sh 脚本来复现这些实验

附录

训练动态

在之前的章节中,我们主要讨论了最终 prompt 在保留的测试拆分上的表现。下面,我们分享了每个数据集开发拆分上算法训练动态的图表。这些图表显示了不同算法如何拟合到提供的数据集。将这些图表与最终分数进行比较,还可以揭示算法在多大程度上过度拟合了数据,而这种过度拟合并没有转化为持续的收益。

支持邮件路由 (3)

大多数优化器始终如一地优于基线 prompt,梯度方法和进化方法都显示出类似的增益。Claude 在所有方法中都明显优于 GPT-4o。即使在使用 meta-prompting 方法的 dev 集上,Claude 和 4o 也未能取得太大改进。

随着时间的推移,开发集上的分数

支持邮件路由 (10)

基于朴素 GPT-4o 的 meta-prompting 和 meta-prompting + reflection 设置未能学习此数据集中的分类规则。我们很快就看到了一个常见的模式形成:如果曲线保持平坦,它们显然没有学习。如果曲线快速接近完美分数,它们可能会过度拟合。中间的算法和具有持续改进的算法往往会转化为最佳测试集性能。

多语言数学

此数据集可能是最不连续的,正如 dev 集性能在 epoch 2、3(甚至更晚)的 epoch 中获得大部分改进所表明的那样,对于一些设置。这也突出了跟踪编辑历史记录(超出最后一次或两次尝试)的实用性。LLM 作为 meta-optimizer 非常有用,因为它们能够将编辑历史记录转化为更有效的更新。

电子邮件助手简单

在这里,我们再次看到 prompt 优化设置 (gpt-4o + metaprompting + reflect) 在 dev 拆分中实现的最高性能实际上并没有转化为测试拆分中的良好性能。

电子邮件助手古怪

虽然 Claude+进化算法设置赢得了最高的测试拆分性能,但我们看到拟合 dev 集最快(和最多)的算法是由 O1 驱动的。o1-进化设置拟合数据集的速度最快,尽管最终未能显着提高测试集上的系统质量。另一方面,不拟合 dev 集的设置也未能显着提高测试集上的 prompt (上文)。

比较 Prompt

虽然我们最终更关心下游指标而不是 prompt 的确切内容,但查看最终 prompt 以了解优化器实际学习修改什么,以及哪些更改导致改进,可能会有所启发。我们将以支持 10 路分类数据集为例。首先,比较由 Sonnet 驱动时,比较四种算法

所有四种算法都能够学习主要的分配规则。基于梯度的方法在寻找需要澄清边界的模糊区域方面似乎不太稳健。其他算法识别“优先级规则”或发明决策树来帮助澄清这些边界。

在同一算法上比较优化器模型,您还可以看到行为上的细微差异。在这种情况下,O1 似乎更倾向于创造性地结合不同的技术(合成 few-shot 和逐步指令),并且倾向于在其特征部分分隔符(“—”)之间使用规则集,而 Claude 在这种情况下似乎是最简洁和直接的,但这两者都学习了优先级规则以及领域映射。GPT-4o 似乎创建了信息密度最低的指令。