一晃24年已经过了一半,我们来重新看下大模型应用中最脆弱的一环Prompt Engineering有了哪些新的解决方案。这一章我们先看看大火的DSPy框架,会先梳理DSPy相关的几篇核心论文了解下框架背后的设计思想和原理,然后以FinEval的单选题作为任务,从简单指令,COT指令,到采样Few-shot和优化指令给出代码示例和效果评估。

论文串烧

  • DEMONSTRATE–SEARCH–PREDICT:

    Composing retrieval and language models for knowledge-intensive NLP
  • DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines
  • In-Context Learning for Extreme Multi-Label Classification
  • Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs
  • DSPy Assertions:

    Computational Constraints for Self-Refining Language Model Pipelines

DSPY这个prompt框架着实火了一阵了,项目也发了上面的许多论文,每篇论文都对应了项目中的一个或几个模块。我们来串一遍以上论文的核心思想。

DEMONSTRATE–SEARCH–PREDICT是DSPy的第一篇,核心思想和现在coze这类流程控制软件很相似(哈哈现在大模型领域的名词异常的多,这个workflow其实和agent,chain,pipeline,bot啥的意思也很相似)。核心在固定流程,模块化推理过程和指令(few-shot)生成过程。

虽然是在RAG任务上提出的DSP框架,但我们抛开RAG的search,predict的流程,论文的核心其实是把任务拆分成多个原子节点,每个原子节点是一个不可再分割的function,通过整体的control flow来串联原子节点。同时这种流程化的框架,使得每个节点都可以基于训练数据生成demonstation,并且可以通过不同的召回逻辑,在推理时进行few-shot的动态选择,来优化每一个节点的效果。

以下是OpenQA任务上的一个workflow的示例,整个流程有三个部分,生成Demonstration,并基于示例,进行检索和推理。

其中示例的生成,会使用训练数据在相同的流程上,取运行过程中每一步的结果作为实例,这里选择了k=3的3-shot示例

在上面DSP的基础上,DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines对流程进一步做了抽象和重构,提出了以三个核心模块为基础的prompt生成和优化框架

  • Signature: 继承了pydantic的BaseModel,定义任务的范式,例如Context,Question -> Answer
  • Module:类似pytorch对模型定义的callable function,定义了任务的workflow,例如上面retrieve-then-read的RAG流程
  • Teleprompter: 基于任务指标对流程进行优化的编译器,这里的优化集中在few-shot的选择和动态流程选择,这里流程选择主要是Ensemble,而非直接对workflow进行修改。论文说还提供了微调能力,其实也是基于流程生成的Demonstration作为样本来微调。

其中Telepropmter提供了BootstrapFewShot, BootstrapFewShotWithRandomSearch,Ensemble等prompt优化器。这篇论文的重心是放在prompt中few-shot选择和优化

以BootstrapFewShotWithRandomSearch为例,Teleprompter会先基于训练集生成一批Demonstration,再基于指定任务的metric,从中采样得到在验证集上效果表现最优的few-shot来构建最终的prompt。

In-Context Learning for Extreme Multi-Label Classification其实是利用了DSPy的框架,在标签超大(≥10,000)的分类任务上构建了一个新的workflow,叫做Infer-Retrieve-Rank。也就是想让模型猜测N个可能的分类标签,然后召回这些标签。

Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs把重心放在了端到端的对任务prompt进行整体优化,除了few-shot之外,还包括对任务指令和任务条件的优化。这里有两个技术难点,一个是prompt空间的搜索范围极大,另一个是整体优化时指标的归因问题。

为解决prompt搜索空间问题,论文借鉴APE,也就是大模型基于input-output样本来分析任务本质,生成任务指令的思路。并且在描述任务时除了必须的训练样本,还提供了多个可选择的任务信息,包括

  • 是否使用大模型生成的2~3句话的任务描述
  • 是否使用任务的流程代码
  • 是否使用历史已经尝试过的指令
  • 是否使用不同的指令风格(tips), 例如更有创意,更简洁

