Mindket

DSPy 教程:让代码和指标来优化你的提示词

黑色横幅,标题是“提示词优化”,下面是“用 AI 生成、改进和测试提示词”。

DSPy 是一个开源的 Python 框架,让你用编程的方式驱动语言模型,而不是手写它的提示词。你用签名声明输入和输出,选一个像 ChainOfThought 这样的模块,写一个给回复打分的指标,再拿几个例子运行优化器。优化器会替你写出更好的指令,并挑选示例。

本节内容

  • 签名声明输入是什么、输出是什么,提示词具体怎么措辞,交给优化器。
  • 文档说,优化器可以从少到五个或十个训练输入起步,再配上你的程序和你的指标。
  • 指标就是一个返回分数的普通 Python 函数,所以在运行任何优化器之前,先把它写好并检查一遍。
  • 优化后的程序会存成纯文本 JSON,你可以打开来读。
全部课程
本页目录
  1. 开始之前
  2. 三个阶段,按这个顺序来
  3. 第 1 步:写签名,而不是写提示词
  4. 第 2 步:选一个模块,设置模型
  5. 第 3 步:收集例子,写指标
  6. 第 4 步:选一个优化器
  7. 第 5 步:在文档的示例上运行 MIPROv2
  8. 把它们合起来,用在你自己的提示词上
  9. 文档报告了什么,你该期待什么
  10. MIPROv2 的发布帖怎么说,以及 DSPy 清单里的一场讲座
  11. 常见错误
  12. 动手试试
  13. 下一门课:上下文工程
  14. 自测一下
  15. 常见问题
  16. 资料来源

开始之前

DSPy 的 README把它称作“编程而不是提示”语言模型的框架,还说这个名字代表 Declarative Self-improving Python,也就是声明式、能自我改进的 Python。你用代码描述任务,DSPy 据此生成提示词,优化器再对照你定义的分数去调整这条提示词。

第 1 到 3 课写了一条提示词,改进了它,又手动测试了各个版本。DSPy 替你跑这个循环:它尝试很多版本,用你的例子给每个版本打分,留下最好的。你需要 Python、一个你的 API 密钥能调用的模型,以及一些例子。PyPI 上的软件包记录显示,最新版本是 3.4.1,2026 年 10 月 12 日上传,支持 Python 3.10 到 3.16(不含 3.16)。用 pip install dspy 安装。

这是整门课里技术性最强的一课。如果你不写 Python,就读它的思路:第 3 课的测试集成了训练数据,你的通过规则成了指标。

三个阶段,按这个顺序来

DSPy 的概览写出了三个阶段,并建议按这个顺序学习和应用。它给出的理由是:在设计糟糕的程序或糟糕的指标上启动优化运行,是没有成效的。

DSPy 建议的 AI 系统搭建顺序
  1. 编程

    定义任务和约束,试几个例子,设计第一版流程。从简单开始,也许只用一个 ChainOfThought 模块。

  2. 评估

    收集一份开发集,定义指标,给系统打分。这个分数是之后一切改动的基线。

  3. 优化

    用优化器,对照你的指标去调整提示词或模型权重。

来源:DSPy docs on GitHub: Learning DSPy, an overview (2026年11月6日 查阅)

第 1 步:写签名,而不是写提示词

按 DSPy 的说法,签名是对模块输入输出行为的声明式说明。它告诉模型要做什么,不管怎么问。字段名是有含义的:question 不是 answer,sql_query 也不是 python_code。

最短的写法是一个字符串,比如 question -> answer 或 document -> summary。任务需要规则时,就加上指令。我们的建议是把你自己提示词里的规则放进去。任务更长时,写一个带文档字符串的类,并用 desc 描述某个字段。

文档建议一开始不要手动调签名里的关键词。优化器多半做得更好,结果也能换到别的模型上继续用。

import dspy

# An inline signature, with instructions
toxicity = dspy.Predict(
    dspy.Signature(
        "comment -> toxic: bool",
        instructions="Mark as 'toxic' if the comment includes insults, harassment, or sarcastic derogatory remarks.",
    )
)
comment = "you are beautiful."
toxicity(comment=comment).toxic
# Output: False

# A class-based signature
from typing import Literal

class Emotion(dspy.Signature):
    """Classify emotion."""

    sentence: str = dspy.InputField()
    sentiment: Literal['sadness', 'joy', 'love', 'anger', 'fear', 'surprise'] = dspy.OutputField()
