DSPy怎么用构建优化的LLM Pipeline?有哪些实际用例?

文章导读
LLM 应用开发已经超越了简单的 prompt engineering。随着系统变得更加复杂,您需要一个更强的心理模型来构建 reasoning、retrieval、tool use、evaluation 和 optimization 的结构化、可维护的工作流。DSPy 正是为此而设计。与手动调整冗长的 prompt 模板不同,您可以定义 signatures,组合 modules,然后针对一个
📋 目录
  1. 关键要点
  2. 什么是 DSPy 以及为什么用于 LLM 管道
  3. 用例 1:使用 ChainOfThought 进行问答
  4. 用例 2:检索增强生成 RAG 流水线
  5. 用例 3:使用 ReAct 的多步推理代理
  6. 用例 4:使用 LLM 指标评估的文本分类
  7. 选择合适的 DSPy Optimizer
  8. 在 上运行 DSPy
  9. FAQ 部分
  10. 结论
A A

LLM 应用开发已经超越了简单的 prompt engineering。随着系统变得更加复杂,您需要一个更强的心理模型来构建 reasoning、retrieval、tool use、evaluation 和 optimization 的结构化、可维护的工作流。DSPy 正是为此而设计。与手动调整冗长的 prompt 模板不同,您可以定义 signatures,组合 modules,然后针对一个 metric 优化整个程序。这让 LLM 开发感觉不像 prompt 试错,而更像是构建一个可衡量、可改进的 software pipeline。

本文涵盖了构建生产级应用时会遇到的实际 DSPy 用例。我们深入探讨 DSPy 如何实现 question answering、retrieval-augmented generation、多步 reasoning agents、text classification 等功能。在此过程中,您将了解 DSPy 对 metric evaluation、assertion-style constraints 以及选择 optimizer 的方法。到最后,您应该对 DSPy 如何帮助您从孤立的 prompts 转向可扩展、结构化、生产就绪的 LLM pipelines 有更清晰的认识。

关键要点

  • DSPy 通过使用 signatures、modules、metrics 和 optimizers 将 LLM 开发转变为可编程的工作流,而不是仅依赖手动 prompt 调整。
  • 它特别适用于生产级 pipelines,这些 pipelines 在一个可维护系统中结合 routing、retrieval、reasoning、tool use、structured output 和 evaluation。
  • 核心 DSPy modules 如 Predict、ChainOfThought、ReAct 和 Module 让您能够构建实际应用,如 QA systems、RAG pipelines、多步 agents 和 classifiers。
  • DSPy optimizers 如 BootstrapFewShot、MIPROv2 和 COPRO 通过针对 metric 调整 instructions 和 demonstrations 来自动提升程序质量。
  • 为了可靠部署,DSPy 与 evaluation、grounding checks、typed outputs、constraint enforcement 以及稳定的基础设施(如用于托管 models、retrieval 和 agent pipelines)结合使用效果最佳。

什么是 DSPy 以及为什么用于 LLM 管道

DSPy 的设计理念是编程声明式 LM 程序(签名、模块和控制流),然后针对指标进行编译,而不是手动设计长提示模板。

DSPy 的作者将其重新表述为将声明式 LM 调用编译成自我改进的管道,如原论文所述。编译步骤会搜索更好的指令、few-shot 示例(在某些模式下)微调权重。在实践中使用 DSPy 更像是“轻量级机器学习”而非提示工程:

  1. 定义你的接口:一个 DSPy 提示签名(输入/输出 + 类型)。
  2. 将管道逻辑实现为模块(DSPy Predict 模块、DSPy ChainOfThought 模块、DSPy ReAct 模块等)+ 使用 dspy.Module 的 Python 控制流。
  3. 定义一个指标函数来衡量质量(通常调用 LLM 进行指标评估,有时通过 DSPy “judge” 程序)。
  4. 运行一个优化器(以前称为“teleprompters”),如 DSPy BootstrapFewShot 优化器或 MIPROv2 优化器,来提升你的分数。

DSPy 与 LangChain 和 LlamaIndex 的定位对比

