面向开发者的提示工程

type
Post
status
Published
summary
之前写过《面向使用者的提示工程》,主要是面向普通用户,在日常使用大语言模型聊天或对话的时候应该如何书写提示词,来改善大模型输出的效果。而本篇主要是面向开发者,介绍在开发 RAG 类基于大模型的应用时应该如何优化和改善提示词,针对特定任务构造能充分发挥大模型能力的 Prompt 的技巧
slug
llms-prompt-for-developer
date
Mar 18, 2024
tags
LLMs
Prompt
提示词
大语言模型
category
大语言模型
password
icon
URL
Property
Apr 12, 2024 11:44 AM

一、导读

之前写过《面向使用者的提示工程》,主要是面向普通用户,在日常使用大语言模型聊天或对话的时候应该如何书写提示词,来改善大模型输出的效果。而本篇主要是面向开发者,介绍在开发 RAG 类基于大模型的应用时应该如何优化和改善提示词,针对特定任务构造能充分发挥大模型能力的 Prompt 的技巧
整理自:

二、提示原则

2.1、原则一:编写清晰、具体的指令

2.1.1、使用分隔符清晰地表示输入的不同部分

作用:
  • 将不同的部分进行分割,避免混淆
  • 避免词注入(用户输入的文本可能与预设的 prompt 冲突,可能导致可以直接通过输入操控语言模型、或者干扰模型而得出较差的效果)
示例:
text = f""" 您应该提供尽可能清晰、具体的指示,以表达您希望模型执行的任务。\ 这将引导模型朝向所需的输出,并降低收到无关或不正确响应的可能性。\ 不要将写清晰的提示词与写简短的提示词混淆。\ 在许多情况下,更长的提示词可以为模型提供更多的清晰度和上下文信息,从而导致更详细和相关的输出。 """ # 需要总结的文本内容 prompt = f""" 把用三个反引号括起来的文本总结成一句话。 ```{text}``` """

2.1.2、寻求结构化的输出

有时候我们需要语言模型给我们一些结构化的输出,如JSON、HTML等,而不仅仅是连续的文本。
示例
prompt = f""" 请生成包括书名、作者和类别的三本虚构的、非真实存在的中文书籍清单,\ 并以 JSON 格式提供,其中包含以下键:book_id、title、author、genre。 """

2.1.3、要求模型检查是否满足条件

如果任务包含不一定能满足的假设(条件),我们可以告诉模型先检查这些假设。
示例
text_1 = f""" 泡一杯茶很容易。首先,需要把水烧开。\ 在等待期间,拿一个杯子并把茶包放进去。\ 一旦水足够热,就把它倒在茶包上。\ 等待一会儿,让茶叶浸泡。几分钟后,取出茶包。\ 如果您愿意,可以加一些糖或牛奶调味。\ 就这样,您可以享受一杯美味的茶了。 """ prompt = f""" 您将获得由三个引号括起来的文本。\ 如果它包含一系列的指令,则需要按照以下格式重新编写这些指令: 第一步 - ... 第二步 - … … 第N步 - … 如果文本中不包含一系列的指令,则直接写“未提供步骤”。" \"\"\"{text_1}\"\"\" """

2.1.4、提供少量示例

给模型一两个已完成的样例,让模型了解我们的要求和期望的输出样式
示例
prompt = f""" 您的任务是以一致的风格回答问题。 <孩子>: 请教我何为耐心。 <祖父母>: 挖出最深峡谷的河流源于一处不起眼的泉眼;最宏伟的交响乐从单一的音符开始;最复杂的挂毯以一根孤独的线开始编织。 <孩子>: 请教我何为韧性。 """

2.2、原则二:给模型时间去思考

如果让语言模型匆忙给出结论,其结果很可能不准确。例如,若要语言模型推断一本书的主题,仅提供简单的书名和一句简介是不足够的。
应通过 Prompt 指引语言模型进行深入思考。可以要求其先列出对问题的各种看法,说明推理依据,然后再得出最终结论。在 Prompt 中添加逐步推理的要求,能让语言模型投入更多时间逻辑思维,输出结果也将更可靠准确。

2.2.1、指定完成任务所需的步骤

示例
text = f""" 在一个迷人的村庄里,兄妹杰克和吉尔出发去一个山顶井里打水。\ 他们一边唱着欢乐的歌,一边往上爬,\ 然而不幸降临——杰克绊了一块石头,从山上滚了下来,吉尔紧随其后。\ 虽然略有些摔伤,但他们还是回到了温馨的家中。\ 尽管出了这样的意外,他们的冒险精神依然没有减弱,继续充满愉悦地探索。 """ # example 1 prompt_1 = f""" 执行以下操作: 1-用一句话概括下面用三个反引号括起来的文本。 2-将摘要翻译成英语。 3-在英语摘要中列出每个人名。 4-输出一个 JSON 对象,其中包含以下键:english_summary,num_names。 请用换行符分隔您的答案。 Text: ```{text}``` """ prompt_2 = f""" 1-用一句话概括下面用<>括起来的文本。 2-将摘要翻译成英语。 3-在英语摘要中列出每个名称。 4-输出一个 JSON 对象,其中包含以下键:English_summary,num_names。 请使用以下格式: 文本:<要总结的文本> 摘要:<摘要> 翻译:<摘要的翻译> 名称:<英语摘要中的名称列表> 输出 JSON:<带有 English_summary 和 num_names 的 JSON> Text: <{text}> """

