提示工程 | 豆包MarsCode AI刷题

143 阅读6分钟

提示工程 | 豆包MarsCode AI刷题

秘密在于,LangChain的输出解析器偷偷的在提示中加了一段话,也就是 {format_instructions} 中的内容。这段由LangChain自动添加的文字,就清楚地指示着我们希望得到什么样的回答以及回答的具体格式。提示指出,模型需要根据一个schema来格式化输出文本,这个 schema 从 ```json 开始,到 ``` 结束

这就是在告诉模型,你就follow这个schema(schema,可以理解为对数据结构的描述)的格式,就行啦!

这就是一个很棒、很典型的提示工程。有了这样清晰的提示,智能程度比较高的模型(比如GPT3.5及以上版本),肯定能够输出可以被解析的数据结构,如JSON格式的数据。

那么这节课我就带着你进一步深究,如何利用LangChain中的提示模板,做好提示工程。

上节课我说过,针对大模型的提示工程该如何做,吴恩达老师在他的 ChatGPT Prompt Engineering for Developers 公开课中,给出了两个大的原则:第一条原则是写出清晰而具体的指示,第二条原则是给模型思考的时间。

无独有偶,在Open AI的官方文档 GPT 最佳实践中,也给出了和上面这两大原则一脉相承的6大策略。分别是:

  1. 写清晰的指示
  2. 给模型提供参考(也就是示例)
  3. 将复杂任务拆分成子任务
  4. 给GPT时间思考
  5. 使用外部工具
  6. 反复迭代问题

怎么样,这些原则和策略是不是都是大白话?这些原则其实不仅能够指导大语言模型,也完全能够指导你的思维过程,让你处理问题时的思路更为清晰。所以说,大模型的思维过程和我们人类的思维过程,还是蛮相通的。

提示的结构

当然了,从大原则到实践,还是有一些具体工作需要说明,下面我们先看一个实用的提示框架。

图片

在这个提示框架中:

  • 指令(Instuction)告诉模型这个任务大概要做什么、怎么做,比如如何使用提供的外部信息、如何处理查询以及如何构造输出。这通常是一个提示模板中比较固定的部分。一个常见用例是告诉模型“你是一个有用的XX助手”,这会让他更认真地对待自己的角色。
  • 上下文(Context)则充当模型的额外知识来源。这些信息可以手动插入到提示中,通过矢量数据库检索得来,或通过其他方式(如调用API、计算器等工具)拉入。一个常见的用例时是把从向量数据库查询到的知识作为上下文传递给模型。
  • 提示输入(Prompt Input)通常就是具体的问题或者需要大模型做的具体事情,这个部分和“指令”部分其实也可以合二为一。但是拆分出来成为一个独立的组件,就更加结构化,便于复用模板。这通常是作为变量,在调用模型之前传递给提示模板,以形成具体的提示。
  • 输出指示器(Output Indicator)标记​​要生成的文本的开始。这就像我们小时候的数学考卷,先写一个“解”,就代表你要开始答题了。如果生成 Python 代码,可以使用 “import” 向模型表明它必须开始编写 Python 代码(因为大多数 Python 脚本以import开头)。这部分在我们和ChatGPT对话时往往是可有可无的,当然LangChain中的代理在构建提示模板时,经常性的会用一个“Thought:”(思考)作为引导词,指示模型开始输出自己的推理(Reasoning)。

下面,就让我们看看如何使用 LangChain中的各种提示模板做提示工程,将更优质的提示输入大模型。

LangChain 提示模板的类型

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

这些模板的导入方式如下:

plain
复制代码
AI练中学

from langchain.prompts.prompt import PromptTemplate
from langchain.prompts import FewShotPromptTemplate
from langchain.prompts.pipeline import PipelinePromptTemplate
from langchain.prompts import ChatPromptTemplate
from langchain.prompts import (
    ChatMessagePromptTemplate,
    SystemMessagePromptTemplate,
    AIMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

我发现有时候不指定 .prompts,直接从LangChain包也能导入模板。

plain
复制代码
AI练中学
from langchain import PromptTemplate

下面我们通过示例来介绍上面这些模版,前两个我们简单了解就好,其中最典型的FewShotPromptTemplate会重点讲。至于PipelinePrompt和自定义模板,使用起来比较简单,请你参考LangChain文档自己学习。

使用 PromptTemplate

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

plain
复制代码
AI练中学
from langchain import PromptTemplate

template = """\
你是业务咨询顾问。
你给一个销售{product}的电商公司,起一个好的名字?
"""
prompt = PromptTemplate.from_template(template)

print(prompt.format(product="鲜花"))

输出:

plain
复制代码
AI练中学
你是业务咨询顾问。
你给一个销售鲜花的电商公司,起一个好的名字?

这个程序的主要功能是生成适用于不同场景的提示,对用户定义的一种产品或服务提供公司命名建议。

在这里,"你是业务咨询顾问。你给一个销售{product}的电商公司,起一个好的名字?" 就是原始提示模板,其中 {product} 是占位符。

然后通过PromptTemplate的from_template方法,我们创建了一个提示模板对象,并通过prompt.format方法将模板中的 {product} 替换为 "鲜花"

这样,就得到了一句具体的提示:你是业务咨询顾问。你给一个销售鲜花的电商公司,起一个好的名字? ——这就要求大语言模型,要有的放矢。

在上面这个过程中,LangChain中的模板的一个方便之处是from_template方法可以从传入的字符串中自动提取变量名称(如product),而无需刻意指定。上面程序中的product自动成为了format方法中的一个参数

当然,也可以通过提示模板类的构造函数,在创建模板时手工指定input_variables,示例如下:

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

输出:

plain
复制代码
AI练中学
你是业务咨询顾问。对于一个面向高端市场的,专注于销售鲜花的公司,你会推荐哪个名字?

上面的方式直接生成了提示模板,并没有通过from_template方法从字符串模板中创建提示模板。二者效果是一样的。