模型生成指令的代码如下


TIPS = {
"none": "",
"creative": "Don't be afraid to be creative when creating the new instruction!",
"simple": "Keep the instruction clear and concise.",
"description": "Make sure your instruction is very informative and descriptive.",
"high_stakes": "The instruction should include a high stakes scenario in which the LM must solve the task!",
"persona": 'Include a persona that is relevant to the task in the instruction (ie. "You are a ...")',
}
class GenerateSingleModuleInstruction(dspy.Signature):
(
"""Use the information below to learn about a task that we are trying to solve using calls to an LM, then generate a new instruction that will be used to prompt a Language Model to better solve the task."""
)
if use_dataset_summary:
dataset_description = dspy.InputField(
desc="A description of the dataset that we are using.",
prefix="DATASET SUMMARY:",
)
if program_aware:
program_code = dspy.InputField(
format=str,
desc="Language model program designed to solve a particular task.",
prefix="PROGRAM CODE:",
)
program_description = dspy.InputField(
desc="Summary of the task the program is designed to solve, and how it goes about solving it.",
prefix="PROGRAM DESCRIPTION:",
)
module = dspy.InputField(
desc="The module to create an instruction for.", prefix="MODULE:",
)
task_demos = dspy.InputField(
format=str,
desc="Example inputs/outputs of our module.",
prefix="TASK DEMO(S):",
)
if use_instruct_history:
previous_instructions = dspy.InputField(
format=str,
desc="Previous instructions we've attempted, along with their associated scores.",
prefix="PREVIOUS INSTRUCTIONS:",
)
basic_instruction = dspy.InputField(
format=str, desc="Basic instruction.", prefix="BASIC INSTRUCTION:",
)
if use_tip:
tip = dspy.InputField(
format=str,
desc="A suggestion for how to go about generating the new instruction.",
prefix="TIP:",
)
proposed_instruction = dspy.OutputField(
desc="Propose an instruction that will be used to prompt a Language Model to perform this task.",
prefix="PROPOSED INSTRUCTION:",
)

基于以上大模型生成的指令候选,以及前面BootstrapFewShot生成的众多示例,下一步就是基于训练集选择最优的指令。这里论文构建了包括randomSearch等多个优化器,论文主推的MIPRO(Multi-prompt Instruction Proposal Optimizer)使用常见的超参优化的TPE算法来拟合以上指令中的多个超参对最终prompt效果的正负面影响,基于训练集上的评估指标最终选出最优的指令。所以是生成指令的超参(包括采样生成的指令)选择,并非直接去迭代更新指令本身。

其实这里也可以使用各类模型可解释算法。核心难点是整个任务中有多个节点,每个节点prompt有多个超参,彼此间互相影响,并最终影响任务的完成效果,但我们只能拿到最终任务完成的标签,无法获得中间节点的输出反馈。和决策树之类的归因算法难点相似。

DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines是DSPy新出的一个子功能-条件判断。考虑常见的prompt构成基本就包括三个部分,任务描述,few-shot示例,还有针对任务完成细节的requirement,前面两篇论文分别给出了生成优化任务描述和采样筛选few-shot的方案,那Assert就是面向requirements的优化方案。

而现实任务中requirement往往是最琐碎的部分,例如像Query改写任务,我们可能需要要求改写query和原始query相似度不能太高,但又不能丢失核心主体,不能丢失或者改写时间实体,query不能太长,不能对query中无关细节等等

论文给出了硬性要求(Assert)和软性建议(Suggest)两种方法,直接加入到前面编写的任务module中,这样任务推理的过程会根据Assert和Suggest直接生成建议,而使用也有两种,一种是模型在推理时命中assert和suggest后,对应建议会直接加入到prompt中用于模型self-refine,另一种是assert可以直接打断模型施法进行重试。

