DSPy:用编程而非提示词来训练语言模型完整中文翻译
一、官方信息表
| 项目 | 说明 |
|---|---|
| 项目名称 | DSPy(Declarative Self-improving Python,声明式自改进 Python) |
| 一句话定位 | 用「编程」而非「写提示词」来构建语言模型系统的框架 |
| GitHub 仓库 | stanfordnlp/dspy |
| 官方文档 | dspy.ai |
| PyPI 包 | dspy |
| 发起团队 | 斯坦福大学 NLP 团队(Omar Khattab 等) |
| 核心论文 | DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines(ICLR 2024) |
二、官方图

三、项目背景与核心理念
DSPy 是一个用来「编程——而不是提示——语言模型」的框架。它让你可以快速迭代地构建模块化的 AI 系统,并提供一整套算法来优化系统里的提示词和模型权重——无论你在做的是简单分类器、复杂的 RAG 检索流水线,还是智能体循环(Agent loop)。
传统做法是手写一大段容易脆断的提示词(prompt),每次模型换了、任务变了,都得手工改提示词。DSPy 反其道而行之:你写的是可组合的 Python 代码,用「签名」(Signature)声明每个模块的输入输出,再交给 DSPy 去教会你的语言模型产出高质量结果。提示词本身在 DSPy 里变成了可学习、可优化的参数,就像神经网络里的权重一样。DSPy 的名字就是 Declarative Self-improving Python 的缩写,它的灵感直接来自 PyTorch 的 nn.Module——只不过把「张量运算模块」换成了「语言模型调用模块」。你可以把它理解成:给语言模型编程就像搭神经网络一样,每个 LM 调用是一层,层与层之间是普通的 Python 控制流,编译(compile)阶段自动把提示词「编译」成最优指令加示例的组合,换模型时整套程序不用重写。
四、环境要求与安装
DSPy 是一个纯 Python 库,官方要求 Python 环境,安装非常简单:
pip install dspy
如果你想直接用 main 分支的最新代码(可能包含尚未发布的实验特性),可以从 GitHub 源码安装:
pip install git+https://github.com/stanfordnlp/dspy.git
配置模型时,DSPy 通过 LiteLLM 兼容几乎所有主流模型供应商(OpenAI、Anthropic、本地模型等),例如:
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))
五、核心概念:模块(Module)
DSPy 模块是使用语言模型的程序的基本构件。 每一个内置模块都抽象了一种提示技术(比如思维链 Chain of Thought、ReAct),关键是它们可以泛化到任意「签名」上。模块带有可学习参数(组成提示词的那些片段、以及 LM 权重),被调用时处理输入并返回输出;多个模块还能像搭积木一样组合成更大的程序。
最基础的模块是 dspy.Predict,其他所有模块都建立在它之上。使用时两步走:先用一个签名声明模块,再传入参数调用它:
sentence = "it's a charming and often affecting journey."
# 1) 用签名声明模块
classify = dspy.Predict('sentence -> sentiment: bool')
# 2) 传入输入调用
response = classify(sentence=sentence)
# 3) 读取输出字段
print(response.sentiment)
输出: True。
在很多场景下,只要把 dspy.Predict 换成 dspy.ChainOfThought,模型质量就会直接提升一档:
question = "What's something great about the ColBERT retrieval model?"
classify = dspy.ChainOfThought('question -> answer', temperature=0.7)
response = classify(question=question)
思维链模块会自动在输出字段之前注入一段 reasoning(推理过程),你可以同时打印出来看:
print(f"Reasoning: {response.reasoning}")
print(f"Answer: {response.answer}")
官方内置模块一览:
dspy.Predict:最基础的预测器,不改动签名,负责保存指令和示例(demonstrations)并更新 LM。dspy.ChainOfThought:教模型在给出答案前先一步步思考。dspy.ProgramOfThought:教模型先输出代码,用代码执行结果决定最终答案。dspy.ReAct:一个可以调用工具来完成给定签名的智能体。dspy.MultiChainComparison:对多条思维链的输出做比较,选出最终预测。dspy.RLM:递归语言模型,在沙箱 Python REPL 里通过递归子调用探索超长上下文——当上下文太长塞不进提示词时用它。dspy.majority:函数式模块,对一组预测做投票,返回最常见的答案。
六、使用示例
6.1 组合多个模块成一个完整程序
DSPy 本质上就是你按任意控制流调用模块的 Python 代码,只在 compile 编译阶段内部追踪你的 LM 调用。下面是一个多跳检索(multi-hop search)程序的例子:
class Hop(dspy.Module):
def __init__(self, num_docs=10, num_hops=4):
self.num_docs, self.num_hops = num_docs, num_hops
self.generate_query = dspy.ChainOfThought('claim, notes -> query')
self.append_notes = dspy.ChainOfThought('claim, notes, context -> new_notes: list[str], titles: list[str]')
def forward(self, claim: str) -> list[str]:
notes = []
titles = []
for _ in range(self.num_hops):
query = self.generate_query(claim=claim, notes=notes).query
context = search(query, k=self.num_docs)
prediction = self.append_notes(claim=claim, notes=notes, context=context)
notes.extend(prediction.new_notes)
titles.extend(prediction.titles)
return dspy.Prediction(notes=notes, titles=list(set(titles)))
实例化后直接调用即可:
hop = Hop()
print(hop(claim="Stephen Curry is the best 3 pointer shooter ever in the human history"))
6.2 典型任务模板
官方文档给出了开箱即用的几类任务:数学题用 dspy.ChainOfThought("question -> answer: float") 直接解;RAG 检索增强生成用 ColBERTv2 检索 Wikipedia 摘要后传入 dspy.ChainOfThought('context, question -> response');分类任务可以用 dspy.Signature 定义输入字段和 Literal 类型的输出字段;信息抽取让模型从一段文本里抽出标题、小标题和实体列表;智能体则用 dspy.ReAct 挂上 evaluate_math、search_wikipedia 等工具。
6.3 用量统计
DSPy 2.6.16 及以上版本内置了语言模型用量追踪:
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini", track_usage=True))
开启后,任何 dspy.Prediction 对象都可以调用 get_lm_usage(),返回每个模型的 completion_tokens、prompt_tokens、total_tokens 明细。启用缓存(cache=True)时,命中缓存的回答不会再计入用量统计,这对控制 API 账单很有用。
6.4 典型任务模板速查
官方文档按任务类型给出了最小可运行示例:数学推理用 ChainOfThought("question -> answer: float"),让模型一步步算出两枚骰子点数之和为 2 的概率;RAG 用 dspy.ColBERTv2 服务检索 Wikipedia 摘要,再把 context 喂给思维链模块回答;三分类情感任务用 dspy.Signature 定义输入句子和 Literal['positive','negative','neutral'] 输出,还能顺带输出置信度;信息抽取一条 dspy.Predict("text -> title, headings: list[str], entities_and_metadata: list[dict]") 就能从新闻稿里抽出标题、小标题和实体表;智能体则把 evaluate_math、search_wikipedia 两个工具函数挂进 dspy.ReAct,让模型自己决定什么时候算数、什么时候查资料。
七、优化器(Optimization)
DSPy 优化器是一个算法,它能调节一个 DSPy 程序的参数(即提示词和/或 LM 权重),让你指定的指标(比如准确率)最大化。 一个典型的优化器接收三样东西:你的 DSPy 程序(可以是单个 dspy.Predict 模块,也可以是复杂的多模块程序)、一个打分函数(评估程序输出并给出分数)、以及少量训练输入(哪怕只有 5 到 10 条、甚至只有输入没有标签也能跑)。数据多当然更好,但 DSPy 支持从小样本起步拿到强结果。
7.1 优化器到底在调什么
不同优化器调优的方式分三类:自动合成少样本示例(如 dspy.BootstrapRS,为每个模块生成优质的 few-shot 演示);提出并智能探索更好的自然语言指令(如 dspy.MIPROv2 和 dspy.GEPA);为模块构建数据集并微调 LM 权重(如 dspy.BootstrapFinetune)。以 MIPROv2 为例:它先跑一遍你的未优化程序收集输入输出轨迹,用指标筛出高质量轨迹;再预览你的程序代码、数据和轨迹,为每条提示草拟多个候选指令;最后在训练集小批量上做离散搜索,选出指令与示例的最佳组合,并用贝叶斯优化持续改进。
优化器之间还可以组合串联:先用 MIPROv2 优化提示词,再把结果喂给 BootstrapFinetune 微调权重,这就是元优化器 dspy.BetterTogether 的思路;也可以取出前 5 个候选程序组成 dspy.Ensemble 集成。
7.2 官方优化器清单
- 自动少样本学习:
LabeledFewShot(从带标签数据随机取 k 条做演示)、BootstrapFewShot(用 teacher 模块自生成演示,并用指标过滤)、BootstrapFewShotWithRandomSearch(随机搜索多组演示选最优)、KNNFewShot(用 KNN 找最相似训练样本做演示)。 - 自动指令优化:
COPRO(坐标上升法迭代改进指令)、MIPROv2(同时优化指令和演示,数据感知)、SIMBA(随机小批量找难题,让 LLM 自我反思生成改进规则)、GEPA(让模型反思轨迹、找出哪里好哪里不好并提出新提示)。 - 自动微调:
BootstrapFinetune(把提示词程序蒸馏成权重更新,输出同样步骤但由微调模型执行的程序)。 - 程序变换:
Ensemble(多个程序集成)。 - 元优化器:
BetterTogether(按「提示→权重→提示」可配置序列串联优化)。
7.3 怎么选优化器
官方建议:样本极少(约 10 条)从 BootstrapFewShot 开始;数据较多(50 条以上)试 BootstrapFewShotWithRandomSearch;只想做指令优化(保持 0 样本提示)用 0-shot 配置的 MIPROv2;愿意花更多推理调用做更长优化(40 次以上试验、200 条以上数据防过拟合)就用 MIPROv2;已经用大模型(7B 以上)跑出效果、又需要更高效的小模型程序,用 BootstrapFinetune 微调一个小模型。典型一次优化运行成本约 2 美元、十分钟左右,具体随模型和数据规模从几美分到几十美元不等。
7.4 优化代码长什么样
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4,
num_candidate_programs=10, num_threads=4)
teleprompter = dspy.BootstrapFewShotWithRandomSearch(metric=YOUR_METRIC_HERE, **config)
optimized_program = teleprompter.compile(YOUR_PROGRAM_HERE, trainset=YOUR_TRAINSET_HERE)
官方给出的实测案例:在 HotPotQA 上用 MIPROv2 的 light 模式优化 ReAct 智能体,得分从 24% 提到 51%;优化 RAG 系统在 StackExchange 子集上从 53% 提到 61%;用 BootstrapFinetune 微调 GPT-4o-mini 做银行意图分类,得分从 66% 提到 87%。优化完的程序可以用 save / load 方法存盘,之后直接加载做推理。
当你有了系统和评估方式之后,还建议把数据分成训练集和留出测试集:训练集(及其子集验证集)通常 30 个样本就能见效,但目标是至少 300 个样本。与深度学习常见的「大训练小验证」相反,提示词优化器推荐 20% 训练、80% 验证 的反向切分——因为基于提示的优化很容易在小训练集上过拟合,大验证集才能保证结果稳定。而 dspy.GEPA 优化器遵循更标准的机器学习约定:尽量扩大训练集,验证集只需够反映下游任务分布即可。官方强调:迭代式开发是关键——反复打磨你的数据、程序结构、评估指标和优化步骤,必要时回到第一步重新审视任务定义、收集更多数据、或换用更复杂的优化器。
八、断言与自我修正
DSPy Assertions 是给 LM 程序加计算约束的机制:dspy.Assert 在约束不满足时触发回溯重试、把「上次输出 + 失败原因」加进签名让模型自我修正,超过最大重试次数仍失败就抛出 dspy.AssertionError 硬停;dspy.Suggest 则是软约束,失败只记录日志继续执行。例如在多跳检索程序里,可以声明「查询长度小于 100 字符」「新查询要与历史查询不同」两条约束。需要说明:新版 DSPy 已将旧的 Assertions 标记为弃用,官方建议改用 dspy.Refine 模块或 dspy.Suggest 实现同等的自我修正能力。
九、常见问题(FAQ)
问:DSPy 和手写提示词到底有什么区别? 手写提示词里,提示文本是你手工维护的脆弱字符串;DSPy 里提示词是带「签名」的模块的可学习参数,你写结构和数据流,优化器负责自动产出好提示词。
问:我需要先写多少条示例才能优化? 官方建议训练集至少 30 条、目标 300 条以上;验证集占比反而要大(推荐 80%),防止优化器过拟合小训练集。
问:DSPy 支持哪些模型?
通过 LiteLLM 兼容几乎所有主流供应商,包括 OpenAI、Anthropic、以及本地部署的开源模型,用 dspy.LM("openai/gpt-4o-mini") 这种 供应商/模型名 格式指定即可。
问:DSPy 断言(Assertions)是什么? DSPy Assertions 是一种计算约束机制,让程序在输出不满足约束时自我修正(self-refine),对应 2023 年 12 月的论文 DSPy Assertions。
问:DSPy 适合做什么规模的任务? 从简单情感分类、信息抽取,到 RAG 流水线、多跳检索、多智能体循环,都覆盖;它的价值在于把提示词工程变成可编译、可优化、可迭代的软件工程。
问:优化一次大概要花多少钱? 官方说法:典型一次优化运行大约 2 美元、十分钟左右;用超大模型或超大数据集时成本会上升,小样本优化也可能只要几美分。
问:优化完的程序怎么保存部署?
优化器 compile 出来的程序对象自带 save / load 方法,存到文件后可以在生产环境直接加载做推理,不需要在服务端保留训练数据。
问:DSPy 和 LangChain 这类编排框架什么关系? LangChain 偏向「把现成提示词和工具串成链」,DSPy 偏向「把提示词当作可学习参数自动优化」;两者可以配合,DSPy 也可以通过工具调用挂接外部检索和工具。
问:DSPy 的历史论文脉络是什么? 最早是 2022 年 12 月的 Demonstrate-Search-Predict(Demonstrate-Search-Predict:为知识密集型 NLP 组合检索与语言模型),2023 年 10 月正式提出 DSPy 编译器,2023 年 12 月提出 Assertions 计算约束,2024 年继续优化 MIPRO 指令优化和微调,2025 年 7 月的 GEPA 证明反思式提示进化可以超过强化学习。
十、跳转链接
- 官方文档:dspy.ai
- GitHub 仓库:stanfordnlp/dspy
- PyPI:dspy
- 社区 Discord:discord.gg/XCGy2WDCQB
- 官方论文:DSPy (ICLR 2024)
- GEPA 论文:Reflective Prompt Evolution
- MIPRO 论文:Optimizing Instructions and Demonstrations
- DSPy Assertions:计算约束论文
- Demonstrate-Search-Predict 原始论文:arXiv:2212.14024
- 推特:@DSPyOSS