提示工程(1):原则和示例

ChatGPT提示工程(Prompt Engineering)

最近正在学习吴恩达的AI课程。结合open AI chatGPT能力,理解和记录相关的知识。本文主要讲述提示工程(prompt engineering),及如何利用和验证大模型的总结、摘要、转换、扩展等能力。最后,会写一个为客户提供点餐服务的对方机器人。整体系列文章会包括以下内容:
1. 原则和示例
– 如何写明确具体的指令
– 给模型时间“思考”
2. 提示迭代开发(Iterative Prompt Development)
3. LLM主要能力示例
– 总结(Summarizing)
– 摘要(Inferring)
– 转换(Transforming)
– 扩展(Expanding)
4. 创新聊天机器人(chatbot)

第一部分:提示工程(Prompt Engineering)的原则和示例

1. LLM的分类

我们通常把大语言模型(LLM)分为2类,一类是基础的LLM;一类是指令调优过的LLM(见下图)。
– 基础的LLM基于文本训练数据,预测下个单词;
– 指令调优化LLM会遵循指令,提供更有价值、准确的预测。其实也是指令高估的目的。
调优的方法是基于人类反馈的强化学习(RLHF,Reinforcement Learning withHuman Feedback)。我们这一系列讲的提示工程(prompt engineering)m会讲解调优的最佳实践。

设想LLM是一位刚刚入职的应届毕业生,需要他去处理一些事务。我们需要十分清晰和具体的指令,给他们一些以前任务完成的样板,甚至一些任务的背景资料等等,他们才能较好的完成,给出我们期待的结果。接下来,我们来讲述如何编写清晰和具体的指令。

2. 提示的原则一:清晰和具体的指令

方法1: 利用分隔符

  • 双引号 “””
  • 单引号 ”’
  • 扛 – – –
  • 尖括号
  • XML 标签

我们来试下分隔符的用法。

import openai
openai.api_key="用你的api key,以ski-开头"

get_completion函数,用于辅助执行LLM交互。
其中输入:提示、采用的gpt模型(默认为gpt-3.5-turbo);
其中输出:gpt返回的文字。

def get_completion (prompt, model="gpt-3.5-turbo"):  # 使用 gpt 3.5 turbo模型
    messages = [{"role": "user", "content": prompt}] 
    response = openai.ChatCompletion.create(  # 使用openai的ChatCompletion函数
        model=model, 
        messages=messages, 
        temperature=0 # 预测的随机程序
    ) 
    return response.choices[0].message["content"]

下例我们合适分隔符:

# 用'''做为分隔符,清晰告知 LLM 所引用的文字

text = f"""
You should express what you want a model to do by \
providing instructions that are as clear and \
specific as you can possibly make them. \
This will guide the model towards the desired output, \
and reduce the chances of receiving irrelevant \
or incorrect responses. Don't confuse writing a \
clear prompt with writing a short prompt. \
In many cases, longer prompts provide more clarity \
and context for the model, which can lead to \
more detailed and relevant outputs.
"""

prompt = f"""
Summarize the text delimited by triple backticks \
into a single sentence.
'''{text}'''
"""

response = get_completion(prompt)
print(response)
To guide a model towards the desired output and reduce irrelevant or incorrect responses, it is important to provide clear and specific instructions, which may require longer prompts for more clarity and context.

这个例子也许看不出分隔符有什么明显的作用。
试想一下,当你的提示prompt与所有引用的文字刚好有冲突的要求(例如:prompt要求对某个主题做总结,而所引用文字提到对某个主题要展开),这时LLM理解与我们预期可能就不一样的。分隔符在这类场景会特别有用。

方法2: 结构化输出

如:HTML、JSON

prompt = f"""
Generate a list of three made-up book titles along \ 
with their authors and genres.
Provide them in JSON format with the following keys: 
book_id, title, author, genre.
"""

response = get_completion(prompt)
print(response)
{
  "books": [
    {
      "book_id": 1,
      "title": "The Enigma of Elysium",
      "author": "Evelyn Sinclair",
      "genre": "Mystery"
    },
    {
      "book_id": 2,
      "title": "Whispers in the Wind",
      "author": "Nathaniel Blackwood",
      "genre": "Fantasy"
    },
    {
      "book_id": 3,
      "title": "Echoes of the Past",
      "author": "Amelia Rivers",
      "genre": "Romance"
    }
  ]
}

方法3: 检查执行某任务的条件或假设是否满足

我们让LLM将制作一杯茶的步骤,从一段文字里整理出来。请见下面示例:

text_1 = f"""
Making a cup of tea is easy! First, you need to get some \
water boiling. While that's happening, \
grab a cup and put a tea bag in it. Once the water is \
hot enough, just pour it over the tea bag. \
Let it sit for a bit so the tea can steep. After a \
few minutes, take out the tea bag. If you \
like, you can add some sugar or milk to taste. \
And that's it! You've got yourself a delicious \
cup of tea to enjoy.
"""

prompt =f"""
You will be provided with text delimited by triple quotes.\
If it contains a sequence of instructions, \
re-write those instructions in the following format:
Step 1 - ...x
Step 2 - ...
...
Step N - ...

If the text does not contain a sequence of instructions, \
then simply write \"No steps provided.\"

\"\"\"\{text_1}\"\"\"
"""

response = get_completion(prompt)
print("Completion for Text 1:")
print(response)
Completion for Text 1:
Step 1 - Get some water boiling.
Step 2 - Grab a cup and put a tea bag in it.
Step 3 - Pour the hot water over the tea bag.
Step 4 - Let the tea steep for a few minutes.
Step 5 - Take out the tea bag.
Step 6 - Add sugar or milk to taste.
Step 7 - Enjoy your cup of tea.

从上面的例子,chatGPT已经把步骤整理出来了。
我们再用一个例子,里面不包括制作的步骤,看看我们会得到什么?请见下面例子。

text_2 = f"""
The sun is shining brightly today, and the birds are \ 
singing. It's a beautiful day to go for a \ 
walk in the park. The flowers are blooming, and the \
trees are swaying gently in the breeze. People \ 
are out and about, enjoying the lovely weather. \ 
Some are having picnics, while others are playing \ 
games or simply relaxing on the grass. It's a \
perfect day to spend time outdoors and appreciate the \
beauty of nature.
"""

prompt =f"""
You will be provided with text delimited by triple quotes.\
If it contains a sequence of instructions, \
re-write those instructions in the following format:
Step 1 - ...x
Step 2 - ...
...
Step N - ...

If the text does not contain a sequence of instructions, \
then simply write \"No steps provided.\"

\"\"\"\{text_2}\"\"\"
"""

response = get_completion(prompt)
print("Completion for Text 2:")
print(response)
Completion for Text 2:
No steps provided.

方法4: Few-shot prompting

在模型执行任务之前,先给一些任务完成的示例

下面的例子先给了模型一串老人与小孩的对话,让模型以这种方式和风格继续这种对话。

prompt = f"""
Your task is to answer in a consistent style.

<child>: Teach me about patience.
«grandparent›: The river that carves the deepest \ 
valley flows from a modest spring: the \
grandest symphony originates from a single note; \
the most intricate tapestry begins with a solitary thread.

<child>: Teach me about resilience.
"""

response = get_completion(prompt)
print(response)
«grandparent›: Resilience is the unwavering strength that emerges from facing adversity. It is the ability to bounce back, to rise above challenges, and to persevere even when the odds seem insurmountable. Like a mighty oak tree that withstands the fiercest storms, resilience is the foundation of inner fortitude and growth.

3. 提示的原则二:给模型时间思考

方法1: 明确完成任务的步骤


step 1: ...
step 2: ...
...
step N: ...

以下的例子,明确了完成任务的步骤。

text = f"""
In a charming village, siblings Jack and Jill set out on \
a quest to fetch water from a hilltop \
well. As they climbed, singing joyfully, misfortune \
struck-Jack tripped on a stone and tumbled \
down the hill, with Jill following suit. \
Though slightly battered, the pair returned home to \
comforting embraces. Despite the mishap, \
their adventurous spirits remained undimmed, and they \ 
continued exploring with delight.
"""

# example 1
prompt_1 = f"""
Perform the following actions:
1 - Summarize the following text delimited by triple \
backticks with 1 sentence.
2 - Translate the summary into French.
3 - List each name in the French summary.
4 - Output a JSON object that contains the following \
keys: french_summary, num_names.

Separate your answers with line breaks.

Text:
'''{text}'''
"""

response = get_completion(prompt_1)
print("Completion for promt 1:")
print(response)
Completion for promt 1:
1 - Jack and Jill, siblings, go on a quest to fetch water from a well on a hill, but they both fall down the hill after Jack trips on a stone, yet they return home and continue exploring with joy.

2 - Jack et Jill, frère et sœur, partent en quête d'eau d'un puits situé au sommet d'une colline, mais ils tombent tous les deux après que Jack trébuche sur une pierre, cependant ils rentrent chez eux et continuent à explorer avec joie.