论文就简单说这么多,下面我们以金融单选题任务为示例尝试对prompt进行优化。

代码示例

下面我们以FinEval的单选题作为任务,尝试使用DSPy进行Prompt生成,Prompt优化,和效果评估。考虑成本这里只使用了100条样本。

基础Prompt

首先定义LLM模型,这里我使用的Azure的GPT4

import dspy
model = dspy.AzureOpenAI(**kwargs)
dspy.settings.configure(lm=model)

使用DSPy定义prompt,就是定义一个Pydantic模型,包括任务描述,输入描述和输出描述,称之为Signature,如下

class SingleChoiceQA(dspy.Signature):
"""单项选择题,给定题目和ABCD四个选项,输出正确的选项"""
question = dspy.InputField(desc='问题和选项')
answer = dspy.OutputField(desc="[ABCD]之一的正确选项")

然后我们把数据导入并转化成DSPy规定的样本格式,同样只要注明输入,Example会自动把剩余字段都当做输出

def format_example(line):
input = line['question']
for choice in ['A', 'B', 'C', 'D']:
input += f'\n{choice}. {line[f"{choice}"]}'
output = line["answer"]
example = dspy.Example(question=input, answer=output).with_inputs('question')
return example

下一步我们来定义任务,DSPy称之为Module,也就是定义任务流,像RAG就是retrieve-read,multihop QA就是多轮的QA,而这里因为是简单的单选题,因此Module定义非常简单。

class SQA(dspy.Module):
def __init__(self):
self.generate_answer = dspy.Predict(SingleChoiceQA) def forward(self, question):
return self.generate_answer(question=question)
singlechoice_qa = SQA()
pred = singlechoice_qa(question=examples[0]['question'])
print('以下为DSPy生成Prompt')
print(model.inspect_history(n=1))

同时我们可以使用inspect_history很方便的查看,DSPy生成的具体Prompt,和对应模型的推理效果,如下

COT优化和评估

在上面基础任务定义的基础上,下一步我们看看能否简单使用COT就能优化任务效果。

加入COT定义的Module如下,DSPy提供了常见的ReACT,POT等思考Prompt。

class SQACOT(dspy.Module):
def __init__(self):
self.generate_answer = dspy.ChainOfThought(SingleChoiceQA) def forward(self, question):
return self.generate_answer(question=question)
singlechoice_qa_cot = SQACOT()

加入COT后的prompt和推理效果如下

接下来我们来定义下任务的评估指标,然后批量评估下使用基础Prompt和COT Prompt的效果差异。

DSPy提供了一些Exact Match,Passage Match之类的指标,但其实自己定义指标最方便。只要和DSPy Metric的输入输出对齐即可。这里我们简单抽取答案中的ABCD和标准答案计算Accuracy。评估代码如下,DSPy支持在返回打分的同时,返回每一条预测的具体结果

from dspy.evaluate.evaluate import Evaluate
def choice_match(example, pred, trace=None):
def extract_choice(gen_ans):
m = re.findall(r'[ABCD]', gen_ans, re.M)
if len(m) >= 1:
answer = m[0]
return answer
return random.choice('ABCD') return extract_choice(pred.answer) == example.answer evaluate_on_qa = Evaluate(devset=test, num_threads=1,
display_progress=True, display_table=True)
output1 = evaluate_on_qa(singlechoice_qa, metric=choice_match,return_outputs=True,return_all_scores=True) output2 = evaluate_on_qa(singlechoice_qa_cot, metric=choice_match,return_outputs=True,return_all_scores=True)

以上评估,基础Prompt的准确率在50%,而COT Prompt的准确率在60%

FewShot优化

再进一步我们使用DSPy最重点打造的FewShot采样优化,看下能否进一步提升效果。这里DSPy提供了多种优化器,适配不同的样本量级,这里考虑成本我们使用了基础的BootstrapFewShot,样本更多可以尝试BootstrapFewShotWithRandomSearch,或者BootstrapFewShotWithOptuna。

