DSPy 教程:用评估驱动提示词优化,读懂签名、模块与优化器

DSPy 值不值得用,关键在于任务能否评估。本文梳理签名、模块与优化器,给出可直接运行的 Python 示例,并用工单分流说明训练、验证和最终测试如何划分、调用次数与模型费用如何估算。读懂 DSPy 提示词优化的边界,比较手写提示词与微调,再判断团队是否具备样例、评分规则和维护能力,适合从哪里开始试验。

发布于

DSPy 教程:用评估驱动提示词优化,读懂签名、模块与优化器

如果一项 AI 任务需要反复执行,结果可以评分,而手工调整提示词已经成了持续的维护负担,就值得试试 DSPy。它把这项工作转成 Python 程序和优化循环。下文设计的小规模首次实验,预算最多为 100 次单步骤程序执行,重试另计。如果业务团队还无法就什么是正确答案达成共识,应先解决这个问题,再引入 DSPy。

本文于 2026 年 10 月 15 日 依据 DSPy 当前文档、PyPI 和 Google 模型价格核验。PyPI 列出的版本为 DSPy 3.4.1,发布于 2026 年 10 月 12 日,要求 Python 不低于 3.10、低于 3.16。安装包名为 dspy。PyPI 包元数据。

DSPy 是什么?compile 到底在做什么?

DSPy 是一个开源 Python 框架,用于把语言模型任务定义成程序,再优化程序中的提示词;使用特定优化器时,也可以调整模型权重。它真正有价值的地方,是围绕你定义的成功标准,建立可重复的改进流程。它并不保证第一次生成的提示词就能胜过精心编写的版本。DSPy 概览。

可以把这个过程想成排练:签名交代任务要求,模块决定如何表演,评估指标则是评分规则。优化器尝试改动,观察结果,再保留有效的调整。如果没有评分规则,即使换着方式排练,也无法判断是否真的有所进步。

签名:把任务说清楚

签名(signature) 声明输入、输出和任务指令。"ticket -> category" 表示输入一条工单,输出一个类别。用类定义签名时,还可以为字段指定类型,并通过文档字符串说明任务。不过,字段如何设计仍然关键:如果业务对“紧急”的定义含糊不清,优化器也无能为力。签名文档。

DSPy 模块:决定任务怎么执行

模块(module) 实现完成任务的具体策略。dspy.Predict 是基础预测组件;dspy.ChainOfThought 在答案前增加一个推理字段;dspy.ReAct 支持推理与工具调用的循环。如果单次模型调用无法完成任务,可以在 Python 中组合多个模块。模块文档。

做客服工单分流时,先从 Predict 开始。只是给一条短消息分类,就加入工具调用循环,会在需求尚未得到验证之前增加系统复杂度。

编译:实际执行的是优化流程

优化器(optimizer) 借助样例和评估指标,调整程序中的指定部分。用于提示词优化时,.compile() 返回的程序包含修改后的指令或示范样例,也就是放进提示词里的例子。它不会把应用变成本地可执行文件,也不会让后续模型调用消失。若要训练模型权重,需要另选相应的优化器。优化器选择指南。

DSPy 当前文档中的首个程序示例,用于生成俳句
DSPy:当前文档中的首个程序示例

DSPy 教程:从当前文档的最小示例入手

当前入门程序的任务是生成一首俳句。这个小例子足以展示接口的用法,不涉及数据库、工具或优化搜索。

在 Python 环境中安装已核验的版本:

Bash
python -m pip install 'dspy[litellm]==3.4.1'

在环境变量 GEMINI_API_KEY 中设置有效的 Google Gemini API 密钥。将以下代码保存为 first_dspy.py,再运行 python first_dspy.py:

Python
import os
import dspy

lm = dspy.LM(
    "gemini/gemini-2.5-flash-lite",
    api_key=os.environ["GEMINI_API_KEY"],
    engine="litellm",
)
dspy.configure(lm=lm)

