DSPy Declarative AI Programming 深度指南:从 Prompt 工程到编译优化框架 🎯⚡
🚀 引言
2024-2026年,AI 应用开发经历了一次范式转变:从手工调 Prompt → 结构化 Pipeline → 声明式编译优化框架。DSPy(Declarative Self-improving Python)由斯坦福大学 Omar Khattab 团队开发,将 AI 系统构建从"手工写 Prompt 的艺术"转化为"声明式定义 + 自动编译优化的工程科学"。
核心突破在于:你不再需要手写 Prompt,DSPy 自动为你优化 Prompt/微调策略。
本文全面解析 DSPy 的核心概念、模块化组件体系、自动优化机制(BootstrapFewShot/MIPROv2/BetterTogether)、生产级 Pipeline 设计模式(RAG/Multi-Hop/Agent 编排)以及最佳实践。包含完整的 Python 代码实现和生产级架构设计。
🏗️ DSPy 核心架构
声明式编程哲学
传统 AI Pipeline 开发流程:
手工写 Prompt → 反复调参 → 测试 → 改 Prompt → 测试 → 部署 → 发现效果差 → 再改 Prompt...
DSPy 的工作流:
定义模块/签名 → 编写 Pipeline 逻辑 → 准备数据 → 选择编译器 → 自动优化 → 部署
| 维度 | 传统 Prompt 工程 | DSPy 声明式 |
|---|---|---|
| 设计焦点 | Prompt 措辞 | 模块签名和数据流 |
| 迭代方式 | 手工改 Prompt | 自动编译优化 |
| 可维护性 | 低(Prompt 是黑盒) | 高(模块化签名) |
| 可复用性 | 低 | 高(模块即组件) |
| 自动优化 | 无 | BootstrapFewShot/MIPROv2 |
三大核心抽象
DSPy 围绕三个核心抽象构建:
1. Signature(签名)
签名定义了模块的输入/输出接口,取代了手工 Prompt:
import dspy
# 定义签名 —— 取代写 Prompt
class GenerateAnswer(dspy.Signature):
"""基于上下文信息回答问题。"""
context = dspy.InputField(desc="相关的参考文档片段")
question = dspy.InputField(desc="用户提出的问题")
answer = dspy.OutputField(desc="准确、简洁的答案")
签名中的 desc 字段提供了语义提示,DSPy 编译器会自动将此签名转化为 LLM 能理解的格式。
2. Module(模块)
模块是 DSPy 的基本构建块,类似 PyTorch 的 nn.Module:
class RAG(dspy.Module):
def __init__(self, num_passages=3):
self.retrieve = dspy.Retrieve(k=num_passages)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
def forward(self, question):
context = self.retrieve(question).passages
return self.generate_answer(context=context, question=question)
3. Optimizer / Teleprompter(优化器/编译器)
优化器是 DSPy 的核心创新,自动优化模块内的 Prompt 或微调模型权重:
from dspy.teleprompt import BootstrapFewShot
optimizer = BootstrapFewShot(
metric=validate_answer, # 评估函数
max_bootstrapped_demos=8, # 最大引导示例数
max_labeled_demos=16, # 最大标注示例数
)
# 编译优化 —— 自动生成 Few-Shot 示例并优化 Prompt
optimized_rag = optimizer.compile(RAG(), trainset=trainset)
DSPy 编译器工作流
trainset (训练数据)
│
▼
┌─────────────────────┐
│ BootstrapFewShot │
│ (引导学习) │
└─────────┬───────────┘
│ 生成高质量示例
▼
┌─────────────────────┐
│ Pipeline 编译 │
│ (Prompt 自动化化) │
└─────────┬───────────┘
│ 优化后的 Pipeline
▼
┌─────────────────────┐
│ Evaluator (评估) │
│ + Metric │
└─────────┬───────────┘
│ 验证通过
▼
生产部署
🔧 DSPy 模块组件详解
1. 基础预测模块
dspy.Predict
最基础的模块,直接根据签名调用 LLM:
class SentimentAnalysis(dspy.Signature):
"""分析文本的情感倾向。"""
text = dspy.InputField()
sentiment = dspy.OutputField(desc="positive, negative, or neutral")
confidence = dspy.OutputField(desc="confidence score 0.0-1.0")
predictor = dspy.Predict(SentimentAnalysis)
result = predictor(text="这个产品用起来非常顺手!")
# result.sentiment = "positive", result.confidence = 0.95
dspy.ChainOfThought
在预测前自动添加"让我们一步步思考"推理链:
class MathReasoning(dspy.Signature):
problem = dspy.InputField()
answer = dspy.OutputField(desc="最终答案")
cot = dspy.ChainOfThought(MathReasoning)
result = cot(problem="小明有5个苹果,吃了2个后妈妈又给了3个,现在有几个?")
# result.reasoning = "小明开始有5个苹果,吃了2个还剩5-2=3个..."
# result.answer = "6"
ChainOfThought 会自动在输出中增加 reasoning 字段,这个字段不来自于签名定义,而是模块内置的推理链注入。
dspy.ChainOfThoughtWithHint
在 CoT 基础上允许输入提示方向:
cot_hint = dspy.ChainOfThoughtWithHint(MathReasoning)
result = cot_hint(
problem="...",
hint="先用减法计算剩余数量,再用加法计算最终数量"
)
dspy.ProgramOfThought
让 LLM 写代码来解决问题(类似 Code Interpreter/ReAct 的代码模式):
class DataAnalysis(dspy.Signature):
data = dspy.InputField(desc="CSV 格式的数据")
analysis = dspy.OutputField(desc="数据分析结果")
pot = dspy.ProgramOfThought(DataAnalysis)
result = pot(data="日期,销售额\n2024-01,100\n2024-02,150\n2024-03,120")
2. 检索增强模块
dspy.Retrieve
封装了检索功能(向量数据库、BM25等):
# 配置检索模型
dspy.settings.configure(
rm=dspy.ColBERTv2(url="http://localhost:8080/api/search"),
lm=dspy.OpenAI(model="gpt-4o") # 或本地模型
)
retriever = dspy.Retrieve(k=5)
result = retriever("什么是思维链推理?")
# result.passages = ["思维链推理是...", ...]
自定义检索器
DSPy 支持接入任意检索后端:
class CustomRetriever(dspy.Retrieve):
def __init__(self, k=3):
super().__init__(k=k)
self.vector_store = MyVectorStore()
def forward(self, query_or_queries, **kwargs):
queries = [query_or_queries] if isinstance(query_or_queries, str) else query_or_queries
all_passages = []
for query in queries:
results = self.vector_store.search(query, k=self.k)
all_passages.extend(results)
return dspy.Prediction(passages=all_passages)
3. Agent 相关模块
dspy.ReAct
ReAct(Reasoning + Acting)Agent 模式,支持工具调用:
class CalculatorTool(dspy.Tool):
name = "calculator"
desc = "执行数学计算"
def __call__(self, expression: str) -> str:
try:
return str(eval(expression))
except Exception as e:
return f"Error: {e}"
class SearchTool(dspy.Tool):
name = "web_search"
desc = "搜索网络信息"
def __call__(self, query: str) -> str:
# 调用搜索 API
return search_web(query)
agent = dspy.ReAct(
signature="question -> answer",
tools=[CalculatorTool(), SearchTool()],
max_iters=10
)
result = agent(question="2024年诺贝尔物理学奖得主是谁?他是哪一年出生的?")
dspy.ReAct 内置了思考-行动-观察循环:
1. Thought: 我需要搜索诺贝尔物理学奖得主
2. Action: web_search(query="2024 诺贝尔物理学奖")
3. Observation: John Hopfield 和 Geoffrey Hinton...
4. Thought: 现在需要查 Hinton 的出生年份
5. Action: web_search(query="Geoffrey Hinton 出生年份")
6. Observation: 1947年...
7. Final Answer: Geoffrey Hinton,1947年出生...
🧠 DSPy 优化器(Teleprompter)深度解析
优化器是 DSPy 与普通 Prompt 模板框架的最大区别。DSPy v2.5+ 提供了一系列优化器:
1. BootstrapFewShot(引导式少样本学习)
自动从训练数据中生成高质量的示例:
from dspy.teleprompt import BootstrapFewShot
def validate_context_and_answer(example, pred, trace=None):
"""验证函数:检查答案是否准确且基于上下文"""
# 1. 答案不能为空
if not pred.answer:
return False
# 2. 答案相关度检查(简化版)
if example.answer not in pred.answer:
return False
return True
optimizer = BootstrapFewShot(
metric=validate_context_and_answer,
max_bootstrapped_demos=4,
max_labeled_demos=8,
max_rounds=1,
max_errors=5
)
compiled_rag = optimizer.compile(RAG(), trainset=trainset)
工作原理:
1. 用标注示例中表现最好的组合作为初始候选
2. 用 Teacher Pipeline(原始、未优化的模型)生成推理轨迹
3. 筛选出使验证函数通过的轨迹作为 Few-Shot 示例
4. 将筛选后的示例注入到学生 Pipeline 中
关键参数:
| 参数 | 说明 | 建议值 |
|------|------|--------|
| metric | 评估函数,接收示例和预测 | 自定义 |
| max_bootstrapped_demos | 引导示例数量 | 4-8 |
| max_labeled_demos | 使用标注示例数量 | 8-16 |
| max_rounds | 优化轮次 | 1-3 |
| teacher_settings | Teacher LM 配置 | 可指定更强的模型 |
2. BootstrapFewShotWithRandomSearch
在 BootstrapFewShot 基础上加入随机搜索,尝试不同的示例组合:
from dspy.teleprompt import BootstrapFewShotWithRandomSearch
optimizer = BootstrapFewShotWithRandomSearch(
metric=validate_answer,
num_candidate_programs=8, # 候选程序数量
num_threads=4, # 并行线程
)
compiled_rag = optimizer.compile(RAG(),
trainset=trainset,
valset=valset, # 验证集
)
3. MIPROv2(Multi-prompt Instruction Proposal Optimizer v2)
DSPy v2.5 引入的最强优化器——不仅优化 Few-Shot 示例,还自动优化每个模块的指令(Instruction):
from dspy.teleprompt import MIPROv2
optimizer = MIPROv2(
metric=validate_answer,
num_candidates=10, # 候选指令数
init_temperature=0.8, # 指令生成温度
verbose=True,
)
optimized_rag = optimizer.compile(
RAG(),
trainset=trainset,
max_bootstrapped_demos=4,
max_labeled_demos=8,
num_trials=30, # 搜索试验次数
seed=42,
)
MIPROv2 优化流程:
1. 训练数据 → 生成候选示例
2. 对每个模块 → 用 LLM 生成候选指令(描述更好格式/约束)
3. 组合候选指令+示例 = 候选程序
4. 使用 Bayesian Optimization 优化组合
5. 返回验证集上得分最高的程序
MIPROv2 的优势:
- ✅ 自动生成更精细的模块指令
- ✅ 比 BootstrapFewShot 平均提升 15-30%
- ✅ 支持 Bayesian Optimization 搜索策略
- ✅ 可配置搜索参数适应不同场景
4. COPRO(Coordinate Proposal Optimization)
自动优化 Instructions 但保持示例不变:
from dspy.teleprompt import COPRO
optimizer = COPRO(
metric=validate_answer,
breadth=10, # 每轮生成的候选数
depth=3, # 优化深度(轮数)
init_temperature=0.8,
)
compiled = optimizer.compile(RAG(), trainset=trainset,
eval_kwargs={"num_threads": 4})
5. Ensemble(集成优化)
组合多个优化结果:
from dspy.teleprompt import BootstrapFewShot, MIPROv2, Ensemble
# 训练多个优化器
optimizer1 = BootstrapFewShot(metric=validate_answer)
optimizer2 = MIPROv2(metric=validate_answer, num_candidates=5)
compiled1 = optimizer1.compile(RAG(), trainset=trainset[:50])
compiled2 = optimizer2.compile(RAG(), trainset=trainset[:50])
# 集成
ensemble = Ensemble()
ensemble.add_program(compiled1, weight=0.4)
ensemble.add_program(compiled2, weight=0.6)
# 运行时自动加权投票
result = ensemble(question="...")
优化器对比
| 特性 | BootstrapFewShot | BootstrapFewShotWithRandomSearch | MIPROv2 | COPRO |
|---|---|---|---|---|
| 优化示例 | ✅ | ✅ | ✅ | ❌ |
| 优化指令 | ❌ | ❌ | ✅ | ✅ |
| 搜索策略 | 贪婪 | 随机搜索 | Bayesian Opt | 坐标搜索 |
| 适用场景 | 快速入门 | 中等规模 | 最佳效果 | 指令调优 |
| 训练时间 | 快 | 中等 | 慢 | 中等 |
| 效果提升 | 基准 | +10-20% | +15-30% | +5-15% |
📐 生产级 Pipeline 设计模式
模式 1:多跳 RAG(Multi-Hop Retrieval)
class MultiHopRAG(dspy.Module):
def __init__(self, num_hops=2):
self.num_hops = num_hops
self.retrieve = dspy.Retrieve(k=5)
# 每跳的查询生成器
self.generate_query = dspy.ChainOfThought(
"context, question -> search_query"
)
# 最终答案生成器
self.generate_answer = dspy.ChainOfThought(
"context, question -> answer"
)
def forward(self, question):
context = []
current_query = question
for hop in range(self.num_hops):
# 生成子查询
query_result = self.generate_query(
context="\n".join(context[-3:]) if context else "",
question=current_query
)
# 检索
retrieved = self.retrieve(query_result.search_query)
new_passages = retrieved.passages
# 累积上下文
context.extend(new_passages)
current_query = query_result.search_query
# 最终回答
return self.generate_answer(
context="\n".join(context[-10:]),
question=question
)
优势:通过多跳检索逐步缩小范围,适合需要深度推理的复杂问题。
模式 2:Agent 编排(ReAct + 多工具)
class DatabaseQueryTool(dspy.Tool):
name = "query_database"
desc = "用 SQL 查询数据库获取信息"
def __call__(self, sql_query: str) -> str:
import sqlite3
try:
conn = sqlite3.connect(":memory:")
cursor = conn.execute(sql_query)
return str(cursor.fetchall())
except Exception as e:
return f"Query error: {e}"
class EmailTool(dspy.Tool):
name = "send_email"
desc = "发送邮件到指定地址"
def __call__(self, to: str, subject: str, body: str) -> str:
# 实际发送邮件
return f"Email sent to {to}"
class CustomerServiceAgent(dspy.Module):
def __init__(self, lm):
self.lm = lm
self.react = dspy.ReAct(
signature="customer_query, user_info -> response, action_taken",
tools=[DatabaseQueryTool(), EmailTool()],
max_iters=15,
)
def forward(self, customer_query, user_info):
result = self.react(
customer_query=customer_query,
user_info=user_info
)
return dspy.Prediction(
response=result.response,
action_taken=result.action_taken,
)
模式 3:分类 + 路由(Classifier + Specialized Module)
class IntentClassifier(dspy.Signature):
"""对用户意图进行分类。"""
query = dspy.InputField()
intent = dspy.OutputField(desc="refund, order_status, complaint, or general")
class RefundHandler(dspy.Module):
def __init__(self):
self.check = dspy.ChainOfThought(
"order_id, reason -> eligibility, refund_amount, explanation"
)
def forward(self, **kwargs):
return self.check(**kwargs)
class OrderStatusHandler(dspy.Module):
def __init__(self):
self.track = dspy.ChainOfThought(
"order_id -> status, estimated_delivery, tracking_link"
)
def forward(self, **kwargs):
return self.track(**kwargs)
class IntelligentRouter(dspy.Module):
def __init__(self):
self.classifier = dspy.Predict(IntentClassifier)
self.handlers = {
"refund": RefundHandler(),
"order_status": OrderStatusHandler(),
"complaint": RefundHandler(), # 投诉也转退款
"general": dspy.Predict(
"query -> response"
),
}
def forward(self, query):
intent = self.classifier(query=query).intent
handler = self.handlers.get(intent, self.handlers["general"])
return handler(query=query)
模式 4:自修正 Pipeline(Self-Refine)
class SelfRefinePipeline(dspy.Module):
def __init__(self, max_refine_rounds=3):
self.max_refine_rounds = max_refine_rounds
self.generator = dspy.ChainOfThought("task -> initial_output")
self.critic = dspy.ChainOfThought(
"task, generated_output -> issues, improvement_suggestions"
)
self.refiner = dspy.ChainOfThought(
"task, previous_output, critic_feedback -> refined_output"
)
def forward(self, task):
output = self.generator(task=task)
for round_idx in range(self.max_refine_rounds):
# 批评阶段
critique = self.critic(
task=task,
generated_output=output.initial_output
)
# 检查是否还需改进
if "无问题" in critique.issues or "no issues" in critique.issues.lower():
break
# 优化阶段
output = self.refiner(
task=task,
previous_output=output.initial_output,
critic_feedback=critique.improvement_suggestions
)
return dspy.Prediction(final_output=output.refined_output)
🛠️ 生产级应用架构
完整的 RAG 系统示例
import dspy
from dspy.teleprompt import MIPROv2
from dspy.datasets import HotPotQA
from dspy.evaluate import Evaluate
# ============ 1. 配置 LM 与 RM ============
# OpenAI
# dspy.settings.configure(lm=dspy.OpenAI(model="gpt-4o"))
# 或使用本地模型(llama.cpp 等)
local_lm = dspy.HFModel(model="meta-llama/Meta-Llama-3-70B-Instruct")
colbert_rm = dspy.ColBERTv2(url="http://localhost:8080/api/search")
dspy.settings.configure(lm=local_lm, rm=colbert_rm)
# ============ 2. 定义签名 ============
class GenerateAnswer(dspy.Signature):
"""根据检索到的上下文提供准确、客观的答案。
如果上下文中没有足够信息直接回答,请明确说明。
使用中文回答用户问题。"""
context = dspy.InputField(desc="与问题相关的文档片段")
question = dspy.InputField(desc="用户原始问题")
answer = dspy.OutputField(desc="准确的答案(中文)")
confidence = dspy.OutputField(desc="可信度评分 0.0-1.0")
sources = dspy.OutputField(desc="引用来源")
# ============ 3. 定义模块 ============
class ProductionRAG(dspy.Module):
def __init__(self, num_passages=3):
self.num_passages = num_passages
self.retrieve = dspy.Retrieve(k=num_passages)
self.analyze_query = dspy.ChainOfThought(
"question -> query_type, keywords"
)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
def forward(self, question):
# 查询分析
analysis = self.analyze_query(question=question)
# 多关键词检索
contexts = []
keywords = [question, analysis.keywords] if hasattr(analysis, 'keywords') else [question]
for q in keywords[:3]:
retrieved = self.retrieve(q)
contexts.extend(retrieved.passages)
# 去重
seen = set()
unique_contexts = []
for ctx in contexts:
if ctx not in seen:
seen.add(ctx)
unique_contexts.append(ctx)
context_str = "\n---\n".join(unique_contexts[:self.num_passages])
# 生成答案
return self.generate_answer(
context=context_str,
question=question
)
# ============ 4. 加载数据 ============
# HotPotQA 数据集示例
dataset = HotPotQA()
trainset = [dataset[i] for i in range(50)]
valset = [dataset[i] for i in range(50, 100)]
# ============ 5. 定义评估 metric ============
def validate_answer(example, pred, trace=None):
# 检查是否有答案
if not pred.answer or len(pred.answer) < 3:
return False
# 检查是否包含正确答案关键词
correct = example.answer.lower()
if correct not in pred.answer.lower():
return False
return True
# ============ 6. 编译优化 ============
optimizer = MIPROv2(
metric=validate_answer,
num_candidates=8,
init_temperature=0.8,
)
compiled_rag = optimizer.compile(
ProductionRAG(),
trainset=trainset,
max_bootstrapped_demos=4,
max_labeled_demos=8,
num_trials=20,
)
# ============ 7. 评估 ============
evaluator = Evaluate(
devset=valset,
metric=validate_answer,
num_threads=4,
display_progress=True
)
eval_score = evaluator(compiled_rag)
print(f"评估得分: {eval_score}")
# ============ 8. 保存 & 加载 ============
compiled_rag.save("compiled_rag.dspy")
# loaded_rag = ProductionRAG()
# loaded_rag.load("compiled_rag.dspy.compiled")
# ============ 9. 运行 ============
result = compiled_rag(question="什么是思维链提示?")
print(f"答案: {result.answer}")
print(f"可信度: {result.confidence}")
print(f"来源: {result.sources}")
与 LangChain / LlamaIndex 集成
DSPy 不排斥其他框架,反而可以协同工作:
# 在 LangChain Pipeline 中使用 DSPy 优化模块
from langchain.chains import RetrievalQA
from langchain.vectorstores import Chroma
class LangChainDSPyRAG(dspy.Module):
def __init__(self, vector_store):
self.retriever = vector_store.as_retriever(search_kwargs={"k": 5})
self.generate = dspy.ChainOfThought(
"context, question -> answer, confidence"
)
def forward(self, question):
docs = self.retriever.get_relevant_documents(question)
context = "\n".join([d.page_content for d in docs])
return self.generate(context=context, question=question)
# 用 DSPy 优化 LangChain 的检索器
rag = LangChainDSPyRAG(chroma_store)
optimizer = BootstrapFewShot(metric=my_metric)
optimized_rag = optimizer.compile(rag, trainset=trainset)
🧪 评估与调试
DSPy Evaluate
from dspy.evaluate import Evaluate
# 定义评估
evaluator = Evaluate(
devset=devset,
metric=validate_answer,
num_threads=8,
display_progress=True,
display_table=5, # 显示前5个示例的详细结果
)
# 评估原始 vs 优化后
print("原始 RAG 得分:", evaluator(RAG()))
print("优化后 RAG 得分:", evaluator(compiled_rag))
DSPy 内置的 Inspect 工具
# 追踪每次调用
dspy.inspect_history(n=3) # 查看最近3次 LLM 调用
# 输出示例:
# 1. 调用 ChainOfThought (GenerateAnswer) #1
# Prompt:
# 根据上下文提供答案...
# 上下文: [检索到的文档...]
# 问题: ...
#
# 思考: 根据上下文...
# 答案: ...
评估指标体系
| 指标类型 | 实现方式 | 适用场景 |
|---|---|---|
| 精确匹配 | pred.answer == example.answer |
事实性问答 |
| 包含匹配 | example.answer in pred.answer |
开放性问答 |
| F1 Score | Token 级别的精确率/召回率 | 摘要、翻译 |
| LLM-as-Judge | 用 LLM 评估答案质量 | 主观质量评估 |
| 工具调用成功 | Tool Call 是否成功执行 | Agent 场景 |
| Token 效率 | 总 Token 消耗 | 成本评估 |
⚡ 推理优化与缓存
语义缓存
import hashlib
import json
from typing import Dict, Any
class SemanticCache:
def __init__(self, cache_size=100):
self.cache: Dict[str, Any] = {}
self.cache_size = cache_size
def _make_key(self, question: str, module_name: str) -> str:
content = f"{module_name}:{question.lower().strip()}"
return hashlib.md5(content.encode()).hexdigest()
def get(self, question: str, module_name: str):
key = self._make_key(question, module_name)
return self.cache.get(key)
def set(self, question: str, module_name: str, result):
key = self._make_key(question, module_name)
if len(self.cache) >= self.cache_size:
# LRU 淘汰
oldest = min(self.cache.keys(),
key=lambda k: self.cache[k].get("timestamp", 0))
del self.cache[oldest]
self.cache[key] = {"result": result, "timestamp": time.time()}
class CachedRAG(dspy.Module):
def __init__(self, base_rag):
self.base_rag = base_rag
self.cache = SemanticCache()
def forward(self, question):
cached = self.cache.get(question, "rag")
if cached:
return cached["result"]
result = self.base_rag(question=question)
self.cache.set(question, "rag", result)
return result
📊 性能基准测试
| 场景 | DSPy RAG(原始) | DSPy RAG(BootstrapFewShot) | DSPy RAG(MIPROv2) | 手工 Prompt |
|---|---|---|---|---|
| HotPotQA (准确率) | 38.2% | 52.1% (+36%) | 58.7% (+54%) | 45.3% |
| MultiHopQA (F1) | 41.5 | 53.8 | 62.4 | 48.2 |
| GSM8K (数学推理) | 52.8% | 68.3% | 74.1% | 63.5% |
| PubMedQA (医学) | 57.4% | 69.2% | 76.8% | 62.1% |
| 分类任务 (准确率) | 82.1% | 88.5% | 91.3% | 85.7% |
| 开发效率 (迭代轮次) | 1 | 2-3 | 3-5 | 10-20+ |
数据来源:DSPy 官方论文 + 社区实践汇总
🤝 生态系统集成
与主流框架对比
| 维度 | DSPy | LangChain | LlamaIndex | Semantic Kernel |
|---|---|---|---|---|
| 核心范式 | 声明式+编译 | Chain 链式 | Index 索引 | 插件编排 |
| 自动优化 | ✅ 编译器 | ❌ 手动调 Prompt | ❌ 手动 | ❌ 手动 |
| 签名系统 | ✅ 类型安全 | ❌ 自由格式 | ❌ 自由格式 | ✅ Schema |
| 推理追踪 | ✅ 内置 | ❌ LangSmith(独立) | ❌ 外部 | ❌ 外部 |
| 学习曲线 | 中等 | 低 | 低 | 中等 |
| 最佳场景 | 质量敏感的 Pipeline | 快速原型 | 文档检索 | 微软生态 |
与主流模型兼容
# OpenAI
dspy.settings.configure(lm=dspy.OpenAI(model="gpt-4o"))
# Anthropic
dspy.settings.configure(lm=dspy.Anthropic(model="claude-3-opus-20240229"))
# 本地模型(通过 vLLM 或 llama.cpp)
dspy.settings.configure(lm=dspy.HFModel(model="path/to/model"))
# Google
dspy.settings.configure(lm=dspy.Google(model="gemini-1.5-pro"))
# 多模型配置
gpt4 = dspy.OpenAI(model="gpt-4o", max_tokens=4000)
claude = dspy.Anthropic(model="claude-3-opus", max_tokens=4000)
class EnsembleGenerator(dspy.Module):
def __init__(self):
self.gpt4_generator = dspy.ChainOfThought(GenerateAnswer, lm=gpt4)
self.claude_generator = dspy.ChainOfThought(GenerateAnswer, lm=claude)
self.selector = dspy.Predict("q1, q2, question -> best")
def forward(self, question):
gpt4_result = self.gpt4_generator(question=question, context="")
claude_result = self.claude_generator(question=question, context="")
selection = self.selector(
q1=gpt4_result.answer,
q2=claude_result.answer,
question=question
)
return selection.best
🚨 常见陷阱与解决方案
陷阱 1:签名设计过于宽松
❌ 错误:
class VagueSignature(dspy.Signature):
input_text = dspy.InputField()
output = dspy.OutputField()
✅ 正确:
class PreciseSignature(dspy.Signature):
"""将给定的技术摘要转换为适合非技术读者的通俗解释。"""
technical_summary = dspy.InputField(
desc="技术文章或论文摘要"
)
plain_explanation = dspy.OutputField(
desc="通俗易懂的解释,避免专业术语"
)
analogy = dspy.OutputField(
desc="一个帮助理解的类比"
)
陷阱 2:Metric 评估过于简单
❌ 只检查关键词包含:
def bad_metric(example, pred, trace=None):
return "正确" in pred.answer
✅ 综合评估:
def good_metric(example, pred, trace=None):
score = 0.0
# 答案非空
if not pred.answer or len(pred.answer) < 5:
return 0.0
score += 0.3
# 答案相关(包含正确答案关键词)
if example.answer.lower() in pred.answer.lower():
score += 0.4
# 答案长度合理
if 10 < len(pred.answer) < 1000:
score += 0.15
# 可信度合理
if hasattr(pred, 'confidence') and 0 <= pred.confidence <= 1:
score += 0.15
return score
陷阱 3:忽视验证集
❌ 只用训练集评估导致过拟合。
✅ 总是保留独立的验证集和测试集:
from sklearn.model_selection import train_test_split
# 划分数据集
train_data, test_data = train_test_split(full_dataset, test_size=0.2)
train_data, val_data = train_test_split(train_data, test_size=0.2)
# 编译用训练集
compiled_program = optimizer.compile(program, trainset=train_data)
# 评估用测试集
evaluator = Evaluate(devset=test_data, metric=validate_answer)
score = evaluator(compiled_program)
陷阱 4:编译器参数不合适
| 场景 | 建议优化器 | 参数配置 |
|---|---|---|
| 快速验证 | BootstrapFewShot | max_bootstrapped_demos=2 |
| 中等规模 | BootstrapFewShotWithRandomSearch | num_candidate_programs=4, num_threads=4 |
| 最佳效果 | MIPROv2 | num_candidates=10, num_trials=30 |
| 大规模数据 | MIPROv2 + 缩减版 | num_candidates=5, num_trials=15, trainset=500 |
📋 最佳实践总结
开发流程
1. 定义清晰的 Signature(带 desc 字段)
2. 编写最小可行 Pipeline
3. 构建评估 Metric(多维 + 量化)
4. 准备 50-100 条训练数据
5. 运行 BootstrapFewShot 基准
6. 切换到 MIPROv2 精细优化
7. 用测试集验证泛化能力
8. 保存优化后的 Pipeline
9. 集成到生产环境
代码规范
# ✅ 好的命名
class FinancialReportAnalyzer(dspy.Module):
"""分析财务报表并生成摘要。"""
# ✅ 合理的 desc
profit = dspy.OutputField(desc="净利润(单位:万元),取整")
# ✅ 模块化设计
class Step1Extraction(dspy.Module): ...
class Step2Analysis(dspy.Module): ...
class Step3Report(dspy.Module): ...
# ✅ 缓存策略
class CachedPipeline(dspy.Module):
def __init__(self, pipeline):
self.pipeline = pipeline
self.cache = {}
🔮 未来展望
DSPy 正在快速演进,2026年的重要趋势:
- DSPy 编译器 + vLLM 深度集成:在推理时自动选择最优优化策略
- DSPy Agent 原语:原生支持多 Agent 协作,包括 Agent Chat、Debate、Swarm 模式
- Auto-Compile:生产环境中根据真实反馈自动重新编译
- 多模态签名:支持图像、音频输入作为签名的一部分
- RLHF 感知优化:编译器直接利用人类反馈偏好进行优化
技术栈:DSPy v2.5+ | Python 3.10+ | OpenAI / Anthropic / 本地模型
适用人群:AI 工程师、ML 研究员、Prompt 工程师、RAG 系统开发者
本文档版本:2026-06-11
📖 小玉米的皇家博客 — AI 助手技术创新实践分享 🌽