BootstrapFewShot可以指定few-shot中包含几个模型预测生成的样本(max_bootstrapped_demos),和几个真实标签的训练样本(max_labeld_demos)

teleprompter = BootstrapFewShot(metric=choice_match,
max_bootstrapped_demos=4,
max_labeled_demos=16)
compiled_qa = teleprompter.compile(singlechoice_qa_cot, trainset=train) score3, results3, output3, df3 = evaluate_on_qa(compiled_qa, metric=choice_match,
return_outputs=True,
return_all_scores=True)

加入采样Few-Shot后的推理准确率提升到了75% ,使用2个推理Demos,和4个真实标签的Demos拼接而成的模型Prompt如下

指令优化

再看下指令优化,这里使用的是COPRO优化器,也就是使用prompt让大模型基于原有prompt优化生成新的prompt,优化指令和第一轮优化生成的prompt如下

第二轮之后指令优化会给出之前尝试过的所有指令,和每个指令在验证集上的打分,并让模型进行有针对性的优化,称之为GenerateInstructionGivenAttempts,指令如下

在0.7的temperature下,每一轮模型会基于上一轮的最优prompt生成breadth=5个新的prompt,并重复以上过程depth=3轮,最后选取在验证集上效果最优的prompt。

COPRO_teleprompter = COPRO(prompt_model=model ,
metric=choice_match,
breadth=5,
depth=3,
init_temperature=0.7,
track_stats=True)
kwargs = dict(num_threads=1, display_progress=True, display_table=5)
COPRO_compiled_qa = COPRO_teleprompter.compile(singlechoice_qa_cot,
trainset=train,
eval_kwargs=kwargs)
print(model.inspect_history(n=1))

最终优化后的最优的prompt指令如下

但在测试集上最终并没有提升准确率还是60%,其中一个主要原因也是单选QA任务本身比较基础,在指令上可以优化的空间不算太大,指令优化再更复杂,非常规任务上的效果会更显著些。

整体上DSPy确实提供了模块化,标准化设计Prompt的方案,但是在任务描述上的优化方案现在还比较有限,上面GenerateInstructionGivenAttempts虽然提供了历史尝试过的指令和验证集打分,但缺少了模型从历史prompt的回答中总结模型当前指令存在什么问题的步骤,后面可能可以考虑更多reflection相关的指令优化方案像TextGrad,这个等我玩过再来总结吧~

想看更全的大模型相关论文梳理·微调及预训练数据和框架·AIGC应用,移步Github >> DecryPrompt

解密prompt系列35. 标准化Prompt进行时! DSPy论文串烧和代码示例的更多相关文章

  1. 解密Prompt系列2. 冻结Prompt微调LM: T5 & PET & LM-BFF

    这一章我们介绍固定prompt微调LM的相关模型,他们的特点都是针对不同的下游任务设计不同的prompt模板,在微调过程中固定模板对预训练模型进行微调.以下按时间顺序介绍,支持任意NLP任务的T5,针 ...

  2. 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

    本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...

  3. 3.Java 加解密技术系列之 SHA

    Java 加解密技术系列之 SHA 序 背景 正文 SHA-1 与 MD5 的比较 代码实现 结束语 序 上一篇文章中介绍了基本的单向加密算法 — — MD5,也大致的说了说它实现的原理.这篇文章继续 ...

  4. 解密Prompt系列6. lora指令微调扣细节-请冷静,1个小时真不够~

    上一章介绍了如何基于APE+SELF自动化构建指令微调样本.这一章咱就把微调跑起来,主要介绍以Lora为首的低参数微调原理,环境配置,微调代码,以及大模型训练中显存和耗时优化的相关技术细节 标题这样写 ...

  5. 解密Prompt系列3. 冻结LM微调Prompt: Prefix-Tuning & Prompt-Tuning & P-Tuning

    这一章我们介绍在下游任务微调中固定LM参数,只微调Prompt的相关模型.这类模型的优势很直观就是微调的参数量小,能大幅降低LLM的微调参数量,是轻量级的微调替代品.和前两章微调LM和全部冻结的pro ...

  6. .NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书

    简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...

  7. 9.Java 加解密技术系列之 RSA

    Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项 ...

  8. 5.Java 加解密技术系列之 DES

    Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比 ...

  9. 4.Java 加解密技术系列之 HMAC

    Java 加解密技术系列之 HMAC 序 背景 正文 代码 结束语 序 上一篇文章中简单的介绍了第二种单向加密算法 — —SHA,同时也给出了 SHA-1 的 Java 代码.有这方面需求的童鞋可以去 ...

  10. 2.Java 加解密技术系列之 MD5

    Java 加解密技术系列之 MD5 序 背景 正文 结束语 序 上一篇文章中,介绍了最基础的编码方式 — — BASE64,也简单的提了一下编码的原理.这篇文章继续加解密的系列,当然也是介绍比较基础的 ...

