如何用DSPy生成prompt示例

之前探索了使用DSPy的简单示例

https://blog.csdn.net/liliang199/article/details/155614507

这里进一步探索DSPy的符合应用,包括问答、情感分类、RAG系统等。

所用示例参考和修改自网络资料。

1 DSPy基础应用

1.1 DSPy配置

首先是LLM模型设置,这里配置LLM模型ollama/gemma3n:e2b,示例代码如下。

复制代码
import dspy

# 1. 配置语言模型 (这里以OpenAI为例,需提前设置API密钥)
lm = dspy.LM(model="ollama/gemma3n:e2b", api_base="http://localhost:11434")
dspy.configure(lm=lm)

另外,还可以配置兼容openai接口的LLM模型,过程参考如下链接。

https://blog.csdn.net/liliang199/article/details/155614507

1.2 DSPy测试

这是一个最简流程,展示了定义签名、选择模块、调用的核心步骤,验证DSPy的有效性。

复制代码
# 2. 定义签名:指定输入和输出
class BasicQA(dspy.Signature):
    """回答简短的事实性问题。"""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField(desc="通常为1到5个词")

# 3. 创建预测模块
qa_module = dspy.Predict(BasicQA)

# 4. 调用模块
result = qa_module(question="量子计算的创始人是谁?")
print(f"答案: {result.answer}")

输出如下,这里通过BasicQA限定输入、输出的约束。

要求回答简单的事实性问题,答案要求1到5个词。

显然,DSPy生成的回答简明扼要,就Peter Shor2两个词,遵循了BasicQA的要求。

答案: Peter Shor

2 DSPy深度应用

这里考虑DSPy的进一步应用,比如应用到情感分类、构建RAG系统、使用优化器提升性能。

2.1 加入推理链 - 情感分类

使用 ChainOfThought 模块,让模型展示推理过程,通常能得到更准确的结果。

这里没有使用提示词,而是通过SentimentSignature给定任务定义,由DSPy生成提示词。

相比直接使用提示词的方式,在保持效果的前提下,这种实现方式更简洁明了。

复制代码
import dspy
from typing import Literal

# 1. 定义更详细的签名
class SentimentSignature(dspy.Signature):
    """对文本进行情感分类。"""
    sentence: str = dspy.InputField(desc="需要分类的文本")
    sentiment: Literal['positive', 'negative', 'neutral'] = dspy.OutputField(desc="情感类别")

# 2. 使用思维链模块
classifier = dspy.ChainOfThought(SentimentSignature)

# 3. 调用并查看推理过程
result = classifier(sentence="这部电影的视觉效果令人惊叹,但剧情略显拖沓。")
print(f"情感: {result.sentiment}")
print(f"推理: {result.reasoning}")  # ChainOfThought会额外提供推理字段

输出如下所示,这里通过SentimentSignature定义输入和输出需要分类的类别。

然后,使用思维链模块适配SentimentSignature。

可以看出,尽管没有进行模型训练,DSPy对输入进行了准确分类。

情感: neutral

推理: 这句话表达了对电影视觉效果的积极评价,但同时也指出了剧情的不足。整体而言,这句话的情感倾向是复杂的,既有积极的,也有消极的。考虑到视觉效果的突出,以及剧情的不足,可以认为整体情感偏向积极。

2.2 构建RAG问答系统

这是DSPy的典型应用。这里提供一个RAG问答系统示例,整合检索和生成。

这个例子使用本地数据模拟检索,能直接运行并理解DAG的核心流程。

以下是RAG逻辑核心逻辑签名模块

复制代码
# ===== 3. 定义DSPy签名 =====
class GenerateAnswer(dspy.Signature):
    """基于给定上下文回答问题。"""
    context = dspy.InputField(desc="相关背景信息")
    question = dspy.InputField()
    answer = dspy.OutputField(desc="简洁、准确的答案,基于上下文")

相比直接采用提示词实现RAG检索和生成,这种方式逻辑清晰,简洁有效,更方便编程实现。

RAG整体代码示例如下。