出自 DSPy 的签名页面内联签名,2026 年 11 月 6 日阅读。默认类型是 str。
任务写成字符串的签名
问答question -> answer
情感分类sentence -> sentiment: bool
摘要document -> summary
基于段落的问答context: list[str], question: str -> answer: str
带推理的选择题question, choices: list[str] -> reasoning: str, selection: int

第 2 步:选一个模块,设置模型

模块把签名变成一次模型调用,并对它施加某种技巧。dspy.Predict 是最基础的一个,模块页面说其他模块都是以它为基础搭起来的。用 dspy.LM 设置一次模型就行。文档里的 OpenAI 示例从 OPENAI_API_KEY 读取密钥,语言模型页面还给出了 gemini/ 和 anthropic/ 前缀,以及各自的密钥变量。

用签名声明模块,把输入字段当关键字参数去调用它,再从结果里读输出字段。把 dspy.Predict 换成 dspy.ChainOfThought,模型会先一步一步推理。文档说,在很多情况下仅这一步就能提高质量,结果里还会多出一个 reasoning 字段。

更大的程序是一个装着几个模块的类,用 __init__ 声明模块,用 forward 去调用它们。编程页面建议先用单个模块,只有当输出里看到的问题需要时,才加步骤。

import dspy

# Authenticate via the OPENAI_API_KEY environment variable
lm = dspy.LM('openai/gpt-4o-mini')
dspy.configure(lm=lm)

sentence = "it's a charming and often affecting journey."  # example from the SST-2 dataset.

# 1) Declare with a signature.
classify = dspy.Predict('sentence -> sentiment: bool')

# 2) Call with input argument(s).
response = classify(sentence=sentence)

# 3) Access the output.
print(response.sentiment)
# Output: True
出自模块页面,2026 年 11 月 6 日阅读。
模块它做什么
dspy.Predict基础预测器,不改动签名。
dspy.ChainOfThought让模型在回答之前一步一步思考。
dspy.ReAct可以调用工具来完成签名的智能体。
dspy.MultiChainComparison比较多个 ChainOfThought 的输出,得出最终预测。
dspy.RLM通过沙盒 Python REPL 和递归的子模型调用,去探索很大的上下文。
dspy.majority一个投票函数,从多个预测里返回票数最多的那个。

第 3 步:收集例子,写指标

你的例子是 dspy.Example 对象,用起来像字典。数据页面里的 with_inputs 标出哪些字段是输入,其余的算标签。看指标是什么,你只需要输入,或者需要输入加最终输出。文档说,中间各步的标签你几乎用不上。

指标是一个函数,接收一个例子和程序的输出,返回一个分数。它还接受一个可选的第三个参数 trace,一开始可以不管。短答案用精确匹配就够了。长回复的话,文档建议写一个检查多项属性的小 DSPy 程序,必要时让模型当评判。文档还说,第一次就写对的可能性不大,所以先从简单的写起,再迭代。

先写指标,再去优化任何东西,因为你定义不出来的东西,很难持续改进。然后用 Evaluate 工具在开发集上给没优化的程序打分。它可以多线程运行,并打印一部分输入、输出和分数。这个分数就是你的基线。

import dspy

article_summary = dspy.Example(article="This is an article.", summary="This is a summary.").with_inputs("article")

def validate_answer(example, pred, trace=None):
    return example.answer.lower() == pred.answer.lower()

from dspy.evaluate import Evaluate

# Set up the evaluator, which can be re-used in your code.
evaluator = Evaluate(devset=YOUR_DEVSET, num_threads=1, display_progress=True, display_table=5)

# Launch evaluation.
evaluator(YOUR_PROGRAM, metric=YOUR_METRIC)
  • 对大多数提示词优化器,文档推荐一种不寻常的划分:20% 用于训练,80% 用于验证,原因是提示词优化器常常在小训练集上过拟合。
  • GEPA 是例外。它沿用通常的做法:训练集尽量大,验证集只要大到足以反映真实任务就行。
  • 另外留一份测试集,和前两者分开,进入优化阶段后,文档建议这样做。
出自 DSPy 的优化器、评估和优化页面,2026 年 11 月 6 日阅读。
用途文档说可以从这么多开始文档说最好达到
给优化器的训练输入5 或 10 个例子,只要输入有更多就更好
给程序打分的开发集20 个输入例子200 个
用于优化的训练集30 个例子至少 300 个

第 4 步:选一个优化器

优化器接收你的程序、你的指标和一些训练输入,返回一个更好的程序。优化器页面说,它可以调整提示词、模型权重,或者两者都调。先用哪一个,取决于你有多少数据。最后一列是文档自己给的入门建议。

GEPA 不在那份建议里。它是一种反思式优化器:由一个模型读程序是怎么失败的,依据是你的指标连同分数一起返回的文字反馈,再提出更好的指令。