haiku_signature = "subject -> haiku"
haiku_generator = dspy.Predict(haiku_signature)
result = haiku_generator(subject="computer science")
print(result.haiku)

最后四行来自当前文档的首个程序。初始化部分遵循 DSPy 的模型配置方式,但将模型换成了 Google Gemini 2.5 Flash-Lite,让下文实验统一使用一个成本较低的模型。模型提供方字符串采用 LiteLLM 的 Gemini 接入格式;DSPy LM API 支持在这里显式指定后端。

DSPy 根据签名构建提示词,将其发送给已配置的模型,再解析返回的 haiku 字段。这只是推理示例,并未运行优化流程,也不承诺会生成某首特定的诗,或带来质量提升。

用 DSPy 做提示词优化,先定义评估指标

没有评估指标,就谈不上有意义的优化。 评估指标是把预测结果转成分数的函数。对于工单分流,可以将预测类别与人工确认的标签比较;对于生成式回答,判断正确性可能需要评分标准或可执行的检查逻辑。DSPy 的评估指标接口接收你提供的评分函数,但不会替业务决定应该奖励什么结果。评估指标与评测。

这也是为什么需要一套规模不大、但有标注的评测集。如果你已经厌倦了把“简洁一点”改成“简短作答”,不如收集真实的失败案例:退款申请被分到了技术支持,登录问题被误判成账单问题,或一条消息同时提出了两个请求。在查看新提示词的输出之前,先标注好预期结果。

首次试点可以使用 60 个不同的样例,明确拆成 训练集 20 个、验证集 20 个、最终测试集 20 个样例。这只是本文建议的实验规模,既不是 DSPy 的要求,也不能据此证明系统已经具备生产环境所需的可靠性。

  • 训练样例 为优化器提供可学习的材料。
  • 验证样例 用于比较版本,并辅助开发决策。
  • 最终测试样例 在候选程序和评测规则确定之前保持封存。

同一客户或同一事件的相关工单应归入同一个数据子集。否则,近乎重复的样例可能让优化后的提示词显得比实际更有泛化能力。也要纳入那些少见却重要的失败案例,别让每个子集都只剩下简单题。

建筑风格的优化循环连接样例、程序、评估指标和优化器,旁边设有独立的留出测试区
最终留出集始终置于调优循环之外。

“没有指标就无法优化”也需要说得更准确一些。未优化的 DSPy 程序可以不带评估指标运行,LabeledFewShot 也能直接附加样例,无须为其评分。但这只是配置变化,不能证明任务效果有所改善。每项任务也不一定都要有人工编写的参考答案:可执行的正确性检查同样能提供优化信号。对于业务分类任务,经过确认的标签通常是最清晰的起点。少样本基线。

DSPy 优化器怎么选?先认清当前文档中的名称

从能解决已知问题的最简单优化器开始。只有评估指标能区分候选程序的好坏,扩大搜索范围才有意义。

当前的优化器 API 索引列出了以下条目:BetterTogether、BootstrapFewShot、BootstrapFewShotWithRandomSearch、BootstrapFinetune、BootstrapRS、COPRO、Ensemble、GEPA、InferRules、KNN、KNNFewShot、LabeledFewShot、MIPROv2 和 SIMBA。

这些条目并不全是独立的搜索算法。BootstrapRS 是 BootstrapFewShotWithRandomSearch 的别名;KNN 则是 KNNFewShot 使用的检索辅助组件。当前选择指南还介绍了适用于智能体类程序的 AvatarOptimizer,但它并未出现在该 API 索引中。优化器家族详解、选择指南。

要调整什么需要了解的名称首先考虑什么
提示词中的样例LabeledFewShot、BootstrapFewShot、BootstrapFewShotWithRandomSearch / BootstrapRS先建立简单的示范样例基线,再搜索大量样例组合。
为每个输入匹配的样例KNNFewShot,由 KNN 提供支持适合不同输入需要不同样例的场景,但会增加检索和运行时开销。
指令COPRO、GEPA如果具体的失败反馈能指导修改,可以使用 GEPA。
指令与示范样例MIPROv2、SIMBA、InferRules当初始样例或规则不够用时,可以考虑。
模型权重或组合策略BootstrapFinetune、BetterTogether需要有充分理由训练权重,并且所用模型支持训练。
组合已有候选程序Ensemble多个程序可以共同生成答案,但会增加推理开销。

