MLflow DSPy Flavor
dspy
flavor 正在积极开发中,并标记为实验性。 公共 API 可能会发生更改,并且随着 flavor 的发展,可能会添加新功能。
简介
DSPy 是一个用于以算法方式优化 LM 提示和权重的框架。 它旨在通过用模块化组件替换手工制作的提示字符串来改进提示工程的过程。 这些模块简洁、定义明确,并保持高质量和表达能力,从而提高提示创建的效率和可扩展性。 通过参数化这些模块并将提示视为优化问题,DSPy 可以更好地适应不同的语言模型,有可能优于专家制作的提示。 这种模块化还能够更轻松地探索复杂的管道,从而可以根据特定任务或细微的指标微调性能。
为什么将 DSPy 与 MLflow 一起使用?
DSPy 库与 MLflow 的原生集成可以帮助用户管理 DSPy 的开发生命周期。 以下是将 DSPy 与 MLflow 一起使用的一些主要优势
- MLflow Tracking 允许您跟踪 DSPy 程序的训练和执行。 借助 MLflow API,您可以记录各种工件并组织训练运行,从而提高模型性能的可见性。
- MLflow Model 将您编译的 DSPy 程序与其依赖项版本、输入和输出接口以及其他基本元数据打包在一起。 这使您可以轻松部署编译的 DSPy 程序,并且知道环境在 ML 生命周期中的不同阶段保持一致。
- MLflow Evaluate 在 MLflow 中提供本机功能来评估 GenAI 应用程序。 此功能有助于有效评估来自您 DSPy 编译程序的推理结果,确保强大的性能分析并促进快速迭代。
- MLflow Tracing 是一种强大的可观察性工具,用于监视和调试 DSPy 模型内部发生的事情,帮助您快速识别潜在的瓶颈或问题。 凭借其强大的自动日志记录功能,您可以检测 DSPy 应用程序,而无需添加任何代码,只需运行一个命令即可。
开始使用
在本入门教程中,您将学习 DSPy 的最基本组件,以及如何利用与 MLflow 的集成来存储、检索和使用 DSPy 程序。
概念
Module
模块是处理特定文本转换的组件,例如回答问题或总结。 它们取代了传统的手写提示,并且可以从示例中学习,从而使其更具适应性。
Signature
签名是模块输入和输出行为的自然语言描述。 例如,“问题 -> 答案” 指定模块应将问题作为输入并返回答案。
Optimizer
优化器通过调整模块以满足性能指标来改进 LM 管道,无论是通过生成更好的提示还是微调模型。
Program
程序是一组连接到管道中的模块,用于执行复杂的任务。 DSPy 程序非常灵活,允许您使用编译器优化和调整它们。
自动跟踪
MLflow Tracing 跟踪是一项强大的功能,允许您监视和调试 DSPy 程序。 借助 MLflow,您只需在代码中调用 mlflow.dspy.autolog()
函数即可启用自动跟踪。
import mlflow
mlflow.dspy.autolog()
启用后,MLflow 将在每次执行 DSPy 程序时生成跟踪,并将它们记录在您的 MLflow 实验中。
了解更多关于 MLflow DSPy 跟踪功能的信息。
在 MLflow 实验中跟踪 DSPy 程序
创建 DSPy 程序
Module 对象是 DSPy 和 MLflow 集成的核心。 借助 DSPy,您可以通过模块或一组模块创建复杂的代理逻辑。
pip install mlflow dspy -U
import dspy
# Define our language model
lm = dspy.LM(model="openai/gpt-4o-mini", max_tokens=250)
dspy.settings.configure(lm=lm)
# Define a Chain of Thought module
class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought("question -> answer")
def forward(self, question):
return self.prog(question=question)
dspy_model = CoT()
将程序记录到 MLflow
您可以使用 mlflow.dspy.log_model()
函数将 dspy.Module
对象记录到 MLflow 运行中。
我们还将指定一个 模型签名。 MLflow 模型签名定义了模型输入和输出的预期架构,从而确保模型推理期间的一致性和正确性。
import mlflow
# Start an MLflow run
with mlflow.start_run():
# Log the model
model_info = mlflow.dspy.log_model(
dspy_model,
name="model",
input_example="what is 2 + 2?",
)
加载模块以进行推理
可以使用 mlflow.pyfunc.load_model()
函数加载保存的模块以进行推理。 此函数提供由 DSPy 模块支持的 MLflow Python 模型。
import mlflow
# Load the model as an MLflow PythonModel
model = mlflow.pyfunc.load_model(model_info.model_uri)
# Predict with the object
response = model.predict("What kind of bear is best?")
print(response)
{
"reasoning": """The question "What kind of bear is best?" is often associated with a
humorous reference from the television show "The Office," where the character Jim
Halpert jokingly states, "Bears, beets, Battlestar Galactica." However, if we consider
the question seriously, it depends on the context. Different species of bears have
different characteristics and adaptations that make them "best" in various ways.
For example, the American black bear is known for its adaptability, while the polar bear is
the largest land carnivore and is well adapted to its Arctic environment. Ultimately, the
answer can vary based on personal preference or specific criteria such as strength,
intelligence, or adaptability.""",
"answer": """There isn\'t a definitive answer, as it depends on the context. However, many
people humorously refer to the American black bear or the polar bear when discussing
"the best" kind of bear.""",
}
DSPy 的 MLflow PythonModel 支持流式传输。 要启用流式传输,请确保满足以下条件
- 安装
dspy
版本大于 2.6.23。 - 使用签名记录您的模型。
- 确保模型的所有输出都是字符串。
stream_response = model.predict_stream("What kind of bear is best?")
for output in stream_response:
print(output)
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": "The"}
{
"predict_name": "prog.predict",
"signature_field_name": "reasoning",
"chunk": " question",
}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " of"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " what"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " kind"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " of"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " bear"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " is"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " best"}
{"predict_name": "prog.predict", "signature_field_name": "reasoning", "chunk": " is"}
...
要将 DSPy 程序本身加载回来,而不是加载 PyFunc 包装的模型,请使用 mlflow.dspy.load_model()
函数。
model = mlflow.dspy.load_model(model_uri)
优化器自动日志记录
MLflow DSPy flavor 支持 DSPy 优化器的自动日志记录。 有关详细信息,请参阅优化器自动日志记录页面。
常见问题
如何保存编译模型与未编译模型?
DSPy 通过更新各种 LLM 参数(例如提示、超参数和模型权重)来编译模型,以优化训练。 虽然 MLflow 允许记录编译和未编译的模型,但通常最好使用编译模型,因为它预计在实践中表现更好。
MLflow 可以序列化什么?
当在 MLflow 中使用 mlflow.dspy.log_model()
或 mlflow.dspy.save_model()
时,DSPy 程序将被序列化并作为 .pkl
文件保存到跟踪服务器。 这使得可以轻松部署。 在底层,MLflow 使用 cloudpickle
来序列化 DSPy 对象,但某些 DSPy 工件不可序列化。 相关示例如下。
- API 令牌。 这些应该单独管理,并通过环境变量安全地传递。
- DSPy 跟踪对象,主要在训练期间使用,而不是在推理期间使用。
如何管理密钥?
使用 MLflow DSPy flavor 进行序列化时,令牌将从设置对象中删除。 用户有责任将所需的密钥安全地传递到部署环境。
如何保存 DSPy settings
对象?
为了确保程序的可重现性,服务上下文将转换为 Python 字典,并使用模型工件进行 pickle 处理。 服务上下文是 GenAI 框架中流行的概念。 简而言之,它存储对您的项目全局的配置。 具体来说,对于 DSPy,我们可以设置语言模型、重新排序器、适配器等信息。
DSPy 将此服务上下文存储在 Settings
单例类中。 记录模型时,不会持久化在 Settings
对象中设置的敏感 API 访问密钥。 部署 DSPy 模型时,您必须确保部署环境已设置这些密钥,以便 DSPy 模型可以远程调用需要访问密钥的服务。