我停止写提示词,开始写 Python
Source: Dev.to
Prompt 混乱
一年里,我把大语言模型当成命令行使用:输入指令,祈祷输出,微调措辞,添加 “IMPORTANT:”,像仪式一样移动句子。结果我积累了一堆提示文件:
v1.txt
v2_final.txt
v2_final_REALLY_final.txt这些文件都没有记录为什么它们能工作。当出现问题时,我根本分不清是提示、模型还是数据出了错。没有版本控制,没有测试——只有感觉。
迎接 DSPy
DSPy(来自斯坦福 NLP)把模型翻转了:你不写提示,你写 Python。
class AnalyzeStartup(dspy.Signature):
"""Analyze a startup pitch."""
pitch: str = dspy.InputField()
viability_score: int = dspy.OutputField()
strengths: list[str] = dspy.OutputField()
weaknesses: list[str] = dspy.OutputField()
verdict: str = dspy.OutputField()就这么简单——不需要 “You are an expert startup analyst…”,也不需要 “Respond in JSON format…”。DSPy 会把这个签名编译成提示。当你需要更好的提示时,运行优化器;DSPy 会根据有效示例重写提示。
从提示技巧到签名
之前:
“如果我把示例放在指令前面,效果会更好。有时。除非是 GPT‑4o。”
之后:
我只写一个签名。DSPy 会找出最佳的提示格式。提示成为实现细节;我关心的是输入、输出和行为——而不是措辞。
可测试的 LLM 代码
之前:
手动检查输出。
之后:
def test_startup_analyzer():
result = startup_analyzer(pitch="We're building AI for dog grooming...")
assert 1 0
assert len(result.weaknesses) > 0真实的测试写在我的测试套件里,使用断言。
一行代码切换模型
之前:
每个模型都需要单独的提示调优(GPT‑4、Claude、Gemini 等)。
之后:
# Swap models
lm = dspy.LM("openai/gpt-4o-mini")
# lm = dspy.LM("anthropic/claude-3-sonnet")
# lm = dspy.LM("gemini/gemini-2.0-flash")
dspy.configure(lm=lm)同样的代码,换不同的模型。DSPy 负责提示的转换。
优化器完成调优
我不再手动微调提示,而是给 DSPy 提供好的输出示例,让它自行找出最佳提示:
optimizer = BootstrapFewShot(metric=my_metric, max_bootstrapped_demos=4)
optimized = optimizer.compile(StartupAnalyzer(), trainset=train_examples)DSPy 运行实验,找到有效示例,构建提示,我只需审阅结果。
范式转变
- 旧方式: LLM 是你用英语对话的魔盒;成功取决于提示技巧。
- DSPy 方式: LLM 是函数调用。你声明接口,框架负责实现。
这就像在代码库中散落原始 SQL 查询与使用 ORM 的区别:前者脆弱、无类型、难以重构;后者结构化、可测试、易于维护。
更深入的探索
我写了一本关于使用 DSPy 的完整指南——实用章节、真实代码以及艰难的经验教训。它叫 Harmless DSPy;如果想先看看是否适合你,第一章是免费的。
DSPy 由 Omar Khattab 和斯坦福 NLP 团队开发。它是开源的,积极维护,已经真正改变了我使用 LLM 的方式。