3 - Jack, Jill.

4 - {
  "french_summary": "Jack et Jill, frère et sœur, partent en quête d'eau d'un puits situé au sommet d'une colline, mais ils tombent tous les deux après que Jack trébuche sur une pierre, cependant ils rentrent chez eux et continuent à explorer avec joie.",
  "num_names": 2
}
# example 2, asking for output in a specified format
prompt_2 = f"""
Your task is to perform the following actions:
1 - Summarize the following text delimited by <> with 1 sentence.
2 - Translate the summary into French.
3 - List each name in the French summary.
4 - Output a json object that contains the 
    following keys: french_summary, num_names.

Use the following format:
Text: <text to summarize>
Summary: <summary>
Translation: <summary translation>
Names: <list of names in Italian summary>
Output JSON: <json with summary and num_names>
Text to summarize: <{text}>
"""

response=get_completion(prompt_2)
print("\nCompletion for prompt 2:")
print(response)
Completion for prompt 2:
Summary: Jack and Jill, siblings from a charming village, go on a quest to fetch water from a hilltop well but encounter misfortune along the way. 
Translation: Jack et Jill, frère et sœur d'un charmant village, partent en quête d'eau d'un puits au sommet d'une colline mais rencontrent des malheurs en chemin.
Names: Jack, Jill
Output JSON: {"french_summary": "Jack et Jill, frère et sœur d'un charmant village, partent en quête d'eau d'un puits au sommet d'une colline mais rencontrent des malheurs en chemin.", "num_names": 2}

方法2: 指示模型在做出结论之前推理出自己的解决方案

我们让模型来解一道应用题。先给出题目,并给出学生的解答。让模型判断一下学生的解答是否正确。

prompt = f"""
Determine if the student's solution is correct or not.

Question:
I'm building a solar power installation and I need \
help working out the financials.

- Land costs 100 / square foot
- I can buy solar panels for250 / square foot
- I negotiated a contract for maintenance that will cost \
me a flat 100k per year, and an additional10 / square \
foot

what is the total cost for the first year of operations 
as a function of the number of square feet.

Student's Solution:
Let x be the size of the installation in square feet.
Costs:
1. Land cost: 100x
2. Solar panel cost: 250x
3. Maintenance cost: 100,000 + 100x
Total cost: 100x + 250x + 100,000 + 100x = 450x + 100,000
"""

response = get_completion(prompt)
print(response)
The student's solution is correct. The total cost for the first year of operations is indeed 450x + 100,000, where x is the size of the installation in square feet.

模型认为学生的解答是正确的。实际上学生解错了。

现在我们用这个方法来纠正模型的这个错误呢?下面的提示是这样写的:
第一步:模型自己来解答这道题
第二步:与学生的解答相比较,评估学生解答是否正确
并且,我们明确了输出格式,如:问题、解答、步骤等等

prompt = f"""
Your task is to determine if the student's solution is correct or not.
To solve the problem do the following:
- First, work out your own solution to the problem.
- Then compare your solution to the student's solution and evaluate if the student's solution is correct or not.
Don't decide the student's solution is correct until you have dork the problem yourself.

Use the following format:
Question:
'''
question here
'''
Student's solution:
'''
student's solution here
'''
Actual solution:
'''
steps to work out the solution and your solution here
'''
Is the student's solution the same as actual solution just calculated:
'''
yes or no
'''
Student grade:
'''
correct or incorrect
'''

Question:
I'm building a solar power installation and I need \
help working out the financials.

- Land costs 100 / square foot
- I can buy solar panels for250 / square foot
- I negotiated a contract for maintenance that will cost
me a flat 100k per year, and an additional10 / square foot

what is the total cost for the first year of operations 
as a function of the number of square feet.

Student's Solution:
Let x be the size of the installation in square feet.
Costs:
1. Land cost: 100x
2. Solar panel cost: 250x
3. Maintenance cost: 100,000 + 100x
Total cost: 100x + 250x + 100,000 + 100x = 450x + 100,000
"""

response = get_completion(prompt)
print(response)
Actual Solution:
Let x be the size of the installation in square feet.
Costs:
1. Land cost: 100 * x =100x
2. Solar panel cost: 250 * x =250x
3. Maintenance cost: 100,000 +10 * x = 100,000 +10x
Total cost: 100x +250x + 100,000 +10x = 360x +100,000

Is the student's solution the same as actual solution just calculated:
No

Student grade:
Incorrect

通过这些指令,模型发现了学习解答是错误的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注