DSPy 经常被拿来与编排框架(如 LangChain)和数据中心 RAG 框架(如 LlamaIndex)比较。一种有帮助的思考它们差异的方式是:

  • LangChain 围绕组合链、代理、工具和集成(广泛的“连接事物”的工具)。
  • LlamaIndex 围绕数据摄取、构建索引以及在你的数据上查询 LLM(围绕 RAG 风格的检索器 + 查询引擎构建)。
  • DSPy 强调在你的技术栈中对 LM 行为的程序化优化:签名、模块、指标和优化器,可以自动改进系统中的提示/示例。

许多真实世界的生产栈会结合这些方法:使用 LlamaIndex(或其他检索器)来驱动摄取和检索,然后使用 DSPy 包装生成和路由逻辑,以优化提示和类型化输出。

本教程中你将使用的 DSPy 核心构建块

Signatures 描述模型应该做什么:输入字段、输出字段及其语义名称。可以选择指定类型和指令。字段名称很重要,因为它们指示角色(“question” vs “answer”、“context” vs “summary”等)。

Modules 定义如何解决它。主要模块:

  • dspy.Predict:基本构建块,使用 LM 将输入映射到输出。由 signature 配置。
  • dspy.ChainOfThought:逐步推理的预测器。输出与你的 signature 相同,但前面会添加一个“reasoning”字段。
  • dspy.ReAct:迭代的“Reasoning and Acting”工具使用代理循环,模型选择工具并产生最终输出。
  • dspy.Module:多步程序的基类,你需要实现 forward() 并组合子模块。

Adapters 决定你的 LM I/O 有多“结构化”。ChatAdapter 是 DSPy 的默认字段标记格式。JSONAdapter 强制支持结构化输出格式的模型发出 JSON,以便可靠解析类型化输出。

统一的端到端管道示例

这段代码实现了一个小型但真实的“路由器”程序,将 Predict、RAG + ChainOfThought 和 ReAct 的端到端流程结合在一起:

# pip install -U dspy  (or: pip install -U dspy-ai)
import dspy
from typing import Literal
# 1) 在应用顶部附近一次性配置语言模型。
lm = dspy.LM("openai/gpt-4o-mini")  # 从环境变量读取 OPENAI_API_KEY
dspy.configure(lm=lm, adapter=dspy.JSONAdapter())
# 2) 一个小型意图分类器 (Predict) 用于路由请求。
class Route(dspy.Signature):
    """将用户请求路由到最佳处理器。"""
    query: str = dspy.InputField()
    intent: Literal["rag_qa", "tool_agent", "direct_qa"] = dspy.OutputField()

router = dspy.Predict(Route)
# 3) 一个 RAG 风格的回答器(稍后完整实现)。
class RagAnswer(dspy.Signature):
    """仅使用提供的上下文段落进行回答。"""
    context: list[str] = dspy.InputField()
    question: str = dspy.InputField()
    answer: str = dspy.OutputField()
    citations: list[int] = dspy.OutputField(desc="使用的上下文段落索引")

rag_answerer = dspy.ChainOfThought(RagAnswer)
# 4) 一个带有工具的 ReAct 代理(稍后实现工具)。
def add(a: float, b: float) -> float:
    return a + b

agent = dspy.ReAct(signature="question -> answer", tools=[add], max_iters=8)
# 5) 将其组合成一个程序。
class UnifiedAssistant(dspy.Module):
    def forward(self, query: str, retrieved_passages: list[str] | None = None):
        route = router(query=query).intent
        if route == "rag_qa":
            ctx = retrieved_passages or []
            return rag_answerer(context=ctx, question=query)
        if route == "tool_agent":
            return agent(question=query)
        # 默认:直接 QA,仍使用 CoT 风格模块以增强鲁棒性
        direct = dspy.ChainOfThought("question -> answer")
        return direct(question=query)
assistant = UnifiedAssistant()

上述脚本构建了一个轻量级的 DSPy 助手,能够在一个单一工作流中处理多种类型的用户查询。在设置 LLM 和 JSON adapter 后,它创建一个 Predict 路由器,用于分类新查询属于三种意图之一:基于 RAG 的问答、基于工具的代理推理,或直接问答。需要外部知识的查询被路由到一个 ChainOfThought RAG 模块,该模块根据检索到的段落回答问题并返回引用。需要使用工具的查询被路由到一个与 add 工具耦合的 ReAct 代理;所有其他查询会回退到直接 ChainOfThought 回答模块。这个程序展示了 DSPy 如何在一个单一模块化助手中编排路由、检索、推理和工具使用。

