Doramagic 项目包 · 项目说明书
dspy 项目
生成时间:2026-05-16 04:11:08 UTC
DSPy概述
DSPy(Declarative Self-Improving Python)是一个用于构建和优化基于语言模型(LM)复杂管道的框架。该框架由斯坦福NLP团队开发,旨在通过声明式编程范式简化大型语言模型应用的开发和优化过程。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
核心定位与价值
DSPy的核心价值在于将语言模型调用从硬编码的提示词转变为可声明式定义、可自动优化的程序组件。根据项目文档,DSPy能够"将声明式语言模型调用编译成自我改进的管道",这使得开发者可以专注于程序逻辑而非提示工程细节。
系统架构
整体架构图
graph TD
A[用户程序] --> B[DSPy Module]
B --> C[Signature定义]
B --> D[Predict组件]
B --> E[ChainOfThought组件]
C --> F[InputField/OutputField]
D --> G[语言模型 LM]
E --> G
G --> H[优化器 Teleprompter]
H --> I[训练集 Trainset]
I --> H
H --> B
G --> J[检索模型 RM]
J --> K[外部知识库]核心组件层次
| 层级 | 组件 | 说明 |
|---|---|---|
| 用户层 | DSPy Module | 自定义程序模块,继承dspy.Module |
| 定义层 | Signature | 声明输入输出字段及其描述 |
| 执行层 | Predict/ChainOfThought | 执行语言模型调用 |
| 优化层 | Teleprompter | 自动优化提示和参数 |
| 集成层 | LM/RM Adapter | 支持多种语言模型和检索器 |
核心抽象
Module基类
DSPy的Module是所有程序组件的基类,提供了语言模型管理和预测组件发现功能:
class MyProgram(dspy.Module):
def __init__(self):
super().__init__()
self.qa = dspy.Predict("question -> answer")
self.summarize = dspy.Predict("text -> summary")
Module类提供以下关键方法:
| 方法 | 功能 | 资料来源 |
|---|---|---|
named_predictors() | 返回所有Predict组件的(名称, 实例)元组列表 | module.py:92-100 |
predictors() | 返回所有Predict实例的列表 | module.py:103-120 |
set_lm(lm) | 为所有Predict设置语言模型 | module.py:128-143 |
get_lm() | 获取当前使用的语言模型 | module.py:145-152 |
Signature系统
Signature用于声明模块的输入输出字段语义,是DSPy中连接程序逻辑与语言模型的关键抽象:
class MySignature(dspy.Signature):
question: str = dspy.InputField(desc="用户问题")
answer: str = dspy.OutputField(desc="模型回答")
Signature支持动态修改:
prepend(): 在输入字段前插入新字段append(): 在输出字段后追加新字段delete(): 删除指定字段
数据模型
Example类
dspy.Example是DSPy中用于表示训练样本和测试样本的核心数据结构:
example = dspy.Example(question="What is 2+2?", answer="4").with_inputs("question")
主要方法:
| 方法 | 功能 | 示例 |
|---|---|---|
with_inputs(*keys) | 标记输入字段 | .with_inputs("question") |
inputs() | 获取仅包含输入字段的新Example | example.inputs() |
labels() | 获取仅包含标签字段的新Example | example.labels() |
toDict() | 递归转换为JSON友好字典 | example.toDict() |
copy(**kwargs) | 创建副本并覆盖指定字段 | ex.copy(answer="5") |
without(*keys) | 返回移除指定字段的副本 | ex.without("source") |
资料来源:example.py:1-250
特殊类型
DSPy提供了多种适配不同场景的特殊数据类型:
#### History类型
用于会话历史管理,允许在提示中包含多轮对话上下文:
history = dspy.History(messages=[
{"question": "法国的首都是什么?", "answer": "巴黎"},
{"question": "德国的首都是什么?", "answer": "柏林"}
])
资料来源:history.py:1-60
#### Document类型
支持文档格式的数据,可用于检索增强生成(RAG)场景:
doc = Document(
data="水的沸点是100°C",
title="物理基础",
context="标准大气压下"
)
资料来源:document.py:1-100
#### Citation类型
支持引用信息,用于需要标注来源的场景:
class Citations(dspy.Signature):
documents: list[Document] = dspy.InputField()
question: str = dspy.InputField()
answer: str = dspy.OutputField()
citations: list[Citation] = dspy.OutputField()
资料来源:citation.py:1-80
回调系统
DSPy提供了灵活的回调机制用于监控和调试程序执行:
class LoggingCallback(dspy.Callback):
def on_module_start(self, call_id, instance, inputs):
print(f"Module started: {inputs}")
def on_module_end(self, call_id, outputs):
print(f"Module finished: {outputs}")
| 回调方法 | 触发时机 |
|---|---|
on_module_start() | Module的forward方法被调用时 |
on_module_end() | Module的forward方法完成时 |
on_lm_start() | 语言模型开始生成时 |
on_lm_end() | 语言模型生成完成时 |
资料来源:callback.py:1-100
安装与使用
安装方式
pip install dspy
安装最新开发版本:
pip install git+https://github.com/stanfordnlp/dspy.git
资料来源:README.md:1-20
基础使用流程
graph LR
A[定义Signature] --> B[创建Module]
B --> C[配置LM]
C --> D[准备Trainset]
D --> E[编译优化]
E --> F[执行预测]Teleprompter优化系统
DSPy的优化器(Teleprompter)负责自动优化程序的提示和参数:
| 优化器 | 用途 |
|---|---|
BootstrapFewShotWithRandomSearch | 小样本引导+随机搜索 |
BootstrapFinetune | 引导微调 |
BetterTogether | 组合优化策略 |
BetterTogether是一个典型的组合优化器,可同时执行提示优化(p阶段)和权重优化(w阶段):
optimizer = BetterTogether(
metric=metric,
p=GEPA(metric=metric, auto="medium"),
w=BootstrapFinetune(metric=metric)
)
嵌入与检索
Embedder组件
支持自定义嵌入函数和批量处理:
def my_embedder(texts):
return np.random.rand(len(texts), 10)
embedder = dspy.Embedder(my_embedder)
embeddings = embedder(["hello", "world"], batch_size=1)
关键参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
model | str, Callable | 必填 | 嵌入模型或函数 |
batch_size | int | 200 | 批处理大小 |
caching | bool | True | 是否启用缓存 |
资料来源:embedding.py:1-100
检索器支持
DSPy支持多种检索器后端,包括Weaviate等向量数据库:
retriever_model = WeaviateRM("my_collection_name", weaviate_client=client)
dspy.configure(lm=llm, rm=retriever_model)
典型应用模式
问答系统
class QAModule(dspy.Module):
def __init__(self):
super().__init__()
self.predict = dspy.Predict("question -> answer")
def forward(self, question):
return self.predict(question=question)
lm = dspy.LM("openai/gpt-4o-mini")
qa = QAModule()
qa.set_lm(lm)
result = qa(question="什么是DSPy?")
带推理链的问答
cot = dspy.ChainOfThought("question -> answer")
result = cot(question="1+1等于几?")
检索增强生成
retrieve = dspy.Retrieve(k=3)
passages = retrieve("机器学习基础").passages
开发环境配置
DSPy要求Python 3.10或更高版本。使用uv进行环境管理:
uv venv --python 3.10
uv sync --extra dev
运行测试:
uv run pytest tests/predict
相关研究
DSPy基于以下核心研究论文:
- [2025年7月] GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning
- [2024年6月] Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs
- [2023年10月] DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines
总结
DSPy通过声明式编程范式和自动优化机制,大大简化了基于语言模型应用的开发流程。其核心组件包括:
- Module系统:提供程序结构的统一抽象
- Signature机制:声明式定义输入输出语义
- Teleprompter优化器:自动化提示和参数优化
- Adapter适配层:支持多种语言模型和工具集成
这套架构使得开发者可以专注于业务逻辑,而将提示工程的具体实现交给DSPy的优化系统自动处理。
资料来源:[example.py:1-250]()
安装与快速开始
DSPy(Declarative Self-Improving Language Model Programs)是一个用于编译声明式语言模型调用的框架,使语言模型程序能够自我改进。本节介绍如何安装 DSPy 框架以及如何快速上手使用该框架进行开发。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy(Declarative Self-Improving Language Model Programs)是一个用于编译声明式语言模型调用的框架,使语言模型程序能够自我改进。本节介绍如何安装 DSPy 框架以及如何快速上手使用该框架进行开发。
DSPy 的设计理念是将语言模型调用声明化,通过优化器和签名系统自动优化提示和演示,从而提升程序性能。
环境要求
| 要求项 | 最低版本 | 说明 |
|---|---|---|
| Python | 3.10+ | 必须使用 Python 3.10 或更高版本 |
| 包管理器 | pip/uv | 用于安装 DSPy 包 |
资料来源:CONTRIBUTING.md:1
安装方式
使用 pip 安装(推荐)
通过 pip 直接安装稳定版本:
pip install dspy
资料来源:README.md:7
安装最新开发版本
如需安装最新的开发版本(从 main 分支),可使用以下命令:
pip install git+https://github.com/stanfordnlp/dspy.git
资料来源:README.md:12
开发环境安装
如需参与 DSPy 开发,推荐使用 uv 或 conda 进行环境管理。
#### 使用 uv 设置开发环境
git clone {url-to-your-fork}
cd dspy
uv sync
验证安装是否成功:
uv run pytest tests/predict
#### 使用 conda 设置开发环境
conda create -n dspy-dev python=3.10
conda activate dspy-dev
pip install -e ".[dev]"
验证安装:
pytest tests/predict
快速开始
基本概念
在使用 DSPy 之前,需要了解以下核心概念:
| 概念 | 类名 | 用途 |
|---|---|---|
| 示例 | dspy.Example | 表示训练或评估数据,包含输入字段和标签字段 |
| 模块 | dspy.Module | 自定义语言模型程序的基类 |
| 预测器 | dspy.Predict | 执行语言模型调用的核心组件 |
| 语言模型 | dspy.LM | 与各种语言模型提供商交互的接口 |
创建 Example 对象
Example 是 DSPy 中表示数据的基本单元。可以通过关键字参数创建:
import dspy
# 创建包含问题答案的示例
example = dspy.Example(question="1+1 等于多少?", answer="2")
资料来源:dspy/primitives/example.py:31-32
标记输入字段
使用 with_inputs() 方法标记哪些字段是输入字段:
example = dspy.Example(
question="今天天气如何?",
answer="晴天"
).with_inputs("question")
标记后,可以使用方法分离输入和标签:
example.inputs().toDict() # {'question': '今天天气如何?'}
example.labels().toDict() # {'answer': '晴天'}
资料来源:dspy/primitives/example.py:87-97
定义模块和预测器
创建一个简单的问答模块:
class SimpleQA(dspy.Module):
def __init__(self):
super().__init__()
self.predict = dspy.Predict("question -> answer")
def forward(self, question):
return self.predict(question=question)
资料来源:dspy/primitives/module.py:1-50
设置语言模型
使用 set_lm() 方法为模块设置语言模型:
lm = dspy.LM("openai/gpt-4o-mini")
qa = SimpleQA()
qa.set_lm(lm)
资料来源:dspy/primitives/module.py:67-78
执行推理
设置好语言模型后,可以执行推理:
result = qa(question="法国的首都是什么?")
print(result.answer)
使用回调监控执行
DSPy 支持通过回调函数监控模块和语言模型的调用:
from dspy.utils.callback import BaseCallback
class LoggingCallback(BaseCallback):
def on_module_start(self, call_id, instance, inputs):
print(f"模块调用: {inputs}")
def on_module_end(self, call_id, outputs):
print(f"模块输出: {outputs}")
# 在语言模型中使用回调
lm = dspy.LM("gpt-3.5-turbo", callbacks=[LoggingCallback()])
资料来源:dspy/utils/callback.py:1-60
构建训练集
将多个 Example 组合成训练集用于优化:
trainset = [
dspy.Example(question="2+2 等于多少?", answer="4").with_inputs("question"),
dspy.Example(question="3+3 等于多少?", answer="6").with_inputs("question"),
]
资料来源:dspy/primitives/example.py:98-102
工作流程图
graph TD
A[创建 Example 数据] --> B[定义 Module]
B --> C[设置 Language Model]
C --> D[执行推理]
D --> E{是否需要优化?}
E -->|是| F[创建训练集和验证集]
F --> G[选择 Teleprompter 优化器]
G --> H[编译优化程序]
H --> I[使用优化后的程序]
E -->|否| I
I --> J[最终部署使用]下一步
- 了解更多 DSPy 核心概念,请参阅签名(Signature)文档
- 学习高级优化技术,请参阅 Teleprompter 相关文档
- 了解支持的语言模型提供商,请参阅 LM 配置文档
相关文档
| 文档 | 说明 |
|---|---|
| DSPy Docs | 官方完整文档 |
| GEPA | 反思式提示进化算法论文 |
| DSPy 论文 | 框架核心论文 |
资料来源:[CONTRIBUTING.md:1]()
签名(Signatures)
签名(Signature)是 DSPy 框架中定义模块输入输出接口的核心抽象。一个签名描述了语言模型程序的输入字段(InputField)和输出字段(OutputField),以及附加的指令说明。签名作为 DSPy 程序的结构化蓝图,定义了数据如何流入和流出各个模块。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
签名(Signature)是 DSPy 框架中定义模块输入输出接口的核心抽象。一个签名描述了语言模型程序的输入字段(InputField)和输出字段(OutputField),以及附加的指令说明。签名作为 DSPy 程序的结构化蓝图,定义了数据如何流入和流出各个模块。
签名的主要作用包括:
- 接口定义:明确指定模块的输入和输出字段
- 提示词构建:自动生成结构化的提示词给语言模型
- 数据验证:确保输入输出数据的结构正确性
- 元编程支持:支持签名的动态组合、修改和转换
资料来源:dspy/signatures/signature.py
核心概念
字段类型
DSPy 提供两种基本字段类型来定义签名中的数据:
| 字段类型 | 用途 | 说明 |
|---|---|---|
InputField | 输入字段 | 描述语言模型需要接收的输入数据 |
OutputField | 输出字段 | 描述语言模型需要生成的输出数据 |
每个字段都可以通过 desc 参数添加描述文本,这些描述会被纳入提示词中,帮助语言模型理解字段的含义。
签名结构
graph TD
A[签名 Signature] --> B[instructions 说明]
A --> C[fields 字段集合]
C --> D[InputField 输入字段]
C --> E[OutputField 输出字段]
D --> F[field_name 字段名]
D --> G[annotation 类型注解]
D --> H[desc 描述文本]
E --> F2[field_name 字段名]
E --> G2[annotation 类型注解]
E --> H2[desc 描述文本]Signature 类 API
主要方法
| 方法名 | 用途 | 返回类型 |
|---|---|---|
with_instructions(instructions) | 创建带新指令的签名副本 | type[Signature] |
with_updated_fields(name, **kwargs) | 更新指定字段的属性 | type[Signature] |
prepend(name, field, type_=None) | 在签名开头插入新字段 | type[Signature] |
append(name, field, type_=None) | 在签名末尾追加新字段 | type[Signature] |
insert(pos, name, field, type_=None) | 在指定位置插入字段 | type[Signature] |
delete(name) | 删除指定字段 | type[Signature] |
资料来源:dspy/signatures/signature.py:1-200
with_instructions 方法
创建具有新指令文本的签名类副本:
class MySig(dspy.Signature):
input_text: str = dspy.InputField(desc="Input text")
output_text: str = dspy.OutputField(desc="Output text")
NewSig = MySig.with_instructions("Translate to French.")
# NewSig.instructions == "Translate to French."
此方法不会修改原签名,而是返回一个新的签名类。
资料来源:dspy/signatures/signature.py
with_updated_fields 方法
更新指定字段的元数据属性:
class MySig(dspy.Signature):
question: str = dspy.InputField()
answer: str = dspy.OutputField()
UpdatedSig = MySig.with_updated_fields(
"answer",
desc="The final answer",
prefix="Result: "
)
资料来源:dspy/signatures/signature.py
字段操作方法
graph LR
A[原 Signature] -->|prepend| B[在开头插入]
A -->|append| C[在末尾追加]
A -->|insert| D[在指定位置]
A -->|delete| E[删除字段]
B --> F[new Signature]
C --> F
D --> F
E --> Fprepend 方法 - 在输入字段部分的开头插入新字段:
NewSig = MySig.prepend("context", dspy.InputField(desc="Context for translation"))
append 方法 - 在输出字段部分的末尾追加新字段:
NewSig = MySig.append("confidence", dspy.OutputField(desc="Translation confidence"))
delete 方法 - 返回移除指定字段后的新签名:
NewSig = MySig.delete("unnecessary_field")
资料来源:dspy/signatures/signature.py
make_signature 函数
除了使用类语法定义签名外,DSPy 还提供了 make_signature 工具函数,支持多种签名定义格式:
函数签名
def make_signature(
signature: str | dict,
*,
fresh_fields: bool = True,
check_args: bool = True,
custom_types: dict[str, type] | None = None,
) -> dict[str, FieldInfo]:
支持的格式
| 格式类型 | 示例 | 说明 |
|---|---|---|
| 字符串格式 | "question -> answer" | 使用 -> 分隔输入输出 |
| 字典格式 | {"question": str, "answer": str} | 键值对形式 |
| 元组格式 | {"q": (str, InputField())} | 指定类型和字段 |
# 字符串格式
sig1 = make_signature("question, context -> answer")
# 字典格式
sig2 = make_signature({
"question": (str, InputField()),
"answer": (str, OutputField())
})
# 使用自定义类型
class MyType:
pass
sig3 = make_signature(
"input: MyType -> output",
custom_types={"MyType": MyType}
)
使用示例
基本用法
import dspy
class RAGSignature(dspy.Signature):
"""回答基于给定上下文的问题"""
context: str = dspy.InputField(desc="用于回答问题的上下文信息")
question: str = dspy.InputField(desc="需要回答的问题")
answer: str = dspy.OutputField(desc="基于上下文得出的答案")
# 使用签名创建预测器
predict = dspy.Predict(RAGSignature)
result = predict(context="巴黎是法国的首都。", question="法国的首都是哪里?")
print(result.answer) # 输出生成的答案
与 Example 类集成
签名与 Example 类紧密配合使用:
import dspy
# 创建带输入标记的示例
example = dspy.Example(
question="What is 2+2?",
answer="4"
).with_inputs("question")
# example.inputs() 返回只包含 question 的示例
# example.labels() 返回只包含 answer 的示例
资料来源:dspy/primitives/example.py
在模块中使用
签名可以被 DSPy 模块继承和组合:
import dspy
class MyModule(dspy.Module):
def __init__(self):
super().__init__()
self.qa = dspy.Predict("question -> answer")
self.summarize = dspy.Predict("text -> summary")
def forward(self, question: str) -> dspy.Prediction:
return self.qa(question=question)
资料来源:dspy/primitives/module.py
高级用法
动态签名构建
通过组合方法动态构建复杂签名:
base_sig = dspy.make_signature("input_text -> output_text")
# 链式调用添加字段
enhanced_sig = (
base_sig
.prepend("system_prompt", dspy.InputField(desc="系统提示词"))
.append("confidence", dspy.OutputField(desc="置信度"))
)
class EnhancedPredictor(dspy.Signature):
pass
EnhancedPredictor.__signature__ = enhanced_sig
签名字段更新
修改现有签名的字段描述:
original = dspy.make_signature("query -> result")
# 更新字段描述
refined = original.with_updated_fields(
"query",
desc="搜索查询词",
prefix="查询: "
)
refined = refined.with_updated_fields(
"result",
desc="搜索结果",
prefix="结果: "
)
最佳实践
1. 清晰的字段描述
为每个字段提供准确的 desc 描述,这会直接影响语言模型的理解和输出质量:
class GoodSignature(dspy.Signature):
email_content: str = dspy.InputField(
desc="完整的电子邮件内容,包括发件人、主题和正文"
)
sentiment: str = dspy.OutputField(
desc="情感分类结果,必须是 'positive'、'negative' 或 'neutral' 之一"
)
2. 类型注解
使用适当的类型注解可以增强代码可读性和 IDE 支持:
class TypedSignature(dspy.Signature):
user_id: int = dspy.InputField(desc="用户唯一标识符")
query: str = dspy.InputField(desc="用户查询文本")
response: str = dspy.OutputField(desc="生成的响应文本")
confidence: float = dspy.OutputField(desc="响应置信度,范围 0-1")
3. 签名组合策略
当构建复杂流水线时,考虑按功能拆分签名:
graph TD
subgraph 预处理阶段
A1[TextInput] --> A2[PreprocessedText]
end
subgraph 处理阶段
A2 --> B1[AnalyzeText]
B1 --> B2[AnalysisResult]
end
subgraph 生成阶段
B2 --> C1[GenerateResponse]
C1 --> C2[FinalOutput]
end相关模块
| 模块 | 路径 | 用途 |
|---|---|---|
| signatures/signature.py | dspy/signatures/signature.py | Signature 类定义 |
| signatures/field.py | dspy/signatures/field.py | InputField 和 OutputField |
| signatures/utils.py | dspy/signatures/utils.py | make_signature 工具函数 |
| signatures/\_signature_do_not_use_directly.py | dspy/signatures/ | 内部实现 |
参考链接
资料来源:[dspy/signatures/signature.py](https://github.com/stanfordnlp/dspy/blob/main/dspy/signatures/signature.py)
内置模块参考
DSPy 内置模块是框架提供的核心组件,用于构建和执行语言模型程序。这些模块封装了常见的提示词工程模式,包括思维链推理、工具调用、并行处理等,使开发者能够以声明式的方式组合复杂的 LLM 应用。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy 内置模块是框架提供的核心组件,用于构建和执行语言模型程序。这些模块封装了常见的提示词工程模式,包括思维链推理、工具调用、并行处理等,使开发者能够以声明式的方式组合复杂的 LLM 应用。
内置模块均继承自 dspy.Module 基类,提供了统一的接口和行为规范。每个模块都可以通过签名(Signature)定义输入输出字段,并支持与优化器(Teleprompter)配合使用进行自动优化。
资料来源:dspy/primitives/module.py:1-50
模块体系架构
DSPy 的内置模块遵循分层设计架构,核心模块为 Predict,其他高级模块在其基础上组合扩展。
graph TD
A[dspy.Module 基类] --> B[Predict 基础模块]
B --> C1[ChainOfThought 思维链]
B --> C2[Parallel 并行预测]
B --> C3[Retry 重试机制]
B --> C4[BestOfN N选一]
C1 --> D1[ReAct 推理+行动]
C1 --> D2[ProgramOfThought 程序思维]
C1 --> D3[MultiChainComparison 多链比较]
D1 --> E[CodeAct 代码行动]
B --> F[Refine 细化迭代]
B --> G[RLM 推理语言模型]模块基类
dspy.Module 是所有内置模块的基类,提供了通用功能支持。
核心方法
| 方法名 | 说明 | 返回值 |
|---|---|---|
named_predictors() | 返回所有命名预测器元组列表 | list[tuple[str, Predict]] |
predictors() | 返回所有 Predict 实例 | list[Predict] |
set_lm(lm) | 为所有预测器设置语言模型 | None |
get_lm() | 获取模块使用的语言模型 | LM 实例 |
map_named_predictors(func) | 对所有预测器应用转换函数 | self |
inspect_history(n) | 查看最近 n 次 LM 调用历史 | None |
设置语言模型
import dspy
lm = dspy.LM("openai/gpt-4o-mini")
program = dspy.Predict("question -> answer")
program.set_lm(lm)
资料来源:dspy/primitives/module.py:45-75
基础模块
Predict
Predict 是 DSPy 最核心的模块,用于基于签名执行语言模型调用。
#### 基本用法
import dspy
# 简单签名
predict = dspy.Predict("question -> answer")
result = predict(question="What is 1+1?")
# 使用类签名
class MySignature(dspy.Signature):
question: str = dspy.InputField()
answer: str = dspy.OutputField()
predict = dspy.Predict(MySignature)
#### 初始化参数
| 参数 | 类型 | 说明 | 默认值 | |
|---|---|---|---|---|
signature | `str \ | Signature` | 输入输出字段定义 | 必填 |
lm | `LM \ | None` | 语言模型实例 | None |
remote_cache | `dict \ | None` | 远程缓存字典 | None |
推理模块
ChainOfThought(思维链)
ChainOfThought 在 Predict 基础上自动加入推理步骤,要求模型先输出思考过程再给出最终答案。
#### 工作原理
- 修改签名,在输出字段前添加
reasoning字段 - 生成提示词引导模型进行逐步推理
- 提取并返回最终答案
import dspy
cot = dspy.ChainOfThought("question -> answer")
result = cot(question="What is the capital of France?")
print(result.reasoning) # 中间推理过程
print(result.answer) # 最终答案
#### 继承链
Module -> Predict -> ChainOfThought
资料来源:dspy/predict/chain_of_thought.py
MultiChainComparison(多链比较)
MultiChainComparison 允许多个推理链并行执行,并对结果进行比较以选出最优答案。
#### 工作流程
graph TD
A[输入问题] --> B1[推理链1]
A --> B2[推理链2]
A --> B3[推理链3]
B1 --> C[比较结果]
B2 --> C
B3 --> C
C --> D[最优答案]import dspy
mcc = dspy.MultiChainComparison(n=3)
result = mcc(question="Explain quantum entanglement")
资料来源:dspy/predict/multi_chain_comparison.py
工具调用模块
ReAct(推理与行动)
ReAct 结合了推理(Reasoning)和行动(Acting)能力,支持模型使用工具与环境交互。
#### 特性
- 支持定义自定义工具
- 自动管理工具调用循环
- 推理过程透明可见
import dspy
react = dspy.ReAct("question -> answer")
result = react(question="最新科技新闻有哪些?")
CodeAct(代码行动)
CodeAct 扩展了 ReAct 模式,专门用于生成和执行 Python 代码来解决复杂问题。
import dspy
code_act = dspy.CodeAct("problem -> solution")
result = code_act(problem="计算斐波那契数列前20项的和")
#### 执行流程
graph LR
A[问题] --> B[生成代码]
B --> C[执行代码]
C --> D{结果正确?}
D -->|是| E[返回结果]
D -->|否| B迭代优化模块
Refine(细化迭代)
Refine 通过迭代方式逐步细化答案,每次迭代基于前一次的结果进行调整。
import dspy
refine = dspy.Refine("question -> answer", max_iters=3)
result = refine(question="解释机器学习原理")
#### 迭代过程
- 初始化:生成初始答案
- 评估:检查当前答案质量
- 细化:根据反馈更新答案
- 重复:直到满足条件或达到最大迭代次数
Retry(重试机制)
Retry 在预测失败时自动重试,并可选择性地向模型提供错误信息以引导修正。
import dspy
retry_predict = dspy.Retry("question -> answer")
result = retry_predict(question="What is 1+1?")
#### 重试策略
| 参数 | 说明 | 默认值 |
|---|---|---|
max_retries | 最大重试次数 | 3 |
on_error | 错误处理回调 | 内置格式化 |
并行与选择模块
Parallel(并行预测)
Parallel 允许同时执行多个预测器,适合需要并行处理多种推理路径的场景。
import dspy
parallel = dspy.Parallel(
dspy.Predict("input -> output_a"),
dspy.Predict("input -> output_b"),
dspy.ChainOfThought("input -> output_c")
)
results = parallel(input="some text")
BestOfN(N选一)
BestOfN 生成 N 个候选答案,并使用指定的选择标准选出最优结果。
import dspy
bon = dspy.BestOfN("question -> answer", n=5)
result = bon(question="最佳编程语言是什么?")
#### 选择机制
graph TD
A[生成N个候选] --> B[应用评分函数]
B --> C[排序候选结果]
C --> D[返回最优答案]资料来源:dspy/predict/best_of_n.py
Program of Thought
ProgramOfThought 采用代码作为中间推理表示,通过生成和执行 Python 代码片段来解决问题。
import dspy
pot = dspy.ProgramOfThought("problem -> answer")
result = pot(problem="求解微分方程 dy/dx = 2x")
#### 与 CodeAct 的区别
| 特性 | ProgramOfThought | CodeAct |
|---|---|---|
| 交互方式 | 生成代码片段 | 生成并执行完整代码 |
| 执行环境 | 隔离的解释器 | 完整 Python 环境 |
| 适用场景 | 数学计算、逻辑推理 | 复杂系统操作 |
资料来源:dspy/predict/program_of_thought.py
RLM(推理语言模型)
RLM 是底层的语言模型封装模块,提供对各种 LLM 提供商的统一接口。
import dspy
lm = dspy.LM("openai/gpt-4o-mini")
result = lm(question="What is the meaning of life?")
#### 支持的模型格式
provider/model-name(如openai/gpt-4o-mini)- 支持的提供商包括 OpenAI、Anthropic、Google、本地模型等
资料来源:dspy/predict/rlm.py
模块导出清单
所有内置模块可通过 dspy.predict 命名空间访问:
| 模块 | 导入路径 | 说明 |
|---|---|---|
Predict | dspy.Predict | 基础预测模块 |
ChainOfThought | dspy.ChainOfThought | 思维链推理 |
CoT | dspy.CoT | ChainOfThought 别名 |
ReAct | dspy.ReAct | 推理+行动 |
ProgramOfThought | dspy.ProgramOfThought | 程序思维 |
MultiChainComparison | dspy.MultiChainComparison | 多链比较 |
Parallel | dspy.Parallel | 并行预测 |
Refine | dspy.Refine | 迭代细化 |
BestOfN | dspy.BestOfN | N选一 |
CodeAct | dspy.CodeAct | 代码行动 |
Retry | dspy.Retry | 重试机制 |
组合使用示例
构建复杂管道
import dspy
class MyProgram(dspy.Module):
def __init__(self):
super().__init__()
self.cot = dspy.ChainOfThought("question -> reasoning, answer")
self.refine = dspy.Refine("initial_answer -> refined_answer")
self.verify = dspy.Predict("question, answer -> is_correct")
def forward(self, question):
cot_result = self.cot(question=question)
refined = self.refine(initial_answer=cot_result.answer)
verification = self.verify(question=question, answer=refined.refined_answer)
return {
"reasoning": cot_result.reasoning,
"answer": refined.refined_answer,
"verified": verification.is_correct
}
program = MyProgram()
result = program(question="What is the square root of 144?")
与优化器结合
from dspy.teleprompt import BootstrapFewShot
# 使用内置模块构建程序
student = dspy.ChainOfThought("question -> answer")
# 编译优化
optimizer = BootstrapFewShot(metric=your_metric)
compiled = optimizer.compile(student, trainset=trainset)
最佳实践
1. 选择合适的模块
| 场景 | 推荐模块 |
|---|---|
| 简单问答 | Predict |
| 需要推理过程 | ChainOfThought |
| 多角度分析 | MultiChainComparison |
| 需要工具交互 | ReAct |
| 代码生成执行 | CodeAct / ProgramOfThought |
| 提高可靠性 | Retry / BestOfN |
2. 性能考虑
Parallel适用于可并行的独立任务BestOfN会增加 N 倍的 API 调用,应根据延迟要求选择Refine的max_iters参数需权衡质量与成本
3. 调试技巧
# 检查模块的 LM 调用历史
program.inspect_history(n=5)
# 查看当前使用的语言模型
lm = program.get_lm()
# 批量替换预测器
program.map_named_predictors(lambda p: dspy.Retry(p.signature))
资料来源:[dspy/primitives/module.py:1-50](https://github.com/stanfordnlp/dspy/blob/main/dspy/primitives/module.py)
原语与数据结构
DSPy 框架的原语(Primitives)与数据结构构成了整个框架的核心抽象层。这些基础组件定义了如何表示数据、执行程序、管理模块间的通信,以及实现代码的沙箱执行能力。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy 框架的原语(Primitives)与数据结构构成了整个框架的核心抽象层。这些基础组件定义了如何表示数据、执行程序、管理模块间的通信,以及实现代码的沙箱执行能力。
DSPy 的原语系统主要包括以下几个核心组件:
| 组件 | 文件路径 | 职责 |
|---|---|---|
Example | dspy/primitives/example.py | 数据样本表示与输入/输出字段管理 |
Prediction | dspy/primitives/prediction.py | 程序执行结果的容器 |
Module | dspy/primitives/module.py | 所有 DSPy 程序的基类 |
PythonInterpreter | dspy/primitives/python_interpreter.py | Python 代码的安全执行环境 |
CodeInterpreter | dspy/primitives/code_interpreter.py | 代码解释器与 REPL 支持 |
资料来源:dspy/primitives/__init__.py
核心数据结构
Example 类
Example 是 DSPy 中用于表示数据样本的基础数据结构,类似于字典但提供了更丰富的语义支持。
#### 基本功能
import dspy
# 创建 Example 实例
example = dspy.Example(question="巴黎是哪国的首都?", answer="法国").with_inputs("question")
# 访问字段
print(example.question) # 输出: 巴黎是哪国的首都?
print(example.answer) # 输出: 法国
#### 字段分类系统
Example 类通过 with_inputs() 方法将字段分为两类:
- 输入字段(Inputs):程序执行时需要提供的外部数据
- 标签字段(Labels):期望的输出结果,用于评估和训练
# 使用 inputs() 和 labels() 方法分离字段
input_fields = example.inputs() # 只包含 question
label_fields = example.labels() # 只包含 answer
资料来源:dspy/primitives/example.py:1-200
#### 常用方法
| 方法 | 功能 | 返回类型 |
|---|---|---|
with_inputs(*keys) | 标记输入字段 | Example |
inputs() | 获取输入字段子集 | Example |
labels() | 获取标签字段子集 | Example |
copy(**kwargs) | 创建带修改的副本 | Example |
without(*keys) | 移除指定字段 | Example |
toDict() | 转换为字典格式 | dict |
get(key, default) | 安全获取字段值 | 任意类型 |
keys() / values() / items() | 字典式访问 | list |
#### 序列化支持
toDict() 方法支持递归序列化,能够处理嵌套的 Example 对象、Pydantic 模型、列表和字典,确保输出为 JSON 友好的格式:
def convert_to_serializable(value):
if hasattr(value, "toDict"):
return value.toDict()
elif isinstance(value, BaseModel):
return value.model_dump()
elif isinstance(value, list):
return [convert_to_serializable(item) for item in value]
elif isinstance(value, dict):
return {k: convert_to_serializable(v) for k, v in value.items()}
资料来源:[dspy/primitives/__init__.py]()
优化器详解
DSPy 的优化器(Optimizer,亦称 Teleprompter)是框架的核心组件,负责自动优化程序中的提示词(Prompt)和演示示例(Demos),以提升语言模型在特定任务上的表现。优化器通过编译(Compile)过程,将声明式的 DSPy 程序转换为经过优化的自改进流水线。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy 的优化器(Optimizer,亦称 Teleprompter)是框架的核心组件,负责自动优化程序中的提示词(Prompt)和演示示例(Demos),以提升语言模型在特定任务上的表现。优化器通过编译(Compile)过程,将声明式的 DSPy 程序转换为经过优化的自改进流水线。
DSPy 优化器的工作机制遵循"Bootstrap"范式:先用初始配置运行程序,收集失败的案例,再利用语言模型自动生成改进的提示词或演示示例,如此迭代优化直到达到满意的性能水平。 资料来源:dspy/teleprompt/bettertogether.py
架构设计
优化器继承体系
所有 DSPy 优化器均继承自 dspy.teleprompt.Teleprompter 基类。基类定义了 compile() 接口,各子类实现具体的优化策略。
graph TD
A[Teleprompter 基类] --> B[BootstrapFewShot]
A --> C[BootstrapFewShotWithRandomSearch]
A --> D[BootstrapFinetune]
A --> E[MIPROv2]
A --> F[GEPA]
A --> G[BetterTogether]
A --> H[Ensemble]
A --> I[COPRO]
A --> J[KNNFewShot]
A --> K[SimBA]
A --> L[GRPO]
G --> |组合多个优化器| M[元优化器]核心编译流程
graph LR
A[Program] --> B[初始化运行]
B --> C[收集轨迹]
C --> D{评估指标}
D --> |未达标| E[生成候选]
E --> F[评估候选]
F --> G[选择最优]
G --> D
D --> |达标| H[优化后程序]内置优化器详解
1. BootstrapFewShotWithRandomSearch
这是 DSPy 中最基础的优化器,结合了 Bootstrap 演示生成和随机搜索策略。它会生成多个候选配置(不同的提示词和演示组合),然后在验证集上评估选择最优方案。 资料来源:dspy/teleprompt/random_search.py
#### 核心参数
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
metric | Callable | 评估指标函数,签名 metric(example, pred, trace) -> bool | 必填 |
max_bootstrapped_demos | int | 每个预测模块最多保留的演示数量 | 4 |
max_rounds | int | 最大优化轮次 | 1 |
num_candidates | int | 随机搜索的候选数量 | 10 |
num_threads | int | 并行线程数 | 1 |
#### 使用示例
import dspy
# 定义评估指标
def metric(example, pred, trace=None):
return example.answer.lower() == pred.answer.lower()
# 创建优化器
optimizer = BootstrapFewShotWithRandomSearch(
metric=metric,
max_bootstrapped_demos=4,
num_candidates=10
)
# 编译程序
compiled_program = optimizer.compile(
student=program,
trainset=trainset,
valset=valset
)
2. BootstrapFinetune
BootstrapFinetune 是 DSPy 的微调优化器,通过 Bootstrap 生成的优质数据对语言模型进行微调。它先生成高质量的演示示例,然后利用这些数据对轻量级语言模型进行微调。 资料来源:dspy/teleprompt/bootstrap_finetune.py
#### 核心参数
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
metric | Callable | 评估指标函数 | 必填 |
teacher_settings | dict | 教师模型的设置 | None |
finetune_settings | dict | 微调设置(如训练轮数、学习率) | {} |
max_bootstrapped_demos | int | Bootstrap 演示数量上限 | 8 |
3. MIPROv2 (Multi-Instruction Prompt Optimization v2)
MIPROv2 是先进的提示优化器,采用贝叶斯优化策略同时优化指令和演示。它通过考虑指令与演示之间的交互作用,实现更高效的提示词优化。 资料来源:dspy/teleprompt/mipro_optimizer_v2.py
#### 核心参数
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
metric | Callable | 评估指标函数 | 必填 |
num_trials | int | 贝叶斯优化试验次数 | 20 |
max_bootstrapped_demos | int | 演示数量上限 | 4 |
num_examples | int | 每轮使用的训练样本数 | 200 |
auto | str | 自动模式级别:"light"、"medium"、"heavy" | None |
bootstrap_dataset_size | int | Bootstrap 数据集大小 | None |
#### 优化策略
MIPROv2 的核心创新在于将指令优化与演示选择联合考虑:
graph TD
A[贝叶斯优化器] --> B[指令提议器]
A --> C[演示采样器]
B --> D[候选指令集合]
C --> E[候选演示集合]
D --> F[笛卡尔积组合]
E --> F
F --> G[评估函数]
G --> H[更新贝叶斯模型]
H --> A4. GEPA (Generalized Evolved Prompt Agent)
GEPA 是基于进化算法的提示优化器,通过反思性提示进化策略实现自动优化。它在多阶段语言模型程序的优化中表现出色。 资料来源:dspy/teleprompt/gepa/gepa.py
#### 核心参数
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
metric | Callable | 评估指标函数 | 必填 |
auto | str | 自动模式:"light"、"medium"、"full" | None |
num_prompt_instructions | int | 基础指令数量 | 10 |
max_bootstrap两会 | int | Bootstrap 演示上限 | 4 |
5. BetterTogether (元优化器)
BetterTogether 是 DSPy 的元优化器框架,可以将多个优化器组合成流水线。它支持自定义优化器组合策略,实现复杂的优化流程。 资料来源:dspy/teleprompt/bettertogether.py
#### 设计理念
BetterTogether 将优化过程分解为两个阶段:
- 提示优化阶段 (Prompt Optimization, p):优化指令和提示词
- 权重优化阶段 (Weight Optimization, w):通过 Bootstrap Finetune 优化权重
#### 使用示例
from dspy.teleprompt import BetterTogether, MIPROv2, BootstrapFinetune
# 方式一:使用自定义优化器组合
optimizer = BetterTogether(
metric=metric,
p=MIPROv2(metric=metric, auto="medium"),
w=BootstrapFinetune(metric=metric)
)
# 方式二:使用默认优化器
optimizer = BetterTogether(metric=metric)
# 编译并指定策略
compiled = optimizer.compile(
student=program,
trainset=trainset,
valset=valset,
strategy="p -> w" # 提示优化后接权重优化
)
#### 策略配置
| 策略字符串 | 说明 |
|---|---|
"p" | 仅执行提示优化 |
"w" | 仅执行权重优化 |
"p -> w" | 先提示优化后权重优化 |
"w -> p" | 先权重优化后提示优化 |
"p -> w -> p" | 交替优化 |
6. COPRO (Coordinate Prompt Optimization)
COPRO 是一种协同提示优化方法,通过分析程序结构来优化各个模块的提示词。 资料来源:dspy/teleprompt/copro_optimizer.py
7. SimBA (Simple Bootstrap Agent)
SimBA 是轻量级的 Bootstrap 优化器,适用于资源受限场景。它简化了优化流程,同时保持较好的优化效果。 资料来源:dspy/teleprompt/simba.py
8. KNNFewShot (K-Nearest Neighbors Few-Shot)
KNNFewShot 利用 K 近邻算法为每个测试样本选择最相关的演示示例,实现动态演示选择。 资料来源:dspy/teleprompt/knn_fewshot.py
9. Ensemble
Ensemble 优化器通过集成多个不同配置的预测模块来提升整体性能,适用于需要高稳定性的生产环境。 资料来源:dspy/teleprompt/ensemble.py
10. GRPO (Group Relative Policy Optimization)
GRPO 是一种基于强化学习的优化方法,通过组内相对策略优化来提升语言模型程序性能。 资料来源:dspy/teleprompt/grpo.py
优化器选择指南
graph TD
A[开始选择] --> B{场景类型}
B -->|快速原型开发| C[BootstrapFewShotWithRandomSearch]
B -->|高质量演示| D[BootstrapFinetune]
B -->|联合优化| E[MIPROv2]
B -->|进化策略| F[GEPA]
B -->|复杂流水线| G[BetterTogether]
B -->|动态演示| H[KNNFewShot]
B -->|集成预测| I[Ensemble]
C --> J[性能基准]
D --> J
E --> J
F --> J
G --> J
H --> J
I --> J场景推荐
| 场景 | 推荐优化器 | 理由 |
|---|---|---|
| 快速实验 | BootstrapFewShotWithRandomSearch | 配置简单、速度快 |
| 资源充足追求最优 | MIPROv2 | 贝叶斯优化效果好 |
| 多阶段流水线 | GEPA / BetterTogether | 支持复杂优化策略 |
| 边缘部署 | SimBA | 轻量级实现 |
| 高稳定性需求 | Ensemble | 多模型集成 |
Teleprompter 基类接口
所有优化器都实现以下核心接口:
class Teleprompter:
def compile(
self,
student: Module,
*,
trainset: list[Example],
valset: list[Example] = None,
**kwargs
) -> Module:
"""编译学生程序"""
raise NotImplementedError
compile 方法参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
student | Module | 是 | 待优化的 DSPy 程序 |
trainset | list[Example] | 是 | 训练数据集 |
valset | list[Example] | 否 | 验证数据集,部分优化器需要 |
max_bootstrapped_demos | int | 否 | Bootstrap 演示上限 |
max_rounds | int | 否 | 最大优化轮次 |
num_threads | int | 否 | 并行线程数 |
评估指标设计
优化器依赖高质量的评估指标函数。指标函数应满足以下签名:
def metric(example: Example, pred: Prediction, trace=None) -> bool | float:
"""
参数:
example: 测试样本
pred: 模型预测结果
trace: 轨迹信息(可选,用于 Bootstrap 过程
返回:
bool 或 float: 评估结果
"""
指标函数示例
# 精确匹配指标
def exact_match(example, pred, trace=None):
return example.answer.lower().strip() == pred.answer.lower().strip()
# 带权重的复合指标
def weighted_metric(example, pred, trace=None):
exact = example.answer.lower() == pred.answer.lower()
confidence = pred.get("confidence", 1.0)
return exact * confidence
# 使用 trace 信息(用于 Bootstrap)
def bootstrap_metric(example, pred, trace):
if trace is None:
return example.answer.lower() == pred.answer.lower()
# Bootstrap 过程中可使用更多上下文信息
return int(trace.get("cost", 1)) < 10
最佳实践
1. 数据集划分
# 正确划分数据集
trainset = [example.with_inputs("question") for example in train_examples]
valset = [example.with_inputs("question") for example in val_examples]
# 确保 valset 有足够的样本用于可靠评估
assert len(valset) >= 20, "验证集应至少包含 20 个样本"
2. 指标设计原则
- 可量化:指标应能客观衡量输出质量
- 稳定可靠:多次运行应产生一致结果
- 与任务目标一致:指标应反映实际业务需求
3. 优化器配置建议
| 配置项 | 建议值 | 说明 |
|---|---|---|
max_bootstrapped_demos | 4-8 | 过多演示可能增加上下文负担 |
num_trials (MIPROv2) | 20-50 | 试验次数越多效果越好但耗时增加 |
num_candidates | 10-20 | 候选数量影响搜索空间大小 |
4. 性能调优
# 使用并行化加速
optimizer = BootstrapFewShotWithRandomSearch(
metric=metric,
num_threads=8 # 利用多核 CPU
)
# 控制资源使用
optimizer = MIPROv2(
metric=metric,
num_trials=20, # 限制试验次数
num_examples=100 # 限制样本数
)
常见问题
Q1: 优化器编译失败怎么办?
检查以下几点:
- 确认
metric函数签名正确且可调用 - 确保
trainset和valset非空且格式正确 - 验证
Example对象已通过with_inputs()设置输入字段
Q2: 如何选择合适的优化器?
参考"优化器选择指南"章节,从场景复杂度、可用资源和性能要求三个维度考量。
Q3: 优化后的性能不理想怎么办?
- 尝试更换优化器类型
- 调整优化器参数(如增加试验次数)
- 改进评估指标函数
- 检查数据集质量和规模
Q4: 如何调试优化过程?
import logging
logging.basicConfig(level=logging.INFO)
# 启用详细输出
optimizer = MIPROv2(metric=metric, verbose=True)
参考链接
来源:https://github.com/stanfordnlp/dspy / 项目说明书
语言模型客户端
DSPy 的语言模型客户端是框架与各种大语言模型(LLM)交互的核心抽象层。它提供了统一的接口,使开发者能够通过简洁的 API 调用不同的语言模型提供商,同时支持缓存、回调、批处理等高级功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy 的语言模型客户端是框架与各种大语言模型(LLM)交互的核心抽象层。它提供了统一的接口,使开发者能够通过简洁的 API 调用不同的语言模型提供商,同时支持缓存、回调、批处理等高级功能。
语言模型客户端在 DSPy 架构中扮演着至关重要的角色:它被 dspy.Module 中的预测器(如 dspy.Predict、dspy.ChainOfThought 等)调用,为整个程序提供推理能力。
架构设计
模块层次结构
DSPy 的语言模型客户端采用分层架构设计:
graph TD
A[dspy.LM 统一入口] --> B[BaseLM 抽象基类]
B --> C[OpenAI 客户端]
B --> D[LiteLLM 客户端]
B --> E[Databricks 客户端]
B --> F[Local LM 客户端]
G[Embedding 嵌入客户端] --> H[Embedder 类]
G --> I[缓存层 Cache]核心组件
| 组件 | 文件路径 | 职责 |
|---|---|---|
dspy.LM | dspy/clients/lm.py | 统一入口,支持多种模型提供商 |
BaseLM | dspy/clients/base_lm.py | 抽象基类,定义接口规范 |
OpenAI | dspy/clients/openai.py | OpenAI API 专用客户端 |
_LiteLLM | dspy/clients/_litellm.py | LiteLLM 封装,支持 100+ 模型 |
Databricks | dspy/clients/databricks.py | Databricks 模型服务 |
LocalLM | dspy/clients/lm_local.py | 本地部署模型 |
Embedder | dspy/clients/embedding.py | 文本嵌入模型客户端 |
Cache | dspy/clients/cache.py | 请求缓存管理 |
Provider | dspy/clients/provider.py | 模型提供商配置 |
使用方式
基本初始化
import dspy
# 使用 OpenAI 模型
lm = dspy.LM("openai/gpt-4o-mini")
# 使用本地模型
lm = dspy.LM("ollama/llama3")
# 配置回调函数
from dspy.utils.callback import LoggingCallback
lm = dspy.LM("gpt-3.5-turbo", callbacks=[LoggingCallback()])
在模块中使用
语言模型客户端通过 dspy.Module 的 set_lm() 方法与预测器关联:
import dspy
class MyProgram(dspy.Module):
def __init__(self):
super().__init__()
self.predict = dspy.Predict("question -> answer")
def forward(self, question):
return self.predict(question=question)
# 创建程序并设置语言模型
lm = dspy.LM("openai/gpt-4o-mini")
program = MyProgram()
program.set_lm(lm)
获取模块当前使用的语言模型:
current_lm = program.get_lm()
Embedder 嵌入客户端
Embedder 类是 DSPy 中用于处理文本嵌入的专用客户端,支持自定义嵌入函数和多种模型。
核心参数
| 参数 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
model | `str \ | Callable` | - | 模型名称或自定义嵌入函数 |
batch_size | int | 200 | 批处理大小 | |
caching | bool | True | 是否启用缓存 | |
**kwargs | dict | - | 传递给模型的额外参数 |
使用示例
import dspy
import numpy as np
# 示例 1:使用预定义模型
embedder = dspy.Embedder("openai/text-embedding-3-small")
embeddings = embedder(["hello", "world"], batch_size=1)
assert embeddings.shape == (2, 1536)
# 示例 2:使用自定义函数
def my_embedder(texts):
return np.random.rand(len(texts), 10)
embedder = dspy.Embedder(my_embedder)
embeddings = embedder(["hello", "world"], batch_size=1)
assert embeddings.shape == (2, 10)
内部处理流程
Embedder 的 _preprocess() 方法负责输入预处理:
def _preprocess(self, inputs, batch_size=None, caching=None, **kwargs):
# 1. 处理单个字符串输入
if isinstance(inputs, str):
is_single_input = True
inputs = [inputs]
else:
is_single_input = False
# 2. 验证所有输入为字符串
if not all(isinstance(inp, str) for inp in inputs):
raise ValueError("All inputs must be strings.")
# 3. 合并默认参数与自定义参数
batch_size = batch_size or self.batch_size
caching = caching if caching is not None else self.caching
merged_kwargs = self.default_kwargs.copy()
merged_kwargs.update(kwargs)
# 4. 分批处理
input_batches = []
for i in range(0, len(inputs), batch_size):
input_batches.append(inputs[i : i + batch_size])
return input_batches, caching, merged_kwargs, is_single_input
回调机制
DSPy 提供回调系统用于监控和调试语言模型调用。回调通过 BaseCallback 抽象类定义:
from dspy.utils.callback import BaseCallback
class LoggingCallback(BaseCallback):
def on_module_start(self, call_id, instance, inputs):
print(f"LM is called with inputs: {inputs}")
def on_module_end(self, call_id, outputs):
print(f"LM is finished with outputs: {outputs}")
回调使用方式:
# 方式 1:全局配置
dspy.configure(callbacks=[LoggingCallback()])
# 方式 2:组件级别配置
lm = dspy.LM("gpt-3.5-turbo", callbacks=[LoggingCallback()])
缓存机制
DSPy 的缓存层位于 dspy/clients/cache.py,用于存储和检索已计算的模型响应,避免重复 API 调用。
缓存的主要特性:
- 基于请求参数的内容寻址
- 支持配置 TTL(生存时间)
- 可与各种模型客户端无缝集成
模型提供商
支持的提供商类型
| 提供商 | 客户端类 | 说明 |
|---|---|---|
| OpenAI | OpenAI | OpenAI API 原生支持 |
| Azure | 通过 OpenAI | Azure OpenAI Service |
| Anthropic | 通过 _LiteLLM | Claude 系列模型 |
通过 _LiteLLM | Gemini 系列 | |
| Meta | 通过 _LiteLLM | Llama 系列 |
| Databricks | Databricks | Databricks 模型服务 |
| Ollama | LocalLM | 本地部署模型 |
| LM Studio | LocalLM | 本地部署模型 |
模型标识符格式
# OpenAI 格式
dspy.LM("openai/gpt-4o")
dspy.LM("openai/gpt-4o-mini")
# 自定义格式
dspy.LM("ollama/llama3")
dspy.LM("local/my-model")
最佳实践
1. 全局配置 vs 组件配置
# 全局配置:所有组件共享同一语言模型
dspy.configure(lm=dspy.LM("gpt-4o"))
# 组件配置:特定组件使用特定模型
lm_special = dspy.LM("gpt-4o")
program.set_lm(lm_special)
2. 回调用于调试
class DebugCallback(BaseCallback):
def on_module_start(self, call_id, instance, inputs):
logger.debug(f"Calling LM with: {inputs}")
def on_module_end(self, call_id, outputs):
logger.debug(f"LM returned: {outputs}")
lm = dspy.LM("gpt-4o", callbacks=[DebugCallback()])
3. 嵌入模型批处理优化
# 大批量处理时使用较大 batch_size
embedder = dspy.Embedder("openai/text-embedding-3-small", batch_size=100)
相关文档
源码索引
| 文件 | 功能描述 |
|---|---|
dspy/clients/__init__.py | 客户端模块入口,导出 LM、Embedder 等 |
dspy/clients/lm.py | LM 类实现,支持多种提供商 |
dspy/clients/base_lm.py | BaseLM 抽象基类 |
dspy/clients/openai.py | OpenAI 专用客户端 |
dspy/clients/_litellm.py | LiteLLM 封装 |
dspy/clients/databricks.py | Databricks 客户端 |
dspy/clients/lm_local.py | 本地模型客户端 |
dspy/clients/embedding.py | 嵌入模型客户端 Embedder |
dspy/clients/cache.py | 缓存实现 |
dspy/clients/provider.py | 提供商配置 |
dspy/primitives/module.py | 模块的 set_lm/get_lm 方法 |
dspy/utils/callback.py | 回调系统实现 |
来源:https://github.com/stanfordnlp/dspy / 项目说明书
适配器系统
DSPy 的适配器系统(Adapter System)是框架中负责将程序签名(Signature)转换为语言模型可处理的格式化消息的核心组件。适配器充当 DSPy 程序与底层语言模型 API 之间的桥梁,负责处理输入输出的结构化转换、字段序列化以及响应解析等关键任务。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy 的适配器系统(Adapter System)是框架中负责将程序签名(Signature)转换为语言模型可处理的格式化消息的核心组件。适配器充当 DSPy 程序与底层语言模型 API 之间的桥梁,负责处理输入输出的结构化转换、字段序列化以及响应解析等关键任务。
适配器系统的主要职责包括:
- 消息格式化:将 DSPy 签名中的输入字段转换为语言模型 API 可接受的格式
- 响应解析:将语言模型的输出解析回 DSPy 的结构化数据结构
- 自定义类型支持:处理复杂数据类型(如图像、历史对话等)的序列化与反序列化
- 多格式支持:支持多种输出格式规范(如 JSON、XML、Chat 格式等)
系统架构
核心组件层次
graph TD
A[DSPy 程序] --> B[签名 Signature]
B --> C[适配器 Adapter]
C --> D{适配器类型}
D --> E[ChatAdapter]
D --> F[JSONAdapter]
D --> G[XMLAdapter]
D --> H[TwoStepAdapter]
D --> I[BAMLAdapter]
C --> J[语言模型 LM API]
J --> K[响应 Response]
K --> C
C --> L[Prediction]适配器类型对比
| 适配器类型 | 输出格式 | 解析方式 | 使用场景 |
|---|---|---|---|
| ChatAdapter | Chat Messages | 结构化解析 | 通用对话场景 |
| JSONAdapter | JSON | JSON 解析 | 结构化数据输出 |
| XMLAdapter | XML | XML 解析 | XML 格式要求 |
| TwoStepAdapter | 两阶段格式 | 两步解析 | 复杂推理任务 |
| BAMLAdapter | BAML | BAML 解析器 | 类型安全生成 |
资料来源:dspy/adapters/__init__.py
基础适配器接口
BaseAdapter 抽象基类
所有适配器都继承自 BaseAdapter 抽象基类,定义了适配器的核心接口规范:
class BaseAdapter(ABC):
"""适配器基类,定义所有适配器必须实现的接口"""
@abstractmethod
def format(self, signature, demos, inputs):
"""将签名和输入格式化为模型消息"""
pass
@abstractmethod
def parse(self, signature, response):
"""解析模型响应为预测结果"""
pass
适配器核心方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
| format | signature, demos, inputs | list[dict] | 格式化输入消息 |
| parse | signature, response | Prediction | 解析输出响应 |
| format_field_value | value, field | str | 格式化单个字段值 |
| post_save_hook | output, signature | None | 保存后钩子 |
Chat 适配器
ChatAdapter 是 DSPy 默认的适配器实现,专门用于处理对话格式的语言模型 API(如 OpenAI ChatGPT、Google Gemini 等)。
消息格式转换
ChatAdapter 将 DSPy 的签名转换为标准的聊天消息格式:
graph LR
A[Signature<br/>InputFields] --> B[ChatAdapter]
C[Demos<br/>Few-Shot] --> B
B --> D[System Message<br/>历史指令]
B --> E[User Messages<br/>输入+演示]
B --> F[Assistant Messages<br/>历史响应]核心实现逻辑
def format(self, signature, demos, inputs):
# 构建系统消息(包含指令)
messages = [self._build_system_message(signature)]
# 添加演示示例
for demo in demos:
messages.extend(self._format_demo(demo))
# 添加当前输入
messages.append(self._build_user_message(inputs))
return messages
资料来源:dspy/adapters/chat_adapter.py
JSON 适配器
JSONAdapter 专为需要结构化 JSON 输出的场景设计,适用于需要机器解析输出的应用。
工作流程
graph TD
A[输入字段] --> B[构建Prompt]
B --> C[添加JSON Schema说明]
C --> D[调用LM]
D --> E{响应格式}
E -->|有效JSON| F[json.loads解析]
E -->|无效JSON| G[尝试修复格式]
F --> H[Prediction]
G --> H格式控制机制
JSONAdapter 通过在提示词中嵌入 JSON Schema 来指导模型生成符合规范的输出:
json_schema = {
"type": "object",
"properties": {
"field_name": {"type": "string", "description": "..."}
},
"required": ["field_name"]
}
资料来源:dspy/adapters/json_adapter.py
XML 适配器
XMLAdapter 使用 XML 标签格式封装输出字段,适用于需要明确结构化层次的场景。
标签规范
| 组件 | 标签格式 | 说明 |
|---|---|---|
| 输出块 | <answer> ... </answer> | 包含整个输出 |
| 字段 | <field_name> 值 </field_name> | 单个输出字段 |
| 嵌套 | 层级嵌套标签 | 复杂数据结构 |
解析机制
XMLAdapter 使用正则表达式匹配提取字段值:
pattern = rf"<{field_name}>(.*?)</{field_name}>"
match = re.search(pattern, response)
资料来源:dspy/adapters/xml_adapter.py
TwoStep 适配器
TwoStepAdapter 实现两阶段推理模式,适用于需要"思考-回答"分离的复杂任务。
两阶段流程
graph LR
A[问题] --> B[第一阶段<br/>推理/分析]
B --> C[中间推理结果]
C --> D[第二阶段<br/>生成答案]
D --> E[最终答案]配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| reasoning_field | str | "reasoning" | 推理字段名 |
| answer_field | str | "answer" | 答案字段名 |
| reasoning_type | str | "chain_of_thought" | 推理类型 |
资料来源:dspy/adapters/two_step_adapter.py
自定义类型系统
类型注册机制
DSPy 适配器系统支持自定义复杂类型的处理,通过标识符分割内容:
graph TD
A[消息内容] --> B{包含自定义类型?}
B -->|是| C[查找标识符]
C --> D[<<CUSTOM-TYPE-START-IDENTIFIER>>]
D --> E[提取JSON内容]
E --> F[解析自定义类型]
F --> G[重建消息结构]
B -->|否| H[纯文本处理]类型标识符
| 标识符 | 用途 |
|---|---|
<<CUSTOM-TYPE-START-IDENTIFIER>> | 自定义类型内容开始 |
<<CUSTOM-TYPE-END-IDENTIFIER>> | 自定义类型内容结束 |
资料来源:dspy/adapters/types/base_type.py
内置自定义类型
#### History 类型
History 类型用于管理多轮对话历史:
class History(BaseModel):
"""对话历史类"""
messages: list[dict] # 消息列表,每条消息包含历史对话内容
使用示例:
class MySignature(dspy.Signature):
question: str = dspy.InputField()
history: dspy.History = dspy.InputField()
answer: str = dspy.OutputField()
history = dspy.History(messages=[
{"question": "法国的首都是什么?", "answer": "巴黎"},
{"question": "德国的首都是什么?", "answer": "柏林"},
])
资料来源:dspy/adapters/types/history.py
#### Image 类型
Image 类型支持图像输入处理:
class Image(BaseModel):
"""图像类型,支持URL和本地文件"""
url: str # base64数据URI或URL
支持的数据格式:
| 格式 | 说明 | 适用场景 |
|---|---|---|
| http://... | 网络URL | 公开图像 |
| https://... | 安全URL | 公开图像 |
| data:image/...;base64,... | Base64编码 | 本地/内联图像 |
| file://... | 本地文件路径 | 本地图像 |
图像处理方法:
| 方法 | 说明 |
|---|---|
encode_image() | 编码图像为可传输格式 |
format() | 格式化为 API 消息格式 |
from_url() | 从URL创建(已废弃) |
from_file() | 从文件创建 |
资料来源:dspy/adapters/types/image.py
使用指南
选择合适的适配器
graph TD
A[开始] --> B{输出需求?}
B -->|通用对话| C[ChatAdapter]
B -->|结构化数据| D{数据复杂度?}
D -->|简单| E[JSONAdapter]
D -->|复杂| F[TwoStepAdapter]
B -->|XML格式要求| G[XMLAdapter]
B -->|类型安全| H[BAMLAdapter]配置默认适配器
import dspy
# 全局配置
dspy.settings.configure(adapter=dspy.ChatAdapter())
# 或在程序中指定
class MyProgram(dspy.Module):
def __init__(self):
self.predict = dspy.Predict(
"question -> answer",
adapter=dspy.JSONAdapter()
)
自定义适配器
from dspy.adapters import BaseAdapter
class MyCustomAdapter(BaseAdapter):
def format(self, signature, demos, inputs):
# 自定义格式化逻辑
return messages
def parse(self, signature, response):
# 自定义解析逻辑
return dspy.Prediction(...)
最佳实践
1. 适配器选择建议
| 场景 | 推荐适配器 | 原因 |
|---|---|---|
| 通用应用 | ChatAdapter | 灵活、通用 |
| API 数据提取 | JSONAdapter | 结构化、机器可读 |
| 文档生成 | XMLAdapter | 层次清晰 |
| 推理任务 | TwoStepAdapter | 分离思考与答案 |
| 生产系统 | BAMLAdapter | 类型安全 |
2. 性能优化
- 批处理:使用
batch_size参数控制批处理大小 - 缓存:启用缓存机制减少重复计算
- 类型选择:根据输出复杂度选择最合适的适配器
3. 错误处理
适配器应处理以下常见错误:
| 错误类型 | 处理策略 |
|---|---|
| 解析失败 | 回退到备用解析器或提示重试 |
| 格式不匹配 | 尝试自动修复或抛出明确错误 |
| 超限 | 截断或分片处理 |
总结
DSPy 的适配器系统为框架提供了灵活的消息格式化和解析能力,通过统一的接口抽象支持多种输出格式规范。适配器的模块化设计使得开发者可以轻松扩展新的格式支持,同时内置的多种适配器覆盖了大多数常见使用场景。自定义类型系统的支持进一步增强了框架的表达能力,使得复杂的数据结构处理变得简单可控。
资料来源:[dspy/adapters/base.py](https://github.com/stanfordnlp/dspy/blob/main/dspy/adapters/base.py)
检索增强模块
DSPy的检索增强模块(Retrieval Augmentation Module)是框架中负责从外部知识源获取相关文档或段落的核心组件。该模块通过检索模型(Retriever Model)实现语义搜索功能,使语言模型能够在生成回答时利用外部知识库中的相关信息。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy的检索增强模块(Retrieval Augmentation Module)是框架中负责从外部知识源获取相关文档或段落的核心组件。该模块通过检索模型(Retriever Model)实现语义搜索功能,使语言模型能够在生成回答时利用外部知识库中的相关信息。
检索增强模块的主要职责包括:
- 与向量数据库或检索服务集成,实现语义相似度搜索
- 提供统一的检索接口,支持多种后端实现
- 将检索结果格式化为可被签名(Signature)处理的数据结构
- 支持自定义嵌入模型和检索策略
架构设计
模块层级结构
DSPy的检索增强系统采用分层架构设计,从底层到顶层依次为:
| 层级 | 组件 | 职责 |
|---|---|---|
| 嵌入层 | Embedder | 将文本转换为向量表示 |
| 检索层 | 各类RM实现 | 执行向量相似度搜索 |
| 接口层 | Retrieve | 提供统一的模块化调用接口 |
| 配置层 | dspy.configure() | 全局配置检索模型 |
核心类关系
graph TD
A[dspy.configure] --> B[RM Retriever Model]
B --> C[weaviate_rm.WeaviateRM]
B --> D[databricks_rm.DatabricksRM]
B --> E[colbertv2.ColBERTv2]
F[Retrieve模块] --> B
G[Embedder] --> H[嵌入服务]
B --> GRetrieve 模块
Retrieve是DSPy中用于执行检索的核心模块,继承自Module基类。它作为检索系统的统一入口点,将用户的查询转换为检索请求并返回相关文档。
基本用法
import dspy
# 配置语言模型和检索模型
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))
dspy.configure(rm=WeaviateRM("my_collection", weaviate_client=client))
# 创建Retrieve模块
retrieve = dspy.Retrieve(k=5)
results = retrieve("什么是机器学习")
API 参数说明
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| k | int | 3 | 返回的最相关文档数量 |
| force_by_id | bool | False | 是否强制按ID检索 |
工作流程
sequenceDiagram
用户 ->> Retrieve: 调用retrieve(query)
Retrieve ->> RM: query(query_str, k)
RM ->> 向量数据库: 相似度搜索
向量数据库 ->> RM: 返回Top-K文档
RM ->> Retrieve: 格式化检索结果
Retrieve ->> 用户: 返回Passages对象检索模型(Retriever Model)
检索模型是实际执行向量搜索的后端实现。DSPy支持多种检索后端,每种实现都遵循统一的接口规范。
Retriever 基类接口
所有检索模型都需要实现以下核心方法:
| 方法 | 返回类型 | 说明 |
|---|---|---|
forward(query) | list[str] | 根据查询返回相关文档列表 |
query(query_str, k) | list | 执行检索并返回k个结果 |
__call__(*args, **kwargs) | list[str] | 模块调用接口 |
WeaviateRM 实现
WeaviateRM是与Weaviate向量数据库集成的检索模型实现。
构造函数参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| weaviate_collection_name | str | 是 | Weaviate集合名称 |
| weaviate_client | WeaviateClient | 是 | Weaviate客户端实例 |
| weaviate_collection_text_key | str | 否 | 集合中存储文本的字段名,默认"content" |
| k | int | 否 | 检索结果数量,默认3 |
| tenant_id | str | 否 | 多租户支持 |
配置示例:
import dspy
import weaviate
llm = dspy.Cohere(model="command-r-plus", api_key=api_key)
weaviate_client = weaviate.connect_to_local("your-path-here")
retriever_model = WeaviateRM("my_collection_name", weaviate_client=weaviate_client)
dspy.configure(lm=llm, rm=retriever_model)
retrieve = dspy.Retrieve(k=1)
topK_passages = retrieve("what are the stages in planning").passages
内部机制:
该实现通过weaviate_client.collections.get()获取集合对象,然后使用集合的查询接口执行向量相似度搜索。文本内容通过weaviate_collection_text_key字段提取。
DatabricksRM 实现
DatabricksRM是专门为Databricks平台设计的检索模型,利用Databricks向量搜索服务进行语义检索。
ColBERTv2 实现
ColBERTv2是基于ColBERT算法的延迟交互式检索实现,适用于需要细粒度语义匹配的场景。
from dspy.dsp.colbertv2 import ColBERTv2
retriever = ColBERTv2()
results = retriever("query text", k=5)
DPR 实现
DSPy还提供了基于Dense Passage Retrieval(DPR)的工具函数,位于dspy/dsp/utils/dpr.py中,用于处理双塔模型的检索逻辑。
嵌入模块
Embedder 类
Embedder是封装嵌入模型的统一接口,支持自定义嵌入函数和批量处理。
构造函数参数:
| 参数 | 类型 | 默认值 | 说明 | |
|---|---|---|---|---|
| model | str \ | Callable | 必填 | 嵌入模型名称或自定义函数 |
| batch_size | int | 200 | 批处理大小 | |
| caching | bool | True | 是否启用结果缓存 | |
| kwargs | dict | {} | 传递给嵌入服务的额外参数 |
使用示例:
import dspy
import numpy as np
# 使用自定义嵌入函数
def my_embedder(texts):
return np.random.rand(len(texts), 10)
embedder = dspy.Embedder(my_embedder)
embeddings = embedder(["hello", "world"], batch_size=1)
预处理与后处理
Embedder类包含两个关键内部方法:
_preprocess():处理输入数据,支持单个字符串或字符串列表,自动进行批量分割_postprocess():处理嵌入结果,支持返回原始格式或批量格式
数据结构
Passages 数据结构
检索结果以Passages对象形式返回,包含以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| passages | list[str] | 检索到的文档段落列表 |
result = retrieve("查询内容")
print(result.passages) # ['文档1内容', '文档2内容', ...]
示例数据结构
Example类用于组织训练数据和评估数据,支持与检索系统配合使用:
example = dspy.Example(
question="什么是检索增强生成?",
answer="检索增强生成是一种结合检索系统和语言模型的技术。"
).with_inputs("question")
# 检索相关文档
context = example.inputs().toDict()
配置管理
全局配置
通过dspy.configure()进行全局配置:
import dspy
dspy.configure(
lm=dspy.LM("openai/gpt-4o-mini"), # 语言模型
rm=WeaviateRM(...) # 检索模型
)
模块级配置
也可以在模块级别设置语言模型:
class MyRAG(dspy.Module):
def __init__(self):
super().__init__()
self.retrieve = dspy.Retrieve(k=3)
self.qa = dspy.Predict("context, question -> answer")
def forward(self, question):
context = self.retrieve(question).passages
return self.qa(context=context, question=question)
最佳实践
检索参数调优
| 场景 | 建议配置 |
|---|---|
| 快速原型开发 | k=3, 使用轻量级嵌入模型 |
| 生产环境 | k=5-10, 启用缓存, 使用高精度嵌入 |
| 长文档检索 | 设置合适的chunk_size, 使用rerank |
性能优化建议
- 启用缓存:对于重复查询较多的场景,设置
caching=True - 批量处理:合理设置
batch_size参数,平衡内存和吞吐量 - 连接池复用:在生产环境中复用向量数据库连接
相关模块
| 模块 | 文件路径 | 用途 |
|---|---|---|
| Module基类 | dspy/primitives/module.py | 所有DSPy模块的基类,包含set_lm()和get_lm()方法 |
| Predict | dspy/predict/predict.py | 预测模块,可与Retrieve组合使用 |
| Example | dspy/primitives/example.py | 数据示例类,用于组织训练和评估数据 |
| History | dspy/adapters/types/history.py | 对话历史类型,支持多轮检索场景 |
扩展开发
自定义检索模型
要实现自定义检索模型,需要继承相关基类并实现核心接口:
class MyRetriever(dspy.Module):
def __init__(self, collection_name, k=3):
self.collection_name = collection_name
self.k = k
def forward(self, query):
# 实现检索逻辑
results = self._search_vector_db(query, self.k)
return results
def _search_vector_db(self, query, k):
# 向量搜索实现
pass
集成新向量数据库
在dspy/retrievers/目录下创建新的RM实现文件,参考weaviate_rm.py的结构,确保实现统一的__call__接口和检索参数规范。
来源:https://github.com/stanfordnlp/dspy / 项目说明书
评估与指标
DSPy 框架的评估与指标系统是验证和优化语言模型程序的核心组件。该系统提供了标准化的评估接口、灵活的指标定义机制,以及与 DSPy 优化器(Teleprompter)深度集成的评估流程。评估系统的设计遵循模块化原则,允许开发者自定义评估逻辑,同时保持与框架其他部分的一致性。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
DSPy 框架的评估与指标系统是验证和优化语言模型程序的核心组件。该系统提供了标准化的评估接口、灵活的指标定义机制,以及与 DSPy 优化器(Teleprompter)深度集成的评估流程。评估系统的设计遵循模块化原则,允许开发者自定义评估逻辑,同时保持与框架其他部分的一致性。
在 DSPy 中,评估主要通过 dspy.Evaluate 类驱动,而指标(Metrics)则是用于衡量预测质量的回调函数。两者结合构成了完整的程序性能评估体系,支持从简单的精确匹配到复杂的语义相似度等多种评估场景。
核心架构
评估系统组件关系
graph TD
A[用户程序 dspy.Module] --> B[dspy.Evaluate 评估器]
B --> C[评估指标 Metric 函数]
C --> D[Example 测试集]
B --> E[Prediction 预测结果]
E --> C
C --> F[评估分数 Score]
B --> G[Teleprompter 优化器]
G --> H[BootstrapFewShot / MIPROv2 等]关键类结构
| 类名 | 文件位置 | 职责 |
|---|---|---|
Evaluate | dspy/evaluate/evaluate.py | 评估引擎,协调评估流程 |
Metric | dspy/evaluate/metrics.py | 指标基类与预置指标 |
AutoEvaluation | dspy/evaluate/auto_evaluation.py | 自动评估支持 |
Example | dspy/primitives/example.py | 测试样本数据结构 |
Prediction | dspy/primitives/prediction.py | 预测结果数据结构 |
Example 数据结构
Example 是 DSPy 中用于表示测试样本的基础数据结构,它将输入字段和标签字段分离,为评估提供标准化的数据格式。 资料来源:dspy/primitives/example.py:1-50
创建与使用 Example
import dspy
# 创建带标签的示例
example = dspy.Example(
question="What is the capital of France?",
answer="Paris"
).with_inputs("question")
# 提取输入字段
inputs = example.inputs()
# Example({'question': 'What is the capital of France?'}) (input_keys={'question'})
# 提取标签字段
labels = example.labels()
# Example({'answer': 'Paris'}) (input_keys={'question'})
Example 核心方法
| 方法 | 说明 | 返回值 |
|---|---|---|
with_inputs(*keys) | 标记输入字段 | 新的 Example 实例 |
inputs() | 获取输入部分 | 仅包含输入字段的 Example |
labels() | 获取标签部分 | 仅包含标签字段的 Example |
toDict() | 转换为字典 | 递归可序列化的字典 |
copy(**kwargs) | 复制并覆盖字段 | 新的 Example 实例 |
without(*keys) | 移除指定字段 | 新的 Example 实例 |
toDict() 方法支持递归序列化嵌套的 Example 对象、Pydantic 模型、列表和字典,确保评估结果可以JSON化输出。 资料来源:dspy/primitives/example.py:80-120
评估器(Evaluate)
Evaluate 类概述
dspy.Evaluate 是评估系统的核心类,负责执行整个评估流程。它接受待评估的程序、测试集和指标函数,并返回聚合的评估分数。
基本用法
import dspy
# 定义评估指标
def exact_match_metric(example, pred, trace=None):
return example.answer.lower() == pred.answer.lower()
# 准备测试集
testset = [
dspy.Example(question="What is 1+1?", answer="2").with_inputs("question"),
dspy.Example(question="What is 2+2?", answer="4").with_inputs("question"),
]
# 创建评估器
evaluate = dspy.Evaluate(
dev=testset,
metric=exact_match_metric,
num_threads=1,
)
# 执行评估
score = evaluate(your_program)
Evaluate 参数配置
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dev | list[Example] | 必需 | 开发/测试集 |
metric | Callable | 必需 | 评估指标函数 |
num_threads | int | 1 | 并行评估线程数 |
max_errors | int | -1 | 最大允许错误数 |
return_outputs | bool | False | 是否返回详细输出 |
display | bool | True | 是否显示进度 |
评估流程
sequenceDiagram
participant User as 用户
participant Eval as Evaluate
participant Module as dspy.Module
participant Metric as Metric函数
participant Example as Example数据
User->>Eval: evaluate(program)
Loop 遍历测试集
Eval->>Module: forward(example.inputs())
Module-->>Eval: Prediction
Eval->>Metric: metric(example, pred, trace)
Metric-->>Eval: score (bool/float)
End
Eval->>Eval: 聚合分数
Eval-->>User: 平均分数指标函数(Metrics)
指标函数签名
指标函数是评估的核心,它们接受三个参数并返回布尔值或浮点数:
def metric(
example: Example, # 测试样本,包含输入和标签
pred: Prediction, # 模型预测结果
trace: Trace | None # 可选的执行轨迹(用于优化器)
) -> bool | float
预置指标
DSPy 在 dspy.evaluate.metrics 模块中提供了一些常用的预置指标。开发者也可以根据需求自定义指标函数。 资料来源:dspy/evaluate/metrics.py:1-50
自定义指标示例
#### 精确匹配指标
def exact_match_metric(example, pred, trace=None):
"""检查预测答案是否与标签完全匹配(忽略大小写)"""
return example.answer.lower() == pred.answer.lower()
# 使用示例
gold = dspy.Example(question="What is 1+1?", answer="2").with_inputs("question")
pred = dspy.Prediction(answer="2")
exact_match_metric(gold, pred) # True
#### 包含检查指标
def answer_contains_metric(example, pred, trace=None):
"""检查标签是否被预测答案包含"""
return example.answer.lower() in pred.answer.lower()
#### 带权重的复合指标
def composite_metric(example, pred, trace=None):
"""组合多个子指标"""
exact_match = example.answer.lower() == pred.answer.lower()
length_penalty = len(pred.answer) > 0
return float(exact_match) * 0.8 + float(length_penalty) * 0.2
自动评估(Auto Evaluation)
DSPy 提供了自动评估功能,支持在没有人工标注标签的情况下进行程序评估。这对于迭代优化过程中的快速反馈特别有用。 资料来源:dspy/evaluate/auto_evaluation.py:1-30
自动评估工作流
graph LR
A[程序输出] --> B[Auto Evaluator]
B --> C{是否有参考标签}
C -->|是| D[使用参考指标]
C -->|否| E[使用LLM评判]
D --> F[评估分数]
E --> FLLM 作为评估器
当没有预定义标签时,可以使用大语言模型本身来评估输出质量:
import dspy
# 使用LLM进行自动评估
def llm_judge_metric(example, pred, trace=None):
lm = dspy.LM("openai/gpt-4")
prompt = f"""评估以下回答的质量:
问题: {example.question}
回答: {pred.answer}
回答是否准确、完整且相关?只需回答 '是' 或 '否'。"""
response = lm(prompt)
return "是" in response.lower()
evaluate = dspy.Evaluate(
dev=testset,
metric=llm_judge_metric,
)
数据集(datasets)
DSPy 的数据集模块提供了加载和管理评估数据的功能。Dataset 类是数据管理的基础抽象,支持多种数据格式和加载方式。 资料来源:dspy/datasets/__init__.py:1-30
加载内置数据集
import dspy
from dspy.datasets import GSM8K, HotPotQA
# 加载 GSM8K 数学数据集
gsm8k = GSM8K()
trainset = gsm8k.train
devset = gsm8k.dev
# 加载 HotPotQA 问答数据集
hotpot = HotPotQA()
testset = hotpot.dev
DataLoader API
DataLoader 提供了标准化的数据加载接口,支持训练集、验证集和测试集的划分: 资料来源:dspy/datasets/dataloader.py:1-50
| 方法 | 说明 |
|---|---|
from Hub | 从模型Hub加载数据集 |
from_jsonl | 从JSONL文件加载 |
from_dicts | 从字典列表加载 |
train_test_split | 划分训练集和测试集 |
自定义数据集
from dspy.datasets import Dataset
class MyDataset(Dataset):
def __init__(self, path):
super().__init__()
self._data = self._load_from_file(path)
def _load_from_file(self, path):
# 自定义加载逻辑
pass
# 使用自定义数据集
dataset = MyDataset("path/to/data.jsonl")
trainset = dataset.train
devset = dataset.dev
与优化器的集成
评估系统与 DSPy 的 Teleprompter 优化器紧密集成。优化器使用评估指标来引导搜索最优的程序配置(提示词、示例选择等)。
graph LR
A[BootstrapFewShot] --> B[评估指标]
C[MIPROv2] --> B
D[GEPA] --> B
B --> E[优化搜索]
E --> F[最优配置]完整优化流程
import dspy
# 1. 定义程序
program = dspy.ChainOfThought("question -> answer")
# 2. 准备数据集
trainset = [
dspy.Example(question=q, answer=a).with_inputs("question")
for q, a in question_answer_pairs
]
# 3. 定义指标
def exact_match(example, pred, trace=None):
return example.answer.lower() == pred.answer.lower()
# 4. 使用优化器(内部使用评估)
optimizer = dspy.MIPROv2(metric=exact_match)
compiled_program = optimizer.compile(
program,
trainset=trainset,
max_bootstrapped_demos=4,
)
最佳实践
指标设计原则
- 确定性:相同输入应产生相同分数,避免随机性
- 高效性:指标函数会被频繁调用,应尽量轻量
- 可解释性:分数应能清晰反映输出质量
- 可组合性:支持复合指标以评估多个维度
评估执行建议
| 场景 | 建议 |
|---|---|
| 快速原型开发 | 使用 num_threads=-1 启用所有CPU核心 |
| 调试 | 设置 return_outputs=True 获取详细输出 |
| 生产环境 | 设置合理的 max_errors 避免无限等待 |
| 大规模评估 | 分批评估并保存中间结果 |
常见问题处理
处理评估超时:
evaluate = dspy.Evaluate(
dev=testset,
metric=my_metric,
max_errors=10, # 跳过有问题的样本
num_threads=4,
)
获取详细评估日志:
evaluate = dspy.Evaluate(
dev=testset,
metric=my_metric,
return_outputs=True,
display=True,
)
results = evaluate(program)
for i, (example, pred, score) in enumerate(results.outputs):
print(f"[{i}] Score: {score}")
相关模块
- 预测模块 (Predict) - 生成预测的模块
- 优化器 (Teleprompter) - 优化程序配置的优化器
- 示例模块 (Example) - 数据结构基础
参考链接
- DSPy 官方文档:https://dspy.ai
- 评估指标文档:dspy.evaluate.metrics
- 数据集模块:dspy.datasets
来源:https://github.com/stanfordnlp/dspy / 项目说明书
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
可能影响授权、密钥配置或安全边界。
可能阻塞安装或首次运行。
可能增加新用户试用和生产接入成本。
可能增加新用户试用和生产接入成本。
Pitfall Log / 踩坑日志
项目:stanfordnlp/dspy
摘要:发现 19 个潜在踩坑项,其中 1 个为 high/blocking;最高优先级:安全/权限坑 - 来源证据:PythonInterpreter: paths containing commas are silently misparsed by Deno's --allow-read。
1. 安全/权限坑 · 来源证据:PythonInterpreter: paths containing commas are silently misparsed by Deno's --allow-read
- 严重度:high
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:PythonInterpreter: paths containing commas are silently misparsed by Deno's --allow-read
- 对用户的影响:可能影响授权、密钥配置或安全边界。
- 建议检查:来源问题仍为 open,Pack Agent 需要复核是否仍影响当前版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_43291e191b234ac883662982bf693e18 | https://github.com/stanfordnlp/dspy/issues/9749 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
2. 安装坑 · 来源证据:3.0.4b1
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:3.0.4b1
- 对用户的影响:可能阻塞安装或首次运行。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_76f47f2d6cbc4f299fe2a852b20617ef | https://github.com/stanfordnlp/dspy/releases/tag/3.0.4b1 | 来源类型 github_release 暴露的待验证使用条件。
3. 安装坑 · 来源证据:3.1.2
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:3.1.2
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_3733e2d7817440638629959030da2ddb | https://github.com/stanfordnlp/dspy/releases/tag/3.1.2 | 来源类型 github_release 暴露的待验证使用条件。
4. 安装坑 · 来源证据:3.1.3
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:3.1.3
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_2b7f0c4a046840b4b453167ce581b80a | https://github.com/stanfordnlp/dspy/releases/tag/3.1.3 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
5. 安装坑 · 来源证据:3.2.0
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:3.2.0
- 对用户的影响:可能阻塞安装或首次运行。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_976a3edffce44ac3984c9da4a10a2575 | https://github.com/stanfordnlp/dspy/releases/tag/3.2.0 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
6. 安装坑 · 来源证据:Use Tool functions that require external libaries in CodeAct
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安装相关的待验证问题:Use Tool functions that require external libaries in CodeAct
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_3c605227d53e42b69651c46c3e76c162 | https://github.com/stanfordnlp/dspy/issues/8839 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
7. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 建议检查:将假设转成下游验证清单。
- 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
- 证据:capability.assumptions | github_repo:587050620 | https://github.com/stanfordnlp/dspy | README/documentation is current enough for a first validation pass.
8. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
- 证据:evidence.maintainer_signals | github_repo:587050620 | https://github.com/stanfordnlp/dspy | last_activity_observed missing
9. 安全/权限坑 · 下游验证发现风险项
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:下游已经要求复核,不能在页面中弱化。
- 建议检查:进入安全/权限治理复核队列。
- 防护动作:下游风险存在时必须保持 review/recommendation 降级。
- 证据:downstream_validation.risk_items | github_repo:587050620 | https://github.com/stanfordnlp/dspy | no_demo; severity=medium
10. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 建议检查:把风险写入边界卡,并确认是否需要人工复核。
- 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
- 证据:risks.scoring_risks | github_repo:587050620 | https://github.com/stanfordnlp/dspy | no_demo; severity=medium
11. 安全/权限坑 · 来源证据:3.0.4
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:3.0.4
- 对用户的影响:可能阻塞安装或首次运行。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_d192b20b863c476ca31d4ba476cec875 | https://github.com/stanfordnlp/dspy/releases/tag/3.0.4 | 来源讨论提到 api key 相关条件,需在安装/试用前复核。
12. 安全/权限坑 · 来源证据:3.0.4b2
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:3.0.4b2
- 对用户的影响:可能影响授权、密钥配置或安全边界。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_392f60c647b74a6592f1692bcdc0070f | https://github.com/stanfordnlp/dspy/releases/tag/3.0.4b2 | 来源讨论提到 api key 相关条件,需在安装/试用前复核。
13. 安全/权限坑 · 来源证据:3.1.0
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:3.1.0
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_364bbccd7d4241c9b6841303fefb5a85 | https://github.com/stanfordnlp/dspy/releases/tag/3.1.0 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
14. 安全/权限坑 · 来源证据:3.1.0b1
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:3.1.0b1
- 对用户的影响:可能增加新用户试用和生产接入成本。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_4599cbf0d1fd41b4b3c47e5c1aae247a | https://github.com/stanfordnlp/dspy/releases/tag/3.1.0b1 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
15. 安全/权限坑 · 来源证据:3.1.1
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:3.1.1
- 对用户的影响:可能影响授权、密钥配置或安全边界。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_5656ac7c80214b9fb410d129ccec33d2 | https://github.com/stanfordnlp/dspy/releases/tag/3.1.1 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
16. 安全/权限坑 · 来源证据:3.2.1
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:3.2.1
- 对用户的影响:可能影响授权、密钥配置或安全边界。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_e2250d3118a04c5e8d213eb2fce4e68d | https://github.com/stanfordnlp/dspy/releases/tag/3.2.1 | 来源讨论提到 node 相关条件,需在安装/试用前复核。
17. 安全/权限坑 · 来源证据:[Bug] PythonInterpreter fails with default setup due to missing Deno read permissions for Pyodide
- 严重度:medium
- 证据强度:source_linked
- 发现:GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题:[Bug] PythonInterpreter fails with default setup due to missing Deno read permissions for Pyodide
- 对用户的影响:可能影响授权、密钥配置或安全边界。
- 建议检查:来源显示可能已有修复、规避或版本变化,说明书中必须标注适用版本。
- 防护动作:不得脱离来源链接放大为确定性结论;需要标注适用版本和复核状态。
- 证据:community_evidence:github | cevd_bb4eb14c9ce944f0a7654217c34b1d1d | https://github.com/stanfordnlp/dspy/issues/9501 | 来源讨论提到 python 相关条件,需在安装/试用前复核。
18. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
- 防护动作:issue/PR 响应未知时,必须提示维护风险。
- 证据:evidence.maintainer_signals | github_repo:587050620 | https://github.com/stanfordnlp/dspy | issue_or_pr_quality=unknown
19. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
- 证据:evidence.maintainer_signals | github_repo:587050620 | https://github.com/stanfordnlp/dspy | release_recency=unknown
来源:Doramagic 发现、验证与编译记录