2.2.2、指导模型在下结论之前找出一个自己的解法

还可以通过明确指导语言模型进行自主思考,来获得更好的效果。
假设我们要语言模型判断一个数学问题的解答是否正确,可以在 Prompt 中先要求语言模型自己尝试解决这个问题,思考出自己的解法,然后再与提供的解答进行对比,判断正确性。这种先让语言模型自主思考的方式,能帮助它更深入理解问题,做出更准确的判断。
示例
prompt = f""" 请判断学生的解决方案是否正确,请通过如下步骤解决这个问题: 步骤: 首先,自己解决问题。 然后将您的解决方案与学生的解决方案进行比较,对比计算得到的总费用与学生计算的总费用是否一致,并评估学生的解决方案是否正确。 在自己完成问题之前,请勿决定学生的解决方案是否正确。 使用以下格式: 问题:问题文本 学生的解决方案:学生的解决方案文本 实际解决方案和步骤:实际解决方案和步骤文本 学生计算的总费用:学生计算得到的总费用 实际计算的总费用:实际计算出的总费用 学生计算的费用和实际计算的费用是否相同:是或否 学生的解决方案和实际解决方案是否相同:是或否 学生的成绩:正确或不正确 问题: 我正在建造一个太阳能发电站,需要帮助计算财务。 - 土地费用为每平方英尺100美元 - 我可以以每平方英尺250美元的价格购买太阳能电池板 - 我已经谈判好了维护合同,每年需要支付固定的10万美元,并额外支付每平方英尺10美元; 作为平方英尺数的函数,首年运营的总费用是多少。 学生的解决方案: 设x为发电站的大小,单位为平方英尺。 费用: 1. 土地费用:100x美元 2. 太阳能电池板费用:250x美元 3. 维护费用:100,000+100x=10万美元+10x美元 总费用:100x美元+250x美元+10万美元+100x美元=450x+10万美元 实际解决方案和步骤: """
⚠️
大语言模型可能会产生幻觉问题(自行构造出似是而非的细节),由于幻觉信息往往令人无法辨别真伪,开发者必须警惕并尽量避免它的产生。
可以先让语言模型直接引用文本中的原句,然后再进行解答。这可以追踪信息来源,降低虚假内容的风险。

三、迭代优化

以下是一些常见的问题可供参考
  • 生成文本太长
    • 优化:使用最多50个词
    • 问题:精度不会很准,但是接近预设长度,需要多次尝试
  • 细节处理错误:细节信息错误,侧重角度不对等
    • 请对三个反引号之间的评论文本进行概括,最多30个字,并且侧重在快递服务上。
    • 请对三个反引号之间的评论文本进行概括,最多30个词汇,并且侧重在产品价格和质量上。
  • 指定输出格式
    • 优化:在描述之后,包括一个表格,提供产品的尺寸。表格应该有两列。第一列包括尺寸的名称。第二列只包括英寸的测量值。

四、任务类型

使用上面提到的优化迭代方法进行不断的优化和迭代;

4.1、文本概括

示例:单一文本概括
prompt = "您的任务是从电子商务网站上生成一个产品评论的简短摘要。" # 如果只想要提取某一个单独的信息并过滤其他所有的信息可以使用文本提取 prompt = "您的任务是从电子商务网站上的产品评论中提取相关信息。"
多条文本概括
for 循环、整合品论、分布式

4.2、推断

示例:情感分类
prompt = f""" 以下用三个反引号分隔的产品评论的情感是什么? 用一个单词回答:「正面」或「负面」。 评论文本: ```{lamp_review}``` """ prompt = f""" 识别以下评论的作者表达的情感。包含不超过五个项目。将答案格式化为以逗号分隔的单词列表。 评论文本: ```{lamp_review}``` """
示例:信息提取
prompt = f""" 从评论文本中识别以下项目: - 评论者购买的物品 - 制造该物品的公司 评论文本用三个反引号分隔。将你的响应格式化为以 “物品” 和 “品牌” 为键的 JSON 对象。 如果信息不存在,请使用 “未知” 作为值。 让你的回应尽可能简短。 评论文本: ```{lamp_review}``` """
示例:信息提取和情感分析
prompt = f""" 从评论文本中识别以下项目: - 情绪(正面或负面) - 审稿人是否表达了愤怒?(是或否) - 评论者购买的物品 - 制造该物品的公司 评论用三个反引号分隔。将你的响应格式化为 JSON 对象,以 “情感倾向”、“是否生气”、“物品类型” 和 “品牌” 作为键。 如果信息不存在,请使用 “未知” 作为值。 让你的回应尽可能简短。 将 “是否生气” 值格式化为布尔值。 评论文本: ```{lamp_review}``` """
示例:推断主题
prompt = f""" 确定以下给定文本中讨论的五个主题。 每个主题用1-2个词概括。 请输出一个可解析的Python列表,每个元素是一个字符串,展示了一个主题。 给定文本: ```{story}``` """
示例:推断主题并判断
prompt = f""" 判断主题列表中的每一项是否是给定文本中的一个话题, 以列表的形式给出答案,每个元素是一个Json对象,键为对应主题,值为对应的 0 或 1。 主题列表:美国航空航天局、当地政府、工程、员工满意度、联邦政府 给定文本: ```{story}``` """

