DSPy 是什么:Prompt 工程的范式转换

传统 Prompt 工程的核心痛点:Prompt 是手写的、脆弱的、不可优化的。你花数小时调出一个"看起来不错"的 Prompt,换个模型就失效了。DSPy 提出了一个激进的想法——不要手写 Prompt,让框架自动优化

DSPy(Declarative Self-improving Language Programs)来自斯坦福 NLP 组,核心理念是将 LLM 编程从"写 Prompt"转变为"声明意图 + 自动优化"。

核心架构:三件套

Signature:声明输入输出

import dspy

# 声明式定义:输入是什么,输出是什么
class QA(dspy.Signature):
    """回答问题,基于给定上下文"""
    context: str = dspy.InputField(desc="参考文档")
    question: str = dspy.InputField(desc="用户问题")
    answer: str = dspy.OutputField(desc="简洁准确的回答")

class Summarizer(dspy.Signature):
    """生成长文本的摘要"""
    text: str = dspy.InputField(desc="原始文本")
    summary: str = dspy.OutputField(desc="200字以内的摘要")

Signature 的关键在于:你只描述"做什么",不描述"怎么做"。框架会根据 Signature 自动生成 Prompt。

Module:组合 LLM 逻辑

# 类似 PyTorch 的模块化设计
class RAG(dspy.Module):
    def __init__(self):
        self.retrieve = dspy.Retrieve(k=3)
        self.generate = dspy.ChainOfThought(QA)
    
    def forward(self, question):
        context = self.retrieve(question).passages
        prediction = self.generate(context=context, question=question)
        return dspy.Prediction(answer=prediction.answer)

# 使用
rag = RAG()
result = rag(question="量子计算的基本原理是什么?")
print(result.answer)

DSPy 内置模块:

模块功能
dspy.Predict基础预测,直接调用 LLM
dspy.ChainOfThought链式思考,让模型先推理再回答
dspy.ReAct推理+行动循环(工具调用)
dspy.Retrieve检索模块
dspy.MultiChainComparison多路 CoT 对比

Teleprompter:自动 Prompt 优化

这是 DSPy 的杀手级能力。Teleprompter 会自动搜索最优 Prompt:

from dspy.teleprompt import BootstrapFewShot, MIPRO

# 准备训练数据
trainset = [
    dspy.Example(question="法国首都?", answer="巴黎").with_inputs("question"),
    dspy.Example(question="Python的创建者?", answer="Guido van Rossum").with_inputs("question"),
    # ... 更多样本
]

# 自动优化
teleprompter = BootstrapFewShot(metric=dspy.evaluate.answer_exact_match)
optimized_rag = teleprompter.compile(rag, trainset=trainset)

# 优化后的模块包含自动选择的 few-shot 示例
optimized_rag(question="日本最高山?")

MIPRO:更高级的优化器

from dspy.teleprompt import MIPRO

# MIPRO 同时优化指令和 few-shot 示例
teleprompter = MIPRO(
    metric=my_metric,
    num_candidates=10,
    init_temperature=1.0,
)

optimized = teleprompter.compile(
    student=rag,
    trainset=trainset,
    valset=valset,
)

MIPRO 的优化过程:

  1. 指令优化:生成多个指令候选,评估选择最优
  2. Few-shot 选择:从训练集中搜索最佳示例组合
  3. 联合搜索:在指令 × 示例的联合空间中搜索

实战:构建自动优化的 RAG

import dspy

# 配置 LM
lm = dspy.LM("openai/gpt-4o", api_key="...")
dspy.configure(lm=lm)

# 配置检索
colbert = dspy.ColBERTv2(url="http://localhost:8000")
dspy.configure(rm=colbert)

# 定义 Signature
class AnswerWithCitation(dspy.Signature):
    """基于检索到的文档回答问题,并标注引用来源"""
    context: str = dspy.InputField(desc="检索到的相关文档")
    question: str = dspy.InputField(desc="用户的问题")
    answer: str = dspy.OutputField(desc="基于文档的回答")
    citation: str = dspy.OutputField(desc="引用的文档编号")

