12天带你速通大模型基础应用(二)自动化调优Prompt

🌟 DSPy项目背景

DSPy 是斯坦福大学开发的LLM编程框架,在GitHub上已获得27.5k+ stars

代表着声明式AI应用开发的新范式。其核心理念是通过编写组合式Python代码,而不过度依赖Prompt工程。

项目地址:
github.com/stanfordnlp...

从问题开始

假如让你构建一个AI应用,任务是对用户评论进行情感分析。使用提示词Prompt的方式下,你会怎么做?

ini 复制代码
prompt = "请分析以下文本的情感,返回0-10的分数,数字越大表示越积极:{text}"
response = llm.generate(prompt.format(text="我很开心!"))

但这种方式存在什么问题?当提示内容复杂的时候,每次调整都需要重写Prompt。当面对不同任务时,都要重新设计Prompt。当模型更换时,可能还需要重新调试Prompt。

那同样的任务,通过Dspy是怎么解决的?Dspy的核心是:通过在客户端声明数据格式,将LLM调用看作是API调用。

这里的关键是声明式,首先要理解传统的API的调用方式,通常由服务端预先定义好接口格式,然后客户端必须按照服务端的规范发送请求,数据格式是"服务端主导"的,服务端说什么格式,客户端就必须用什么格式。举个例子,服务端按下面定义,那么客户端传参数时,必须传city、date。:

bash 复制代码
response = requests.post('/api/weather', {
    'city': '北京',        
    'date': '2025-08-23'          # 必须按服务端要求
})
temp = response['temperature']  # 服务端决定返回什么字段

而Dspy是客户端(代码)定义输入输出格式,服务端LLM去自适应,是声明式的开发方式。

ini 复制代码
# DSPy:LLM适应你定义的格式
class WeatherQuery(dspy.Signature):
    city = dspy.InputField()           # 输入city
    temperature = dspy.OutputField()          # 输出温度

这样做的好处是,不必要跟随着LLM的响应结果走了。传统API固定了响应格式,当LLM输出格式不稳定时,还需要兼容修改解析代码,影响解析结果。

Dspy实现机制-四个核心模块

这里用情感分析的例子来贯穿这四个核心模块。

Signature:接口定义模块

Signature负责显式定义LLM交互的输入输出格式,使得模型响应无需手动解析字段,确保每次LLM调用都有明确的共识。根据应用复杂度的不同,DSPy提供了两种Signature定义方式:

方式一:类基签名(适用于复杂任务)

当需要精确控制字段类型、描述和约束时,推荐使用类基签名。它通过继承 dspy.Signature 类实现,包含 五个核心组件 :

  • • docstring:任务描述指令,定义LLM调用的目的
  • • 字段名称:用于携带输入数据和访问输出数据的标识符
  • • 输入输出标识: InputField、OutputField 标记字段作用
  • • desc:字段的额外信息描述,当字段名不够自解释时很有用
  • • 类型注解:支持基本Python类型、自定义类或Pydantic模型
python 复制代码
class SentimentClassifier(dspy.Signature):
    """对给定文本进行情感分类."""
    text: str = dspy.InputField(desc="需要分析情感的输入文本")
    sentiment: int = dspy.OutputField(
        desc="情感分数,数值越高表示越积极正面,范围0-10",
        choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    )

方式二:字符串基签名(适用于快速原型)

当需要快速实验和原型开发时,可直接使用字符串签名:

ini 复制代码
# 字符串基签名示例
classify = dspy.Predict("text -> sentiment: int")

Module:逻辑封装模块

Module负责封装与LLM交互的业务逻辑。当通过Signature定义好输入输出接口后,Module将这些接口组织成可执行的推理流程,把多个Signature组合成复杂推理链,再通过forward()方法管理复杂的业务逻辑执行。根据应用复杂度的不同,DSPy提供了两种Module使用方式:

方式一:直接使用内置Module(适用于简单任务)

当任务相对简单时,可以直接使用DSPy提供的内置模块:

  • • dspy.Predict :最基础的模块,内部已经实现了init 和 forward ,直接将Signature转化为可执行的LLM调用
  • • dspy.ChainOfThought :带推理过程的模块,在输出中增加reasoning字段
  • • dspy.ReAct :推理和行动结合的模块,适用于需要工具调用的场景
ini 复制代码
# 使用内置模块的情感分析示例
classify = dspy.Predict(SentimentClassifier)
result = classify(text="我很开心!")

方式二:自定义Module(适用于复杂应用)

当需要构建复杂的多步骤推理流程时,需要继承 dspy.Module 并自定义逻辑:

  • • 继承 dspy.Module :获得模块化的基础能力
  • • 实现 init方法 :初始化子模块和配置属性
  • • 实现 forward 方法 :定义复杂的业务逻辑执行流程
  • • 组合多个子模块 :将多个Signature组合成复杂推理链
