
一句话总结: DSPy(Declarative Self-improving Language Programs)是由斯坦福 NLP 团队打造的声明式 LLM 编程框架,它彻底摒弃手工编写提示(prompt engineering)的做法,转而通过可学习的模块化组件(如 Retrieval、Generate、Predict)和自动优化器(如 BootstrapFewShot、MIPRO),让系统能根据任务指标(如准确率、F1)自动调整提示、示例甚至推理流程,实现“代码即提示,训练即优化”的范式跃迁。
自 2022 年 ChatGPT 爆火以来,“提示工程”(Prompt Engineering)成为连接人类意图与大模型能力的桥梁。无数开发者花费大量时间:
然而,这种做法存在根本性缺陷:
正如斯坦福 CRFM 实验室在 DSPy 论文中所言:
“Prompting is the new programming—but it shouldn’t be artisanal.”
DSPy 的诞生,正是为了将 LLM 编程从“手工艺”带入“工程化”时代。它不把提示视为静态字符串,而是可学习、可组合、可优化的程序组件。
自 2023 年开源以来,DSPy 已被 Google Research、Hugging Face、Together.ai 等机构用于构建鲁棒的 RAG 系统、问答代理和推理引擎,并在 HotPotQA、StrategyQA 等复杂 QA 基准上超越手工提示方案。
本文将深入剖析 DSPy 的核心思想、模块设计、优化机制及实战案例,展示如何用代码代替“提示调参”,构建可自我改进的 LLM 应用。
让我们看一个典型的手工提示:
prompt = f"""
You are an expert QA system.
Given the following context:
{context}
Answer the question: {question}
Be concise and only use information from the context.
"""
这种方法的问题在于:
更糟的是,当你切换到另一个模型(如从 GPT-4 切换到 Llama-3-70B),整个提示可能失效,需要重新设计。
**我们需要一个框架,让 LLM 程序具备“学习能力”**。
DSPy 的设计基于两大原则:
你只需**声明“要做什么”**,而非“怎么做”。例如:
框架负责选择合适的底层实现(如使用 BM25 还是向量检索,使用 zero-shot 还是 few-shot)。
提示中的关键部分(如指令、示例)不再是硬编码字符串,而是可被优化器更新的参数。优化目标是下游任务的指标(如问答准确率)。
这类似于传统 ML 中的“训练”:你提供输入-输出对,系统自动调整内部参数以最小化损失。
DSPy 将 LLM 程序分解为一系列可组合的模块(Modules),每个模块封装一种能力。
Retrieve:智能检索模块from dspy import Retrieve
retriever = Retrieve(k=3) # 自动使用内置的 ColBERTv2 或 FAISS
topK_passages = retriever(query="What is quantum computing?")
Predict / ChainOfThought:生成模块from dspy import Predict, ChainOfThought
# 简单预测
predictor = Predict("question -> answer")
# 思维链推理
cot = ChainOfThought("question -> reasoning, answer")
注意:这里没有写任何提示!DSPy 会自动生成初始提示模板。
ProgramOfThought:程序化推理(高级)对于数学或代码任务,可生成可执行的中间步骤:
from dspy import ProgramOfThought
pot = ProgramOfThought("question -> program, answer")
这是 DSPy 最革命性的部分——**优化器(Teleprompter)**。
你提供一个验证集(input-output pairs)和一个评估函数,DSPy 会自动优化你的程序。
BootstrapFewShot:自举式少样本学习from dspy.teleprompt import BootstrapFewShot
# 定义你的程序
class BasicQA(dspy.Module):
def __init__(self):
self.retrieve = dspy.Retrieve(k=3)
self.generate = dspy.Predict("context, question -> answer")
def forward(self, question):
context = self.retrieve(question).passages
return self.generate(context=context, question=question)
# 编译(即优化)
teleprompter = BootstrapFewShot(metric=validate_answer) # validate_answer 是你的评估函数
compiled_qa = teleprompter.compile(BasicQA(), trainset=devset)
MIPRO:贝叶斯优化提示MIPRO(Multivariable In-context Prompt Optimization)使用贝叶斯优化,同时调整:
实验表明,MIPRO 在多个基准上比手工提示提升 10–20% 准确率。
Ensemble:模块集成可自动组合多个优化后的程序,进一步提升鲁棒性。
假设我们要在 HotPotQA(多跳问答)上构建系统。
# 加载验证集(需包含 question, answer, gold_titles)
devset = [dspy.Example(question=q, answer=a).with_inputs("question")
for q, a in zip(questions, answers)]
class MultiHopRAG(dspy.Module):
def __init__(self):
self.retrieve = dspy.Retrieve(k=4)
self.generate_query = dspy.ChainOfThought("question -> search_query")
self.answer = dspy.ChainOfThought("context, question -> answer")
def forward(self, question):
# 第一跳
query1 = self.generate_query(question=question).search_query
context1 = self.retrieve(query1).passages
# 第二跳(基于第一跳结果生成新查询)
query2 = self.generate_query(question=f"{question} Given: {context1}").search_query
context2 = self.retrieve(query2).passages
final_context = "\n".join([context1, context2])
return self.answer(context=final_context, question=question)
teleprompter = MIPRO(prompt_model=dspy.GPT3_5_Turbo(), task_model=dspy.Claude2())
optimized_rag = teleprompter.compile(MultiHopRAG(), trainset=devset)
# 在测试集上评估
score = evaluate(optimized_rag, testset, metric=exact_match)
# 部署时直接调用
response = optimized_rag(question="Who founded the company that makes TensorFlow?")
整个过程无需手动写一行提示!
维度 | LangChain / LlamaIndex | DSPy |
|---|---|---|
编程范式 | 命令式(Imperative) | 声明式(Declarative) |
提示管理 | 手工编写、硬编码 | 自动优化、可学习 |
模型切换 | 需重写提示 | 几乎无需修改代码 |
优化目标 | 无(依赖人工) | 直接优化任务指标 |
适用场景 | 快速原型、简单 RAG | 需要高准确率、可复现的生产系统 |
关键区别:
斯坦福团队正开发 DSPy Studio(可视化优化平台),未来将进一步降低使用门槛。
DSPy 代表了 LLM 编程的下一个范式:从写提示到写程序,从人工调参到自动优化。它不是否定提示工程,而是将其提升到工程化、可扩展的新高度。
对于追求高准确率、强鲁棒性、跨模型兼容的 AI 应用,DSPy 提供了一条通往生产级系统的清晰路径。
正如其文档所言:
“Stop prompting. Start programming.”