通过符号程序搜索提升prompt工程

news2025/1/14 1:13:05

原文地址:supercharging-prompt-engineering-via-symbolic-program-search

通过自动探索​​大量提示变体来找到更好的提示

2024 年 4 月 22 日

众所周知,LLMs的成功在很大程度上仍然取决于我们用正确的指导和例子来提示他们的能力。随着新一代LLMs变得越来越强大,提示已经变得足够复杂,足以被视为课程本身。这些提示程序很像菜谱——都有一套遵循和转换原材料的指令,无论是数据还是成分。

因此,提示工程类似于改进配方。家庭厨师通常会坚持整体食谱,但会做出一些小改变—例如在面食中省略大蒜或添加欧芹。像DSPy这样的框架在优化上下文示例时遵循这个整体范例。然而,专业级厨师以食谱为灵感,经常完全重新诠释菜肴的成分。例如,他们可能将面食中的意大利面视为淀粉成分,并可能将其替换为新鲜制作的面疙瘩以获得类似的成分。

是什么让专业级厨师能够如此富有创意地工作?他们以抽象的方式思考食谱,就像上面的意大利面例子一样。手动提示工程类似于专业级烹饪。它可以获得令人印象深刻的结果,但需要大量的时间和知识。我们真正想要的是手动提示工程的创造力,但又不需要付出努力。

抽象提示的力量

假设我们想改进一个用于标注说话人回答的提示。我们最终会用许多不同的输入来运行它,但现在先插入一个具体的输入:

Instructions: Does Speaker 2's answer mean yes or no?
Output labels: no, yes
Input: Speaker 1: "You do this often?" Speaker 2: "It's my first time."
Output:

暂且假设我们有一个抽象的提示表示法,它可以抽出不同的组成部分,并且易于操作。也许可以这样:

5

有了它,你就可以自动完成在及时原型开发过程中必须进行的大量(半)手工修补工作。进行诸如转述之类的小编辑只是一个开始。想试试思维链推理吗?添加一段 “让我们逐步思考”。将数据格式改为 JSON 格式如何?只需更改 InputData 参数的 formatattribute 即可。你还可以探索:

  • 从单一示例到批量注释
  • 在 RAG 场景中更改检索器和排序功能
  • 重新排列某些段落的顺序
  • 压缩说明的某些部分
  • ETC

从本质上讲,你可以输入你最喜欢的提示工程启发式。这种抽象的提示表示法让我们能够真正发挥创意,自动探索大量可能的提示。

将提示转化为抽象程序

要表示抽象提示符,我们首先要将其转换为非符号提示符程序,将其分解为单独的组件,以 Python 类的形式实现:

class Component:
    def __init__(self, **kwargs): pass
class Metaprompt(Component): pass
class Paragraph(Component): pass
class InputData(Component): pass
    
prompt = Metaprompt(
    children=[
        Paragraph(text="Instructions: "),
        Paragraph(
            id="instructions",
            text="Does Speaker 2's answer mean yes or no?",
        ),
        Paragraph(id="labels", text="Output labels: yes, no"),
        InputData(),
        Paragraph(text="Output: "),
    ]
)

到目前为止,一切顺利。这与 DSpy 所做的工作类似,但更为通用,因为我们还表示了提示符的内部结构。

接下来,我们要把它变成一个符号提示程序,这样就可以进行任意修改(这也超出了静态 DSPy 程序的范围)。pyGlove 将 Python 类转化为可操作的符号对象,其属性在实例化后仍可完全编辑。

有了 pyGlove,我们只需添加 pg.symbolize 装饰器即可:

import pyglove as pg
@pg.symbolize
class Component:
    def __init__(self, **kwargs): pass

现在,我们可以通过大量的说明符来查询和修改提示程序,就像使用 DOM 树一样。比方说,我们想把上面的程序转化为下面的程序:

6

请注意,我们现在问的是 "回答是否表示是?",而不是提供 "是 "和 "否 "的输出标签。为此,我们需要 (i) 更改指令文本,(ii) 删除第三个节点。有了 pyGlove,这就很容易了:

prompt.rebind({'children[1].text': 'Does the response mean yes?'})'children[1].text': 'Does the response mean yes?'})
prompt.rebind({'children[2]': pg.MISSING_VALUE})
print(prompt)

打印输出确认我们成功了:

Metaprompt(
  children = [
    0 : Paragraph(
      text = 'Instructions: '
    ),
    1 : Paragraph(
      id = 'instructions',
      text = 'Does the response mean yes?'
    ),
    2 : InputData(),
    3 : Paragraph(
      text = 'Output: '
    )
  ]
)