转述自 DSPy 的优化器页面和 GEPA 页面,2026 年 11 月 6 日阅读。
优化器它调整什么文档说在这些情况下先用它
BootstrapFewShot少样本示例,通过运行你的程序生成,指标通过的才保留例子很少,十个上下
BootstrapFewShotWithRandomSearch同样的做法,用随机搜索重复多次有 50 个或更多例子
MIPROv2指令和少样本示例一起调,或者只调指令只想优化指令,或者能跑更长的运行(40 次或更多试验)并有 200 个或更多例子
GEPA指令,通过对失败的反思和文字反馈来调不在入门建议里,它的指标返回分数和反馈文字
BootstrapFinetune模型的权重大模型能用,而你需要一个高效的程序,于是微调一个小模型

第 5 步:在文档的示例上运行 MIPROv2

MIPROv2 页面有一个完整的示例,用来优化一个数学程序。它先设置模型,再用 auto="medium" 创建优化器,在 GSM8K 训练集上编译单个 dspy.ChainOfThought("question -> answer"),最后保存结果。auto 可以取 light、medium 或 heavy。

先弄懂 MIPROv2,因为它调的东西最多。页面把它的工作分成三步。

import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric

# Import the optimizer
from dspy.teleprompt import MIPROv2

# Initialize the LM
lm = dspy.LM('openai/gpt-4o-mini', api_key='YOUR_OPENAI_API_KEY')
dspy.configure(lm=lm)

# Initialize optimizer
teleprompter = MIPROv2(
    metric=gsm8k_metric,
    auto="medium", # Can choose between light, medium, and heavy optimization runs
)

# Optimize program
print(f"Optimizing program with MIPROv2...")
gsm8k = GSM8K()
optimized_program = teleprompter.compile(
    dspy.ChainOfThought("question -> answer"),
    trainset=gsm8k.train,
)

# Save optimize program for future use
optimized_program.save(f"optimized.json")
  1. 自举少样本示例:把训练例子送进你的程序,留下输出正确的那些。
  2. 提出指令:由一个模型写出候选指令,依据是你数据的摘要、你程序代码的摘要、自举出来的示例,以及一条随机的提示,比如“发挥创意”或“简明扼要”。
  3. 搜索:贝叶斯优化决定哪些指令和示例搭配在一起。它在小批量上跑 num_trials 次试验,再把最好的在完整验证集上检查一遍。

把它们合起来,用在你自己的提示词上

下面的脚本把上面的片段合成一次运行,用在你自己的任务上。它是我们为这一课把文档里出现过的调用拼在一起的,我们没有运行过。换上你自己的规则、例子和指标,再把模型名换成你的密钥能调用的模型。

脚本后面的编号步骤是工作的顺序。第一次运行用 light 模式,文档里那个便宜的示例就是这样用的。

import dspy
from dspy.evaluate import Evaluate

dspy.configure(lm=dspy.LM('openai/gpt-4o-mini'))

# 1. Your task as a program: your prompt's rules go in the instructions.
program = dspy.ChainOfThought(
    dspy.Signature(
        'question -> answer',
        instructions='PASTE THE RULES FROM YOUR PROMPT HERE',
    )
)

# 2. Your examples, with the input fields marked. Fill in your own rows.
trainset = [
    dspy.Example(question='...', answer='...').with_inputs('question'),
]
devset = [
    dspy.Example(question='...', answer='...').with_inputs('question'),
]

# 3. Your metric: the pass rule you wrote in lesson 3, as a function.
def validate_answer(example, pred, trace=None):
    return example.answer.lower() == pred.answer.lower()

# 4. Score the program before you change anything.
evaluator = Evaluate(devset=devset, num_threads=1, display_progress=True, display_table=5)
evaluator(program, metric=validate_answer)

# 5. Optimize in the cheapest mode, then score again on the same devset.
optimizer = dspy.MIPROv2(metric=validate_answer, auto='light')
optimized = optimizer.compile(program, trainset=trainset)
evaluator(optimized, metric=validate_answer)

# 6. Save it. The file is plain JSON, so you can read what the optimizer wrote.
optimized.save('optimized.json')
  1. 至少写 50 个你的任务例子,包含输入和你期望的输出。文档说,20 个例子作开发集就有用,30 个例子作训练集就能带来明显的价值,所以开发列表放 20 个,训练列表放 30 个,有条件再多加一些。
  2. 把你的提示词改成签名:输入输出字段照写,你的规则放进指令里。
  3. 写指标时,让它通过的,正是你在第 3 课里手动会判为通过的。
  4. 运行脚本。它会给程序打分,用 MIPROv2 的 light 模式优化它,再打一次分,然后保存。
  5. 打开 optimized.json,读一读优化器选出的指令和示例。文档说这个文件包含每个参数和步骤,所以你能看到它生成了什么。
  6. 只有开发集的分数上升了,而且你在意的那些失败消失了,才保留这次改动。

