03 提示工程|豆包MarsCode AI刷题

262 阅读9分钟

针对大模型的提示工程应该怎么做

参考吴恩达老师的 ChatGPT Prompt Engineering for Developers 公开课和Open AI的官方文档 GPT 最佳实践

  • 写出清晰而具体的指示
  • 给模型提供示例
  • 将复杂任务拆分成子任务
  • 给模型思考的时间
  • 使用外部工具
  • 反复迭代问题

提示的框架

image.png

  • 指令instruction: 告诉模型这个任务大概要做什么怎么做。一个常见的用例是告诉模型“你是一个有用的XX助手”
  • 上下文Context: 充当模型的额外知识来源。这些信息可以手动插入到提示中,通过矢量数据库检索得来,或通过其他方式(如调用API、计算器等工具)拉入。
  • 提示输入Prompt Input: 具体的问题或者需要大模型做的具体事情,这个部分和”指令“部分其实也可以合二为一,拆分出来更方便结构化。这个通常是一个变量。
  • 输出指示器Output Indicator: 标记要生成的文本的开始。就像是解题中的”解“,表示后面都是推理结果。

提示模板PromptTemplate 、ChatPromptTemplate

LangChain中提供String(StringPromptTemplate)和Chat(BaseChatPromptTemplate)两种基本类型的模板,并基于它们构建了不同类型的提示模板:

image.png

以上的模板可以直接import langchain.prompts

下面通过示例简单说明一下PromptTemplate的使用。

prompt = PromptTemplate(
    input_variables=["product", "market"], 
    template="你是业务咨询顾问。对于一个面向{market}市场的,专注于销售{product}的公司,你会推荐哪个名字?"
)
print(prompt.format(product="鲜花", market="高端"))

通过提示模板类的构造函数,在创建模板的时候指定input_variables,这里的{变量}为占位符

对于OpenAI推出的ChatGPT这一类的聊天模型LangChain也提供了一系列的模板

先要了解OpenAI中的Chat Model中的格式

消息必须是消息对象的数组;每个对象都有一个角色(系统、用户或助理)和内容;对话首先由系统消息格式化(可选),然后是交替的用户消息和助理消息;用户消息提供助理响应的请求或评论;助理消息存储以前的助理响应,但也可以由你编写以给出所需行为的示例;

# 导入聊天消息类模板
from langchain.prompts import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)
# 模板的构建
template="你是一位专业顾问,负责为专注于{product}的公司起名。"
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="公司主打产品是{product_detail}。"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
prompt_template = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

# 格式化提示消息生成提示
prompt = prompt_template.format_prompt(product="鲜花装饰", product_detail="创新的鲜花设计。").to_messages()

# 下面调用模型,把提示传入模型,生成结果
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI Key'
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
result = chat(prompt)
print(result)

FewShot

Few-Shot(少样本)、One-Shot(单样本)和与之对应的 Zero-Shot(零样本)的概念都起源于机器学习。如何让机器学习模型在极少量甚至没有示例的情况下学习到新的概念或类别。

在提示工程(Prompt Engineering)中,Few-Shot 和 Zero-Shot 学习的概念也被广泛应用。

  • 在Few-Shot学习设置中,模型会被给予几个示例,以帮助模型理解任务,并生成正确的响应。
  • 在Zero-Shot学习设置中,模型只根据任务的描述生成响应,不需要任何示例。

接下来介绍一个使用LangChain中的FewShotPromptTemplate构建最合适的鲜花文案,大致思路是:

创建示例样本

samples = [
    {
        "flower_type": "玫瑰",
        "occasion": "爱情",
        "ad_copy": "玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。",
    },
    ]

创建提示模板

这里的可以由已经创建的示例输入进模板用来生成一个一个具体可用的提示。

prompt_sample = PromptTemplate(
    input_variables=["flower_type", "occasion", "ad_copy"],
    template="鲜花类型: {flower_type}\n场合: {occasion}\n文案: {ad_copy}",
)

创建 FewShotPromptTemplate 对象

通过使用之前创建的prompt_sample,以及samples列表中的所有示例, 创建一个FewShotPromptTemplate对象,生成更复杂的提示。

prompt = FewShotPromptTemplate(
    examples=samples,
    example_prompt=prompt_sample,
    suffix="鲜花类型: {flower_type}\n场合: {occasion}",
    input_variables=["flower_type", "occasion"],
)

调用大模型创建新文案

这个模板可以指导模型生成对应的输出,然后创建一个新的提示,并将其输出给大模型。

model = ChatOpenAI(
    model=os.environ.get("LLM_MODELEND"),
)
result = model(prompt.format(flower_type="野玫瑰", occasion="爱情"))

使用示例选择器

实际上,一次性把所有示例发送给模型低效且浪费流量。这里LangChain提供了示例选择器,来选择最合适的样本。(注意,因为示例选择器使用向量相似度比较的功能)

# 初始化示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
    samples,
    DoubaoEmbeddings(
        model=os.environ.get("EMBEDDING_MODELEND"),
    ),
    Chroma,
    k=1,
)