就是这样!从根本上说,pyGlove 给了我们一种处理 Python 类(和函数)的方法,就像处理源代码一样,而且开销很小。现在,我们有了灵活且易于操作的表示法,让我们来使用它们吧。

等一下。我们现在可能有了表示和修改提示的方法,但还缺少一个自动优化提示的过程。

一旦厨师们了解了菜谱的抽象概念和组成部分,他们就会尝试多种变体,改进口味、成本或表现形式,直到感觉合适为止。要对提示抽象进行同样的处理,我们需要一种搜索算法、一个目标以及一组标注样本,这样才能知道我们是否取得了进展。

使用 SAMMO 调整指令

为了说明 SAMMO 的核心工作流程,我们现在将展示如何调整上面提示示例中的指令部分。一旦我们完成了这个玩具示例,我们就可以讨论更高级的应用,如 RAG 优化或压缩。

关键步骤如下:

  1. 确定起始提示
  2. 准备好数据--几百个带标签的示例就足够了。
  3. 确定目标
  4. 选择一组突变体
  5. 运行优化

步骤 1:定义开始提示

这一步我们在上文已经做得差不多了。SAMMO 期望使用一个函数,因此我们必须将其封装为一个函数。如果你想存储额外的信息,可以用 Callable 代替。我们还将把它封装在一个输出组件中以运行它。

def starting_prompt():
    instructions = MetaPrompt(
        Paragraph(text="Instructions: "),
        Paragraph(
            id="instructions",
            text="Does Speaker 2's answer mean yes or no?",
        ),
        Paragraph(id="labels", text="Output labels: yes, no"),
        InputData(),
        Paragraph(text="Output: "),
    )
    return Output(instructions.with_extractor())

步骤 2:准备好数据

SAMMO 使用名为 DataTable 的简单数据结构将输入与输出(标签)配对。这将有助于我们进行评估和记账。

mydata = DataTable.from_records(
    records, # list of {"input": <>, "output": <>}# list of {"input": <>, "output": <>}
    constants={"instructions": default_instructions}, 
)

步骤 3:确定目标

我们感兴趣的是优化精确度,因此这就是我们下面要实现的目标:

def accuracy(y_true: DataTable, y_pred: DataTable) -> EvaluationScore:
    y_true = y_true.outputs.normalized_values()
    y_pred = y_pred.outputs.normalized_values()
    n_correct = sum([y_p == y_t for y_p, y_t in zip(y_pred, y_true)])
    return EvaluationScore(n_correct / len(y_true))

步骤 4:选择一组突变体

在这里,你可以尽情发挥自己的创造力。你可以实现自己的运算符来生成新的提示变体,也可以简单地依赖 SAMMO 提供的预置变异运算符。

在下文中,我们将采用后者,从一些标注的示例中混合使用转述和诱导指令,基本上实现了自动提示工程(APE)。

mutation_operators = BagOfMutators(
    starting_prompt=StartingPrompt(d_train),
    InduceInstructions({"id": "instructions"}, d_train),"id": "instructions"}, d_train),
    Paraphrase({"id": "instructions"}),
)

步骤 5:运行优化

runner = OpenAIChat(
    model_id="gpt-3.5-turbo-16k","gpt-3.5-turbo-16k",
    api_config={"api_key": YOUR_KEY},
    cache="cache.tsv",
)
prompt_optimizer = BeamSearch(runner, mutation_operators, accuracy, depth=6)
transformed = prompt_optimizer.fit_transform(d_train)

介绍性提示示例实际上取自 BigBench 含义任务,我们将用它来运行本实验。如果使用 100 个样本进行训练和测试,并以 48 个候选评估为预算进行优化,你会发现 SAMMO 将起始提示的准确率从 0.56 提高到了 0.77 - 提高了 37.5%。哪些指令效果最好?

...
Paragraph(
    "Consider the dialogue, context, and background ""Consider the dialogue, context, and background "
    "information provided to determine the most suitable output label",
    id="instructions",
)
...

有趣的是,不同的 LLM 喜欢的指令大相径庭。如上所述,GPT-3.5 最喜欢通用指示。在相同的训练和预算设置下,SAMMO 选择的 Llama-2 最佳提示在指令部分使用了空字符串:

...
Paragraph(
    "","",
    id="instructions",
)
...

实际操作: RAG 调整

