DSPy 优化器(前称 Teleprompters)
DSPy 优化器是一种算法,可以调整 DSPy 程序的参数(即提示和/或语言模型权重),以最大化您指定的指标,例如准确性。
典型的 DSPy 优化器需要三个要素
-
您的 DSPy 程序。这可能是一个模块(例如
dspy.Predict
)或一个复杂的多模块程序。 -
您的指标。这是一个函数,用于评估程序输出并为其分配分数(分数越高越好)。
-
少量训练输入。数量可以非常少(例如,只有 5 或 10 个样本),并且可能不完整(只有程序的输入,没有标签)。
如果您有很多数据,DSPy 可以充分利用。但即使从少量数据开始,您也能获得不错的结果。
注意: 之前称为 teleprompters。我们正在进行正式的名称更新,这将在整个库和文档中体现。
DSPy 优化器会调整什么?它是如何调整的?
DSPy 中的不同优化器通过以下方式调整程序质量:为每个模块合成优质的少样本示例(如 dspy.BootstrapRS
1)、为每个提示提出并智能探索更好的自然语言指令(如 dspy.MIPROv2
2),以及为您的模块构建数据集并用它们来微调系统中的语言模型权重(如 dspy.BootstrapFinetune
3)。
DSPy 优化器有哪些例子?不同的优化器是如何工作的?
以 dspy.MIPROv2
优化器为例。首先,MIPRO 开始进行自举阶段 (bootstrapping stage)。它会获取您的程序(此时可能尚未优化),并在不同的输入上多次运行,为您的每个模块收集输入/输出行为的跟踪记录。它会过滤这些跟踪记录,仅保留那些在您指标评分较高的轨迹中出现的记录。其次,MIPRO 进入基础提案阶段 (grounded proposal stage)。它预览您的 DSPy 程序代码、您的数据以及运行程序产生的跟踪记录,并利用它们为程序中的每个提示草拟许多潜在的指令。第三,MIPRO 启动离散搜索阶段 (discrete search stage)。它从您的训练集中采样小批量数据,为流水线中的每个提示提出指令和跟踪记录的组合,并在小批量数据上评估候选程序。利用得到的分数,MIPRO 更新一个代理模型,该模型有助于随着时间的推移改进提案。
DSPy 优化器如此强大的一点在于它们可以组合使用。您可以运行 dspy.MIPROv2
,然后将生成的程序作为输入再次传递给 dspy.MIPROv2
,或者传递给 dspy.BootstrapFinetune
,以获得更好的结果。这在一定程度上是 dspy.BetterTogether
的精髓所在。或者,您可以运行优化器,然后提取前 5 个候选程序并构建它们的 dspy.Ensemble
。这使得您能够高度系统地扩展推理时计算(例如,集成)以及 DSPy 独有的推理前计算(即优化预算)。
目前有哪些 DSPy 优化器可用?
可以通过 from dspy.teleprompt import *
访问优化器。
自动少样本学习
这些优化器通过自动生成并将优化后的示例包含在发送给模型的提示中来扩展签名,从而实现少样本学习。
-
LabeledFewShot
:简单地从提供的标注输入和输出数据点构建少样本示例(demo)。需要指定k
(提示的示例数量)和trainset
(从中随机选择k
个示例)。 -
BootstrapFewShot
:使用一个teacher
模块(默认为您的程序)为程序的每个阶段以及trainset
中的标注示例生成完整的演示。参数包括max_labeled_demos
(从trainset
中随机选择的演示数量)和max_bootstrapped_demos
(由teacher
生成的额外示例数量)。自举过程使用指标来验证演示,在“编译后”的提示中仅包含通过指标的演示。高级用法:支持使用一个结构兼容的不同的 DSPy 程序作为teacher
程序,以处理更困难的任务。 -
BootstrapFewShotWithRandomSearch
:对生成的演示应用BootstrapFewShot
多次,并进行随机搜索,在优化过程中选择最佳程序。参数与BootstrapFewShot
类似,额外增加了num_candidate_programs
,用于指定在优化过程中评估的随机程序数量,包括未编译程序、经过LabeledFewShot
优化的程序、使用未打乱示例编译的BootstrapFewShot
程序,以及num_candidate_programs
个使用随机示例集编译的BootstrapFewShot
程序。 -
KNNFewShot
:使用 k-近邻算法查找给定输入示例的最近训练示例演示。然后将这些最近邻演示用作 BootstrapFewShot 优化过程的训练集。
自动指令优化
这些优化器为提示生成最优指令,对于 MIPROv2,还可以优化少样本演示集。
-
COPRO
:为每个步骤生成和优化新指令,并使用坐标上升法(利用指标函数和trainset
进行爬山搜索)对其进行优化。参数包括depth
,即优化器运行提示改进的迭代次数。 -
MIPROv2
:在每个步骤中生成指令和少样本示例。指令生成是数据感知和演示感知的。使用贝叶斯优化来有效地搜索跨模块的生成指令/演示空间。
自动微调
此优化器用于微调底层大型语言模型。
BootstrapFinetune
:将基于提示的 DSPy 程序提炼为权重更新。输出是一个 DSPy 程序,它具有相同的步骤,但每个步骤由微调后的模型而不是基于提示的语言模型执行。
程序转换
Ensemble
:集成一组 DSPy 程序,可以使用完整集合或随机采样一个子集整合成一个程序。
我应该使用哪个优化器?
最终,找到适合您的任务的“正确”优化器及最佳配置需要进行实验。在 DSPy 中取得成功仍然是一个迭代过程——要获得任务的最佳性能,您需要探索和迭代。
话虽如此,以下是一些入门的通用指南
- 如果您有非常少的示例(约 10 个),请从
BootstrapFewShot
开始。 - 如果您有更多数据(50 个或更多示例),请尝试
BootstrapFewShotWithRandomSearch
。 - 如果您更喜欢仅进行指令优化(即您希望提示保持 0-shot),请使用配置为 0-shot 优化的
MIPROv2
进行优化。 - 如果您愿意使用更多推理调用来执行更长时间的优化运行(例如 40 次或更多试验),并且有足够的数据(例如 200 个或更多示例以防止过拟合),那么尝试
MIPROv2
。 - 如果您能够使用其中一种优化器与大型语言模型(例如,7B 或更多参数)结合使用,并且需要一个非常高效的程序,请使用
BootstrapFinetune
为您的任务微调小型语言模型。
如何使用优化器?
它们都共享这个通用接口,但在关键字参数(超参数)上存在一些差异。关键优化器的详细文档可以在这里找到,完整列表可以在这里找到。
我们以最常用的 BootstrapFewShotWithRandomSearch
为例看看。
from dspy.teleprompt import BootstrapFewShotWithRandomSearch
# Set up the optimizer: we want to "bootstrap" (i.e., self-generate) 8-shot examples of your program's steps.
# The optimizer will repeat this 10 times (plus some initial attempts) before selecting its best attempt on the devset.
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4, num_candidate_programs=10, num_threads=4)
teleprompter = BootstrapFewShotWithRandomSearch(metric=YOUR_METRIC_HERE, **config)
optimized_program = teleprompter.compile(YOUR_PROGRAM_HERE, trainset=YOUR_TRAINSET_HERE)
入门 III:优化 DSPy 程序中的语言模型提示或权重
一个典型的简单优化运行成本约为 2 美元,耗时约十分钟,但在使用超大型语言模型或超大数据集运行优化器时要小心。优化器运行成本可能低至几美分,高至数十美元,具体取决于您的语言模型、数据集和配置。
这是一个最小但完全可运行的示例,演示如何设置一个通过维基百科搜索回答问题的 dspy.ReAct
Agent,然后使用 dspy.MIPROv2
在廉价的 light
模式下,通过从 HotPotQA
数据集中抽样的 500 对问答对对其进行优化。
在 DSPy 2.5.29 上进行一次类似的非正式运行,将 ReAct 的得分从 24% 提高到 51%。
给定一个用于 search
的检索索引、您偏好的 dspy.LM
以及包含问题和真实答案的小型 trainset
,以下代码片段可以针对内置的 dspy.SemanticF1
指标优化您的具有长输出的 RAG 系统,该指标作为一个 DSPy 模块实现。
如需一个完整的 RAG 运行示例,请开始这个教程。它将 RAG 系统在 StackExchange 社区子集上的质量从 53% 提高到 61%。
这是一个最小但完全可运行的示例,演示如何设置一个将短文本分类到 77 个银行标签之一的 dspy.ChainOfThought
模块,然后使用 dspy.BootstrapFinetune
和来自 Banking77
的 2000 对文本-标签对来微调 GPT-4o-mini 在此任务上的权重。我们使用了 dspy.ChainOfThoughtWithHint
变体,它在自举时接受一个可选的 hint
,以最大化训练数据的效用。当然,提示在测试时不可用。更多内容可以在这个教程中找到。
点击显示数据集设置代码。
可能的输出(最后一行)
Prediction(
reasoning='A pending cash withdrawal indicates that a request to withdraw cash has been initiated but has not yet been completed or processed. This status means that the transaction is still in progress and the funds have not yet been deducted from the account or made available to the user.',
label='pending_cash_withdrawal'
)
在 DSPy 2.5.29 上进行一次类似的非正式运行,将 GPT-4o-mini 的得分从 66% 提高到 87%。
保存和加载优化器输出
程序经过优化器运行后,将其保存也很有用。稍后,可以从文件中加载程序用于推理。为此,可以使用 load
和 save
方法。
生成的文件是纯文本 JSON 格式。它包含源程序中的所有参数和步骤。您可以随时读取它,查看优化器生成的内容。您可以通过 `optimized_program.save(YOUR_SAVE_PATH, save_field_meta=True)` 添加 save_field_meta
来额外保存字段列表,包含键 name
、field_type
、description
和 prefix
。
要从文件中加载程序,您可以实例化该类的一个对象,然后调用其 load 方法。