MIPROv2 提出候选指令,再用贝叶斯优化探索指令与示范样例的组合;这种搜索方法会参考先前获得的分数。SIMBA 则按小批次处理样例,并提出规则或示范样例。它们采用的是不同方法,并非给 BootstrapFewShot 换了个名字。MIPROv2 API、SIMBA API。

GEPA 使用反思模型读取执行反馈,并提出指令修改方案。比起只有一个失败分数,分数再加上具体解释更有价值,例如:“退款申请即使提到了功能故障,也应归入账单类。”详细文档允许只返回数值的评估指标,但也说明这样会失去更丰富的反馈。GEPA 工作机制。

首次优化实验,先把规模限定好

与开放式指令搜索相比,小规模 BootstrapFewShot 实验更容易核算开销。下面的方案只使用一个 Predict 模块,以确定性的标签匹配作为评估指标,并让同一个模型承担教师和预测角色。

DSPy BootstrapFewShot:从小规模实验开始

准备 train.jsonl、validation.jsonl 和 test.jsonl,每个文件包含 20 条不同的、经过人工标注的工单。每行都是一个 JSON 对象,包含 text 和 label 字段;标签只能是 billing、technical、account 和 other。例如,要求更改发票地址的工单可以标为 billing。这里必须使用你自己的样例,不能拿前面的俳句输出充数。

将下面这个独立脚本保存为 optimize_tickets.py,设置好同一个 API 密钥后运行:

Python
import json
import os
from typing import Literal
import dspy

lm = dspy.LM(
    "gemini/gemini-2.5-flash-lite",
    api_key=os.environ["GEMINI_API_KEY"],
    engine="litellm",
    cache=False,
)
dspy.configure(lm=lm)

class RouteTicket(dspy.Signature):
    """Choose the support queue responsible for the ticket's main request."""
    text: str = dspy.InputField()
    label: Literal["billing", "technical", "account", "other"] = (
        dspy.OutputField()
    )

def load_examples(path):
    with open(path, encoding="utf-8") as source:
        rows = [json.loads(line) for line in source if line.strip()]
    assert len(rows) == 20
    return [dspy.Example(**row).with_inputs("text") for row in rows]

train = load_examples("train.jsonl")
validation = load_examples("validation.jsonl")
test = load_examples("test.jsonl")
assert len({e.text for e in train + validation + test}) == 60

def correct_label(example, prediction, trace=None):
    return prediction.label == example.label

program = dspy.Predict(RouteTicket)
evaluate = dspy.Evaluate(
    devset=validation, metric=correct_label, num_threads=1
)
print("Baseline validation:", evaluate(program).score)

optimizer = dspy.BootstrapFewShot(
    metric=correct_label,
    max_bootstrapped_demos=4,
    max_labeled_demos=0,
    max_rounds=1,
)
optimized = optimizer.compile(program, trainset=train)
print("Optimized validation:", evaluate(optimized).score)

# Freeze this candidate before opening the final test results.
final_test = dspy.Evaluate(
    devset=test, metric=correct_label, num_threads=1
)
print("Baseline final test:", final_test(program).score)
print("Optimized final test:", final_test(optimized).score)
optimized.save("candidate_ticket_router.json")

这段代码依据文档中的 BootstrapFewShot 构造函数和评测接口改编,不代表任何实测基准结果。它最多收集四个成功的示范样例,每个训练样例允许进行一次自举尝试,并且不直接添加原始标注样例作为示范。保存的文件只是待审核的候选程序,不会自动进入生产环境。

这个方案的执行次数如下:

  • 在验证集上评测基线:20 次程序执行。
  • 对训练集进行自举:最多 20 次教师程序执行;如果提前收集到足够的合格示范样例,次数还会更少。
  • 在验证集上评测优化后的程序:20 次程序执行。
  • 在最终测试集上评测两个版本:40 次程序执行。