用例 1:使用 ChainOfThought 进行问答

默认情况下,DSPy 的 ChainOfThought 模块针对那些通过提供中间推理来提高正确性的问题而设计。让我们考虑以下代码:

import os
import dspy
from dspy.evaluate import Evaluate
from dspy.evaluate.metrics import answer_exact_match
# 每个进程只需配置一次。
# (需要在环境中设置 OPENAI_API_KEY。)
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))
# 一个简化的 CoT QA 模块。
qa_cot = dspy.ChainOfThought("question -> answer")
# 一个小型开发集(从小开始,然后逐步扩展)。
devset = [
    dspy.Example(question="What is the capital of France?", answer="Paris").with_inputs("question"),
    dspy.Example(question="What is 2+2?", answer="4").with_inputs("question"),
]
# 指标:最终答案字段的完全匹配。
def em_metric(example, pred, trace=None):
    return answer_exact_match(example, pred)
evaluator = Evaluate(devset=devset, num_threads=2, display_progress=True)
baseline = evaluator(qa_cot, metric=em_metric)
print("Baseline score:", baseline)

这个程序建立了一个小型的 DSPy 问答评估管道。它使用 openai/gpt-4o-mini 模型初始化 DSPy,然后定义了一个简单的 ChainOfThought 模块,该模块接受问题并生成答案。程序定义了一个包含两个示例 QA 对的小型开发数据集,并构建了一个 exact-match 指标,用于将预测答案与预期答案进行评估。然后,它启动 DSPy 的 Evaluate 工具,以并行方式将该模块应用于数据集中的每个问题。它计算并输出基准分数,表明未经优化的 Chain-of-Thought QA 模块回答这些样本问题的准确度。

使用 BootstrapFewShot 改进 QA

如果您只有少量示例,BootstrapFewShot 是一个很好的起点。这个优化器从标注示例 + 由教师创建的 bootstrapped demos 中组合 demos,并过滤只保留通过您的指标的 demos。

from dspy.teleprompt import BootstrapFewShot
# 非常小的训练集是可以接受的(DSPy 设计为从小开始)。
trainset = devset
teleprompter = BootstrapFewShot(
    metric=em_metric,
    max_bootstrapped_demos=2,
    max_labeled_demos=2,
)
qa_optimized = teleprompter.compile(student=qa_cot, trainset=trainset)
optimized_score = evaluator(qa_optimized, metric=em_metric)
print("Optimized score:", optimized_score)

在这里,我们使用 DSPy 的 BootstrapFewShot 优化器改进了原始的 qa_cot 问答模块。我们使用小型 trainset 作为学习示例,以获得更好的 few-shot 演示。然后,我们使用最多 2 个 bootstrapped demos + 2 个标注 demos 编译了模型的优化版本。最后,我们对新模型运行评估,使用相同的 exact-match 指标,并打印优化分数,以显示性能是否比基准有所提升。

用例 2:检索增强生成 RAG 流水线

Retrieval-Augmented Generation 解决了主要痛点。没有 RAG 时,LLM 无法访问您的私有或持续变化的知识,除非您在推理时直接提供它。一个典型的端到端 RAG 流水线包括摄取/分块、embeddings、存储 + 检索,以及基于检索文档的最终生成。

具有类型化输出和结构化 JSON 的逐步 RAG

在以下程序中,我们定义了一个类型化签名(列表和整数),使用 JSONAdapter,并将引用返回为检索段落的索引。

import dspy

# 使用 JSONAdapter 配置 LM,以便列表(如 citations)
# 从模型输出中可靠解析。
lm = dspy.LM("openai/gpt-4o-mini")  # 从环境变量读取 OPENAI_API_KEY
dspy.configure(lm=lm, adapter=dspy.JSONAdapter())

# 用于演示的最小本地语料库;替换为您的文档或 vector DB。
corpus = [
    "Linux divides memory into regions; on 32-bit systems highmem is not permanently mapped.",
    "Low memory is directly addressable by the kernel; high memory is mapped on demand.",
    "Unrelated passage about iPhone apps.",
]

# 用于稠密检索的嵌入器。
embedder = dspy.Embedder("openai/text-embedding-3-small", dimensions=512)
search = dspy.retrievers.Embeddings(embedder=embedder, corpus=corpus, k=2)