复制代码
import dspy
import json

# ===== 2. 构建模拟知识库(实际项目中替换为真实向量数据库) =====
class SimpleRetriever:
    """一个简单的内存检索器,模拟向量数据库功能"""
    def __init__(self, documents):
        # documents格式: [{"text": "...", "id": 1}, ...]
        self.documents = documents
    
    def retrieve(self, query, k=3):
        """简单关键词匹配检索(实际应用应使用向量检索)"""
        query_lower = query.lower()
        scored_docs = []
        
        for doc in self.documents:
            text = doc["text"].lower()
            # 简单评分:计算查询词在文档中出现的次数
            score = sum(1 for word in query_lower.split() if word in text)
            if score > 0:
                scored_docs.append((score, doc["text"]))
        
        # 按分数排序并返回前k个
        scored_docs.sort(reverse=True, key=lambda x: x[0])
        return [text for _, text in scored_docs[:k]]

# 创建示例知识库(你的实际文档数据)
knowledge_base = [
    {"id": 1, "text": "爱因斯坦在1921年因对理论物理的贡献,特别是发现光电效应定律而获得诺贝尔物理学奖。"},
    {"id": 2, "text": "光电效应是指当光照射到金属表面时,会从金属中发射出电子的现象。这一发现对量子力学的发展至关重要。"},
    {"id": 3, "text": "阿尔伯特·爱因斯坦(1879-1955)是德裔理论物理学家,相对论的创始人,也是量子力学的重要奠基人之一。"},
    {"id": 4, "text": "诺贝尔物理学奖是根据阿尔弗雷德·诺贝尔的遗嘱设立的,旨在表彰在物理学领域做出杰出贡献的科学家。"},
    {"id": 5, "text": "1921年的诺贝尔物理学奖颁奖典礼于1922年举行,因为1921年没有候选人被认为符合获奖标准。"},
]

# 初始化检索器
retriever = SimpleRetriever(knowledge_base)

# ===== 3. 定义DSPy签名 =====
class GenerateAnswer(dspy.Signature):
    """基于给定上下文回答问题。"""
    context = dspy.InputField(desc="相关背景信息")
    question = dspy.InputField()
    answer = dspy.OutputField(desc="简洁、准确的答案,基于上下文")

# ===== 4. 构建RAG模块 =====
class RAG(dspy.Module):
    def __init__(self, retriever, num_passages=3):
        super().__init__()
        self.retriever = retriever
        self.num_passages = num_passages
        # 使用ChainOfThought让模型先推理再回答
        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
    
    def forward(self, question):
        # 1. 检索阶段:获取相关文档
        contexts = self.retriever.retrieve(question, k=self.num_passages)
        context_str = "\n---\n".join(contexts)
        
        # 2. 生成阶段:基于检索到的上下文生成答案
        prediction = self.generate_answer(
            context=context_str, 
            question=question
        )
        
        # 返回完整结果
        return dspy.Prediction(
            contexts=contexts,
            answer=prediction.answer,
            reasoning=prediction.reasoning  # ChainOfThought提供的推理过程
        )

# ===== 5. 初始化RAG系统 =====
rag_system = RAG(retriever, num_passages=2)

# ===== 6. 测试RAG系统 =====
def test_rag_system():
    """测试RAG系统的示例问题"""
    test_questions = [
        "爱因斯坦因什么获得诺贝尔奖?",
        "什么是光电效应?",
        "谁创立了相对论?"
    ]
    
    for question in test_questions:
        print(f"\n{'='*60}")
        print(f"问题: {question}")
        print(f"{'='*60}")
        
        # 获取答案
        result = rag_system(question)
        
        # 打印检索到的上下文
        print("检索到的上下文:")
        for i, ctx in enumerate(result.contexts, 1):
            print(f"{i}. {ctx[:100]}...")  # 只显示前100字符
        
        # 打印推理过程(如果有)
        if hasattr(result, 'reasoning') and result.reasoning:
            print(f"\n模型推理: {result.reasoning}")
        
        # 打印最终答案
        print(f"\n最终答案: {result.answer}")