合计 最多 100 次单步骤执行,其中包含评测;单独编译最多占 20 次。如果每次程序执行只发出一次成功的模型请求,没有重试,也没有解析失败后的回退调用,那么最多就是 100 次任务模型调用。前面的俳句运行检查另计。引入 LLM 裁判、智能体循环、重试,或再做一轮优化,都会改变总量。

四个建筑分区分别展示 20 次基线执行、最多 20 次自举执行、20 次对比执行和 40 次最终测试执行
首次实验的预算示例,不含重试或额外的模型步骤。

按 Google 对 Gemini 2.5 Flash-Lite 的 Standard 付费文本公开标价计算,输入为每百万 token $0.10,输出为每百万 token $0.40。假设 100 次调用平均每次使用 1,000 个输入 token 和 100 个输出 token,费用为 $0.014:100,000 ÷ 1,000,000 × $0.10 + 10,000 ÷ 1,000,000 × $0.40。 Google 价格页。

这只是模型费用的算术估算,既不是实测账单,也不是支出上限。输入量假设必须包含 DSPy 的格式化内容和附加的示范样例;工单更长、输出更多,或产生计费的思考 token,都会增加费用。估算没有计入批处理或缓存折扣。最终应以模型服务商记录的实际用量为准。

DSPy 框架、手写提示词和微调,该怎么选?

如果需要用可重复的方法改进一个可衡量的程序,可以使用 DSPy。如果手写提示词已经满足任务要求,就继续使用。如果已有证据表明调整提示词不够用,并且模型训练符合部署约束,再考虑微调。

方法调整的内容需要负责的部分适合先用在哪
手写提示词人工编辑的指令与样例任务定义与评测规模小、需求稳定,且现有提示词已够用的任务
DSPy 提示词优化由程序选择的指令或示范样例Python 程序、样例和评估指标需要系统性改进的重复分类、信息提取或问答流程
微调通过训练数据学习模型权重训练数据、模型对训练的支持以及评测值得通过训练并维护一个模型变体来实现的稳定行为

这些方法可以配合使用。DSPy 提供 BootstrapFinetune,BetterTogether 则能组合提示词优化与权重优化。实际区别在于需要改动和维护什么,而不在于哪个名称听起来更先进。提示词与权重优化。

何时值得切换,取决于日常维护负担:如果每次更换模型或出现新的失败案例,工程师都得回头手工修改好几个提示词,带评分的优化循环就有了吸引力。如果一个简短提示词已经通过验收标准,就还没有证据表明换成框架会带来收益。

谁适合马上尝试,谁应该等待或跳过?

对于工程师,适合动手的前提是:有重复执行的任务、可运行的基线,以及有代表性的失败案例。 工单分流和结构化信息提取都是合适的起点,因为预期输出便于检查。先优化一个小组件,再扩展系统。DSPy 的能力边界在于目标定义的质量:即便评估指标奖励的是错误行为,它仍然可能据此选出分数更高的候选程序。

业务运营人员应负责标签定义和错误优先级。 客服主管可能认为,把账户无法登录的事件分错队列,远比误分一条普通账单咨询严重。如果评分对两种错误一视同仁,优化方向就可能偏离主管的优先级。先明确这项业务规则,再让工程师提高分数。

采购决策者应要求提供未见样例上的证据。 要问清楚:比较的是哪个基线,哪些案例退步了,当前上线运行的程序包含哪些环节,以及流程是否仍满足延迟要求。优化器的名称本身不能作为验收依据。如果团队正在组织评测工作,可以延伸阅读本站的 Promptfoo 评测。

如果只是偶尔写文案、做一次性研究,或流程变化太快、来不及积累样例,业务团队就不必使用 DSPy。 如果无人维护 Python 代码,或无法就评分规则达成共识,也应跳过。一个好用的提示词、一份检查清单,再配合人工审核,可能才是投入与需求更匹配的方案。如果真正缺的是源数据,或业务流程尚未定义清楚,就先等等;优化措辞无法补上这两者。