随机推荐

  1. 3个月搞定计算机二级C语言!高效刷题系列进行中

    前言 大家好,我是梁国庆. 计算机二级应该是每一位大学生的必修课,相信很多同学的大学flag中都会有它的身影. 我在大学里也不止一次的想要考计算机二级office,但由于种种原因,备考了几次都不了了之 ...

  2. win10系统,磁盘出现惊叹号和一把锁符号如何关闭去掉

    如标题描述,图标如下 解决方法如下:搜索cmd -> 以管理员身份运行 输入命令如下 根据c,d,e盘符的文件量大小执行时间有些差异. manage-bde -off c:就可以解密c盘,成为b ...

  3. mysql加解密,substring substring_index函数

    mysql加解密,substring substring_index函数 SELECT to_base64(AES_ENCRYPT('测试串','key12345678')) ;SELECT AES_ ...

  4. 又跳槽!3年Java经验收割成都大厂的面试心得(干货满满&文末有福利)

    中厂->阿里->字节,成都->杭州->成都 系列文章目录和关于我 0.前言 笔者在不足两年经验的时候从成都一家金融科技中厂跳槽到杭州阿里淘天集团,又于今年5月份从杭州淘天跳槽到 ...

  5. WebUI自动化测试-监听元素有无变化

    from datetime import datetime,timedelta from selenium.webdriver.common.by import By def get_inocSum( ...

  6. 硬件开发笔记(二十):AD21导入外部下载的元器件原理图库、封装库和3D模型

    前言   在硬件设计的过程中,会遇到一些元器件,这些元器件在本地已有的库里面没有,但是可以从外部下载或者获取到对应的.  本篇就是引入TPS54331D电源芯片作为示例,详细描述整个过程.   创建T ...

  7. MoneyPrinterPlus:AI自动短视频生成工具-阿里云配置详解

    MoneyPrinterPlus是一个很好的自动短视频生成工具,虽然是一个非常好的工具,但是有些小伙伴可能不太清楚具体应该如何配置才能让它跑起来. 因为MoneyPrinterPlus依赖一些具体的配 ...

  8. Linux设备模型:2、基本对象 Kobject、Kset、Ktype

    原文:http://www.wowotech.net/device_model/kobject.html 作者:wowo 发布于:2014-3-7 0:25 分类:统一设备模型 前言 Kobject是 ...

  9. Freertos学习:02-FreeRTOSConfig.h

    --- title: rtos-freertos-02-FreeRTOSConfig.h EntryName: rtos-freertos-02-FreeRTOSConfig date: 2020-0 ...

  10. 《DNK210使用指南 -CanMV版 V1.0》第二章 Kendryte K210简介

    第二章 Kendryte K210简介 1)实验平台:正点原子DNK210开发板 2)章节摘自[正点原子]DNK210使用指南 - CanMV版 V1.0 3)购买链接:https://detail. ...