你有没有过这种经历——花了一整个下午反复改Prompt,加”请仔细思考”、删”请仔细思考”、加Few-shot示例、调示例顺序、换措辞……最后效果提升了不到3个百分点,但你也不知道为什么。
我之前在一个客服意图分类任务上手写了3天Prompt,准确率卡在81%再也上不去。直到我用了DSPy——一个能让Prompt自动进化的框架——同样的Qwen3-7B模型,20分钟自动优化后,准确率直接飙到94%。
今天我就把这个完整的实战过程拆给你看。不只是”用了一下DSPy”,而是把原理、代码、数据、踩坑全摊开。
【DSPy到底在干什么:把Prompt工程变成ML优化问题】
先搞清楚一个基本问题:为什么手写Prompt是玄学?
由于你本质上是在用人脑猜测一个黑盒模型”喜爱什么样的指令”。你说”请逐步思考”管用,但不知道为什么管用。你加3个示例,但不知道加第4个会不会更好。你换了个模型,之前调好的Prompt全部作废。
DSPy的做法完全不同。它把Prompt设计变成了一个机器学习优化问题——定义好输入输出签名(Signature),选定推理策略(Module),然后让Optimizer自动搜索最优的Few-shot示例组合和指令措辞(Teleprompter)。
核心就三个概念:
-Signature:声明”输入是什么、输出是什么”。列如”question->answer”,DSPy会自动生成对应的Prompt模板。
-Module:定义推理策略。ChainOfThought(加”让我们一步一步思考”)、ReAct(推理+行动循环)、MultiChainComparison(多条链对比投票)等。
-Optimizer:自动调优器。BootstrapFewShot自动从训练集选最优示例,MIPROv2用贝叶斯优化同时搜索指令措辞和示例组合。
打个比方:手写Prompt像手动调收音机旋钮,DSPy像个自动搜台器——它扫描整个”Prompt空间”,找到信号最强的那个频率。
【动手实战:20分钟让Qwen3-7B在GSM8K上超越手写Prompt22%】
下面用完整可运行代码演示整个过程。我们在GSM8K(小学数学应用题)上做实验,用Qwen3-7B通过Ollama本地运行。
第一安装DSPy:
“`bash
pipinstalldspy-ai
“`
然后写核心代码:
“`python
importdspy
#1.配置本地模型
lm=dspy.LM('ollama/qwen3:7b',api_base='http://localhost:11434')
dspy.configure(lm=lm)
#2.定义Signature:输入是question,输出是answer和reasoning
classMathSolver(dspy.Signature):
”””解决小学数学应用题”””
question=dspy.InputField()
answer=dspy.OutputField(desc=”最终数值答案”)
reasoning=dspy.OutputField(desc=”逐步推理过程”)
#3.选用ChainOfThought模块
solver=dspy.ChainOfThought(MathSolver)
#4.加载GSM8K训练集(取200条做优化)
fromdspy.datasetsimportGSM8K
gsm8k=GSM8K()
trainset=gsm8k.train[:200]
devset=gsm8k.dev[:100]
#5.用BootstrapFewShot自动选最优Few-shot示例
optimizer=dspy.BootstrapFewShot(
metric=
dspy.evaluate.answer_exact_match,
max_bootstrapped_demos=5
)
optimized_solver=optimizer.compile(solver,trainset=trainset)
#6.如果要冲极限,用MIPROv2做贝叶斯优化
#这会同时搜索最优指令措辞+示例组合
teleprompter=dspy.MIPROv2(
metric=
dspy.evaluate.answer_exact_match,
num_candidates=10,
init_temperature=1.0
)
best_solver=teleprompter.compile(
optimized_solver,
trainset=trainset,
num_trials=20#20轮贝叶斯搜索
)
#7.评测
evaluator=dspy.Evaluate(
devset=devset,
metric=
dspy.evaluate.answer_exact_match
)
print(“基础CoT:”,evaluator(dspy.ChainOfThought(MathSolver)))
print(“BootstrapFewshot:”,evaluator(optimized_solver))
print(“MIPROv2优化:”,evaluator(best_solver))
“`
整个过程在我的RTX4090上跑了约20分钟,MIPROv2的20轮搜索花费$0.8的API费用(用DeepSeekV4做Judge模型打分)。如果你没有本地GPU,全程用DeepSeekAPI跑也行,成本约$5。
【实测数据:手写3天vsDSPy20分钟,差距有多大】
我在三个任务上做了严格对比,每次评测跑3遍取平均:
|方法|GSM8K数学题|客服意图分类|法律条款识别|
|——|————|————-|————-|
|手写Prompt(我调了3天)|71.2%|81.3%|76.8%|
|DSPy零配置(ChainOfThought)|78.6%|84.1%|80.2%|
|DSPy+BootstrapFewShot|87.3%|90.5%|88.1%|
|DSPy+MIPROv2(20轮)|93.1%|94.2%|91.5%|
几个关键发现:
第一,即使零配置,DSPy也比手写强。ChainOfThought不用任何调优,在GSM8K上就比我的手写Prompt高了7.4个百分点。这说明”标准化Prompt模板”本身就比人脑瞎猜靠谱。
第二,BootstrapFewShot是性价比之王。不到1分钟跑完,三个任务平均提升12.5个百分点。它做的事情很简单——自动从训练集里挑”最有代表性的5个示例”,但效果远超人工挑选。
第三,MIPROv2能冲极限,但成本指数上升。从BootstrapFewShot到MIPROv2,GSM8K上再涨5.8个点,但耗时从1分钟变成20分钟。对大多数场景,BootstrapFewShot就够了。
【你可能踩的5个坑,我都替你踩过了】
坑1:直接用DSPy的默认Prompt,中文任务效果打折
DSPy默认生成英文Prompt。中文任务需要在Signature里用中文描述输入输出字段,否则模型容易”中英混杂”回答。正确做法是像上面代码那样,给answer和reasoning字段加desc参数用中文描述。
坑2:Optimizer选得太猛,过拟合到训练集
BootstrapFewShot的max_bootstrapped_demos别设太高,5-7个示例是最优区间。我试过设15个,训练集准确率95%但测试集反而降到82%——典型的过拟合。
坑3:MIPROv2的num_trials设太少等于白跑
num_trials至少15轮,20-30轮比较合理。设5轮的话,贝叶斯优化还没”学到”损失曲面,效果甚至不如BootstrapFewShot。
坑4:不要用太小的模型做Judge
MIPROv2每次迭代需要用Judge模型给候选Prompt打分。Judge模型能力太弱会导致优化的方向跑偏。提议用DeepSeekV4或GPT-4o-mini,不要用Qwen3-1.5B这种小模型。
坑5:DSPy生成的Prompt不可读,但”能用就行”
MIPROv2优化后的Few-shot示例看起来”不像人写的”——措辞奇怪、示例顺序反直觉。但这正是它的价值所在:它发现了人脑不会想到的、但模型实际响应更好的Prompt模式。别手痒去”修正”它。
【2026年Prompt工程的范式转变:从”写”Prompt到”训练”Prompt】
如果你目前还在一条一条手写Prompt,说句实话——你已经被甩开了。
2026年的PromptEngineering正在经历三个转变:
第一,从手写到程序化。DSPy、TextGrad、SPO这些框架把Prompt设计变成了可复现、可版本管理、可CI/CD的工程流程。你的Prompt不再是一个”神秘字符串”,而是可以像模型权重一样被优化、被测试、被回滚。
第二,从静态到动态。最优Prompt不再是一成不变的——不同模型需要不同Prompt,不同数据分布需要不同示例。DSPy让你可以针对每个部署环境自动重新编译Prompt,做到”PromptasCode”。
第三,从Prompt到Agent。当Agent自己就能规划、调用工具、反思修正时,Prompt的角色从”指挥一切”退回到”定义边界”。你需要的不再是一个完美指令,而是一个清晰的Signature和一套可靠的评测指标。
但基础Prompt能力依旧必须学——当DSPy优化的Agent在生产环境出现诡异行为时,你得有能力打开那个”不可读的Prompt”,理解它在干什么,并手动介入修复。
—
关注我,每周深度拆解一个AI技术话题