DSPy 用声明式模块和优化器替代手工 Prompt 的框架。
DSPy 把 LLM 程序写成 Signature、Module 和 Optimizer:Signature 声明输入输出,Module(Predict、ChainOfThought 等)负责调用,Optimizer 用训练样例自动挑选示例和指令。
它适合有标注数据、需要稳定提升任务指标的场景。没有评测集时,优化器没有目标,DSPy 不会自动变好。
pip install -U dspy
export OPENAI_API_KEY="sk-..."
包名已从 dspy-ai 迁移到 dspy,旧版 dspy.OpenAI 在 2.5 之后被 dspy.LM 取代。
用 Signature 和 ChainOfThought 定义一个问答程序:
python - <<'PY'
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini", temperature=0.0))
class QA(dspy.Signature):
"""根据给定上下文回答问题,不要编造上下文之外的信息。"""
context: str = dspy.InputField()
question: str = dspy.InputField()
answer: str = dspy.OutputField()
program = dspy.ChainOfThought(QA)
result = program(context="df -h 查看文件系统使用率", question="怎么查磁盘?")
print(result.answer)
PY
用 BootstrapFewShot 在训练集上编译,并保存编译结果:
python - <<'PY'
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini", temperature=0.0))
trainset = [
dspy.Example(question="怎么查磁盘?", answer="df -h").with_inputs("question"),
dspy.Example(question="怎么查内存?", answer="free -h").with_inputs("question"),
]
def metric(example, pred, trace=None):
return example.answer.lower() in pred.answer.lower()
student = dspy.ChainOfThought("question -> answer")
optimizer = dspy.BootstrapFewShot(metric=metric, max_bootstrapped_demos=4,
max_labeled_demos=4, max_errors=3)
compiled = optimizer.compile(student, trainset=trainset)
compiled.save("qa_program.json")
print(compiled(question="怎么查端口?").answer)
PY
接入本地 vLLM 的 OpenAI 兼容接口:
python - <<'PY'
import dspy
lm = dspy.LM("openai/Qwen/Qwen2.5-7B-Instruct", api_base="http://localhost:8000/v1",
api_key="EMPTY", max_tokens=1024)
dspy.configure(lm=lm)
print(dspy.Predict("question -> answer")(question="什么是 OOMKilled?").answer)
PY
dspy 和旧包 dspy-ai 会导入到旧代码;卸载旧包,确认 pip show dspy 的路径。dspy.configure 设置的是上下文级默认 LM,线程或异步任务里可能拿不到;在任务内用 dspy.context(lm=...) 显式绑定。(example, pred, trace=None),返回布尔或分数;返回字符串会让优化器行为异常。max_errors。save 只保存模块状态(示例、指令),不保存代码和权重;加载时要先实例化相同的程序类。合上页面,先回答,再展开对照。
save 保存的是示例和指令状态,不含代码、模型或依赖版本。加载时应使用相同的程序类、相同的 LM 配置和兼容的 DSPy 版本。