DSPy 有哪些被夸大的说法?

“用编程代替提示词”并不意味着提示词消失了。DSPy 负责生成和管理提示词,人仍然要定义任务、分析失败,并决定结果是否可接受。

“编译”不意味着模型永久学会了什么。对于提示词优化器,学到并保存下来的内容是指令或示范样例。推理时仍然要调用模型,示范样例也会占用提示词空间。学习得到的状态可以保存为 JSON,再加载到一个新程序中。保存与加载。

“自动优化”也不意味着效果必然更好。真正有意义的比较,是在未见过的输入上与现有方案对照。开发阶段分数更高,可能只是过拟合、裁判标准太宽松,或数据集漏掉了代价高昂的失败场景。

还要注意,评估指标调用次数不等于模型服务商 API 调用次数。GEPA 的 max_metric_calls 限制的是评分函数调用次数;反思过程也会调用模型,而一次被评分的程序执行本身就可能发起多次请求。它的 auto 设置并不对应一个通用的账单金额。GEPA 预算控制。

工程师常问的 DSPy 问题

DSPy 的工作原理是什么?

先用签名声明输入和输出,选择或组合模块,再配置语言模型。适配器负责构建消息并解析结果。在此基础上,优化器可以结合样例和评估指标,改进程序中的指定部分。

DSPy 可以用于生产环境吗?

是否具备生产可用性,要看你自己的程序。固定包版本和模型配置,保留基线,测试有代表性的失败案例,并明确回滚条件。有一个当前发布版本,并不等于你的工作流已经通过验证。

现在还有必要使用 DSPy 吗?

有,前提是语言模型任务需要反复执行、效果可以衡量,而且提示词存在持续维护需求。如果简单提示词已能满足需要,或任务缺乏稳定的评测规则,DSPy 的价值就会小得多。

LangChain 和 DSPy 的主要区别是什么?

LangChain 是构建智能体的框架,提供模型和工具集成。DSPy 的侧重点是声明模型任务,再围绕评估指标优化程序。选择取决于要解决的问题:是把智能体的各个组件连接起来,还是系统性地改进一个可评分的任务。LangChain 概览。

DSPy 能用来优化提示词吗?

能。根据所选优化器,它可以筛选示范样例、修改指令,或同时搜索两者的组合。提示词优化不会改变底层模型权重;微调是另一条路径。

DSPy 是谁开发的?

DSPy 由 Omar Khattab 及其合作者开发。代码仓库归属 Stanford NLP 并在其名下维护;软件包的研究文献引用中列出了参与作者。项目与作者。

DSPy 的 GEPA 如何工作?

GEPA 把程序执行反馈交给反思模型,由它提出指令修改方案,再评估候选程序并返回选中的版本。具体的失败反馈能为搜索提供比单独分数更充分的依据,但这并不保证质量一定提升。

DSPy 框架的全称是什么?

根据官方软件包说明,DSPy 是 Declarative Self-improving Python 的缩写。

下一步怎么做?

周一,选一个反复出现的工单分流或信息提取错误,请流程负责人标注有代表性的样例。固定基线,定义评分规则,再运行一轮规模受控的实验。批准候选程序前,先检查哪些答案发生了变化。如果还无法定义分数,眼下最有价值的工作就是先把业务规则谈清楚。

订阅邮件,阅读实用的 AI 工程解析。

发布日期
分类
Build
Agent Skills 实战:一套技能如何在不同 AI 工具间复用

Agent Skills 实战:一套技能如何在不同 AI 工具间复用

Agent Skills 如何让一套流程在不同 AI 工具间复用?本文讲清 SKILL.md 规范,对照 Claude Code、Codex、Cursor、Gemini CLI 与 GitHub Copilot 的支持方式,用运营周报示例演示部署检查,并拆解上下文成本、MCP 的分工和权限边界。2026年10月15日Build
2026 嵌入模型选型指南:OpenAI、Gemini、Voyage 与开源方案怎么选