class RagAnswer(dspy.Signature):
    """仅使用提供的上下文段落进行回答。"""
    context: list[str] = dspy.InputField(desc="retrieved passages")
    question: str = dspy.InputField()
    answer: str = dspy.OutputField(desc="final answer grounded in context")
    citations: list[int] = dspy.OutputField(desc="indices of context passages used")


class RAG(dspy.Module):
    def __init__(self):
        super().__init__()
        self.respond = dspy.ChainOfThought(RagAnswer)

    def forward(self, question: str):
        # 检索 top-k 段落。
        retrieved = search(question)
        ctx = retrieved.passages

        # 生成答案和引用。
        pred = self.respond(context=ctx, question=question)

        # 对引用索引进行轻量级验证。
        citations = pred.citations or []
        pred.citations = [i for i in citations if 0 <= i < len(ctx)]

        # 返回结构化预测。
        return dspy.Prediction(
            context=ctx,
            answer=pred.answer,
            citations=pred.citations,
            reasoning=pred.reasoning,
        )

# 实例化 RAG 模块。
rag = RAG()

# 运行演示问题。
out = rag(question="What are high memory and low memory in Linux?")

print("Answer:")
print(out.answer)
print("\nCitations (indices into context):")
print(out.citations)

在这里,我们从小型知识库中检索信息以回答问题。语言模型使用 JSONAdapter 配置,以正确解析结构化输出(引用列表)。创建基于 embedding 的检索器,从语料库中找到最相关的段落。类型化 Signature 定义了结构化的 RAG 任务,包含 contextquestionanswercitations 字段。RAG 模块遵循 ChainOfThought,从检索的段落中生成有依据的答案。最后,在返回结构化预测之前检查引用索引的有效性,并运行关于 Linux 内存的演示查询。

添加一个同时检查正确性和依据的 RAG 指标

这是一个复合指标的小示例。它检查标签是否匹配,以及预测答案是否在检索的上下文中找到。它为评估返回浮点数,为引导返回布尔值。

from dspy.evaluate import Evaluate
def grounded_answer_metric(example, pred, trace=None):
    # 答案的不区分大小写的精确或近似精确匹配。
    answer_match = example.answer.lower() in pred.answer.lower()
    # 答案应至少出现在一个检索段落中。
    context_match = any(pred.answer.lower() in c.lower() for c in pred.context)
    if trace is None:
        # 用于评估:0 到 1 之间的软分数。
        return (answer_match + context_match) / 2.0
    # 用于引导/优化:要求两者都满足。
    return answer_match and context_match

devset = [
    dspy.Example(
        question="What is low memory in Linux?",
        answer="directly addressable by the kernel",
    ).with_inputs("question")
]

evaluator = Evaluate(devset=devset, num_threads=2, display_progress=True)
print(evaluator(rag, metric=grounded_answer_metric))

此代码计算自定义指标,以评分 DSPy RAG 流水线回答问题的效果。grounded_answer_metric 检查两件事:1) 预测是否与预期答案匹配,2) 该答案是否能在检索的上下文段落中找到依据。然后,Evaluate 在小型开发集上运行该指标,以验证您的 RAG 流水线在用于优化或生产前是否返回有依据、正确的答案。

使用 MIPROv2 优化 RAG 程序

在这里,我们使用 DSPy 的 MIPROv2 优化器,根据您的自定义依据指标改进原始 RAG 程序,然后使用小型演示集重新编译模块,并评估优化版本是否性能更好。

from dspy.teleprompt import MIPROv2
# 使用您的自定义指标设置 MIPROv2 优化器。
tp = MIPROv2(
    metric=grounded_answer_metric,
    auto="light",          # 或 "medium" / "heavy"
    num_threads=4,
)
# 使用开发/训练集编译原始 RAG 模块。
rag_optimized = tp.compile(
    rag,
    trainset=devset,
    max_bootstrapped_demos=2,
    max_labeled_demos=2,
)
# 重新评估优化后的 RAG 模块。
print("Evaluation after MIPROv2 optimization:")
print(evaluator(rag_optimized, metric=grounded_answer_metric))

用例 3:使用 ReAct 的多步推理代理

当你有需要使用工具的任务(无论是进行计算、调用内部 API、获取知识还是执行操作),DSPy 提供了 dspy.ReAct,它实现了 ReAct(“推理与行动”)范式:模型进行推理,选择要调用的工具,观察结果,并重复此过程直到能够输出最终答案。ReAct 可以泛化到任何签名。它可以接受函数或 dspy.Tool 对象作为工具。

