通过自定义DSPy模块构建AI应用¶
在本指南中,我们将引导您通过自定义dspy.Module
来构建一个GenAI应用程序。
一个DSPy模块是DSPy程序的基础构建块。
每个内置模块抽象化了一种提示技术(如思维链或ReAct)。关键在于,它们被通用化以处理任何签名。
一个DSPy模块具有可学习的参数(即构成提示和语言模型权重的微小部分),并且可以被调用(调用)以处理输入并返回输出。
多个模块可以组合成更大的模块(程序)。DSPy模块直接受到PyTorch中神经网络模块的启发,但应用于语言模型程序。
虽然您可以在不实现自定义模块的情况下构建DSPy程序,但我们强烈建议将您的逻辑放入自定义模块中,以便您可以使用其他DSPy功能,如DSPy优化器或MLflow DSPy追踪。
在开始之前,请确保你已经安装了DSPY:
!pip install dspy
自定义DSPy模块¶
您可以通过自定义DSPy模块来实现自定义提示逻辑并集成外部工具或服务。为此,请从dspy.Module
子类化并实现以下两个关键方法:
__init__
: 这是构造函数,您可以在其中定义程序的属性和子模块。forward
: 该方法包含您的DSPy程序的核心逻辑。
在forward()
方法中,您不仅限于调用其他DSPY模块;还可以集成任何标准的Python函数,例如与Langchain/Agno智能体、MCP工具、数据库处理程序等交互的函数。
自定义DSPy模块的基本结构如下所示:
class MyProgram(dspy.Module):
def __init__(self, ...):
# Define attributes and sub-modules here
{constructor_code}
def forward(self, input_name1, input_name2, ...):
# Implement your program's logic here
{custom_logic_code}
让我们通过一个实际的代码示例来说明这一点。我们将构建一个包含多个阶段的简单检索增强生成(RAG)应用:
- 查询生成: 根据用户的问题生成合适的查询以检索相关上下文。
- 上下文检索:使用生成的查询获取上下文。
- 答案生成: 基于检索到的上下文和原始问题生成最终答案。
该多阶段程序的代码实现如下所示。
import dspy
class QueryGenerator(dspy.Signature):
"""Generate a query based on question to fetch relevant context"""
question: str = dspy.InputField()
query: str = dspy.OutputField()
def search_wikipedia(query: str) -> list[str]:
"""Query ColBERT endpoint, which is a knowledge source based on wikipedia data"""
results = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')(query, k=1)
return [x["text"] for x in results]
class RAG(dspy.Module):
def __init__(self):
self.query_generator = dspy.Predict(QueryGenerator)
self.answer_generator = dspy.ChainOfThought("question,context->answer")
def forward(self, question, **kwargs):
query = self.query_generator(question=question).query
context = search_wikipedia(query)[0]
return self.answer_generator(question=question, context=context).answer
让我们来看一下forward
方法。我们首先将问题发送给self.query_generator
,这是一个dspy.Predict
,以获取用于上下文检索的查询。然后我们使用该查询调用ColBERT并保留第一个检索到的上下文。最后,我们将问题和上下文发送到self.answer_generator
,这是一个dspy.ChainOfThought
,以生成最终答案。
接下来,我们将创建一个RAG
模块的实例来运行程序。
重要提示: 在调用自定义DSPy模块时,您应该直接使用模块实例(内部会调用__call__
方法),而不是显式调用forward()
方法。__call__
方法在执行forward
逻辑之前会处理必要的内部处理。
import os
os.environ["OPENAI_API_KEY"] = "{your_openai_api_key}"
dspy.configure(lm=dspy.LM("openai/gpt-4o-mini"))
rag = RAG()
print(rag(question="Is Lebron James the basketball GOAT?"))
The question of whether LeBron James is the basketball GOAT is subjective and depends on personal opinions. Many consider him one of the greatest due to his achievements and impact on the game, but others may argue for different players like Michael Jordan.
就是这样!总结来说,要构建你的GenAI应用,我们只需将自定义逻辑放入forward()
方法中,然后创建一个模块实例并调用该实例本身。
为什么需要自定义模块?¶
DSPy 是一个轻量级的编写和优化框架,我们的重点是通过将提示(字符串输入,字符串输出)的LLM转变为编程LLM(结构化输入,结构化输出)来解决提示工程的混乱,以构建稳健的AI系统。
虽然我们提供预构建模块,它们具有自定义提示逻辑,如 dspy.ChainOfThought
用于推理,dspy.ReAct
用于工具调用智能体,以便于构建您的AI应用,但我们并不旨在标准化您构建智能体的方式。
在DSPy中,您的应用程序逻辑只需放入自定义模块的forward
方法中,只要您编写的是python代码,就没有任何约束。通过这种布局,从其他框架或纯SDK使用迁移到DSPy很容易,也很容易迁移出去,因为它本质上只是python代码。