Skip to content

此页面已过时,在 DSPy 2.5 和 2.6 版本中可能不完全准确

常见问题解答

DSPy适合我吗?DSPy与其他框架的对比

DSPy 的哲学理念和抽象方式与其他库和框架有显著不同,因此通常很容易判断 DSPy 是否适合您的用例。如果您是 NLP/AI 研究人员(或正在探索新流程或新任务的从业者),答案通常是肯定的 。如果您是从事其他工作的从业者,请继续阅读。

DSPy 与提示词轻量封装(OpenAI API、MiniChain、基础模板)的对比 换句话说:为什么我不能直接用字符串模板编写提示词? 对于极其简单的场景,这种方式或许完全可行。(如果你熟悉神经网络,这就像用 Python 的 for 循环实现一个微型两层神经网络。勉强能用。)然而,当你需要更高品质(或可控成本)时,就需要迭代探索多阶段分解、改进提示词、数据自举、精细调优、检索增强,和/或使用更小(或更便宜,或本地)的模型。基于基础模型构建的真正表达能力在于这些组件之间的交互。但每次修改一个组件时,很可能破坏(或削弱)其他多个组件。DSPy 清晰抽象了(高效优化了)这些交互中与实际系统设计无关的部分。它让你专注于设计模块级交互:用 10 到 20 行 DSPy 编写的同一程序,可轻松编译为针对 GPT-4 的多阶段指令、针对 Llama2-13b 的详细提示词,或针对 T5-base 的微调方案。哦,你也不再需要在项目核心维护冗长脆弱、模型特定的字符串了。

DSPy vs. 应用开发库如 LangChain, LlamaIndex LangChain 和 LlamaIndex 针对高层次应用开发;它们提供开箱即用的预制应用模块,可与您的数据或配置进行集成。如果您愿意使用通用、现成的提示来处理 PDF 问答或标准文本转 SQL,您将在这些库中找到丰富的生态系统。DSPy 内部不包含针对特定应用的手工制作的提示。相反,DSPy 引入了一小组更强大且通用的模块,可以在您的流水线中根据您的数据学习如何提示(或微调)您的语言模型。当您更改数据、调整程序的控制流或更改目标语言模型时,DSPy 编译器可以将您的程序映射为一组新的提示(或微调),这些提示专门针对此流水线进行了优化。因此,您可能会发现,DSPy 以最少的努力为您的任务获得最高质量的结果,前提是您愿意实现(或扩展)自己的简短程序。简而言之,DSPy 适用于需要轻量级但自动优化的编程模型的情况,而不是预定义提示和集成的库。如果您熟悉神经网络:这类似于 PyTorch(即代表DSPy)和 HuggingFace Transformers(即代表更高层次的库)之间的区别。

DSPy vs. 生成控制库(如Guidance、LMQL、RELM、Outlines) 这些都是令人兴奋的新库,用于控制语言模型的单个补全结果,例如,如果你想强制JSON输出模式或将采样约束到特定的正则表达式。这在许多场景中非常有用,但它通常侧重于对单个语言模型调用的低级结构化控制。它并不能确保你获得的JSON(或结构化输出)对于你的任务是正确或有用的。相比之下,DSPy 自动优化程序中的提示,使其与各种任务需求对齐,这也可能包括生成有效的结构化输出。也就是说,我们正在考虑允许DSPy中的Signatures来表达由这些库实现的正则表达式类约束。

基本用法

我应该如何为我的任务使用DSPy? 我们为此编写了一份八步指南。简而言之,使用DSPy是一个迭代过程。你首先定义你的任务和想要最大化的指标,并准备一些示例输入——通常不带标签(或者如果指标需要,仅对最终输出带标签)。然后,通过选择内置层(modules)来构建你的流水线,为每个层赋予一个signature(输入/输出规范),然后在你的Python代码中自由调用这些模块。最后,使用DSPy的optimizer将你的代码编译成高质量的指令、自动的少样本示例或更新你的LM权重。

如何将我的复杂提示转换为DSPy流水线? 请参考上述相同答案。

DSPy优化器调整什么? 或者说,编译实际上做了什么? 每个优化器都不同,但它们都通过更新提示或语言模型权重来最大化程序的度量指标。当前的DSPy optimizers 可以检查您的数据,通过程序模拟追踪来生成每个步骤的好/坏示例,根据过去的结果提出或改进每个步骤的指令,在自生成的示例上微调语言模型的权重,或者结合其中几种方法来提高质量或降低成本。我们很乐意合并探索更丰富空间的新优化器:您目前为提示工程、"合成数据"生成或自我改进所进行的大多数手动步骤,很可能可以泛化为作用于任意语言模型程序的DSPy优化器。

其他常见问题。我们欢迎提交PR来为这些问题添加正式解答。您可以在现有问题、教程或论文中找到所有或大部分问题的答案。

  • 如何获取多个输出?

您可以指定多个输出字段。对于短格式签名,您可以在"->"指示符后列出多个逗号分隔的输出值(例如"inputs -> output1, output2")。对于长格式签名,您可以包含多个dspy.OutputField

  • 如何定义自己的指标?指标可以返回浮点数吗?