4.3、文本转换

示例:文本翻译
prompt = f""" 将以下中文翻译成西班牙语: \ ```您好,我想订购一个搅拌机。``` """ prompt = f""" 请将以下文本分别翻译成中文、英文、法语和西班牙语: ```I want to order a basketball.``` """
示例:识别语种
prompt = f""" 请告诉我以下文本是什么语种: ```Combien coûte le lampadaire?``` """
示例:写作语气与风格调整
prompt = f""" 将以下文本翻译成商务信函的格式: ```小老弟,我小羊,上回你说咱部门要采购的显示器是多少寸来着?``` """
示例:文件格式转换
prompt = f""" 将以下Python字典从JSON转换为HTML表格,保留表格标题和列名:{data_json} """
示例:拼写及语法纠正
prompt = f"""请校对并更正以下文本,注意纠正文本保持原始语种,无需输出原始文本。 如果您没有发现任何错误,请说“未发现错误”。 例如: 输入:I are happy. 输出:I am happy. ```{text[i]}```""" prompt = f"校对并更正以下商品评论:```{text}```"
示例:综合案例
prompt = f""" 针对以下三个反引号之间的英文评论文本, 首先进行拼写及语法纠错, 然后将其转化成中文, 再将其转化成优质淘宝评论的风格,从各种角度出发,分别说明产品的优点与缺点,并进行总结。 润色一下描述,使评论更具有吸引力。 输出结果格式为: 【优点】xxx 【缺点】xxx 【总结】xxx 注意,只需填写xxx部分,并分段输出。 将结果输出成Markdown格式。 ```{text}``` """

4.4、 文本扩展

示例:定制客户邮件
根据客户的评价和其中的情感倾向,使用大语言模型针对性地生成回复邮件
prompt = f""" 你是一位客户服务的AI助手。 你的任务是给一位重要客户发送邮件回复。 根据客户通过“```”分隔的评价,生成回复以感谢客户的评价。提醒模型使用评价中的具体细节 用简明而专业的语气写信。 作为“AI客户代理”签署电子邮件。 客户评论: ```{review}``` 评论情感:{sentiment} """

4.5、聊天对话

像 ChatGPT 这样的聊天模型实际上是组装成以一系列消息作为输入,并返回一个模型生成的消息作为输出的。
示例:设置角色
messages = [ {'role':'system', 'content':'你是个友好的聊天机器人。'}, {'role':'user', 'content':'Hi, 我是Isa。'} ]
示例:构建构建上下文
messages = [ {'role':'system', 'content':'你是个友好的聊天机器人。'}, {'role':'user', 'content':'Hi, 我是Isa'}, {'role':'assistant', 'content': "Hi Isa! 很高兴认识你。今天有什么可以帮到你的吗?"}, {'role':'user', 'content':'是的,你可以提醒我, 我的名字是什么?'} ]
示例:订餐机器人
context = [{'role':'system', 'content':""" 你是订餐机器人,为披萨餐厅自动收集订单信息。 你要首先问候顾客。然后等待用户回复收集订单信息。收集完信息需确认顾客是否还需要添加其他内容。 最后需要询问是否自取或外送,如果是外送,你要询问地址。 最后告诉顾客订单总金额,并送上祝福。 请确保明确所有选项、附加项和尺寸,以便从菜单中识别出该项唯一的内容。 你的回应应该以简短、非常随意和友好的风格呈现。 菜单包括: 菜品: 意式辣香肠披萨(大、中、小) 12.95、10.00、7.00 芝士披萨(大、中、小) 10.95、9.25、6.50 茄子披萨(大、中、小) 11.95、9.75、6.75 薯条(大、小) 4.50、3.50 希腊沙拉 7.25 配料: 奶酪 2.00 蘑菇 1.50 香肠 3.00 加拿大熏肉 3.50 AI酱 1.50 辣椒 1.00 饮料: 可乐(大、中、小) 3.00、2.00、1.00 雪碧(大、中、小) 3.00、2.00、1.00 瓶装水 5.00 """} ] messages = context.copy() messages.append( {'role':'system', 'content': '''创建上一个食品订单的 json 摘要。\ 逐项列出每件商品的价格,字段应该是 1) 披萨,包括大小 2) 配料列表 3) 饮料列表,包括大小 4) 配菜列表包括大小 5) 总价 你应该给我返回一个可解析的Json对象,包括上述字段'''}, )
If you have any questions, please contact me.