前言:这是一篇很好地讲解了提示词工程的文章,提示词是fine tune大模型的一种比较经济适用的方式,基于提示词搭建一套agent可能是能形成未来生产力的关键一环。
过去的12个月里,大型语言模型(LLMs)以惊人的速度崛起。随着越来越多的LLMs通过开源和/或API提供,访问变得更加容易,使得LLMs不再只属于数据科学家,而是对具有基本软件编写和API调用理解的每个人都可获得。大型语言模型(LLMs)在使用时展现出了强大而新兴的能力。在最基本的层面上,使用这些LLMs的方法是通过向LLM提供一个具体命令,并由LLM生成输出。使用情境可以从要求LLM生成一个简单的博客开始,比如“写一篇100字的关于气候变化的博客”,到更复杂的使用情况。我将使用LLM作为一个更通用的术语,尽管此博客中的代码大部分是在OpenAI的GPT3模型上运行的。本博客中使用的代码可在此存储库[1]中获得。
现在,让我们使用OpenAI的GPT模型运行我们的第一个提示。
使用类似下面的提示的情感分类器:
代码语言:javascript复制import os
import openai
# 设置OPENAI密钥
# 如果您没有密钥,请在此处注册并生成一个 - https://platform.openai.com/signup
# 你可能需要使用信用卡,然后创建一个api密钥"
os.environ["OPENAI_API_KEY"] = "<YOUR-OPENAAI-API-KEY>"
# 设置搜索功能,可以使用Google和其他各种服务进行搜索
# 访问此链接并按照说明创建一个API密钥 - https://serpapi.com/
# 免费版本允许每月最多100次搜索,对于此演示来说已经足够了
os.environ["SERPAPI_API_KEY"] = "<YOUR-SERPAPI-API-KEY>"
prompt = '''
决定一个推文的情感是积极的、中性的还是消极的。
推文:"我喜欢新的蝙蝠侠电影!"
情感:
'''.
回应= openai.Completion.create(
model="text-davinci-003",
prompt=prompt,
temperature=0,
max_tokens=60,
top_p=1.0,
frequency_penalty=0.5,
presence_penalty=0.0
)
print(response["choices"][0]["text"])
########输出########
积极
接下来,我们来看一个更复杂的“思路链”方法,使用一个提示来引导模型根据所需的中间步骤计算出数学问题的答案。
代码语言:javascript复制提示 = '''
Q:Roger有5个网球。他买了2罐网球。
每罐有3个网球。他现在有多少个网球?
A:Roget一开始有5个球。2罐各有3个网球,一共
6个网球。5 6=11。答案是11。
Q:食堂有23个苹果。他们用了20个做午餐,
又买了6个,他们现在有多少个苹果?
'''```
响应= openai.Completion.create(
model="text-davinci-003",
prompt=prompt,
temperature=0,
max_tokens=60,
top_p=1.0,
frequency_penalty=0.5,
presence_penalty=0.0
)
print(response["choices"][0]["text"])
###模型输出###
A:食堂开始时有23个苹果。他们用了20个来做午饭,剩下3个苹果。他们又买了6个,现在有9个苹果。答案是9。
你可以看到同一个模型根据提示可以输出简单到非常复杂的答案。因此,设计提示的方式非常重要。还可以通过将之前与模型的交互与新的提示结合起来,逐步建立一个历史,以帮助模型在完成新的提示时保持上下文的连贯性 — 一种聊天机器人的风格。您还可以将文档或爬取的网站提供的上下文信息输入模型,并通过提问来建立一个问答机器人。您可以要求模型生成执行任务的代码,然后将代码输出作为额外的历史记录,以提出进一步的问题作为新的提示。
最近出现了许多这样的新方法,形成了一门新的学科——“提示工程”。在本博客中,我将介绍其中一些方法,并提供代码示例。本博客是为内部黑客马拉松参与者创建的介绍性文章。
我将介绍的方法有:
•少样本提示•思维链提示[2]•自一致提示[3]•ReAct - 推理与行动提示[4]•PAL - 程序辅助语言模型[5]•MRKL 系统 - 模块化推理、知识和语言[6]•自问自答搜索[7]
这绝不是一个详尽无遗的列表。我挑选了我发现有趣的方法。快速工程是一个快速发展的领域,几乎每天都会有许多新主意被提出。我将要谈论的所有方法都围绕着保持LLM模型冻结,假设它无法进行微调。唯一允许的方式是设计与外部工具集成的提示(例如Python代码执行器、调用其他系统的API、数据库查询等)作为中间步骤。对于代码演示,我将使用一个短时间内在LLM的快速工程开发中非常流行的库——LangChains。
Few Shot Prompting
让我们从讨论最基本的提示样式“Few Shot Prompting”开始。在这个提示下,可以分为三个子部分:
•前缀:给LLM的指令——“给出每个输入的反义词”•示例:一系列带有相应反义词的单词列表•后缀:用户输入,即我们希望模型输出反义词的单词 这被称为“几样式”提示,因为我们在提示的一部分中给模型提供了几个示例,并告诉模型使用这种模式来完成用户查询。模型不需要重新训练,它保持静态。我们只是以特定的方式构建提示,通过几个示例帮助模型产生所期望的结果。
代码语言:javascript复制from langchain import PromptTemplate, FewShotPromptTemplate
# 首先,创建几个样本的列表。
examples = [
{"word": "happy", "antonym": "sad"},
{"word": "tall", "antonym": "short"},
]"
# 接下来,我们指定模板来格式化我们提供的例子。
# 我们使用`PromptTemplate`类来实现这个功能。
example_formatter_template = """
单词: {word}
反义词: {antonym}n
"""
example_prompt = PromptTemplate(
input_variables=["word", "antonym"],
template=example_formatter_template,
)
# 最后,我们创建`FewShotPromptTemplate`对象。
few_shot_prompt = FewShotPromptTemplate(
# 我们要插入到提示中的示例。
examples=examples,
# 我们在插入示例到提示中时的格式。
example_prompt=example_prompt,
# 前缀是一些在提示中示例之前的文本。
# 通常,这包括一些指令。
prefix="给出每个输入的反义词",
# 后缀是一些在提示中示例之后的文本。
# 通常,这是用户输入的地方。
suffix="单词:{input}n反义词:",
# 输入变量是整个提示所期望的变量。
input_variables=["input"],
# 示例分隔符是我们将用来连接前缀、示例和后缀的字符串。
example_separator="nn",
)
# 现在我们可以使用`format`方法生成提示。
print(few_shot_prompt.format(input="big"))
### 输出将发送到LLM的提示
提供每个输入的反义词
单词:happy
反义词:sad
单词:tall
反义词:short
单词:big
反义词:
现在我们可以利用这个提示来预测我们遇到的新词的反义词。
代码语言:javascript复制from langchain.llms import OpenAI
from langchain.chains import LLMChain
# 实例化openai默认模型 - text-davinci-003
llm = OpenAI()
# 设置一个链条,以便能够运行具体模型和具体提示
chain = LLMChain(llm=llm, prompt=few_shot_prompt)
# 运行链条进行一个输入
chain.run("big")
### 输出
"小"
# 再次运行链条进行另一个输入
chain.run("sunny")
### 输出
"多云"
另一个有趣的few-shot示例是使用LLMs生成合成数据。以下是一个例子:
代码语言:javascript复制examples = [
{"word": "快乐", "antonym": "悲伤"},
{"word": "高", "antonym": "矮"},
{"word": "晴朗", "antonym": "多云"}
]
example_formatter_template = """
单词:{word}
反义词:{antonym}n
"""
example_prompt = PromptTemplate(
input_variables=["word", "antonym"],
template=example_formatter_template,
)
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
suffix="添加其他三个示例。",
input_variables=[],
)"
llm = OpenAI()
chain = LLMChain(llm=llm, prompt=few_shot_prompt)
print("### 模型输出 ###")
print(chain.predict())
######################################################
### 模型输出
词语: fast
反义词: slow
词语: generous
反义词: stingy
词语: strong
反义词: weak
虽然我使用了langchain库,但是您可以按照自己喜欢的方式构建提示,并直接调用OpenAI的python库来使用OpenAI的API。或者您可以使用langchain
库,它是一个很好用的库。用你自己的提示和示例尝试一下,并进行调整,直到你开始获得期望的结果。
思维链引导(CoT)
《思维激发链》(Chain of Thought Prompting)是谷歌团队于去年初提出的。这是一个非常简单的想法,但包含了很多强大的力量。这个想法为每个少样本示例添加了推理的中间步骤,以导致最终解决方案,然后要求模型解决另一个用户定义的问题。LLM将使用提供的示例模式,通过给出中间推理步骤和未解决问题的最终答案来完成提示。该论文表明,这种方法大大提高了答案的正确性,相较于幼稚的少样本方法。以下是一个示例:
代码语言:javascript复制模版 = 这个组中的奇数加起来是一个偶数:4, 8, 9, 15, 12, 2, 1.
A: 把所有奇数相加(9, 15, 1)得到25. 答案是False.
这个组中的奇数加起来是一个偶数:15, 32, 5, 13, 82, 7, 1.
A:提示 = PromptTemplate(
input_variables=[],
template=模版
)
llm = OpenAI()
chain = LLMChain(llm=llm, prompt=提示)
print("### 模型输出 ###")
print(chain.predict())
### 模型输出
加起来所有奇数(15,5,13,7,1)得到41. 答案是False.
接下来我们来看一下自一致提示[8]。它是CoT的一个扩展,其中解码(运行模型/生成LLM输出)使用相同的CoT提示进行多次。选择最一致/频繁的答案作为最终输出。理论上,模型产生的候选输出需要根据生成推理路径和答案的概率加权。然而,该论文展示了一种简单且几乎同样好的方法——即简单的多数投票。自一致利用了这样一个直觉,即复杂的推理问题通常能够产生多种不同的思考方式,从而得出唯一正确的答案。下面给出了一个示例来说明这种方法:
代码语言:javascript复制#自洽论文中的第17张表 - https://arxiv.org/pdf/2203.11171.pdf
模板 = """
问:林中有15棵树。林务工人员将在今天种植树木。完成后,将有21棵树。林务工人员今天种植了多少棵树?
答:我们从15棵树开始。后来有21棵树。差额一定是他们种植的树木数量。所以,他们一定种植了21 - 15 = 6棵树。答案是6。
### Model Output
Output 1
A: 她买了5个3美元的百吉饼。这意味着她花了5
Output 2
A: 她买了5个3美元的百吉饼。这意味着她花了5
Output 3
A: 她买了5个3美元的百吉饼。这意味着她花了5
输出1
当我6岁时,我的姐姐的年龄是我的一半。这意味着我的姐姐只有3岁。
现在我70岁,所以我的姐姐是70 - 3 = 67岁。答案是67。
输出2
当我6岁时,我的姐姐的年龄是我的一半。这意味着当我6岁时,我的姐姐是3岁。
这意味着我的姐姐现在是70 - 3 = 67岁。答案是67。
输出3
当我6岁时,我的姐姐的年龄是我的一半。这意味着她只有3岁。
现在我70岁,所以她的年龄是70/2 = 35岁。答案是35。
正如您所见,67出现了两次,而35只出现了一次。该模型给出了其到达答案的推理路径。使用多数投票,我们可以认为67是正确答案。然而,请注意当您再次运行此模型时,最频繁的答案可能是35或其他数字。对于LLM的天真使用,结合CoT和自推理,可以提高准确性,但仍然不能提供保证。有其他方法可以将LLMs与外部工具集成以解决需要事实核查、特定信息检索(例如企业内部会计系统)或某些特定数字计算的问题。 ReAct:在语言模型中协同推理和行动[9]是一种集成了特定任务操作的方法,这些操作可以是进行一些计算、搜索网络和/或查询数据库/数据存储。这样的操作的结果产生一个观察结果,然后导致下一轮的思考->行动->观察。模型经历多个这样的循环,最终产生答案。下面是论文中展示的方法:
Fig 1 https://arxiv.org/pdf/2210.03629.pdf
我们定义了一套在行动步骤中可以使用的工具。在我们的案例中,我们将使用在维基百科中进行搜索
和查找
的功能。有一个名为[wikipedia](https://wikipedia.readthedocs.io/en/latest/)
的Python库提供维基百科搜索的功能。该功能进一步由langchain
中的DocstoreExplorer
封装,它还允许对搜索返回的文档进行查找
。使用与langchain
一起使用ReAct的代码如下:
从 langchain 导入 OpenAI 和 Wikipedia
从 langchain.agents 导入 initialize_agent, Tool
从 langchain.agents.react.base 导入 DocstoreExplorer
docstore=DocstoreExplorer(Wikipedia())
tools = [
Tool(
name="Search",
func=docstore.search,
description="尝试搜索维基页面。"
),
Tool(
name="Lookup",
func=docstore.lookup,
description="查找页面中的术语,模仿 cmd-F 功能。"
)
]
llm = OpenAI(temperature=0, model_name="text-davinci-003")
react = initialize_agent(tools, llm, agent="react-docstore", verbose=True)
question = "What profession does Nicholas Ray and Elia Kazan have in common?"
react.run(question)
这里是模型的输出结果。
代码语言:javascript复制> 进入新的AgentExecutor链...
> 思考1: 我需要搜索尼古拉斯·雷和埃利亚·卡赞,找到他们的职业,然后
> 找到他们共同的职业。
> 动作1: 搜索[尼古拉斯·雷]
> 观察1: 尼古拉斯·雷(原名雷蒙德·尼古拉斯·基恩兹勒二世,1911年8月7日-1979年6月16日)是一位美国电影导演,编剧和演员,以1955年的电影《无法无天》而闻名。他因1947年至1963年期间创作的许多叙事片而受到赞赏,其中包括《夜晚一堂课》、《孤独的地方》、《约翰尼吉他》和《大于生活》,以及他在1970年代期间制作但未完成的实验作品《我们无法回家》,。
> 雷在CinemaScope的构图和色彩运用特别受到赞赏,并且对法国新浪潮影响重大,让让-吕克·戈达尔在对《苦涩的胜利》的评论中写道:“…有电影。而这个电影就是尼古拉斯·雷。”
> 思考2: 尼古拉斯·雷的职业是导演,编剧和演员。接下来我需要搜索埃利亚·卡赞并找到他的职业。
> 行动2:搜索[埃莉亚·卡赞]
> 观察2:埃莉亚·卡赞(; 英文名Elias Kazantzoglou(希腊语: Ηλίας Καζαντζόγλου); 1909年9月7日 – 2003年9月28日)是一位美国电影与戏剧导演、制片人、编剧和演员,被《纽约时报》描述为“百老汇和好莱坞历史上最受尊崇和有影响力的导演之一”。他出生于君士坦丁堡(现伊斯坦布尔),父母是卡帕多奇亚的希腊人,他的家人于1913年来到美国。在就读过威廉姆斯学院和耶鲁戏剧学院后,他从事专业演员工作八年,随后于1932年加入了Group Theatre,并在1947年共同创办了演员工作室。在罗伯特·刘易斯和谢丽尔·克劳福德的带领下,他的演员工作室推出了由李·斯特拉斯堡指导的“方法演技”。卡赞还参演了几部电影,包括《征服之城》(1940年)。他的电影关注他特别关心的个人或社会问题。卡赞写道:“如果对基本主题没有共鸣,我就不会有所行动。”他的第一部这种“问题”电影是与格里高利·派克合作的《绅士协定》(1947年),该片探讨了美国的反犹太主义。该片获得了八项奥斯卡奖提名,其中包括卡赞的首个最佳导演奖。之后是《聘请》(1949年),这是好莱坞主流电影中最早探讨对非裔美国人的种族偏见的电影之一。《欲望号街车》(1951年)是他导演的一部舞台剧改编电影,获得了十二项奥斯卡奖提名,赢得了其中四项,也是马龙·白兰度的突破角色。三年后,他再次导演了白兰度主演的《码头风云》,这是一部关于纽约港口工会腐败的电影。它获得了十二项奥斯卡奖提名,赢得了其中八项。1955年,他执导了约翰·斯坦贝克的《伊甸园之东》,这推介了詹姆斯·迪恩给电影观众。
> 卡赞职业生涯的一个转折点发生在1952年他作为证人在美国众议院非美活动调查委员会面前作证时,当时正值好莱坞黑名单时期,这引起了他许多朋友和同事的强烈负面反应。他的证词帮助结束了前同事莫里斯·卡尔诺夫斯基和阿特·史密斯的职业生涯,以及剧作家克里福德·奥德茨的作品。卡赞和奥德茨曾经达成协议,在委员会面前互相点名。卡赞后来为自己的行为辩护称,他选择了“两个都是痛苦和错误的两个较容忍的选择。”近半个世纪后,他的反共证词仍然引起争议。当卡赞于1999年获得荣誉奥斯卡奖时,数十位演员选择不鼓掌,250名抗议者在现场示威。卡赞以他引人深思、关注问题的电影主题影响了20世纪50年代和60年代的电影。导演斯坦利·库布里克称他“毫无疑问是我们美国最优秀的导演,[能够]与他使用的演员一起创造奇迹。”电影作家伊恩·弗里尔总结说,即使“他的业绩受到政治争议的污点,好莱坞和所有演员都对他感激不尽。”2010年,马丁·斯科塞斯共同导演了纪录片《给埃莉亚的一封信》,作为对卡赞的个人致敬。
> 思考3:埃莉亚·卡赞的职业是导演、制片人、编剧和演员。尼古拉斯·雷和埃莉亚·卡赞共同拥有的职业是导演、编剧和演员。
> 动作3:完美[导演,编剧,演员]
> 完成链。
> “导演,编剧,演员”
你还可以在原始存储库中查看附带论文此处[10]的代码。这可以使用openai
库而不使用langchain
来运行。接下来,我们来看一下PAL(Program-aided Language Models,程序辅助语言模型)。虽然LLM(语言模型学习)在通过CoT方法逐步分解数学或逻辑问题方面很擅长,但即使问题被正确分解,LLM经常会出现数学和逻辑错误。在PAL中,中间推理步骤被生成为“程序”,然后被传递给“解决步骤”。解决步骤会使用像Python解释器这样的运行时来运行这些中间程序。让我们使用基于Python的解释器与LLM一起解决一个数学单词问题。
从 langchain.chains 中导入 PALChain
从 langchain 中导入 OpenAI
llm = OpenAI(model_name='code-davinci-002', temperature=0, max_tokens=512)
pal_chain = PALChain.from_math_prompt(llm, verbose=True)
question = "Jan的宠物数量是Marcia的三倍。Marcia的宠物数量比Cindy多两只。如果Cindy有四只宠物,三个人总共有多少只宠物?"
pal_chain.run(question)
基于PAL的LLM模型生成一个解决问题的程序,然后将其转移到Python解释器中来解决问题。
代码语言:javascript复制> 进入新的PALChain链...
> 定义解决方案():
> """Jan有Marcia的宠物数量的三倍。Marcia比Cindy多两只宠物。如果Cindy有四只宠物,这三个人总共有多少只宠物?"""
> cindy_pets = 4
> marcia_pets = cindy_pets 2
> jan_pets = marcia_pets * 3
> total_pets = cindy_pets marcia_pets jan_pets
> result = total_pets
> 返回 result
> 完成链.
> '28'
背后的原理很简单。在向LLM提示时,我们提供了一些带有示例代码的问题。LLM使用few-shot方法完成输出,然后将该输出交给Python解释器运行。向LLM提供的提示大致如下:
代码语言:javascript复制提示
Q: Olivia有23美元。她以每个3美元的价格买了五个百吉饼。她还剩下多少钱?
# Python解决方案:
def solution():
"""奥利维亚有23美元。她买了5个面包圈,每个面包圈花费3美元。她还剩下多少钱?
"""
money_initial = 23
bagels = 5
bagel_cost = 3
money_spent = bagels * bagel_cost
money_left = money_initial - money_spent
result = money_left
return result
...更多类似的例子....
Q:果园里有15棵树。果园工人将要在今天种植树木。他们完成后,将会有21棵树。
果园工人今天种了多少棵树?
# Python代码解决方案:
def solution():
"""树林中有15棵树。今天树林工人将在树林里种植树木。他们完成后,树林里将有21棵树。
树林工人今天种植了多少棵树?"""
初始树木数 = 15
种植后树木数 = 21
追加的树木数 = 种植后树木数 - 初始树木数
结果 = 追加的树木数
返回 结果
Q: 珍比玛西娅的宠物数量多三倍。玛西娅比辛迪多两只宠物。如果辛迪有四只宠物,这三个人一共有多少只宠物?
# Python解答:
接下来是MRKL Systems[11],其中MRKL代表模块化推理、知识和语言。它在将LLM与外部工具结合方面与ReAct非常相似。ReAct在MRKL论文之后几个月推出,我现在会选择ReAct方法。让我们从langchain
库文档中看一个这样的例子。按照ReAct的风格,模型将推理出一个问题使用以下三种工具之一进行操作:a) 通过SerpApi[12]查询Google Search;b) 查询数据库以获取一些信息;c) 通过生成的Python代码从计算的自然语言描述中实现的Calculator,并通过Python REPL运行生成的代码。让我们看一个案例,我们要求我们的系统找到一个著名演员的女朋友,找出她的当前年龄,最后用这个年龄进行一些计算:
“谁是莱昂纳多·迪卡普里奥的女朋友?她的当前年龄提升到0.43次方是多少?”
首先,我们将设置MRKL系统如下:
from langchain import LLMMathChain, OpenAI, SerpAPIWrapper, SQLDatabase, SQLDatabaseChain
from langchain.agents import initialize_agent, Tool
llm = OpenAI(温度=0)
search = SerpAPIWrapper()
llm_math_chain = LLMMathChain(llm = llm,verbose = True)
db = SQLDatabase.from_uri("sqlite: ///Chinook.db")
db_chain = SQLDatabaseChain(llm = llm,database = db,verbose = True)
工具= [
Tool(
name = "搜索",
func = search.run,
description="在需要回答有关当前事件的问题时很有用。你应该提出有针对性的问题"
),
Tool(
name="计算器",
func=llm_math_chain.run,
description="在需要回答数学问题时很有用"
),
Tool(
name="FooBar DB",
func=db_chain.run,
description="在需要回答FooBar问题时很有用。输入应为包含完整上下文的问题"
)
]
mrkl = initialize_agent(tools,llm,agent="zero-shot-react-description",verbose=True)
现在我们运行这个系统,提出以下问题:
'mrkl.run("谁是莱昂纳多·迪卡普里奥的女友?她目前的年龄提高到0.43次方是多少?")'
mrkl的输出如下所示。您可以看到系统回答这个查询所经历的步骤:
代码语言:javascript复制> 进入新的AgentExecutor链...
> 我需要找出莱昂纳多·迪卡普里奥的女友,并计算她的年龄的0.43次方。
> 动作:搜索
> 动作输入:“莱昂纳多·迪卡普里奥的女友是谁?”
> 观察:卡米拉·莫罗内
> 思考:我需要计算她的年龄的0.43次方
> 动作:计算器
> 动作输入:22^0.43
> 进入新的LLMMathChain链...
> 22^0.43
```python
import math
print(math.pow(22, 0.43))
```
答案:3.777824273683966
> 链结束。
观察:答案:3.777824273683966
```想法:我现在知道最后的答案
最终答案:卡米拉·莫罗内是莱昂纳多·迪卡普里奥的女朋友,她目前的年龄的0.43次方是3.777824273683966。
> 完成链。
> "卡米拉·莫罗内是莱昂纳多·迪卡普里奥的女朋友,她目前的年龄的0.43次方是3.777824273683966。
现在我们知道卡米拉·莫罗内可能不再是莱昂纳多·迪卡普里奥的女朋友了。这表明即使在与外部搜索整合后,模型仍有可能产生错误的输出。当你设计这样的系统时,你的设计必须考虑到没有一个以机器学习为驱动的系统能达到100%,并且你的设计必须为使用这样一个系统的用户提供优雅的回退和某种期望设置。让我们尝试另一个例子,这次从一个代表数字媒体店的数据库chinook[13]中找到一些信息,包括艺术家、专辑、媒体音轨、发票和顾客的表格。我们想要问的问题是:
最近发布了一张名为‘The Storm Before the Calm’的专辑的艺术家的全名是什么,他们是否在FooBar数据库中?如果是的话,他们的专辑有哪些在FooBar数据库中,这些专辑的总时长是多少?” 注意:我们将我们的数据库命名为FooBar,以确保它具有唯一的名称。您可以在上面定义工具列表的变量'tools'中将其设置为任何您喜欢的其他名称。
让我们通过MRKL系统运行此提示,并查看系统经过的思考-行动-观察循环以生成答案。
代码语言:javascript复制mrkl.run("""
最近发布了一张名为'The Storm Before the Calm'的专辑的艺术家的全名是什么,并且他们是否在FooBar数据库中?
如果是,他们的哪些专辑在FooBar数据库中,并且所有这些专辑的总时长是多少?""")
### 模型输出
> 进入新的AgentExecutor链...
> 我需要找出艺术家的全名,查看他们是否在FooBar数据库中,以及他们在数据库中专辑的总时长。
> 操作:搜索
> 操作输入:"The Storm Before the Calm" 艺术家
> 观察:The Storm Before the Calm(全部小写字母风格)是加拿大-美国创作歌手Alanis的第十张(也是第八张国际发行的)录音室专辑...
> 思考:我现在需要检查Alanis Morissette是否在FooBar数据库中。
> 操作:FooBar数据库
> 操作输入:Alanis Morissette是否在FooBar数据库中?
> 进入新的 SQLDatabaseChain 链 ...
> Alanis Morissette 是否在 FooBar 数据库中?
> SQLQuery: SELECT Name FROM Artist WHERE Name LIKE '%Alanis Morissette%';
> SQLResult: [('Alanis Morissette',)]
> 回答: 是的,Alanis Morissette 在 FooBar 数据库中。
> 链结束。
> 观察:是的,艾伦尼斯·莫里塞特(Alanis Morissette)在FooBar数据库中。
> 思考:现在我需要找出她的专辑在FooBar数据库中有哪些,并且这些专辑的总时长是多少。
> 行动:FooBar数据库
> 行动输入:艾伦尼斯·莫里塞特的专辑在FooBar数据库中有哪些,并且所有这些专辑的总时长是多少?
> 进入新的SQLDatabaseChain链……
> FooBar数据库中的Alanis Morissette专辑有哪些,并且所有这些专辑的总时长是多少?
> SQLQuery:SELECT Album.Title, SUM(Track.Milliseconds) AS TotalDuration FROM Album INNER JOIN Track ON Album.AlbumId = Track.AlbumId WHERE Album.ArtistId = (SELECT ArtistId FROM Artist WHERE Name = 'Alanis Morissette') GROUP BY Album.Title;
> SQLResult:[('Jagged Little Pill', 3450925)]
> 答案:FooBar数据库中的Alanis Morissette专辑是'Jagged Little Pill',所有这些专辑的总时长是3,450,925毫秒。
> 链结束。
> 观察:FooBar数据库中的Alanis Morissette的专辑是《Jagged Little Pill》,所有这些专辑的总时长为3,450,925毫秒。
> 思考:我现在知道最终答案了。
> 最终答案:Alanis Morissette是最近发布了一张名为《The Storm Before the Calm》的专辑的艺术家,她在FooBar数据库中的专辑是《Jagged Little Pill》,总时长为3,450,925毫秒。
> 完成链。
> "Alanis Morissette是最近发布了专辑名为'The Storm Before the Calm'的艺术家,她在FooBar数据库中的专辑是'Jagged Little Pill',总时长为3,450,925毫秒。"
正如您所见,通过整合外部搜索功能、数据库访问和其他工具,您可以使用LLMs作为自然语言界面与系统进行交互,构建一个非常强大的应用程序。最后我们来看一下《自问问题搜索》(Self-Ask-With-Search[14]),这篇论文涉及可组合性——让语言模型执行组合推理任务,其中整体解决方案取决于正确地组合子问题的答案。下面是该方法与 CoT 的比较:
图3 — https://arxiv.org/pdf/2210.03350.pdf 如您所见,Self-Ask通过将原始问题拆分为子问题,分别解决它们,然后将所有中间答案组合起来获得最终答案。下面是使用langchain
的同一代码示例。我们将要求我们的模型回答:“当超导性被发现时,美国的总统是谁?”
from langchain import OpenAI, SerpAPIWrapper
from langchain.agents import initialize_agent, Tool"
llm = OpenAI(temperature=0)
search = SerpAPIWrapper()
tools = [
Tool(
name="Intermediate Answer",
func=search.run,
description="用于搜索"
)
]
self_ask_with_search = initialize_agent(tools, llm, agent="self-ask-with-search", verbose=True)
self_ask_with_search.run("当超导现象被发现时,美国的总统是谁?")
模型经历的中间步骤和网络搜索来达到最终答案非常有趣。它展示了模型如何将问题分解成较小的模块化步骤,并使用其他工具获取答案,然后将所有这些答案组合起来得出最终答案。
代码语言:javascript复制> 进入新的AgentExecutor链...
> 是的。
> 进一步追问:超导现象是在什么时候发现的?
> 中间答案:1911年。
> 进一步追问:1911年美国总统是谁?
> 中间答案:威廉·霍华德·塔夫脱被选为第27任美国总统(1909-1913年),后来成为第十任美国首席大法官(1921-1930年),是唯一一位曾在这两个职位上任职的人。
> 所以最终答案是:威廉·霍华德·塔夫脱
> 链结束。
> '威廉·霍华德·塔夫脱'
结论
像GPT3、ChatGPT等大型语言模型一直备受关注。由于媒体的叙述,人们认为这些模型无所不知、非常聪明,可以解决各种问题。然而,事实并非如此。这些模型在非常大规模的网络文本数据上进行训练,使它们能够根据迄今为止所见的字符串或单词来预测下一个词。这些模型没有进行数学或逻辑计算的能力,也不一定能够准确无误地陈述事实。Prompt Engineering通过结合详细的提示、各种外部资源和工具来解决这个缺点。根据《Yann LeCun》的话来说,正如这条推特[15]所述:“是的,对即时工程的需求是缺乏理解的标志。不,仅仅扩展规模并不能解决这个问题。”
预计LLMs将变得越来越能干,可能通过利用一些新方法,并且可能超越仅仅成为“语言模型”。这反过来可能会减少对Prompt Engineering的需求。然而,在这种情况发生之前,Prompt Engineering将会一直存在,并有可能出现许多新的方法。Prompt Engineering是一项高薪且需求量大的技能。文本:「此博客中的代码可在此存储库中找到 - https://github.com/nsanghi/Prompt-Engineering-Intro」
声明
本文由山行翻译整理自:https://medium.com/cloudcraftz/an-introduction-to-prompt-engineering-for-openai-gpt-llms-f109ca4f1739,主要目的是对提示词工程进行一些系统化的整理和科普,感兴趣的请点赞、收藏、关注。
References
[1]
此存储库: https://github.com/nsanghi/Prompt-Engineering-Intro
[2]
思维链提示: https://arxiv.org/pdf/2201.11903.pdf
[3]
自一致提示: https://arxiv.org/pdf/2203.11171.pdf
[4]
ReAct - 推理与行动提示: https://arxiv.org/pdf/2210.03629.pdf
[5]
PAL - 程序辅助语言模型: https://arxiv.org/pdf/2211.10435.pdf
[6]
MRKL 系统 - 模块化推理、知识和语言: https://arxiv.org/pdf/2205.00445.pdf
[7]
自问自答搜索: https://arxiv.org/pdf/2210.03350.pdf
[8]
自一致提示: https://arxiv.org/abs/2203.11171
[9]
ReAct:在语言模型中协同推理和行动: https://arxiv.org/abs/2210.03629
[10]
此处: https://github.com/ysymyth/ReAct/blob/master/hotpotqa.ipynb
[11]
MRKL Systems: https://arxiv.org/pdf/2205.00445.pdf
[12]
SerpApi: https://serpapi.com/
[13]
chinook: https://database.guide/2-sample-databases-sqlite/
[14]
Self-Ask-With-Search: https://arxiv.org/abs/2210.03350
[15]
这条推特: https://twitter.com/ylecun/status/1630611290329686016