# ===== 7. 优化RAG系统(可选:使用BootstrapFewShot) =====
def optimize_rag_system():
    """使用少量示例优化RAG提示"""
    from dspy.teleprompt import BootstrapFewShot
    
    # 准备训练示例
    trainset = [
        dspy.Example(
            question="爱因斯坦的诺贝尔奖贡献是什么?",
            contexts=[
                "爱因斯坦在1921年因对理论物理的贡献,特别是发现光电效应定律而获得诺贝尔物理学奖。",
                "光电效应是指当光照射到金属表面时,会从金属中发射出电子的现象。"
            ],
            answer="发现光电效应定律"
        ).with_inputs('question'),
        
        dspy.Example(
            question="谁创立了相对论?",
            contexts=[
                "阿尔伯特·爱因斯坦(1879-1955)是德裔理论物理学家,相对论的创始人。",
                "爱因斯坦是相对论的创始人,也是量子力学的重要奠基人之一。"
            ],
            answer="阿尔伯特·爱因斯坦"
        ).with_inputs('question'),
    ]
    
    # 定义评估指标
    def validate_answer(example, prediction, trace=None):
        # 简单验证:预测答案是否包含关键词
        correct_keywords = {
            "爱因斯坦的诺贝尔奖贡献是什么?": ["光电效应"],
            "谁创立了相对论?": ["爱因斯坦"]
        }
        
        question = example.question
        if question in correct_keywords:
            return any(keyword in prediction.answer for keyword in correct_keywords[question])
        return True
    
    # 创建优化器
    teleprompter = BootstrapFewShot(
        metric=validate_answer,
        max_bootstrapped_demos=2,
        max_labeled_demos=2
    )
    
    # 优化RAG系统
    print("正在优化RAG系统...")
    optimized_rag = teleprompter.compile(RAG(retriever), trainset=trainset)
    
    return optimized_rag

# ===== 8. 主程序入口 =====
if __name__ == "__main__":
    print("RAG问答系统启动...")
    
    # 测试基础版本
    test_rag_system()
    
    # 询问是否要优化(实际使用时可注释掉这部分)
    print(f"\n{'='*60}")
    user_question = input("\n请输入你的问题(或直接回车使用默认问题): ").strip()
    
    if not user_question:
        user_question = "爱因斯坦在哪年获得诺贝尔奖?"
    
    # 获取答案
    result = rag_system(user_question)
    
    print(f"\n问题: {user_question}")
    print(f"答案: {result.answer}")
    
    if hasattr(result, 'reasoning') and result.reasoning:
        print(f"推理过程: {result.reasoning}")
    
    # 显示来源
    print(f"\n信息来源:")
    for i, ctx in enumerate(result.contexts, 1):
        print(f"[{i}] {ctx}")

输出如下所示

RAG问答系统启动...

============================================================

问题: 爱因斯坦因什么获得诺贝尔奖?

============================================================

检索到的上下文:

模型推理: 爱因斯坦在1921年获得诺贝尔物理学奖,获奖的原因是由于他对光电效应的解释。光电效应是光与物质相互作用时,电子被激发的过程。爱因斯坦提出了光量子(光子)的概念来解释光电效应,这在当时是一个革命性的想法。他的解释为量子力学的发展奠定了基础。

最终答案: 爱因斯坦因他对光电效应的解释而获得诺贝尔奖。

============================================================

问题: 什么是光电效应?

============================================================

检索到的上下文:

模型推理: 光电效应是指光子与物质相互作用时,电子被发射出来的现象。它揭示了光具有粒子性,而不是仅仅是波动。当光子具有足够的能量时,它可以激发电子从原子中脱离。

最终答案: 光电效应是指光线照射到物质表面时,电子被发射出来的现象。它表明光具有粒子性,光子撞击原子并激发电子从原子中脱离。

============================================================

问题: 谁创立了相对论?

============================================================

检索到的上下文:

模型推理: 相对论是由阿尔伯特·爱因斯坦创立的。狭义相对论于1905年发表,广义相对论于1915年发表。

最终答案: 阿尔伯特·爱因斯坦

============================================================

请输入你的问题(或直接回车使用默认问题):

问题: 爱因斯坦在哪年获得诺贝尔奖?

答案: 1905

推理过程: 爱因斯坦于1905年获得诺贝尔物理学奖。

信息来源:

3 DSPy进阶应用

3.1 使用优化器提升性能

对一些进阶应用,DSPy需要用户给出少量标注数据,辅助DSPy优化器优化prompt。

DSPy优化器可以自动利用这些少量标注数据来优化提示。

以下是使用 BootstrapFewShot 的简化流程,包括

1)准备少量训练数据

2)定义评估指标,比如准确率

然后通过bootstrapfewshot模块变异优化给定任务的提示词。

类似于模型训练,分类器优化后,DSPy就可以作预测了,推理延迟会更小,性能会更好。

复制代码
import dspy
from dspy.teleprompt import BootstrapFewShot

# 1. 定义签名和初始模块(同示例二)
classifier = dspy.ChainOfThought(SentimentSignature)

# 2. 准备少量训练数据
trainset = [
    dspy.Example(sentence="产品非常好用,强烈推荐!", sentiment='positive').with_inputs('sentence'),
    dspy.Example(sentence="服务糟糕,体验极差。", sentiment='negative').with_inputs('sentence'),
    # ... 更多示例
]

# 3. 定义评估指标(例如:准确率)
def sentiment_metric(example, prediction):
    # 简单比较预测情感和真实情感是否一致
    return example.sentiment == prediction.sentiment

# 4. 创建并运行优化器
optimizer = BootstrapFewShot(metric=sentiment_metric, max_bootstrapped_demos=2)
optimized_classifier = optimizer.compile(classifier, trainset=trainset)

# 5. 使用优化后的模块
result = optimized_classifier(sentence="这本书内容一般,没什么亮点。")
print(f"优化后的预测: {result.sentiment}")

输出如下

100%|██████████| 2/2 [00:38<00:00, 19.25s/it]

Bootstrapped 0 full traces after 1 examples for up to 1 rounds, amounting to 2 attempts.

优化后的预测: neutral

3.2 使用 BestOfN确保输出质量

使用bestOfN 模块确保输出质量,这个模块会基于奖励函数,从多次生成结果中选出最优答案。

代码示例如下所示。

复制代码
import dspy

# 1. 配置语言模型
# lm = dspy.LM('openai/gpt-4o-mini')
# dspy.configure(lm=lm)

# 2. 定义签名和基础模块
class BasicQA(dspy.Signature):
    """回答简短的事实性问题。"""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField(desc="通常为1到5个词")

# 基础问答模块
base_qa = dspy.ChainOfThought(BasicQA)

# 3. 定义奖励函数(核心)
def reward_is_one_word(example, prediction):
    """
    评估答案质量的奖励函数。
    如果预测答案是一个单词(不含空格),返回1.0(最高奖励),否则返回0.0。
    """
    # 去除首尾空格后检查是否包含空格
    answer = prediction.answer.strip()
    if answer and ' ' not in answer:
        return 1.0  # 是单个单词,给予最高奖励
    return 0.0  # 不是单个单词,奖励为0

# 4. 使用 BestOfN 包装基础模块
optimized_qa = dspy.BestOfN(
    module=base_qa,        # 要优化的基础模块
    N=5,                   # 最多尝试5次
    reward_fn=reward_is_one_word,  # 使用的奖励函数
    threshold=1.0          # 奖励达到1.0则提前终止
)

# 5. 调用优化后的模块
question = "法国的首都是什么?"
print(f"问题: {question}")

# 注意:BestOfN会尝试多次(最多N次),以寻找满足奖励阈值的结果
result = optimized_qa(question=question)

print(f"最终答案: {result.answer}")
# BestOfN会返回所有尝试中奖励函数得分最高的那个预测
# 你还可以访问 result.trace 来查看每次尝试的详细情况(如果配置了跟踪)