一个带有类型化工具的最小 ReAct 代理

下面的脚本实现了一个小型 DSPy ReAct 代理,它通过按需使用工具来回答问题。它设置了一个 LLM,定义了两个工具——一个返回当前 UTC 时间,另一个用于数字相乘——并将这些工具传递给 dspy.ReAct。代理将推理是否应该使用工具,如果需要则调用它,然后返回最终答案。

import dspy
from datetime import datetime, timezone
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"), adapter=dspy.JSONAdapter())

def utc_now() -> str:
    return datetime.now(timezone.utc).isoformat()

def multiply(a: float, b: float) -> float:
    return a * b

# 创建一个可以使用 utc_now 和 multiply 的 ReAct 代理。
agent = dspy.ReAct(
    signature="question -> answer",
    tools=[utc_now, multiply],
    max_iters=6,
)
# 示例查询。
print(agent(question="What time is it in UTC right now?"))
print(agent(question="What is 19.5 * 4.2?"))

生产环境考虑:代理可靠性、成本和防护栏

代理循环可能在没有防护栏和可观测性的情况下悄无声息地累积高成本(重复的 LLM 调用、重复的工具调用)或产生无效操作的幻觉。一个合理的防护栏集包括限制迭代次数(max_iters)、收紧工具 schema 和权限,并在上线前使用类似真实流量的提示进行验证。

使用 DSPy 优化器优化 ReAct 代理

DSPy 优化器可以优化整个程序,包括端到端的复杂多模块系统(如代理、检索和提取),只要你指定要改进的指标。对于许多团队,一个有效的模式是:

  • 使用 BootstrapFewShot(廉价)引导几个演示示例;
  • 然后,根据预算运行 MIPROv2,设置 auto=“light” 或 auto=“medium”。

用例 4:使用 LLM 指标评估的文本分类

分类是 DSPy 的理想用例,因为虽然成功指标(accuracy、F1)很简单直接,但你仍然可以利用 DSPy 的程序化结构、类型化输出和优化器。

使用 Predict 构建类型化分类器

以下代码构建了一个简单的 DSPy 文本分类器,用于支持工单。它设置模型,声明一个签名,包含一个输入(ticket)和一个受限输出(label),然后调用 dspy.Predict 将工单分类为四种类型之一:billingbugfeaturesecurity。在这个例子中,“我被收取了两次费用”的投诉被正确分类为 billing

import dspy
from typing import Literal
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"), adapter=dspy.JSONAdapter())
class TicketLabel(dspy.Signature):
    """将支持工单分类到固定的分类体系中。"""
    ticket: str = dspy.InputField()
    label: Literal["billing", "bug", "feature", "security"] = dspy.OutputField()
clf = dspy.Predict(TicketLabel)
example = clf(ticket="I was charged twice for my subscription this month.")
print(example.label)

使用指标评估(并可选构建 LLM 评判指标)

指标是普通的 Python 函数。它们应遵循签名(example, pred, trace=None);对于复杂输出,指标可以通过额外的 predictor 调用使用 AI 反馈。

下面的代码使用 DSPy 的 Evaluate 工具在小型标记的支持工单数据集上测试分类器 clf。trainset 包含三个示例。对于每个示例,工单文本被标记为正确的类别(billingbugfeature)。传递 .with_inputs("ticket") 告诉 DSPy 模型只接收工单文本作为输入。accuracy_metric 函数检查分类器的预测标签是否与真实标签匹配。如果预测正确则返回 1.0,否则返回 0.0。Evaluate 使用 2 个线程在数据集上运行 clf,显示运行进度,print(evaluator(clf, metric=accuracy_metric)) 打印最终结果,通常是模型在这些示例上的准确率。

from dspy.evaluate import Evaluate
trainset = [
    dspy.Example(ticket="I was charged twice.", label="billing").with_inputs("ticket"),
    dspy.Example(ticket="The app crashes on launch.", label="bug").with_inputs("ticket"),
    dspy.Example(ticket="Please add export to CSV.", label="feature").with_inputs("ticket"),
]
def accuracy_metric(example, pred, trace=None):
    return float(example.label == pred.label)
