DSPy(Declarative Self-improving Python)是斯坦福大学 NLP 实验室开发的开源 Python 框架,提出了「Prompt 编程」范式:开发者用声明式签名(Signature)描述任务的输入输出,用模块(Module)组装推理流程,再通过优化器(Optimizer)自动生成和调优 prompt,把传统手工调 prompt 的体力活变成可测试、可复用、可自动优化的编译过程。它解决的核心问题是 prompt 工程的脆弱性——换模型、换数据、改格式都需重新手工调整指令。本篇攻略覆盖 DSPy 的安装配置、核心三要素(Signature/Module/Optimizer)、RAG 快速上手、生产部署要点,并与 LangChain、LlamaIndex 等框架对比,帮助读者判断是否值得引入。
掌握 DSPy 意味着把「反复试 prompt」的迭代交给编译器,你的核心竞争力从调词转向设计模块与度量,这是 LLM 工程师进阶声明式开发范式的关键能力。
目录
速览卡是工具类内容的固定首屏模块:30 秒判断「这工具是什么、能不能商用、适不适合我」。
为什么需要 DSPy:手工调 Prompt 的痛点 → 声明式编译
传统 prompt 工程的做法是:针对任务写一段指令,跑一条数据看效果,效果不好就改措辞、加示例、调格式,反复迭代直到满意。这种方式的深层问题有三个。第一,prompt 是纯文本,无法做单元测试、版本管理与复用,一个需求变更往往要重写整段指令。第二,prompt 与具体模型强耦合,从 GPT 换到 Claude 通常需要重新调参。第三,示例选择、指令措辞、格式要求这些关键因素交错影响,人工很难在全局空间里搜索最优组合。
DSPy 把问题域彻底翻转:开发者不再写 prompt,而是描述「这个模块输入什么、输出什么」。这一步通过签名完成,框架负责用语言模型把签名实例化为具体的 prompt。推理流程由模块组装,类似 PyTorch 的 nn.Module——有 forward 方法、可嵌套、可组合。优化器(Optimizer,2.0 前叫 Teleprompter)拿到少量标注数据后,通过编译(compile)自动完成示例挑选、指令改写、思维链引导等优化,把调 prompt 变成可复现的编译过程。
与 LangChain 等编排框架的定位差异:LangChain 强调「链」的组装与生态集成,DSPy 强调「如何找到最优的 prompt 方案」。DSPy 不重复造轮子——检索组件可以接入 LangChain 的 Retriever,Agent 也可以内嵌 ReAct 模块,它专注的是编译优化这一层,两者可叠加使用。
安装与环境配置:3 步就绪
步骤一·安装:DSPy 从 PyPI 安装,要求 Python 3.9+。建议装在虚拟环境中,避免污染全局环境。
步骤二·配置:2.x 用统一的 dspy.LM 接口接入多家模型提供商,模型标识格式为「提供商/模型名」。OpenAI 之外,Anthropic、Ollama 本地模型同样支持——本地模型通过 api_base 参数指定服务地址即可,无需改业务代码。
步骤三·验证:确认安装版本、模型连通。先跑一个最小的签名调用,能返回结果即环境就绪。
python -m venv .venv && source .venv/bin/activatepip install dspypython -c "import dspy; print(dspy.__version__)"
import dspy # 配置语言模型(以 OpenAI 为例,也可用 anthropic/... 或 ollama_chat/...)lm = dspy.LM(model="openai/gpt-4o-mini", api_key="sk-...")dspy.configure(lm=lm) # 连通性验证:让模型输出一句话result = dspy.Predict("sentence -> sentiment")(sentence="DSPy 很棒")print(result.sentiment)
快速上手:10 分钟跑通一个 RAG 管道
最小可用流程分三步:定义签名 → 组装模块 → 直接调用。这个流程展示 DSPy 的核心心智——你不写 prompt,只描述数据契约。dspy.ChainOfThought 会自动注入「先推理再作答」的中间步骤指令。
1. 定义签名 GenerateAnswer:用 dspy.Signature 声明任务描述与输入/输出字段。字段用 dspy.InputField / dspy.OutputField 标注,desc 参数给模型提供字段含义的提示,推荐编写——它直接影响输出质量。
2. 定义模块 RAG:继承 dspy.Module,在 __init__ 中声明子模块——dspy.Retrieve(k=3) 负责检索、dspy.ChainOfThought(GenerateAnswer) 负责生成;在 forward 方法中编排数据流:先检索取回段落,再让生成模块基于段落作答。
3. 实例化并调用:rag(question) 返回结果对象,从 .answer 属性取答案。
结果说明:首次调用走零样本路径,模型依据自动生成的指令回答,通常能得到「水星」这类正确答案。进阶技巧:准备 20–100 条带答案的训练样本,用 BootstrapFewShot 编译一次,示例自动挑选、指令自动优化,回答质量通常明显提升——这是 DSPy 与传统 RAG 框架最大的体验差异。
import dspy lm = dspy.LM(model="openai/gpt-4o-mini")dspy.configure(lm=lm) # 第一步:定义签名class GenerateAnswer(dspy.Signature): """基于给定上下文,回答用户问题。""" context = dspy.InputField(desc="可能包含答案的段落") question = dspy.InputField() answer = dspy.OutputField(desc="简洁、准确的答案") # 第二步:组装模块class RAG(dspy.Module): def __init__(self, num_passages=3): super().__init__() self.retrieve = dspy.Retrieve(k=num_passages) self.generate_answer = dspy.ChainOfThought(GenerateAnswer) def forward(self, question): context = self.retrieve(question).passages return self.generate_answer(context=context, question=question) # 第三步:直接调用(此时为零样本模式)rag = RAG()result = rag("太阳系中哪颗行星离太阳最近?")print(result.answer)
核心能力详解:3 大支柱
支柱一·Signature(签名)——prompt 的数据契约。 签名是 DSPy 的最小单元,用类型化字段代替自由文本指令。"question -> answer" 这种简写适合原型;完整写法用 dspy.Signature,支持任务描述、字段说明、字段前缀。签名的设计让 prompt 具备可测试性——字段类型约束了输入输出,可以在编译前做校验。实践中建议为每个字段写 desc,它是模型理解的锚点。签名跨模型复用,换模型不换签名。
支柱二·Module(模块)——可组合的推理单元。 模块把签名实例化为具体行为:dspy.Predict 是单步预测;dspy.ChainOfThought 自动注入中间推理步骤;dspy.ReAct 实现工具调用循环;dspy.Retrieve 封装检索。模块支持嵌套与继承,与 PyTorch 的 nn.Module 心智一致,因此有深度学习背景的工程师上手成本很低。RAG、Agent、多跳推理等复杂结构都可以由模块自由组合出来。
支柱三·Optimizer(优化器)——把调 prompt 变成编译。 这是 DSPy 与其它框架的本质区别。优化器接收训练集与度量函数(metric),在编译时搜索示例、改写指令、选择思维链方式。常用优化器有四个:LabeledFewShot 从训练集挑示例,零成本基线;BootstrapFewShot 用模型自我生成的示例,适合少量数据;MIPROv2 做指令+示例联合搜索,效果上限最高但耗时;BootstrapFewShotWithRandomSearch 是折中方案。2.5 起提供 dspy.optimizer.Auto 自动模式,快速实验用它最简单。
生产部署与监控:从上线到运维
部署方式一·编译产物序列化。 训练环境完成 compile 后,优化好的 prompt 与示例存储在模块参数中。通过 dspy.save(path) / dspy.load(path) 导出导入,如同保存模型权重。线上服务加载已编译对象,跳过编译步骤只跑推理(forward),延迟与成本与普通 LLM 调用一致。正式流程建议:开发环境编译 → 产物存入制品库 → 生产环境只加载产物,保证可复现。
部署方式二·与现有服务集成。 DSPy 不自带服务器,把它作为 Python 库嵌入 FastAPI/Flask 即可。检索组件可替换为适配器接入 LangChain/Weaviate 等外部检索器。高并发场景使用异步 LM 调用,并开启 2.x 的 LM 级缓存,避免相同输入的重复 token 开销。DSPy 也支持通过观测平台接入 tracing,记录每次调用的输入输出、延迟与 token 消耗。
可观测性。 编译过程会记录每个候选方案的 metric 得分,可以据此回溯「为什么选这个指令」。上线后重点监控三个指标:首 token 延迟、token 成本、metric 在真实流量上的回退幅度。编译优化的效果可能因数据分布漂移而衰减,需要定期用新数据重新编译——把重编译作为常态化运维动作,而不是一次性工作。
<p class="para-label">避坑清单:</p>
<ul class="dash-list"><li>坑 1:Token 成本超预期——Bootstrap 类优化器会多次调用模型,小任务先把训练集缩到 50–100 条,用 auto="light" 降低实验开销。</li><li>坑 2:把 compile 写进每次请求——编译耗时分钟级且成本高,务必离线一次性编译并把产物保存复用。</li><li>坑 3:忽略签名 desc 字段——优化器是在签名设定的搜索空间内找解,糟糕的字段描述会系统性拉低优化上限。</li></ul>
| 维度 | DSPy | LangChain | LlamaIndex | Instructor |
|---|---|---|---|---|
| 定位 | Prompt 编程与自动优化框架 | 通用 LLM 应用编排框架 | 数据/知识库为中心的 RAG 框架 | 结构化输出与函数调用封装 |
| 编排范式 | 声明式模块 + 编译优化 | 链/图的命令式组装 | 索引+查询引擎流水线 | 装饰器绑定 Pydantic 模式 |
| 类型约束 | 签名声明 IO 契约 | 弱约束,纯文本 prompt | 数据模型关联 | Pydantic 强类型输出 |
| 学习曲线 | 中(需理解编译模型) | 低(概念直观) | 低-中 | 低 |
| 生态集成 | 适配器接 LangChain/向量库 | 极为丰富(数百集成) | 40+ 数据源与向量库 | 兼容任意 LLM 客户端 |
| 生产部署 | 自建服务,产物可序列化 | 提供 LangServe 部署方案 | 提供部署与托管方案 | 随主框架部署的库 |
| License | MIT | MIT | MIT | MIT |
| 适合谁 | 追求 prompt 系统化调优的团队 | 快速拼装复杂流水线的团队 | 文档问答/知识库为主的团队 | 需要严格 JSON 输出的开发者 |
选型建议:核心痛点是「prompt 反复调不好、换模型就崩」,选 DSPy,用自动优化替代手调;核心需求是快速组装多工具流水线,LangChain 生态更顺;纯知识库问答场景 LlamaIndex 开箱即用;只需结构化输出时加一层 Instructor 即可,不必引入完整框架。
版本迭代
DSPy 从 2023 年初的论文概念起步,2024 年 2.0 做了结构性重写(Teleprompter 更名 Optimizer、统一 dspy.LM/dspy.Module 接口),2024 下半年 2.5 引入 Auto 模式与适配器层,把优化从「手动选配置」推进到「自动配置」,主线是降低使用门槛、扩大任务覆盖面(截至训练数据,可能已有更新版本)。
| 版本 | 时间 | 变化 | 提升 |
|---|---|---|---|
| v1.x | 2023 | 论文概念落地,Teleprompter 优化器雏形 | 提出签名/模块/编译三要素,支持少量示例自动优化 |
| 2.0 | 2024-03 | 全面重写,Teleprompter 改名 Optimizer | 统一 `dspy.LM` 接口,模块化重构,接入多模型提供商 |
| 2.4 | 2024-06 | 缓存与追踪完善,性能优化 | 引入 LM 级缓存、编译提速,增强检索适配 |
| 2.5 | 2024-10 | Auto 模式、适配器层 | 自动挑选优化器与配置;新增分类/对话等任务适配器 |
DSPy 的迭代重心从「证明优化有效」转向「让优化更好用」——Auto 模式让新手无需理解优化器细节即获得基线优化效果,适配器层把签名从「文本问答」扩展到分类、对话、结构化输出等真实业务形态。2.5 仍是最新正式版,但编译优化的核心范式稳定,本攻略示例对未来版本兼容。DSPy 论文在知识密集型任务上实测自动优化效果优于手工 prompt,具体分数随任务与基座模型而异,选型时应以自有数据集复测为准。
AI 应用场景
RAG 管道的系统化调优
阶段:RAG 管道构建与自动优化
解决的问题:传统 RAG 的 prompt 由人工编写,检索段落格式、指令措辞、few-shot 示例都要手工试错;换 embedding 或 LLM 后整套 prompt 可能重调。DSPy 把检索与生成声明为模块,用 BootstrapFewShot 等优化器自动挑选示例与改写指令,调优变成一次 compile。
具体案例:官方论文(arXiv:2310.03714)在 HotPotQA 等知识密集型任务上实测证明,DSPy 自动优化得到的 prompt 在多数任务上优于精心手工调优的基线。工程实践中,100–500 条标注样本即可显著改善检索生成质量,且优化产物可随模型升级一键重编译。
Agent 工具的自动行为优化
阶段:Agent 推理与工具调用编排
解决的问题:ReAct 类 Agent 的「如何选工具、何时停止反思」全靠 prompt 里一段指令约束,指令含糊会导致工具误用或死循环。DSPy 的 dspy.ReAct 将推理步声明为签名,优化器可基于少量「问题—正确工具序列」样本自动调优工具选择指令。
具体案例:在工具调用评测集上,用 BootstrapFewShot 编译 ReAct 模块后,工具选择准确率明显高于写死的指令模板;新增工具时只需扩充训练样本重新编译,不需要重写 prompt。对多工具、多步骤的 Agent 场景,这套机制直接替代人工维护工具说明书。
大规模分类与信息提取的 prompt 治理
阶段:文档智能与结构化输出
解决的问题:多标签分类、实体提取等任务类别繁多,手工 prompt 难以覆盖全部边界情况,数据分布一变就要重调。DSPy 2.5 的分类适配器将签名映射为分类任务格式,优化器自动生成针对性的标签释义与示例。
具体案例:数据标注团队用 DSPy 管理数十类的工单分类,以历史已标注数据做训练集编译,不再逐类人工维护 prompt 模板;新类别加入时仅需补充训练样本重编译,迭代周期从按周调模板缩短到按天跑编译,人力投入大幅下降。
常见误区
误区听说 DSPy 能自动调 prompt,就想用它替换掉项目里的 LangChain,觉得编排框架是过时方案。
正解两者层次不同:LangChain 负责链/图编排与生态集成,DSPy 专注模块声明与编译优化。官方适配器明确支持在 DSPy 里接入 LangChain 的检索器等组件。实践中常见组合是 LangChain 做外层调度、DSPy 做核心模块的 prompt 优化。是否替换取决于现有代码结构,而不是「谁更先进」。
为何常见:两者都被称为 LLM 框架,宣传口径都是「简化开发」,容易被归为同类竞争品;实际一个偏「怎么组装」,一个偏「怎么优化」。
误区把它当成「输入任务描述,输出一段完美 prompt」的生成器,期望它吐出一段能复制到别处用的提示词。
正解DSPy 不是 prompt 生成器。编译产物是「模块参数 + 优化后的指令」,与 DSPy 运行时深度绑定,不能脱离框架单独导出 prompt 使用。它的价值是整个模块化流程可测试、可复用、可自动优化,而不是给你一段孤立文本。
为何常见:宣传材料常以「告别手写 prompt」为口号,容易让人误解为 prompt 生成器;优化器确实会产生新指令,但那是编译过程的内部产物。
误区听说 compile 要反复调 LLM,觉得小数据量、小场景用 DSPy 成本太高。
正解LabeledFewShot 编译几乎零额外调用(只做示例挑选);BootstrapFewShot 在 50–100 条样本上也只需一次编译,成本可控;auto="light" 会自动选择轻量配置。成本主要发生在 MIPROv2 这类穷举式优化器上,可用小训练集先试。零样本使用 DSPy(不编译)也完全可行,只是没有优化收益。
为何常见:教程默认演示 MIPROv2 全量编译,让人以为所有优化器都贵;事实上优化器有明确的成本阶梯。
误区看到官方示例都是 Q&A、RAG,就认为它只能做开放域问答。
正解2.5 的适配器层把签名映射到不同任务格式:分类适配器(多标签/多类)、对话适配器、结构化输出适配器。配合 dspy.ChainOfThought 与 dspy.ReAct,能覆盖分类、提取、对话、Agent 工具调用等主流任务。签名输入输出字段自由声明,任何「输入→输出」任务都能建模。
为何常见:官方文档的快速上手默认用问答数据,新用户容易被首屏示例限制想象。
误区觉得有了自动优化,prompt 技巧都过时了,完全不用关心字段描述怎么写。
正解签名的字段 desc、任务描述、示例设计仍然深度影响优化上限——优化器是在你给的初始搜索空间内找最优解,糟糕的签名定义会让编译在一个次优空间里打转。真正的高手把 prompt 经验沉淀到签名与训练数据的设计里,再用优化器放大其效果。
为何常见:营销话术强调「自动」,让人误以为完全免人工;实际上优化器解决的是「搜索」问题,不是「定义」问题。
面试题
Q1. DSPy 中「签名(Signature)」的核心作用是什么?
- A.定义模块输入输出的数据契约← 正确答案
- B.存储编译后的模型权重
- C.负责管理与轮换 API 密钥
- D.负责缓存检索得到的结果
答案:A。签名用类型化字段声明模块的输入输出,是 DSPy Prompt 编程的基石,把自由文本 prompt 变成可测试、可复用的数据契约。B 是编译产物(模块参数),C 是 LM 配置职责,D 是缓存组件,均与签名无关。
Q2. 在 DSPy 2.x 中,统一接入各家语言模型的接口是?
- A.dspy.OpenAI 接口
- B.dspy.LM 接口← 正确答案
- C.dspy.LLM 接口
- D.dspy.Provider 接口
答案:B。2.x 将模型接入统一收敛为 dspy.LM(model="提供商/模型名"),通过 dspy.configure(lm=lm) 设为默认。A 是 1.x 的旧接口风格,C/D 在 DSPy 中不存在。
Q3. 下列哪个是 DSPy 的优化器(Optimizer)?
- A.RetrievalQA 类
- B.ChainOfThought 模块
- C.MIPROv2 优化器← 正确答案
- D.ChatOpenAI 模型
答案:C。MIPROv2 是 DSPy 内置优化器,在编译时联合搜索指令与示例。B 是推理模块而非优化器,A 是 LangChain 的链对象,D 是 LangChain 的模型封装,均为误导项。
Q4. dspy.ChainOfThought 相比 dspy.Predict 的关键差异是?
- A.会主动去调用检索器组件
- B.自动注入先推理后作答的中间步骤← 正确答案
- C.会去调用更强版本的模型
- D.生成篇幅更长的答案文本
答案:B。ChainOfThought 在签名基础上自动加入中间推理步骤(思维链),让模型先推理再输出,通常能提升复杂推理质量。A 是 Retrieve 模块的职责,C 不改变模型选择,D 虽常伴随更长输出但非本质差异。
Q5. 用 BootstrapFewShot 编译时,示例从哪里来?
- A.从互联网随机抓取候选段落
- B.在训练集上自我生成并经度量筛选← 正确答案
- C.由开发者逐一编写生成
- D.从预训练数据集中抽取
答案:B。BootstrapFewShot 用当前模块在训练样本上执行推理,自动产生示例并经度量函数筛选进入 few-shot 池。A/D 无此机制,C 描述的是人工构造示例,不是 Bootstrap 类优化器的核心机制。
Q6. 关于 DSPy 的 compile 流程,下列说法正确的是?
- A.训练集与度量函数是编译的必要输入← 正确答案
- B.编译产物可以保存并加载复用← 正确答案
- C.编译只需一次调用,与 token 成本无关
- D.优化器会在候选 prompt 中搜索较优方案← 正确答案
答案:ABD。compile 接收 trainset 与 metric,在候选方案(示例/指令)中搜索并评估,产物通过 dspy.save/load 持久化复用。C 错误:Bootstrap 类优化器会多次调用模型,token 成本显著,这正是避坑清单第 1 条的来源。
Q7. 快速实验阶段,DSPy 2.5 推荐用哪种方式获得基线优化效果?
- A.手动配置 MIPROv2 做完整搜索
- B.用 Auto 模式自动选择优化器与配置← 正确答案
- C.不用优化器,继续手工调 prompt
- D.写死五百条人工示例做 few-shot
答案:B。2.5 引入 Auto 模式,根据任务与数据规模自动挑选优化器并配置,官方推荐用于快速实验。A 耗时与成本高,C 回到手工 prompt 工程,D 示例数量过多代价大且未利用优化能力。
Q8. DSPy 与 LangChain 的正确关系与用法是?
- A.二者是直接替代关系,项目中必须严格二选一
- B.DSPy 的检索模块可接入 LangChain 的 Retriever← 正确答案
- C.LangChain 负责编排与生态,DSPy 负责核心模块优化← 正确答案
- D.DSPy 内部实现了 LangChain 的全部链工具
答案:BC。二者定位互补而非互斥:LangChain 提供丰富的编排与集成,DSPy 通过适配器接入其检索器等组件,专注模块声明与自动优化。A 是常见错误认知,D 不成立——DSPy 不复制 LangChain 的链生态。
Q9. 生产环境中使用 DSPy 的推荐做法是?
- A.每次请求都先 compile 再推理
- B.编译产物离线生成并序列化,线上只做推理← 正确答案
- C.直接把训练数据原样暴露给线上服务
- D.生产环境重新编译以提升稳定性
答案:B。编译耗时且消耗 token,应在离线流程完成,产物经 dspy.save 保存后加载到线上推理。A 会在每次请求引入分钟级延迟,D 混淆训练与推理阶段,C 既不安全也无必要。
Q10. 关于 DSPy 中签名设计与优化效果的关系,最准确的说法是?
- A.只要优化器够强,签名随便写也不影响最终效果
- B.签名字段描述与任务说明定义了搜索空间,直接影响优化上限← 正确答案
- C.签名只影响代码可读性,与模型输出质量无关
- D.优化器会自动重写开发者定义的任何签名结构
答案:B。优化器在签名设定的结构内搜索指令与示例,糟糕的签名(缺失字段说明、任务描述含混)会压缩搜索空间,导致编译结果次优。A 夸大了优化器的能力边界,C 否认字段描述对输出的影响,D 中优化器不重写签名结构。