您可以将指标定义为简单的Python函数,这些函数处理模型生成并根据用户定义的需求进行评估。指标可以将现有数据(例如黄金标签)与模型预测进行比较,或者使用来自语言模型的验证反馈(例如LLMs-as-Judges)来评估输出的各个组成部分。指标可以返回boolintfloat类型的分数。查看官方Metrics文档以了解更多关于定义自定义指标和使用AI反馈和/或dspy程序进行高级评估的信息。

  • 编译的成本有多高或者速度有多慢?

为了反映编译指标,我们重点展示一个实验以供参考,使用BootstrapFewShotWithRandomSearch优化器在gpt-3.5-turbo-1106模型上编译一个程序,涉及7个候选程序和10个线程。我们报告显示,编译该程序大约需要6分钟,进行3200次API调用,输入270万个令牌,输出15.6万个令牌,总成本为3美元(按当前OpenAI模型定价计算)。

编译DSPy optimizers自然会带来额外的语言模型调用,但我们通过最小化执行来证实这一开销,目标是最大化性能。这为提升较小模型的性能开辟了途径,即通过使用较大模型编译DSPy程序,在编译时学习增强行为,并在推理时将这种行为传播到被测试的较小模型。

部署或可重现性问题

  • 如何保存我编译程序的检查点?

以下是一个保存/加载已编译模块的示例:

cot_compiled = teleprompter.compile(CoT(), trainset=trainset, valset=devset)

#Saving
cot_compiled.save('compiled_cot_gsm8k.json')

#Loading:
cot = CoT()
cot.load('compiled_cot_gsm8k.json')
  • 如何导出用于部署?

导出DSPy程序只需如上所示保存它们!

  • 如何搜索我自己的数据?

开源库如 RAGautouille 使你能够通过像ColBERT这样的高级检索模型搜索自己的数据,并配备嵌入和索引文档的工具。在开发你的DSPy程序时,可以自由集成这些库来创建可搜索的数据集!

  • 如何关闭缓存?如何导出缓存?

从 v2.5 版本开始,你可以通过在 dspy.LM 中设置 cache 参数为 False 来关闭缓存:

dspy.LM('openai/gpt-4o-mini',  cache=False)

您的本地缓存将被保存到全局环境目录 os.environ["DSP_CACHEDIR"] 或对于笔记本环境为 os.environ["DSP_NOTEBOOK_CACHEDIR"]。您通常可以将缓存目录设置为 os.path.join(repo_path, 'cache') 并从这里导出此缓存:

os.environ["DSP_NOTEBOOK_CACHEDIR"] = os.path.join(os.getcwd(), 'cache')

重要

DSP_CACHEDIR 负责旧客户端(包括 dspy.OpenAI、dspy.ColBERTv2 等),而 DSPY_CACHEDIR 负责新的 dspy.LM 客户端。

在AWS lambda部署中,您应该禁用DSP_*和DSPY_*。

高级用法

  • 如何实现并行化? 您可以在编译和评估期间通过分别在DSPy optimizers中或dspy.Evaluate实用函数内指定多线程设置来并行化DSPy程序。

  • 如何冻结模块?

模块可以通过设置其._compiled属性为True来冻结,表示该模块已经过优化器编译,不应再调整其参数。这在优化器内部处理,例如dspy.BootstrapFewShot中,确保在教师传播引导过程中收集的少样本演示之前,学生程序已被冻结。

  • 如何使用DSPy断言?

    a) 如何向程序添加断言: - 定义约束条件:使用dspy.Assert和/或dspy.Suggest在DSPy程序中定义约束条件。这些约束基于您想要强制执行的布尔验证检查,可以简单地使用Python函数来验证模型输出。 - 集成断言:将断言语句保持在模型生成之后(提示:跟随模块层之后)

    b) 如何激活断言: 1. 使用assert_transform_module: - 使用assert_transform_module函数以及backtrack_handler来包装带有断言的DSPy模块。此函数会转换您的程序以包含内部断言回溯和重试逻辑,这些逻辑也可以自定义: program_with_assertions = assert_transform_module(ProgramWithAssertions(), backtrack_handler) 2. 激活断言: - 直接在带有断言的DSPy程序上调用activate_assertionsprogram_with_assertions = ProgramWithAssertions().activate_assertions()

    注意:要正确使用断言,您必须通过上述任一方法激活包含dspy.Assertdspy.Suggest语句的DSPy程序。

错误

  • 如何处理"上下文过长"错误?

如果你在DSPy中遇到"上下文过长"错误,很可能是因为你使用了DSPy优化器在提示中包含演示,这超出了你当前的上下文窗口限制。尝试减少这些参数(例如max_bootstrapped_demosmax_labeled_demos)。此外,你也可以减少检索到的段落/文档/嵌入数量,以确保你的提示能够适应模型的上下文长度限制。

一个更通用的修复方法是简单地增加指定给LM请求的max_tokens数量(例如lm = dspy.OpenAI(model = ..., max_tokens = ...)。

设置详细级别

DSPy 使用 logging library 来打印日志。如果你想调试你的 DSPy 代码,请使用以下示例代码将日志级别设置为 DEBUG。

import logging
logging.getLogger("dspy").setLevel(logging.DEBUG)

Alternatively, if you want to reduce the amount of logs, set the logging level to WARNING or ERROR.

import logging
logging.getLogger("dspy").setLevel(logging.WARNING)
优云智算