2026 嵌入模型选型指南:OpenAI、Gemini、Voyage 与开源方案怎么选

嵌入模型怎么选,才能让 RAG 和客服机器人稳定找到答案?本文对比 OpenAI、Voyage、Gemini、Cohere、Qwen、BGE 与 EmbeddingGemma,梳理价格、向量维度、输入限制、多语言与多模态能力、部署方式和许可证,并说明如何用自己的数据评估检索效果、核算存储成本,以及规划模型和索引迁移。2026年10月15日Build
LangSmith vs Langfuse:链路追踪、评估与自部署怎么选

LangSmith vs Langfuse:链路追踪、评估与自部署怎么选

LangSmith 和 Langfuse 怎么选?本文对比链路追踪、在线与离线评估、数据集、提示词管理、监控和自部署,结合 LangChain、LangGraph 与多框架团队的实际流程,说明云服务计费、开源许可、Enterprise 部署条件及迁移要点,帮助工程团队按审核协作方式和运维责任做出选择。2026年10月14日Build
ChatKit 后端如何迁移?OpenAI AgentKit 停用时间与迁移清单

ChatKit 后端如何迁移?OpenAI AgentKit 停用时间与迁移清单

OpenAI AgentKit 停用后,ChatKit 还能用,但依赖 Agent Builder 的应用必须替换后端。本文梳理 2026 年各项截止日期,说明如何导出工作流、选择 Agents SDK 或 Workspace Agents,并保存评测基线、迁移提示词对象,按权限、分支和结果完成验收。2026年10月14日Build
Base44 替代品怎么选?2026 年 7 款 AI 应用开发工具对比

Base44 替代品怎么选?2026 年 7 款 AI 应用开发工具对比

寻找 Base44 替代品?本文对比 Lovable、Bolt.new、Replit、v0、Emergent、Blink 和 Whacka,梳理美元订阅价格、免费额度、代码导出、数据库、托管和移动应用发布限制。按迁移需求筛选工具,算清构建与运行成本,并在切换前验证登录、数据和完整业务流程,避免只看入门价格就做决定。2026年10月14日Build
vLLM SGLang 对比:从前缀缓存到 GPU 成本,推理框架怎么选

vLLM SGLang 对比:从前缀缓存到 GPU 成本,推理框架怎么选

vLLM 和 SGLang 怎么选?本文从智能体与 RAG 的实际负载出发,对比前缀缓存、结构化 JSON、推测解码、multi-LoRA、硬件兼容性及云端部署,附容器示例和 GPU 成本计算。看清共享上下文何时值得调优、相同 GPU 配置为何费用相同,再根据延迟目标和实测容量判断是否迁移。2026年10月14日Build
LangChain 教程:对比 LlamaIndex,选对 RAG 与智能体框架

LangChain 教程:对比 LlamaIndex,选对 RAG 与智能体框架

LangChain 教程结合 LlamaIndex 对比,讲清 RAG 文档检索与智能体工具编排各自适合的框架。通过 Python 示例、版本与许可证说明,拆解 LlamaParse 和 LangSmith 的套餐、积分及月度费用,并说明何时组合使用、如何划分检索边界,以及迁移时怎样保留数据、权限和工作流状态。2026年10月13日Build
MCP是什么?一文读懂协议原理、API 区别与安全边界

MCP是什么?一文读懂协议原理、API 区别与安全边界

MCP是什么?模型上下文协议如何让 AI 应用接入工具和数据?本文梳理宿主、客户端与服务器的分工,解释 MCP 与 API、RAG 的区别,对比 Claude、ChatGPT、Cursor、VS Code 和 Codex 的接入方式,并说明费用、权限及提示词注入风险,帮助你判断是否需要 MCP,规划受控的只读试点。2026年10月13日Build
订阅通讯

每周日,一封信。写运转中的系统,不写热评。

每周一期。无垃圾邮件。随时退订。