DSPy是斯坦福大学开源的大模型编程框架,核心思路是将提示词从手工编写转为程序化自动优化。传统Prompt工程依赖人工试错,修改模型或换数据集后需要重新调参,DSPy通过声明式签名(Signature)和编译器(Optimizer)实现提示词的自动搜索与迭代,在多个基准测试中超过人工编写的提示词效果。
DSPy核心概念与模块化编程模型
DSPy的编程模型围绕三个核心概念构建:Signature(签名)描述任务的输入输出规范,不写具体提示词;Module(模块)封装可复用的推理逻辑,类似PyTorch的nn.Module;Optimizer(优化器)根据训练数据自动搜索最优提示词组合。
定义一个Signature只需要声明输入字段和输出字段:
import dspy
class QA(dspy.Signature):
'''Answer questions with short factual answers.'''
question = dspy.InputField()
answer = dspy.OutputField(desc="A short factual answer, no explanation.")
class RAG(dspy.Module):
def __init__(self, num_passages=3):
super().__init__()
self.retrieve = dspy.Retrieve(k=num_passages)
self.generate = dspy.ChainOfThought("context, question -> answer")
def forward(self, question):
context = self.retrieve(question).passages
prediction = self.generate(context=context, question=question)
return dspy.Prediction(context=context, answer=prediction.answer)
上面的代码没写一句提示词模板,只声明了检索和生成的数据流。DSPy会根据优化器自动填充提示词内容。
BootstrapFewShot优化器自动选择Few-Shot示例
手工挑选Few-Shot示例耗时且不稳定,DSPy的BootstrapFewShot优化器通过自动采样和评估完成这一过程。它的工作流程是:先在训练集上运行基础模块,找到输出正确的样本作为候选示例,再通过教师模型交叉验证示例质量,最终组合成最优的Few-Shot集合。
from dspy.teleprompt import BootstrapFewShot
# 定义评估函数
def validate_answer(example, pred, trace=None):
return example.answer.lower() == pred.answer.lower()
# 编译优化
optimizer = BootstrapFewShot(
metric=validate_answer,
max_bootstrapped_demos=4,
max_labeled_demos=4,
max_rounds=1
)
compiled_rag = optimizer.compile(rag, trainset=trainset)
编译后的compiled_rag对象携带自动选择的示例,推理时直接使用。更换底层模型(如从GPT-4切到Qwen)后无需手工重写提示词,重新编译即可适配。
MIPROv2指令优化与多阶段编译策略
BootstrapFewShot只优化示例选择,指令文本仍为默认值。MIPROv2优化器在此基础上同时搜索指令文本和示例组合,使用贝叶斯优化在指令空间中搜索。该优化器会生成多个候选指令变体,通过小批量评估筛选高分布指令,再与Few-Shot示例组合做联合搜索。
from dspy.teleprompt import MIPROv2
mipro = MIPROv2(
metric=validate_answer,
prompt_model=dspy.LM("openai/gpt-4o", max_tokens=2000),
task_model=dspy.LM("openai/gpt-4o-mini"),
num_candidates=10,
init_temperature=1.0,
)
compiled_rag_v2 = mipro.compile(rag, trainset=trainset[:50], valset=devset[:50])
MIPROv2的num_candidates参数控制候选指令数量,增大该值提升搜索空间但增加编译耗时。编译阶段调用prompt_model生成指令变体,推理阶段使用成本更低的task_model,实现编译成本和推理成本的分离。
评估与对比:自动优化vs手工提示词
DSPy提供Evaluate模块做批量评估,对比编译前后的效果变化:
from dspy.evaluate import Evaluate
evaluator = Evaluate(
devset=testset,
metric=validate_answer,
num_threads=4,
display_progress=True,
display_table=5,
)
baseline_score = evaluator(rag)
compiled_score = evaluator(compiled_rag)
print(f"Baseline: {baseline_score}, Compiled: {compiled_score}")
在HotpotQA多跳问答任务上,使用BootstrapFewShot编译后的RAG模块准确率比手工提示词基线提升约8-15个百分点。提升幅度取决于训练集规模和评估函数质量,评估函数越精确(如EM匹配vs模糊匹配),编译效果越好。
生产部署中的注意事项
DSPy编译产物是Python对象,部署时需要序列化存储。推荐使用dspy.save和dspy.load持久化编译后的模块,避免每次启动重新编译:
# 保存编译结果
import pickle
with open("compiled_rag.pkl", "wb") as f:
pickle.dump(compiled_rag, f)
# 加载使用
with open("compiled_rag.pkl", "rb") as f:
rag_loaded = pickle.load(f)
result = rag_loaded(question="2024年诺贝尔物理学奖获得者是谁?")
切换底层模型时,建议重新编译。不同模型对指令格式的敏感度不同,BootstrapFewShot在同族模型间迁移效果较好,跨模型族(如GPT到Llama)迁移建议使用MIPROv2重新搜索指令。
DSPy的局限在于依赖标注数据做优化,训练集质量直接影响编译效果。在低数据场景下,可用BootstrapFewShotWithRandomSearch做随机搜索兜底,降低对训练集规模的依赖。复杂多步推理任务建议拆分为多个子模块分别编译,再组合为Pipeline统一评估。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/da-mo-xing-prompt-zi-dong-you-hua-shi-zhan-dspy-kuang-jia/