现在,我们将展示如何将 RAG 管道转换为符号程序,并使用 SAMMO 对其进行调整。我们将使用语义解析作为应用任务,将用户查询转化为特定领域语言 (DSL) 结构,例如,查询某些数据库或调用外部 API。

为了创建起始提示,我们列出了所有运算符的列表,使用基于嵌入的检索器获取五个少量示例,然后指示 LLM 以与示例相同的格式输出答案。

class RagStartingPrompt:
    def __init__(self, dtrain, examples, embedding_runner):
        self._examples = examples
        self._dtrain = dtrain
        self._embedding_runner = embedding_runner
    def __call__(self, return_raw=False):
        structure = [
            Section("Syntax", self._dtrain.constants["list_of_operators"]),
            Section(
                "Examples",
                EmbeddingFewshotExamples(
                    self._embedding_runner, self._examples, 5
                ),
            ),
            Section(
                "Complete and output in the same format as above",
                InputData(),
            ),
        ]
        instructions = MetaPrompt(
            structure,
            render_as="markdown",
            data_formatter=JSONDataFormatter(),
        )  
        return Output(
            instructions.with_extractor(),
            on_error="empty_result",
        )

现在我们有了一个符号程序,让我们发挥创意吧。对于突变,我们探索:

  • 不同数量的少量示例
  • 少量示例的不同格式(XML、JSON、逐行格式
  • 是否提供有关 DSL 的附加信息
  • 显示输入输出对或输入输出组

使用这些示例和总共 24 个候选示例运行 SAMMO,我们可以看到一个明显的趋势。以下是四个不同 LLM 的三个不同数据集的测试集准确率。在绝大多数情况下,我们可以看到 SAMMO 可以大幅提升性能,即使是性能最高的 LLM 也不例外。

7

结论

将提示语转换为符号程序是一个非常强大的想法,可以探索可能的提示语和设置的巨大设计空间。就像专业厨师通过解构和重新诠释食谱来进行烹饪创新一样,符号编程也能让我们在自动提示工程中发挥同样的创造力和实验精神。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1641332.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「C++ STL篇 0-0」string类的使用

目录 〇、概念 1. string类是什么&#xff1f; 2. string类的官方文档 3. 导入string类 一、string类的构造函数 0. 全部构造函数 1. 常用的四个构造函数 2. 可能用到的构造函数 拓1&#xff1a;npos 二、赋值运算符重载 1. 三个赋值运算符重载函数 2. 使用赋值运算符重载函数…

最新SpringBoot项目地方废物回收机构管理系统

采用技术 最新SpringBoot项目地方废物回收机构管理系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 登录页面 后端管理员 管理员首页 员工管理 设…

机器学习批量服务模式优化指南

原文地址&#xff1a;optimizing-machine-learning-a-practitioners-guide-to-effective-batch-serving-patterns 2024 年 4 月 15 日 简介 在机器学习和数据分析中&#xff0c;模型服务模式的战略实施对于在生产环境中部署和操作人工智能模型起着至关重要的作用。其中&…

软考之零碎片段记录(二十九)+复习巩固(十七、十八)

学习 1. 后缀式&#xff08;逆波兰式&#xff09; 2. c/c语言编译 类型检查是语义分析 词法分析。分析单词。如单词的字符拼写等语法分析。分析句子。如标点符号、括号位置等语言上的错误语义分析。分析运算符、运算对象类型是否合法 3. java语言特质 即时编译堆空间分配j…

Linux服务器常用命令总结

view查找日志关键词 注意日志级别&#xff0c;回车后等一会儿&#xff0c;因为文件可能比较大加载完需要时间 当内容显示出来后&#xff0c;使用“/关键词”搜索 回车就能搜到&#xff0c;n表示查找下一个&#xff0c;N表示查找上一个 find 查找 find Family -name book …

文本嵌入的隐私风险:从嵌入向量重建原始文本的探索

随着大型语言模型&#xff08;LLMs&#xff09;的广泛应用&#xff0c;文本嵌入技术在语义相似性编码、搜索、聚类和分类等方面发挥着重要作用。然而&#xff0c;文本嵌入所蕴含的隐私风险尚未得到充分探讨。研究提出了一种控制生成的方法&#xff0c;通过迭代修正和重新嵌入文…

jsp校园商城派送系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 校园商城派送系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用serlvetdaobean mvc 模式&#xff0c;系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Myeclipse8.…

第12章 消息服务 ❤❤❤❤

第12章 消息服务 12.1 JMS_ActiveMQ1. 简介2. ActiveMQ安装Linux安装命令问题1:网页访问不了问题2: 修改密码 3. 整合SpringBoot3.1 依赖3.2 配置3.3 JmsComponent 组件3.4 测试 12.2 AMQP_RabbitMQ1. 简介2. RabbitMQ2.1 Erlang环境安装(略)2.2 安装RabbitMQ(❤❤❤❤)2.3 启动…

FreeRTOS学习——FreeR TOS队列(下)

本篇文章记录我学习FreeRTOS的队列的相关知识&#xff0c;在此记录分享一下&#xff0c;希望我的分享对你有所帮助。 FreeRTOS学习——FreeRTOS队列&#xff08;上&#xff09;-CSDN博客 一、FreeRTOS队列的创建 &#xff08;一&#xff09;、函数原型 在使用队列之前必须先创…

【大数据】学习笔记

文章目录 [toc]NAT配置IP配置SecureCRT配置PropertiesTerminal Java安装环境变量配置 Hadoop安装修改配置文件hadoop-env.shyarn-env.shslavescore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml 环境变量配置 IP与主机名映射关系配置hostname配置映射关系配置 关闭防火墙…

OpenCV(四)—— 车牌号识别

本节是车牌识别的最后一部分 —— 车牌字符识别&#xff0c;从一个完整的车牌图片到识别出车牌上的字符大致需要如下几步&#xff1a; 预处理&#xff1a;将车牌图片灰度化、二值化&#xff0c;并去除识别时的干扰因素&#xff0c;比如车牌铆钉字符分割&#xff1a;将整个车牌…

基于springboot+vue+Mysql的影城管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

CATO原理中的数学与魔术(七)——Baby Hummer的拓展二

在上一篇文章中&#xff0c;我们介绍了《Baby Hummer》的两个拓展&#xff0c;从表演的形式台词&#xff0c;到呈现的策略&#xff0c;都有一定的改进&#xff0c;相关内容请戳&#xff1a; CATO原理中的数学与魔术&#xff08;六&#xff09;——Baby Hummer的拓展一 CATO原理…

WebSocket 多屏同显和异显

介绍 多屏同显:通过在一个应用上进行操作之后,另一个应用也能跟着一起发生改变,例如app1播放了晴天这首音乐,那么app2也要同步播放这首音乐,确保所有屏幕显示的内容完全相同。多屏异显:每个屏幕可以显示不同的内容,或者在内容更新时存在一定的延迟,而不需要严格保持同步…

MLP手写数字识别(1)-MNIST数据集下载与可视化(tensorflow)

1.下载与查看MNIST数据集 from keras.datasets import mnist(x_train_image,y_train_label),(x_test_image,y_test_label) mnist.load_data() print("train images:",x_train_image.shape) print("test images:",x_test_image.shape) print("train …

83、动态规划-打家劫舍

思路&#xff1a; 首先使用递归方式求出最优解。从每个房屋开始&#xff0c;分别考虑偷与不偷两种情况&#xff0c;然后递归地对后续的房屋做同样的决策。这种方法确保了可以找到在不触发警报的情况下可能的最高金额。 代码如下&#xff1a; public static int rob(int[] nu…

【多变量控制系统 Multivariable Control System】(2)给定系统转换方程,绘制奈奎斯特图【新加坡南洋理工大学】

一、系统转换方程 系统的转换方程 G(s) 和回馈矩阵 K(s) 由下2式给出&#xff1a; 二、从转换方程推出系统矩阵A和B from scipy.signal import tf2ss# Convert to state-space representation A, B, C, D tf2ss([1], [1, -2, 1])print("A matrix:", A) print(&quo…

【Unity】在空物体上实现 IPointerClickHandler 不起作用

感谢Unity接口IPointerClickHandler使用说明_哔哩哔哩_bilibiliUnity接口IPointerClickHandler使用说明, 视频播放量 197、弹幕量 0、点赞数 3、投硬币枚数 2、收藏人数 2、转发人数 0, 视频作者 游戏创作大陆, 作者简介 &#xff0c;相关视频&#xff1a;在Unity多场景同时编辑…

基于Springboot的教学资源共享平台(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的教学资源共享平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

VsCode | 修改首页启动页 Logo

VsCode | 修改首页启动页 Logo 最终效果&#xff1a; 插件的安装 先安装插件 Custom CSS and JS Loader 插件配置 Ctrl Shift P 输入 打开用户设置&#xff0c;在末尾添加 "vscode_custom_css.imports": [""]下载 Logo 下载 Logo 点我下载 引入…