evaluator = Evaluate(devset=trainset, num_threads=2, display_progress=True)
print(evaluator(clf, metric=accuracy_metric))

现代 DSPy 中的断言测试和约束执行

在生产环境中,人们经常要求“验证”操作:(“断言测试”;标签必须是 X 之一;JSON 必须可解析;引用必须在范围内)。

dspy.Refine 专为带有 reward_fn 和阈值的 best-of-N 精炼循环而设计。它重复调用模块 N 次并返回最佳预测,如果需要会在尝试之间生成反馈。以下是一个真实的“约束执行”包装器:重试直到输出分类法被遵守。来看看以下代码:

import dspy
from typing import Set
allowed: Set[str] = {"billing", "bug", "feature", "security"}
def label_is_valid(args, pred):
    return 1.0 if pred.label in allowed else 0.0
robust_clf = dspy.Refine(module=clf, N=3, reward_fn=label_is_valid, threshold=1.0)
print(robust_clf(ticket="Please add SSO support.").label)

这段代码使用 dspy.Refine 包装原始分类器,允许 DSPy 重试最多 3 次,并只保留通过 reward_fn 的输出。奖励函数确保预测标签是我们允许的类别之一,threshold=1.0 表示只有完全有效的标签才会被接受,然后返回结果。

选择合适的 DSPy Optimizer

DSPy 现在将这些算法称为 optimizers(之前称为 teleprompters)。根据 optimizer 文档,optimizer 是一种算法,它调整 DSPy 程序的参数(prompts 和/或 LM weights),以使用你的程序、metric 和训练输入最大化你的指标。训练输入通常是一小组示例。

实际决策标准

此表格列出了你的简报优先考虑的 3 个 optimizers——BootstrapFewShot、MIPROv2 和 COPRO——以及 BootstrapFewShotWithRandomSearch,DSPy 建议在你有更多数据后使用它。

Optimizer 它做什么以及何时使用 数据指导和关键配置旋钮
BootstrapFewShot 调整由标记和 bootstrapped 示例组装的 few-shot demos,这些 demos 通过 metric 验证。它适用于小数据集的快速获胜,是强大的首次 compile 选项。 当你有大约 10 个示例时从这里开始。Knobs: max_labeled_demosmax_bootstrapped_demosteacher_settings
BootstrapFewShotWithRandomSearch 像 BootstrapFewShot 一样调整 few-shot demos,但测试多个候选 demo 集并保留最佳的一个。它在保持相对简单的情况下,提供更稳健的 few-shot 选择。 当你有大约 50 个或更多示例时最佳。Knobs: num_candidate_programs,加上 BootstrapFewShot 的 knobs
COPRO 通过迭代搜索调整 prompt instructions,在 optimizer 指南中记录为 coordinate ascent。当你想要 instruction tuning 而不需要过多关注 demos 时很有用。 通常需要 train set 和 metric。Knobs: breadthdepthinit_temperature
MIPROv2 使用 Bayesian optimization 联合调整 instructions 和 few-shot 示例。当你想要更高品质的 prompt optimization 并有足够的预算和数据时,它是最强的选择。 适用于较长的运行,例如 40 个或更多 trials,并有大约 200 个或更多示例以降低过拟合风险。Knobs: auto (“light/medium”)、num_threads,加上 compile() 中的 demo knobs

在 上运行 DSPy

部署应该为你提供两件事:(1) 运行 DSPy 程序的基础设施(稳定的运行时)和 (2) 可靠调用 LLM 以运行 retrieval 并添加 guardrails 的访问权限。

适用于 DSPy pipelines 的部署模式

如果你想要完全控制栈中的一切(vector DB、embeddings、model runtime),可以将你的 DSPy 服务部署到 Virtual Machine (VM) 或 GPU instance。在 GPU Droplets 上构建 RAG 应用,在 ’s RAG tutorials 中有逐步详细说明。

使用完全托管的模型访问以简化操作。 Gradient 平台描述了 serverless inference(无需基础设施管理)以及对主要供应商(OpenAI、Anthropic 等)托管模型的 API 访问,以及平台内直接托管的开源模型的托管可扩展性和安全功能。

使用托管代理功能构建 agentic 应用。 ’s Gradient AI Platform quickstart 描述了带有 knowledge bases 的完全托管 agents,用于 retrieval-augmented generation、多代理路由和 guardrails。