ruby 复制代码
# 自定义模块示例
class CelebrityGuess(dspy.Module):
    def __init__(self):
        self.question_generator = dspy.ChainOfThought(QuestionGenerator)
        self.reflection = dspy.ChainOfThought(Reflection)
    
    def forward(self, celebrity_name):
        # 复杂的多轮对话逻辑
        # ...

Adapter:格式转换模块

Adapter负责在Signature和LLM之间进行格式转换。当通过Signature定义好输入输出接口后,Adapter将这些接口转换成LLM能理解的prompt格式,并将LLM的文本响应解析为结构化数据,实现将语言模型当作"有明确定义输入输出的API"来使用的目标。根据转换复杂度的不同,DSPy提供了两种Adapter使用方式:

方式一:自动选择Adapter(适用于大多数场景)

当使用DSPy的内置模块时,框架会自动选择合适的Adapter:

ini 复制代码
# 自动选择Adapter的情感分析示例
classify = dspy.Predict(SentimentClassifier)
result = classify(text="我很开心!")
# Adapter自动处理prompt构建和响应解析
print(result.sentiment)  # 直接访问结构化结果

方式二:自定义Adapter

当需要特定的prompt格式或解析逻辑时,可以自定义Adapter:

ini 复制代码
# 配置自定义Adapter示例
dspy.settings.configure(
    lm=dspy.LM("openai/gpt-4o-mini"),
    adapter=CustomAdapter()  # 使用自定义适配器
)

实际执行流程(隐式)

Adapter配置完成后,运行时实际的工作流程主要有三步(隐式实现):接受输入->构建prompt->解析响应

    1. 接收三类输入:Signature(签名定义)、User input(用户输入)、Module info(模块信息)
    1. 构建结构化prompt
    1. 解析LLM响应

可以通过dspy.inspect_history()查看Adapter的完整工作过程:

python 复制代码
# LLM的原始输出
"""
[[ ## reasoning ## ]]
The text "我很开心!" expresses a clear positive emotion with the word "开心" (happy). The exclamation mark further emphasizes the positive sentiment.

[[ ## sentiment ## ]]
9
"""

# Adapter解析后的结构化结果
result.reasoning = "'The text "我很开心!" expresses a clear positive emotion with the word "开心" (happy). The exclamation mark further emphasizes the positive sentiment.'"
result.sentiment = 9  # 自动转换为int类型

注意:使用dspy.ChainOfThought才会包含推理过程,直接使用dspy.Predict不会显示推理过程(也就是reasoning),而是直接输出结果。

Optimizer:性能优化模块

Optimizer负责自动优化DSPy程序的性能,解决传统手工调试prompt的痛点。当构建好Module和Signature后,Optimizer通过智能搜索和评估,自动找到最优的prompt模板和few-shot示例组合,实现程序质量的显著提升。根据优化需求的不同,DSPy提供了两种Optimizer使用方式:

方式一:自动模式优化(适用于大多数场景)

当需要快速获得优化效果时,可以使用DSPy提供的自动模式:

  • • MIPRO V2优化器 :专门用于提示模板优化和构建few-shot示例的优化器
  • • 自动模式配置 :提供light、medium、heavy三种预设模式
  • • 组合策略 :使用贝叶斯采样方法搜索最优组合
ini 复制代码
# 使用自动模式的优化示例
optimizer = dspy.MIPROv2(mode="auto")  # 可选:light, medium, heavy
optimized_program = optimizer.compile(
    student=program,
    trainset=train_data,
    valset=val_data,
    metric=accuracy_metric
)

这里的program 就是你自己构建的 DSPy 模块实例 。可以是:dspy.Predictdspy.ChainOfThoughtdspy.ReAct或者自定义模块。train_data是你用来优化的数据集,类似HotPotQA所使用的QA数据集。Optimizer会用这些数据来生成 few-shot 示例(通过 bootstrapping 过程),选择最佳的指令和示例组合。

ini 复制代码
# HotPotQA数据集示例
train_data = [
    {
        "question": "Which magazine was started first Arthur's Magazine or First for Women?",
        "answer": "Arthur's Magazine"
    },
    # ... 更多训练样本
]

方式二:自定义优化

当需要精细控制优化过程时,可以自定义优化器配置:

ini 复制代码
# 自定义优化示例
defcustom_metric(example, prediction):
    return example.answer == prediction.answer

# custom_metric: 使用什么评估指标
# max_bootstrapped_demos: 最多生成多少个bootstrap示例
# max_labeled_demos: 最多使用多少个标注示例
optimizer = dspy.BootstrapFewShot(
    metric=custom_metric,
    max_bootstrapped_demos=8,
    max_labeled_demos=4
)


optimized_program = optimizer.compile(
    student=program,
    trainset=train_data
)

实际执行流程(隐式)