文档报告了什么,你该期待什么

优化器页面给出了三次运行优化前后的分数,没有给运行日期。对 ReAct 和 Banking77 这两组,它说的是:在 DSPy 2.5.29 这个较早版本上,一次和上面那个示例类似的非正式运行,把分数提高了。这两个示例用的都是 GPT-4o-mini,Banking77 那一处页面还直接点了名。对 RAG 那一组,它只指向一篇教程,没有给出模型、版本或日期。把这些柱子当作改动的大致幅度来读,不要当成承诺。每一对对应不同的任务和指标,所以一根柱子只和紧挨着它的那根比。

关于时间和成本,文档把一次简单的优化运行说成大约十分钟,还说成本随模型、数据集和设置差别很大。它提醒你,对很大的模型或数据集要小心。

优化前后的分数,按文档的报告百分比,照优化器页面所印,页面没有给运行日期。金色的柱子是优化后的程序。ReAct 和 Banking77 两组是 DSPy 2.5.29 上、用 GPT-4o-mini 示例做的非正式运行,RAG 那一组出自一篇教程,教程没有点出模型或版本。最后一对微调的是模型权重,所以不属于提示词的改动。
  • ReAct 智能体,优化前24%
  • ReAct 智能体,用 MIPROv2 优化后51%
  • StackExchange 上的 RAG,优化前53%
  • StackExchange 上的 RAG,优化后61%
  • Banking77 分类,优化前66%
  • Banking77 分类,用 BootstrapFinetune 优化后87%

来源:DSPy docs on GitHub: Optimizers (2026年11月6日 查阅)

MIPROv2 的发布帖怎么说,以及 DSPy 清单里的一场讲座

MIPROv2 页面把 X 上的一个长帖当作可视化讲解。它由 Michael Ryan 在 2024 年 6 月 21 日发布,他把 MIPROv2 称作“我们新的、最先进的语言模型程序优化器”。他那句话的总结,正好用来检验你有没有弄懂:如果你能说出其中三个动词各做什么,思路你就有了。

如果你想先看再写代码,DSPy 的资源页面列出了关于这个项目的讲座、博客文章和播客。下面是其中一个,Databricks 的录像。

MIPROv2 会提出指令、自举示例,并优化它们的组合。

Michael Ryan (@michaelryan207), 称 MIPROv2 是“我们的”优化器,引文为译文 · X (2026年11月6日 查阅)
Michael Ryan(@michaelryan207)在 X 上发帖,2024 年 6 月 21 日:我们新的、最先进的语言模型程序优化器 MIPROv2 已在 DSPy 中上线。它比 MIPRO 更快、更省钱、更准确。MIPROv2 会提出指令、自举示例,并优化它们的组合。
Michael Ryan 在 X 上,2024 年 6 月 21 日
Databricks 频道发布的录像,DSPy 自己的资源页面把它列为 DSPy 3.0 and DSPy at Databricks。

X 官方嵌入卡片的截图,拍摄于 2026 年 11 月 6 日,时间为 UTC。这条帖子是一个长帖的开头,后面的帖子不在截图里。点击截图可到 X 上打开原帖。

常见错误

  • 指标还没跑通就启动优化器。文档称这样做没有成效,所以先拿几条你已经手动判过的输出,去检查指标。
  • 用优化器训练过的例子去给优化后的程序打分。开发集或测试集要单独留出来。
  • 一次都没运行就手动改签名里的措辞。让第一次优化运行去做这件事。
  • 信任一个让模型来评判的指标,却不读几条它的判语。评判那一课讲了怎样检查。
  • 指望在你的任务上得到文档里的数字。其中两个来自 DSPy 2.5.29 这个较早版本上的非正式运行,第三个来自一篇教程,用的都是文档自己的模型和数据。
  • 一上来就在大模型上跑重量级的运行。先从 light 开始。

动手试试

  • 运行 pip install dspy,用你自己的密钥跑文档里的情感示例,先用 dspy.Predict,再用 dspy.ChainOfThought。
  • 把你在第 2 课改进过的提示词,改成带指令的签名。
  • 写出你的第一批例子和一个指标,改动之前先给程序打分。
  • 用 light 模式运行 MIPROv2,打开保存下来的 JSON,比较前后两个分数。

