DSPy 框架:用编程方式编译和优化 LLM 调用
在 LLM 应用开发中,我们习惯了这种工作流:
- 写一个 Prompt。
- 跑几个例子。
- 如果不满意,手动改 Prompt。
- 重复 N 次。 这既不可靠,又难以维护。 DSPy (Declarative Self-improving Python) 提出了一种革命性的理念:不要写 Prompt,去定义逻辑。 就像 PyTorch 定义神经网络层一样,DSPy 定义 LLM 模块。 然后,利用优化器 (Teleprompter) 在你的数据集上自动搜索最佳 Prompt 和 Few-Shot 示例。
1. 核心概念:Signature, Module, Teleprompter
1.1 Signature (签名)
类似于函数签名,定义输入输出类型。
import dspy
class GenerateAnswer(dspy.Signature):
"""Answer questions with short factoid answers."""
context = dspy.InputField(desc="may contain relevant facts")
question = dspy.InputField()
answer = dspy.OutputField(desc="often between 1 and 5 words")这就够了。不需要写 "You are a helpful assistant...",也不需要写 "Answer strictly based on context..."。
1.2 Module (模块)
类似于 torch.nn.Module,定义处理逻辑。
class RAG(dspy.Module):
def __init__(self, num_passages=3):
super().__init__()
self.retrieve = dspy.Retrieve(k=num_passages)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
def forward(self, question):
context = self.retrieve(question).passages
prediction = self.generate_answer(context=context, question=question)
return dspy.Prediction(context=context, answer=prediction.answer)这就把 RAG 的逻辑(检索 -> 生成)定义好了。
1.3 Teleprompter (优化器)
这是最神奇的部分。 BootstrapFewShot 是最常用的优化器。 它会拿你的训练集(Question, Answer),让上面的 RAG 模块跑一遍。 如果某条数据跑通了(生成了正确的 Answer),它就把这条数据的中间过程(检索到的 Context,生成的 CoT 推理步骤)存下来,作为 Few-Shot 示例放入 Prompt 中。 如果没跑通,就丢弃。
2. 为什么 DSPy 比手写 Prompt 好?
2.1 自动化 Few-Shot 选择
手写 Few-Shot 很难选出最佳示例。DSPy 通过试错(Bootstrapping),自动找到了那些能让模型推理成功的示例。
2.2 适应性
当你换模型(从 GPT-3.5 换到 Llama 3)时,手写的 Prompt 往往失效了(因为不同模型偏好不同)。 DSPy 只需要重新 compile() 一次,它会针对新模型重新优化 Prompt。
2.3 模块化
复杂的 RAG 流程(多跳推理、自我修正)在 Prompt 里很难写清楚。 在 DSPy 里,就是几个 dspy.Module 的组合。
3. 实战案例:优化 Multi-Hop QA
假设我们要回答“奥巴马出生那年的美国总统是谁?” 这是一个两步推理:
- 奥巴马哪年出生?(1961)
- 1961 年美国总统是谁?(肯尼迪)
3.1 定义 Module
class MultiHop(dspy.Module):
def __init__(self):
self.generate_query = dspy.ChainOfThought("question -> search_query")
self.retrieve = dspy.Retrieve(k=3)
self.generate_answer = dspy.ChainOfThought("context, question -> answer")
def forward(self, question):
# Step 1
query = self.generate_query(question=question).search_query
passages = self.retrieve(query).passages
# Step 2
return self.generate_answer(context=passages, question=question)3.2 编译
from dspy.teleprompt import BootstrapFewShotWithRandomSearch
teleprompter = BootstrapFewShotWithRandomSearch(metric=dspy.evaluate.answer_exact_match)
compiled_multihop = teleprompter.compile(MultiHop(), trainset=trainset)DSPy 会自动尝试生成不同的 search_query,看看哪种 Query 能检索到正确文档,最终回答正确。 它可能会发现:"What year was Obama born?" 比 "Obama birth year" 效果好。 然后它就把这个发现固化到 Prompt 里。
DSPy 代表了 AI 开发的未来方向:声明式编程 (Declarative Programming)。 你只关心做什么 (What),而不关心怎么做 (How)。 Prompt 的细节交给优化器去处理。 如果你还在手动调 Prompt,是时候试试 DSPy 了。