MLflow DSPy Flavor
dspy
flavor 正在积极开发中,并被标记为实验性功能。随着该 flavor 的演进,公共 API 可能会发生变化,并可能添加新功能。
简介
DSPy 是一个用于算法化优化语言模型(LM)提示和权重的框架。它旨在通过用模块化组件替换手工制作的提示字符串来改进提示工程的过程。这些模块简洁、定义明确,并保持高质量和强大的表达能力,使提示创建更高效、更具可扩展性。通过参数化这些模块并将提示视为一个优化问题,DSPy 能够更好地适应不同的语言模型,其性能可能超越专家精心制作的提示。这种模块化还使得探索复杂的流水线变得更加容易,允许根据特定任务或细微的指标进行性能微调。
为何将 DSPy 与 MLflow 结合使用?
DSPy 库与 MLflow 的原生集成为用户管理 DSPy 的开发生命周期提供了帮助。以下是将 DSPy 与 MLflow 结合使用的一些主要好处:
- MLflow Tracking 允许您跟踪 DSPy 程序的训练和执行。通过 MLflow API,您可以记录各种工件并组织训练运行,从而提高模型性能的可见性。
- MLflow Model 将您编译好的 DSPy 程序及其依赖版本、输入输出接口和其他基本元数据打包在一起。这使您可以轻松部署已编译的 DSPy 程序,并确保在机器学习生命周期的不同阶段环境保持一致。
- MLflow Evaluate 在 MLflow 内部提供了评估 GenAI 应用程序的原生功能。此功能有助于高效评估您的 DSPy 编译程序的推理结果,确保强大的性能分析并促进快速迭代。
- MLflow Tracing 是一个强大的可观测性工具,用于监控和调试 DSPy 模型内部发生的情况,帮助您快速识别潜在的瓶颈或问题。凭借其强大的自动日志记录功能,您只需运行一个命令,无需添加任何额外代码,即可对您的 DSPy 应用程序进行检测。
开始使用
在本入门教程中,您将学习 DSPy 最基本的组件,以及如何利用与 MLflow 的集成来存储、检索和使用 DSPy 程序。
概念
Module
模块 (Modules) 是处理特定文本转换的组件,例如回答问题或进行总结。它们取代了传统的手写提示,并且可以从示例中学习,使其更具适应性。
Signature
签名 (signature) 是对模块输入和输出行为的自然语言描述。例如,“问题 -> 答案”指定该模块应接受一个问题作为输入并返回一个答案。
Optimizer
优化器 (optimizer) 通过调整模块以满足性能指标来改进 LM 流水线,这可以通过生成更好的提示或微调模型来实现。
Program
程序 (program) 是一组连接成流水线以执行复杂任务的模块。DSPy 程序非常灵活,允许您使用编译器对其进行优化和调整。
自动追踪
MLflow Tracing 是一项强大的功能,可让您监控和调试 DSPy 程序。使用 MLflow,您只需在代码中调用 mlflow.dspy.autolog()
函数即可启用自动追踪。
import mlflow
mlflow.dspy.autolog()
一旦启用,每当您的 DSPy 程序执行时,MLflow 都会生成追踪信息,并将其记录在您的 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 支持流式传输。要启用流式传输,请确保满足以下条件:
- 安装高于 2.6.23 版本的
dspy
。 - 使用签名记录您的模型。
- 确保模型的所有输出都是字符串。
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 模型能够对需要访问密钥的服务进行远程调用。