下一门课:上下文工程

现在,你能生成、改进、测试并自动调优一条提示词了。上下文工程课程把视野放宽,因为提示词只是 AI 智能体在每一步所看到内容的一部分。

自测一下

  1. DSPy 的签名声明的是什么?

    查看答案

    B. 输入是什么、输出是什么,而不是怎么问 文档把签名称作对模块输入输出行为的声明式说明。它说明模型要做什么,不管怎么问。

  2. DSPy 优化器需要哪三样东西?

    查看答案

    D. 一个程序、一个指标和一些训练输入 优化器页面说,典型的优化器需要你的程序、你的指标和少量训练输入,少到 5 或 10 个也行。

  3. optimized_program.save(path) 写出的是什么?

    查看答案

    C. 你能读懂的纯文本 JSON 文档说,生成的文件是纯文本 JSON,包含所有参数和步骤,所以你能读到优化器生成了什么。

  4. 启动优化运行之前,应该先具备什么?

    查看答案

    A. 设计良好的程序和好的指标 概览说,在设计糟糕的程序或糟糕的指标上启动优化运行,是没有成效的。

常见问题

DSPy 用来做什么?

它用来把语言模型的调用搭成程序,而不用手写每一条提示词。它的 README 举了简单分类器、RAG 流程和智能体循环作例子,按我们的理解,它们的共同点是输出可以打分的任务。

DSPy 怎样优化提示词?

优化器在训练例子上运行你的程序,用你的指标给结果打分,留下得分最高的。按优化器不同,它会写新的指令、挑少样本示例,或者两者都做。MIPROv2 用贝叶斯优化来搜索各种组合。

DSPy 需要多少个例子?

先有一小把就够起步了,输入也不需要标签。文档给开发集和训练集定的目标数量则更大。

DSPy 比手写提示词更好吗?

项目自己说,往往是的。它的签名页面说,在很多情况下,编译得到的提示词比人写的更好,原因是优化器能尝试更多做法,并直接针对指标调整,而不是更有创意。请在你自己的开发集上验证。

用 DSPy 需要会 Python 吗?

需要,DSPy 是一个 Python 库,你要写一个简短的脚本。这一课里的代码大多是一个签名、一个指标函数和几次调用,都是从 DSPy 文档里照抄的。

DSPy 能用 Claude 和 Gemini 吗?

能。文档的语言模型页面展示了 OpenAI、Gemini 和 Anthropic 的模型,还有 Vertex AI、Azure OpenAI、Databricks,以及 GPU 服务器上的本地模型。

资料来源

  1. DSPy on GitHub: README (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/README.md
  2. DSPy docs on GitHub: Learning DSPy, an overview (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/index.md
  3. DSPy docs on GitHub: Programming in DSPy (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/programming/overview.md
  4. DSPy docs on GitHub: Signatures (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/programming/signatures.md
  5. DSPy docs on GitHub: Modules (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/programming/modules.md
  6. DSPy docs on GitHub: Language models (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/programming/language_models.md
  7. DSPy docs on GitHub: Evaluation in DSPy (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/evaluation/overview.md
  8. DSPy docs on GitHub: Data (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/evaluation/data.md
  9. DSPy docs on GitHub: Metrics (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/evaluation/metrics.md
  10. DSPy docs on GitHub: Optimization in DSPy (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/optimization/overview.md
  11. DSPy docs on GitHub: Optimizers (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/learn/optimization/optimizers.md
  12. DSPy docs on GitHub: MIPROv2 (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/api/optimizers/MIPROv2.md
  13. DSPy docs on GitHub: GEPA overview (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/api/optimizers/GEPA/overview.md
  14. DSPy docs on GitHub: Resources (2026年11月6日 查阅)https://github.com/stanfordnlp/dspy/blob/main/docs/docs/community/community-resources.md
  15. PyPI: dspy package record (2026年11月6日 查阅)https://pypi.org/pypi/dspy/json
  16. X: Michael Ryan on MIPROv2 (2026年11月6日 查阅)https://x.com/michaelryan207/status/1804189184988713065
  17. YouTube: Databricks, DSPy 3.0 and DSPy at Databricks (2026年11月6日 查阅)https://www.youtube.com/watch?v=grIuzesOwwU

分享本节课

用之前,先看看开源 AI 项目

在 Mindket 浏览开源项目和它们的安装说明,打开一个看看作者怎样组织里面的提示词。

浏览 GitHub 项目

本节课的 Markdown 版本 · 提示词优化:让 AI 帮你写、改进并测试提示词 · 全部课程