Prompt工程的7个技巧
技巧1:尽可能地详细(越详细越好)
LLMs的一个显著特征是它们是基于非常大规模的文本语料库训练的,这使得它们具备了丰富的世界知识和执行各种各样任务的能力。不过如果没有提供适当长度的上下文,就有可能会影响生成结果的质量。以下是两条为父亲编写生日祝福的Prompt:
普通写法:
Write me a birthday message for my dad.
技巧性写法:
Write me a birthday message for my dad no longer than 200 \
characters. This is a big birthday because he is turning 50. To celebrate, \
I booked us a boys' trip to Cancun. Be sure to include some cheeky humor, he \
loves that.
技巧2:给出示例
给LLMs提供想要生成结果的示例,就能提高其生成结果的质量。用专业技术术语来概括就是“小样本学习”。假设要为Towards Data Science的一篇文章起一个副标题,以下是两种Prompt的对比:
普通写法:
Given the title of a Towards Data Science blog article, write a subtitle for it.
Title: Prompt Engineering—How to trick AI into solving your problems
Subtitle:
技巧性写法:
Given the title of a Towards Data Science blog article, write a subtitle for it.
Title: A Practical Introduction to LLMs
Subtitle: 3 levels of using LLMs in practice
Title: Cracking Open the OpenAI (Python) API
Subtitle: A complete beginner-friendly introduction with example code
Title: Prompt Engineering-How to trick AI into solving your problems
Subtitle:
技巧3:使用结构化文本
保证Prompt遵循有组织的结构不仅使它们更易于阅读和编写,还有助于模型生成更完善的结果。如“技巧2”的示例中明确标记了每个示例的标题和副标题。
此外还有很多其他方法来给Prompt增加结构。如使用全大写字母进行强调,使用分隔符(如```)来突出一段文本,使用标记语言(如Markdown或HTML)来格式化文本,使用JSON来组织信息等。
普通写法:
Write me a recipe for chocolate chip cookies.
技巧性写法:
Create a well-organized recipe for chocolate chip cookies. Use the following \
formatting elements:
**Title**: Classic Chocolate Chip Cookies
**Ingredients**: List the ingredients with precise measurements and formatting.
**Instructions**: Provide step-by-step instructions in numbered format, detailing the baking process.
**Tips**: Include a separate section with helpful baking tips and possible variations.
技巧4:思维链
在Prompt中加入“让我们逐步思考”的文本引导LLMs进行“逐步思考”,有助于将复杂的问题分解为可控的各个子问题,给LLMs更多“思考的时间”。这种方式在任何可拆解的任务中都适用。比如基于最新的Medium博客创建一个LinkedIn帖子:
普通写法:
Write me a LinkedIn post based on the following Medium blog.
Medium blog: {Medium blog text}
技巧性写法:
Write me a LinkedIn post based on the step-by-step process and Medium blog \
given below.
Step 1: Come up with a one line hook relevant to the blog.
Step 2: Extract 3 key points from the article
Step 3: Compress each point to less than 50 characters.
Step 4: Combine the hook, compressed key points from Step 3, and a call to action \
to generate the final output.
Medium blog: {Medium blog text}
技巧5:聊天机器人角色
请求LLMs扮演特定的角色如“你是XX专家等”,尽管你可能并不知道如何能最好地向LLMs描述你的问题,但你可能知道谁会帮助你解决这个问题。以下是示例:
普通写法:
Make me a travel itinerary for a weekend in New York City.
技巧性写法:
Act as an NYC native and cabbie who knows everything about the city. \
Please make me a travel itinerary for a weekend in New York City based on \
your experience. Don't forget to include your charming NY accent in your \
response.
技巧6:反向方法
当我们不知道LLMs知道什么或它如何思考时,很难知道具体该如何输入Prompt。这时就可以用到“反向方法”:命令LLMs向你提问,直到它充分理解你要解决的问题(即上下文)。
普通写法:
What is an idea for an LLM-based application?
技巧性写法:
I want you to ask me questions to help me come up with an LLM-based \
application idea. Ask me one question at a time to keep things conversational.
技巧7:反思、复盘和完善
通过不断反思、复盘以往生成的结果来完善和改进后续生成的结果。常见的用法包括让模型通过询问它是否“完成了任务”或要求它“解释结果背后的推理和假设”来严格评估自己的任务。
技巧性写法:
Review your previous response, pinpoint areas for enhancement, and offer an \
improved version. Then explain your reasoning for how you improved the re
示例代码:使用LangChain开发自动打分器
下面这个就是文章开头用于自动打分的Prompt,很明显用到了“技巧6:聊天机器人角色”、“技巧3:使用结构化文本”和“技巧1:尽可能详细”。
You are a high school history teacher grading homework assignments. \
Based on the homework question indicated by “Q:” and the correct answer \
indicated by “A:”, your task is to determine whether the student's answer is \
correct.
Grading is binary; therefore, student answers can be correct or wrong.
Simple misspellings are okay.
Q: {question}
A: {correct_answer}
Student Answer: {student_answer}
把此Prompt复制并粘贴到ChatGPT中,并替换掉“question”、“correct_answer”和“student_answer”字段就可以正常使用了。
这个Prompt可以看作是一个函数,在给出问题、正确版本答案和学生答案后,它就会自动生成学生的成绩以及集成到软件系统中实现自动打分。但这不是一种可扩展的方式。
在实际应用中更希望能将此Prompt集成到软件系统中,以便可以构建一个用户可以直接使用的应用程序。通过LangChain来实现这一点。
LangChain
LangChain是一个Python库,通过为程序化使用LLMs提供各种便捷的抽象化能力来帮助简化开发基于大语言模型的应用程序。
实现这一功能的关键类称为“Chain”,它可以抽象化生成提示、将其发送到LLMs中并解析输出的过程,以便能够轻松调用它并将其集成到更大的脚本中。
导入
首先,导入Chain模块。
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.schema import BaseOutputParser
在这里使用的是gpt-3.5-turbo模型,将OpenAI API密钥存储在单独的Python文件(sk.py)中,并使用以下代码行来导入它。
from sk import my_sk #importing secret key from another python file
Chain
要定义Chain,需要两个核心元素:LLMs和Prompt。首先创建一个LLMs对象。
# define LLM object
chat_model = ChatOpenAI(openai_api_key=my_sk, temperature=0)
LangChain具有专门用于OpenAI(及其他)聊天模型的类。输入API密钥,并将Temperature设置为0。这里默认模型是gpt-3.5-turbo,可以通过“model_name”输入参数来替代使用gpt-4。也可以通过设置其他输入参数来进一步自定义聊天模型。
接下来定义Prompt模板。此对象支持通过输入字符串动态生成Prompt,并且这些字符串会自动更新基础的模板。
# define prompt template
prompt_template_text = """You are a high school history teacher grading homework assignments. \
Based on the homework question indicated by “**Q:**” and the correct answer indicated by “**A:**”, your task is to determine whether the student's answer is correct. \
Grading is binary; therefore, student answers can be correct or wrong. \
Simple misspellings are okay.
**Q:** {question}
**A:** {correct_answer}
**Student's Answer:** {student_answer}
"""
prompt = PromptTemplate(input_variables=["question", "correct_answer", "student_answer"], \
template = prompt_template_text)
有了LLMs和Prompt,现在就可以定义Chain了。
# define chain
chain = LLMChain(llm=chat_model, prompt=prompt)
接下来将输入传递给Chain并在一行代码中获得成绩。
# define inputs
question = "Who was the 35th president of the United States of America?"
correct_answer = "John F. Kennedy"
student_answer = "FDR"
# run chain
chain.run({'question':question, 'correct_answer':correct_answer, \
'student_answer':student_answer})
# output: Student's Answer is wrong.
尽管这条Chain可以有效地执行评分任务,但其输出可能不适用于自动化流程。比如在上面的代码块中,LLMs正确地说出了学生答案“FDR”是错误的,但如果LLMs能够按照在下游处理环节中也能够正常使用的标准格式进行输出会更好。
输出解析器
下面是可以集成到Chain中的函数,用于将LLMs的输出转换为标准格式:将LLMs的响应转换为布尔值(即True或False)输出。
# define output parser
class GradeOutputParser(BaseOutputParser):
"""Determine whether grade was correct or wrong"""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return "wrong" not in text.lower()
在这里创建一个输出解析器,检查LLM的输出中是否包含单词“wrong”。如果没有,返回True,表示学生的答案是正确的。否则返回False,表示学生的答案是错误的。然后将这个输出解析器整合到Chain中,就可以在运行Chain时无缝解析文本。
# update chain
chain = LLMChain(
llm=chat_model,
prompt=prompt,
output_parser=GradeOutputParser()
)
最后,对所有学生的答案运行Chain并Print输出。
# run chain in for loop
student_answer_list = ["John F. Kennedy", "JFK", "FDR", "John F. Kenedy", \
"John Kennedy", "Jack Kennedy", "Jacquelin Kennedy", "Robert F. Kenedy"]
for student_answer in student_answer_list:
print(student_answer + " - " + str(chain.run({'question':question, 'correct_answer':correct_answer, 'student_answer':student_answer})))
print('\n')
# Output:
# John F. Kennedy - True
# JFK - True
# FDR - False
# John F. Kenedy - True
# John Kennedy - True
# Jack Kennedy - True
# Jacqueline Kennedy - False
# Robert F. Kenedy - False
限制
Prompt工程不仅仅是请求ChatGPT帮助写电子邮件或学习量子计算。它是一种能够改变开发人员构建应用程序方式的新编程范式。不过在实际应用过程中也存在一些限制。
首先,最佳提示策略取决于特定的LLMs。例如,提示GPT-3“逐步思考”在简单的数学推理任务中取得了显著的性能提升。但对于最新版本的ChatGPT,相同的策略似乎对它没有影响(它已经可以逐步思考)。
Prompt工程的另一个限制是它需要大规模的通用语言模型能力,比如ChatGPT,这需要大量的计算资源和财务成本。这对较窄的应用场景来说或许是过度设计。
不过即使如此,相比于传统编程模式,Prompt工程已然能够帮助解决很多问题。况且,这两个限制也可以通过微调预训练语言模型来解决。