# 定义 Module
class SmartRAG(dspy.Module):
    def __init__(self):
        self.retrieve = dspy.Retrieve(k=5)
        self.generate = dspy.ChainOfThought(AnswerWithCitation)
    
    def forward(self, question):
        passages = self.retrieve(question).passages
        context = "\n\n".join(f"[{i+1}] {p}" for i, p in enumerate(passages))
        pred = self.generate(context=context, question=question)
        return dspy.Prediction(answer=pred.answer, citation=pred.citation)

# 定义评估指标
def citation_correctness(example, pred, trace=None):
    # 检查引用编号是否有效
    try:
        idx = int(pred.citation.strip("[]"))
        return 1 <= idx <= 5
    except:
        return False

# 自动优化
from dspy.teleprompt import BootstrapFewShotWithRandomSearch

optimizer = BootstrapFewShotWithRandomSearch(
    metric=citation_correctness,
    max_bootstrapped_demos=4,
    max_labeled_demos=4,
    num_candidate_programs=5,
)

trainset = [
    dspy.Example(question="量子纠缠是什么?").with_inputs("question"),
    dspy.Example(question="Transformer 架构的核心是什么?").with_inputs("question"),
    # ...
]

optimized_rag = optimizer.compile(SmartRAG(), trainset=trainset)

# 对比优化前后
print("=== 优化前 ===")
SmartRAG()(question="BERT 和 GPT 的区别?")
print("=== 优化后 ===")
optimized_rag(question="BERT 和 GPT 的区别?")

DSPy vs LangChain:范式对比

维度DSPyLangChain
核心理念声明式,自动优化命令式,手动编排
Prompt自动生成和优化手写模板
Few-shot自动选择最优示例手动添加
模型迁移自动适配新模型需手动调整 Prompt
学习曲线陡峭(概念多)平缓
生态/集成成长中成熟丰富
适合场景追求最优效果、可度量快速原型、工程集成

代码对比:同一个 RAG 任务

LangChain 方式:

from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

template = """基于以下上下文回答问题。
上下文:{context}
问题:{question}
回答:"""
prompt = PromptTemplate(template=template, input_variables=["context", "question"])

chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=retriever,
    chain_type_kwargs={"prompt": prompt},
)

DSPy 方式:

class RAG(dspy.Module):
    def __init__(self):
        self.retrieve = dspy.Retrieve(k=3)
        self.generate = dspy.ChainOfThought("context, question -> answer")
    
    def forward(self, question):
        context = self.retrieve(question).passages
        return self.generate(context=context, question=question)

# 自动优化后使用
optimized = teleprompter.compile(RAG(), trainset=trainset)

DSPy 的优势在于:不需要手写 template,不需要猜测最佳 few-shot 示例,框架帮你搜索最优解。

适用场景

✅ DSPy 适合

  • 有明确评估指标的任务(如 QA 的准确率、分类的 F1)
  • 有训练数据(哪怕只有 20-50 条)
  • 需要跨模型迁移的场景
  • 追求极致效果的离线任务
  • 学术研究和实验对比

❌ DSPy 不适合

  • 快速原型(学习成本太高)
  • 通用对话(难以定义评估指标)
  • 需要精细控制 Prompt的场景
  • 与 LangChain 生态深度绑定的项目

性能实测

在 GSM8K(小学数学)上的对比:

方法准确率说明
GPT-4o + 手写 CoT92.3%人工精心设计 Prompt
GPT-4o + DSPy (BootstrapFewShot)93.1%自动优化
GPT-4o + DSPy (MIPRO)94.7%指令+示例联合优化
Claude-3.5 + 手写 CoT88.1%Prompt 未针对 Claude 优化
Claude-3.5 + DSPy (MIPRO)91.5%自动适配 Claude

DSPy 的自动优化在大多数场景下能达到或超过人工 Prompt 工程。

总结

DSPy 代表了 LLM 编程的一个重要方向:从手写 Prompt 到自动优化 Prompt。它的价值不在于替代 LangChain 的工程能力,而在于提供了一个可度量、可优化、可迁移的范式。如果你有明确的评估指标和训练数据,DSPy 的自动优化能力会让你事半功倍。反之,如果只是快速搭建原型,LangChain 仍然是更务实的选择。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。