输出如下

问题: 法国的首都是什么?

最终答案: 巴黎

BestOfN会返回所有尝试中奖励函数得分最高的那个预测。

如果配置了跟踪,还可以访问 result.trace 来查看每次尝试的详细情况。

3.3 使用Refine确保输出质量

Refine 模块在 BestOfN 的基础上增加了反馈循环,能让LLM在后续尝试中自行改进。

以下是它的典型用法:

复制代码
# ...(前面的配置和签名定义与上例相同)...

# 使用 Refine 包装基础模块
refining_qa = dspy.Refine(
    module=base_qa,
    N=3,                    # 最多尝试3次
    reward_fn=reward_is_one_word,
    threshold=1.0
)

# 调用 Refine 模块
result = refining_qa(question="世界上最高的山峰是哪座?")
print(f"经过反思和改进后的答案: {result.answer}")

输出如下所示

经过反思和改进后的答案: 珠穆朗玛峰

3.4 实现流式输出与异步处理

对于需要逐步输出或高并发处理的场景,DSPy提供了相应支持。

示例代码如下所示。

复制代码
import dspy
import asyncio

# 流式输出示例[citation:1]
class TestSignature(dspy.Signature):
    input_text: str = dspy.InputField()
    output_text: str = dspy.OutputField()

# 用streamify包装程序
streaming_program = dspy.streamify(dspy.Predict(TestSignature))

async def use_streaming():
    output_stream = streaming_program(input_text="请解释人工智能。")
    async for chunk in output_stream:
        print(chunk, end='', flush=True)  # 逐块打印输出

# 运行异步函数
# asyncio.run(use_streaming()) # 直接运行
asyncio.get_event_loop().create_task(use_streaming()) # jupyter中运行

# 异步批量处理示例[citation:8]
dspy.settings.configure(async_max_workers=4)
async_module = dspy.asyncify(dspy.Predict("question -> answer"))

async def batch_questions(questions):
    tasks = [async_module(question=q) for q in questions]
    responses = await asyncio.gather(*tasks)
    return responses

输出如下所示

Prediction(

output_text='人工智能是指模拟人类智能的计算机系统或软件。它涵盖了广泛的技术,包括机器学习、深度学习、自然语言处理、计算机视觉等。人工智能的目标是创建能够执行通常需要人类智能才能完成的任务,例如学习、推理、问题解决、感知和理解语言。\n\n简单来说,人工智能就是让机器像人一样思考和行动。'

)

reference


prompt自主生成框架 - DSPy

https://blog.csdn.net/liliang199/article/details/155614507

awesome-dspy

https://github.com/ganarajpr/awesome-dspy

Bug\] assert_transform_module not present in dspy 2.6.0 #7805 [https://github.com/stanfordnlp/dspy/issues/7805](https://github.com/stanfordnlp/dspy/issues/7805 "https://github.com/stanfordnlp/dspy/issues/7805")

相关推荐
桃子叔叔9 小时前
AutoPrompt如何实现自动化生成与优化的方案
prompt·autoprompt
聊询QQ:6882388621 小时前
Matlab 实现遗传算法优化冷链物流配送路径规划
prompt
小痞同学1 天前
【AI专题】一、提示词(prompt)
ai·prompt
AlfredZhao1 天前
让 AI 真正好用:一个框架提升你的办公效率
prompt·tcrei
sysu_lluozh3 天前
【驱动AI提示词】提示词设计模式
ai·prompt
xiucai_cs3 天前
AI Prompt
后端·prompt
桃子叔叔3 天前
论文翻译:CONSISTENCY-GUIDED PROMPT LEARNING FOR VISION-LANGUAGE MODELS
机器学习·语言模型·prompt
桃子叔叔3 天前
论文解析:CONSISTENCY-GUIDED PROMPT LEARNING FOR VISION-LANGUAGE MODELS
人工智能·语言模型·prompt
黄埔数据分析3 天前
chatgpt prompt for fpga
fpga开发·prompt