当调用ptimizer.compile() ,DSPy 实际会执行四步流程:

    1. 构建few-shot示例集:方式是通过bootstrapping,从训练数据中取样本,输入DSPy程序执行,记录完整的执行过程,使用度量函数评估输出质量,当得分超过设定阈值时,提取该过程中每个模块的输入-输出对,作为该模块未来的few-shot示例候选;
    1. 生成指令候选:收集功能描述、few-shot示例和风格提示等信息,将它们组合成结构化输入,发送给DSPy proposer(指令生成器),该组件基于这些信息生成多个针对特定模块的指令候选,为后续的优化过程提供更多指令选择;
    1. 智能组合评估:使用贝叶斯抽样方法从few-shot示例集和指令候选集中智能选择组合,构建候选程序并进行评估。评估过程基于用户定义的度量函数和验证数据集,通过将程序输出与标准答案进行比较来计算得分;
    1. 选择最优配置:最终选择得分最高的候选程序作为优化后的最终配置;

案例一-情感分析实现

需求描述

构建一个情感分析系统,要求:

  • 输入:任意文本
  • 输出:0-10的情感分数(0=极度消极,10=极度积极)
  • 附加:提供推理过程

代码实现

结合前面提到的四个模块,可以很容易的实现:

案例二-猜人名游戏多轮对话

需求描述

构建一个"猜名人"游戏AI代理:

  • 游戏规则: 用户想一个名人,AI通过提问Yes/No问题来猜测
  • 限制条件: 最多20次提问机会

设计思路

1. 多轮对话

首先思考多轮对话的设计实现,既然是多轮对话,就要包含历史对话的内容信息。没有历史感知的方式,是每次都重新开始,例如:

ini 复制代码
# 每轮独立,历史容易丢失
for attempt in range(20):
    question = generate_question()  # 从零开始,无历史感知
    answer = get_user_input()

使用dspy要传入完整的历史,每次的决策都是基于全局的上下文:

ini 复制代码
# 每轮都是基于完整历史的智能决策
for attempt in range(20):
    question_result = self.question_generator(
        past_questions="\n".join(past_questions),  # 传入完整历史
        past_answers="\n".join(past_answers)       # 传入完整历史
    )
    # 新的交互立即成为下一轮的历史
    past_questions.append(question_result.new_question)
    past_answers.append(answer)

2. 分层推理-ChainOfThought的reasoning

要想回答正确,需要从宽泛的问题逐步缩小范围到具体答案。通过reasoning和历史上下文,由AI自动来做分层推理。

3. 判断推理成功

设置guess_made,当AI认为有足够的信息可以推断时,guess_made=True时,AI认为信息足够,开始直接猜测。当guess_made=False时,AI生成宽泛的分类问题继续提问。

python 复制代码
class QuestionGenerator(dspy.Signature):
    """Generate a yes/no question to narrow down the celebrity guess."""
    past_questions: str = dspy.InputField(desc="previously asked questions")
    past_answers: str = dspy.InputField(desc="corresponding yes/no answers")
    new_question: str = dspy.OutputField(desc="new yes/no question to ask")
    guess_made: bool = dspy.OutputField(desc="whether this is a direct guess") 

代码实现

定义子模块Signature:

控制流程模块:

游戏演示:

运行结果:

学习教程

我使用PlantUML绘制了一份技能树脑图,把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。

这份大模型路线大纲已经导出整理打包了,在 >gitcode ←←←←←←

L1阶段:启航篇丨极速破界AI新时代

L1阶段:了解大模型的基础知识,以及大模型在各个行业的应用和分析,学习理解大模型的核心原理、关键技术以及大模型应用场景。

L2阶段:攻坚篇丨RAG开发实战工坊

L2阶段:AI大模型RAG应用开发工程,主要学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。

L3阶段:跃迁篇丨Agent智能体架构设计

L3阶段:大模型Agent应用架构进阶实现,主要学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造Agent智能体。

L4阶段:精进篇丨模型微调与私有化部署

L4阶段:大模型的微调和私有化部署,更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调,并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。

L5阶段:专题集丨特训篇 【录播课】

相关推荐
新知图书1 小时前
10.1 项目背景与需求分析(智能客服智能体开发)
人工智能·agent·ai agent·智能体·扣子
赵康1 小时前
AI 写代码之后,Code Review 会议怎么开
ai·llm·skill
程序员cxuan2 小时前
Grok Build 被众人唾骂,结果老马把它开源了
人工智能·后端·程序员
莫逸风2 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
决战灬2 小时前
langgraph之interrupt(理论篇)
人工智能·python·agent
人间凡尔赛4 小时前
2026 AI Agent 多智能体协同编程实战指南:从 Kimi K3 到 GPT-5.6 深度解析
ai·agent·多智能体·编程实战·waic·gpt-5.6·kimik3
爱勇宝5 小时前
《道德经》第 7 章:真正厉害的领导者,不抢主角
前端·后端·程序员
前端Baymax6 小时前
Memory Search索引模型不匹配故障
ai·agent·infra
Hilaku7 小时前
2026 年前端大洗牌:React 服务端到 Vite 的底层重构
前端·javascript·程序员