# 创建一个使用示例选择器的FewShotPromptTemplate对象
prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=prompt_sample,
    suffix="鲜花类型: {flower_type}\n场合: {occasion}",
    input_variables=["flower_type", "occasion"],
)

在这个步骤中,首先创建了一个SemanticSimilarityExampleSelector对象,他可以根据语义相似性选择最相关的示例。然后跟上一部分的操作一样,创建了一个新的FewShotPromptTemplate对象,使用了上一步创建的选择器来选择最相关的示例生成提示。这样避免了把过多的无关模板传递给大模型,以节省Token的用量。

CoT

核心思想是通过生成一系列中间推理步骤来增强模型的推理能力。就像是大脑思考新问题的时候要先去理解问题,再搜索一些有用信息,最后做决策。

Few-Shot CoT中你能得到一些示例,可以加入思考的步骤对模型的推理进行引导,从而产生更好地结果。而Zero-Shot CoT则是告诉模型要一步一步思考,具体怎么做由模型决定。

Chain of Thought 实战

项目需求:在这个示例中,你正在开发一个AI运营助手,我们要展示AI如何根据用户的需求推理和生成答案。然后,AI根据当前的用户请求进行推理,提供了具体的花卉建议并解释了为什么选择这些建议。

CoT的模板设计

作为一个为花店电商公司工作的AI助手,我的目标是帮助客户根据他们的喜好做出明智的决定。

要完成以上目标,要先理解客户的需求,然后考虑各种鲜花的涵义,最后根据这个需求,给出我的推荐。同时,我也会向客户解释我这样推荐的原因。

程序框架

# 创建聊天模型
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(temperature=0)

# 设定 AI 的角色和目标
role_template = "你是一个为花店电商公司工作的AI助手, 你的目标是帮助客户根据他们的喜好做出明智的决定"

# CoT 的关键部分,AI 解释推理过程,并加入一些先前的对话示例(Few-Shot Learning)
cot_template = """
作为一个为花店电商公司工作的AI助手,我的目标是帮助客户根据他们的喜好做出明智的决定。 

我会按部就班的思考,先理解客户的需求,然后考虑各种鲜花的涵义,最后根据这个需求,给出我的推荐。
同时,我也会向客户解释我这样推荐的原因。

示例 1:
  人类:我想找一种象征爱情的花。
  AI:首先,我理解你正在寻找一种可以象征爱情的花。在许多文化中,红玫瑰被视为爱情的象征,这是因为它们的红色通常与热情和浓烈的感情联系在一起。因此,考虑到这一点,我会推荐红玫瑰。红玫瑰不仅能够象征爱情,同时也可以传达出强烈的感情,这是你在寻找的。

示例 2:
  人类:我想要一些独特和奇特的花。
  AI:从你的需求中,我理解你想要的是独一无二和引人注目的花朵。兰花是一种非常独特并且颜色鲜艳的花,它们在世界上的许多地方都被视为奢侈品和美的象征。因此,我建议你考虑兰花。选择兰花可以满足你对独特和奇特的要求,而且,兰花的美丽和它们所代表的力量和奢侈也可能会吸引你。
"""
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate
system_prompt_role = SystemMessagePromptTemplate.from_template(role_template)
system_prompt_cot = SystemMessagePromptTemplate.from_template(cot_template)

# 用户的询问
human_template = "{human_input}"
human_prompt = HumanMessagePromptTemplate.from_template(human_template)

# 将以上所有信息结合为一个聊天提示
chat_prompt = ChatPromptTemplate.from_messages([system_prompt_role, system_prompt_cot, human_prompt])

prompt = chat_prompt.format_prompt(human_input="我想为我的女朋友购买一些花。她喜欢粉色和紫色。你有什么建议吗?").to_messages()

# 接收用户的询问,返回回答结果
response = llm(prompt)
print(response)

这里定义了AI的角色和目标和CoT模板包括了AI的角色和目标描述、思考链条以及遵循思考链条的一些示例,使用PromptTemplate的from_template方法,来生成相应的询问模板。然后使用了ChatPromptTemplate.from_messages方法,整合上述定义的角色,CoT模板和用户询问,生成聊天提示。最后根据这个提示获得模型的回答。 image.png

ToT

进一步扩展了CoT的思想,通过搜索由连贯的语言序列组成的思维树来解决复杂问题。

ToT是一种解决复杂问题的框架,它在需要多步骤推理的任务中,引导语言模型搜索一棵由连贯的语言序列(解决问题的中间步骤)组成的思维树,而不是简单地生成一个答案。ToT框架的核心思想是:让模型生成和评估其思维的能力,并将其与搜索算法(如广度优先搜索和深度优先搜索)结合起来,进行系统性地探索和验证。

image.png

ToT 框架为每个任务定义具体的思维步骤和每个步骤的候选项数量。此外,通过引入强化学习、集束搜索等技术,可以进一步提高搜索策略的性能,并让模型在解决新问题或面临未知情况时有更好的表现。