FAQ 部分

Q1: DSPy 的最佳使用场景是什么?

DSPy 的最佳使用场景是:(a) 你将作为管道的一部分重复调用 LM,(b) 你可以定义一些自动指标来判断调用是否成功,以及 (c) 你希望采用系统化的方法,随着模型、数据或需求的变化,逐步改进提示词/示例/权重。

Q2: DSPy ChainOfThought 与 Predict 模块有何不同?

dspy.Predict 是一个基本模块,它使用 LM 和 signature 将输入映射到输出。dspy.ChainOfThought 是一个专化模块,它通过在 signature 前添加推理字段,显式地“逐步推理”,然后预测输出——当中间推理能提升正确性时非常有用。

Q3: 什么是 DSPy teleprompter 或 optimizer?

术语最近已更新,以前称为“teleprompters”的现在叫 optimizers。Optimizer 是一种算法,它接收你的 DSPy 程序(包括其提示词 + 底层 LM 权重)+ 你的 metric + 训练输入,并调整程序的参数以最大化该 metric。

Q4: DSPy 可以用于 RAG 管道吗?

可以!DSPy 的 RAG 教程会逐步讲解如何构建一个检索器模块(例如,基于 embeddings 的 top-K 搜索),然后在 DSPy*.Module* 中将其与生成模块组合,从而对整个 RAG 程序进行评估和优化。

Q5: BootstrapFewShot 和 MIPROv2 有什么区别?

BootstrapFewShot 专注于组装 few-shot 示例(带标签并 bootstrapped),并根据 metric 评估它们。MIPROv2 使用 bootstrapped traces 联合优化 instructions + 示例,同时在候选 instructions/demos 空间上进行 Bayesian optimization 搜索。DSPy 建议当示例稀缺时从 BootstrapFewShot 开始,当你有足够数据和预算来缓解过拟合问题时,再升级到 MIPROv2。

Q6: DSPy assertions 和 metric 函数是如何工作的?

DSPy metric 以 Python 函数的形式实现,接受 (example, pred, trace=None) 并返回一个分数。在优化过程中,metric 可以选择性地使用 trace 来验证中间步骤或强制执行更严格的规则。传统的 dspy.Assert / dspy.Suggest 构造已在 DSPy 中弃用/不支持,但你现在可以使用 dspy.Refine(或 dspy.Suggest)来进行引导式自我修正和基于约束的优化。

Q7: DSPy 支持结构化输出吗?

支持!在定义 DSPy signature 时,你可以声明类型化字段(包括嵌套的、非原始类型)。Adapter 负责适当格式化这些提示词并解析输出。JSONAdapter 会尽可能提示模型“以 JSON 响应”,以实现更稳健的结构化解析。ChatAdapter 的提示词包含字段标记来分隔类型化字段,并且在使用自定义非原始字段类型时还支持添加 JSON schema。

Q8: DSPy 支持哪些 LLM 提供商?

DSPy 通过其 dspy.LM 包装器支持数十种 LLM 提供商,该包装器基于 LiteLLM,使用简单的 {provider}/{model} 语法,例如 openai/gpt-4o-minianthropic/claude-3-5-sonnet-20240620

结论

SPy 代表了构建现代 LLM 系统方式的重大转变。它不将 prompts 视为静态字符串,而是将它们视为由 signatures、modules、metrics 和 control flow 组成的大型程序的组件。这种方法在你从简单的 completions 升级到编写实际的应用模式时真正发挥光芒,例如 ChainOfThought QA、具有结构化输出的 RAG、基于 ReAct 的工具使用,以及集成质量检查的分类管道。

这里的一个更大要点是,DSPy 不仅仅是一个 prompt engineering 的游乐场。DSPy 是构建、验证、迭代和扩展 LLM 系统的一个实用基础,具有更高的严谨性。随着工程团队对可靠性、可观测性和对 agentic 行为的控制提出更高的保证要求,DSPy 将准备好在生产 AI 栈中扮演更大的角色。未来将属于那些从一开始就构建模块化、可测试且优化驱动的 LLM 工作流的工程师。

参考文献

  • 为什么我应该使用 DSPy Signature?
  • DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines
  • 教程:Retrieval-Augmented Generation (RAG)
  • dspy.Refine
  • Prompting with DSPy: A New Approach