# 一、什么构成了一个好的提示?
与大语言模型高效沟通的核心——提示(Prompt)
# 1、什么是提示工程?
- 提示的定义
- 提示是我们输入给AI的问题或指示,是AI生成回应的基础。
- 提示的重要性
- 高质量的提示能显著提升AI的理解能力、执行效率和输出准确性。
- 提示工程的本质
- 研究如何优化与AI的沟通方式,核心在于提示的设计与迭代优化。
# 2、OpenAI官方推荐的七大提示工程原则
- 使用最新模型
- 指令前置 + 分隔符
- 具体、详细、描述性强
- 提供输出格式示例
- 先零样本,后小样本
- 要求具体明确,避免空洞
- 正向引导,明确应做之事
# 原则一 —— 使用最新模型
- 模型版本演进
- 早期模型如
text-ada
,text-babbage
,text-curie
,text-davinci
主要用于文本补全。 - 当前主流为擅长对话的
GPT-3.5 Turbo
、GPT-4
等。
- 早期模型如
- 选择建议
- 优先选用最新模型(字母靠后或数字更大),理解与生成能力更强。
- 成本是次要考虑因素,需权衡性能与预算。
# 原则二 —— 指令前置并清晰分隔
错误做法
- 指令与上下文混在一起,如:“总结以下内容……[文本]”。
正确做法
将指令放在提示开头,并用
"""
或!!!
明确分隔指令与上下文:请将以下文本的要点用列表形式总结: """ [要总结的文本内容] """
1
2
3
4这有助于模型更好地区分“做什么”和“对什么做”。
# 原则三 —— 具体、详细、描述性强
- 模糊提示示例
- “写一首关于OpenAI的诗” → 输出不可控。
- 优化后的提示示例
- “写一首12行的现代诗,主题为‘AI如何改变人类创造力’,风格要富有哲思和诗意,避免技术术语。”
- 包含了长度、题材、风格、主题、限制条件等细节,输出更符合预期。
# 原则四 —— 提供输出格式示例
无格式引导的问题
- “从文本中提取公司名、人名、主题、子主题” → 输出格式随意。
带模板的提示
提供结构化模板:
公司名: [用逗号分隔] 人名: [用||分隔] 主题: [用||分隔] 子主题: [用||分隔]
1
2
3
4模型会模仿该格式输出,便于后续程序解析。
# 原则五 —— 先零样本,后小样本
- 零样本提示(Zero-shot)
- 直接给出指令,不提供任何示例。
- 适用于简单任务或模型已具备相关能力。
- 小样本提示(Few-shot)
- 当零样本效果不佳时,提供1-3个输入-输出示例。
- 示例能帮助模型理解任务模式和期望输出。
- 后续章节将深入讲解小样本学习技巧。
# 原则六 —— 避免空洞描述,要求具体明确
- 模糊描述示例
- “描述要短,不要太多” → 不够具体。
- 精确描述示例
- “用3到5句话组成一个段落来描述此产品。”
- 明确了长度和结构,减少歧义。
# 原则七 —— 告诉AI“应该做什么”,而非“不要做什么”
- 负面指令的局限
- 如:“不要问用户名或密码,不要重复。”
- 只限制了行为,未指明正确方向。
- 正向引导更有效
- 如:“你的任务是引导用户查阅帮助文档解决问题。请勿询问任何个人隐私信息。”
- 明确了目标行为,引导AI采取积极行动。
# 二、限定输出格式
# 1、为何需要指定输出格式
- 影响信息消费效率
- 明确的输出格式有助于用户更快地理解和消化信息。
- 便于后续处理
- 当使用API与AI交互时,明确的输出格式可以简化从响应中提取信息的过程。
- 通过指定格式(如JSON、XML、YAML等),可以减少代码处理模糊信息结构的复杂性。
# 2、OpenAI对输出格式的支持
- 支持JSON模式的新模型
- OpenAI在新模型上开始支持JSON模式,确保输出的有效性和一致性。
- 旧模型仍需提示控制格式
- 对于不支持JSON模式的旧模型,仍然需要通过提示来要求特定的输出格式。
# 3、JSON的基本概念与语法
- JSON简介
- JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人类阅读和编写,也易于机器解析和生成。
- 数据结构
- 对象:由键值对组成,用大括号
{}
表示。键必须是字符串,值可以是字符串、数字、布尔值、数组或另一个对象。 - 数组:有序的值集合,用方括号
[]
表示。数组中的元素可以是任意类型的数据。
- 对象:由键值对组成,用大括号
# 4、JSON的具体语法细节
- 键值对规则
- 键必须是字符串,并且需要用双引号
" "
包围。 - 值可以是字符串、数字、布尔值、数组或对象。
- 每个键值对之间用逗号
,
分隔。
- 键必须是字符串,并且需要用双引号
- 数据类型的注意事项
- 字符串:必须用双引号包围,单引号无效。
- 数字:整数或浮点数均可。
- 布尔值:
true
和false
,注意区分大小写,与Python不同。 - 数组:支持嵌套,允许复杂的层次结构。
- 对象:同样支持嵌套,增加灵活性。
- 空值:用
null
表示,类似于Python中的None
。
# 5、Python与JSON的转换
使用Python的json库
将JSON字符串转换为Python字典或列表:
import json json_string = '{"name": "Alice", "age": 30}' python_data = json.loads(json_string) print(python_data) # 输出: {'name': 'Alice', 'age': 30}
1
2
3
4将Python字典或列表转换为JSON字符串:
python_dict = {'name': 'Alice', 'age': 30} json_string = json.dumps(python_dict) print(json_string) # 输出: {"name": "Alice", "age": 30}
1
2
3
# 6、将AI返回值处理成JSON格式
# 导入库并创建客户端
from openai import OpenAI
import json
client = OpenAI()
# 构建任务提示词
prompt = f"""
生成一个由三个虚构的订单信息所组成的列表,以JSON格式进行返回。
JSON列表里的每个元素包含以下信息:
order_id、customer_name、order_item、phone。
所有信息都是字符串。
除了JSON之外
"""
# 封装通用请求函数
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": prompt
}
]
)
# 获取AI响应
content = response.choices[0].message.content
# JSON格式化
json.loads(content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[{'order_id': '123',
'customer_name': 'John Smith',
'order_item': 'Shoes',
'phone': '1234567890'},
{'order_id': '456',
'customer_name': 'Jane Doe',
'order_item': 'T-shirt',
'phone': '9876543210'},
{'order_id': '789',
'customer_name': 'Tom Thompson',
'order_item': 'Jeans',
'phone': '4567890123'}]
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
json.loads(content)[0]["phone"]
1
'1234567890'
1
# 三、零样本VS小样本
# 1、什么是小样本提示?
- 零样本提示(Zero-Shot Prompting)
- 直接向AI提出问题或指令,不提供任何示例。
- 示例:
"总结以下文本:..."
- 缺点:输出可能不符合预期格式或风格,效果不稳定。
- 小样本提示(Few-Shot Prompting)
- 在提问前,先提供1到多个“输入-输出”示例作为示范。
- AI会基于这些示例进行上下文学习(In-Context Learning):
- 记忆示例中的知识。
- 模仿示例的格式、风格和逻辑进行回应。
- 优势:无需训练模型,即可让AI快速适应新任务,成本低且灵活。
# 2、如何实现小样本提示
- 使用
messages
参数构建对话历史- 在调用
client.chat.completions.create()
时,messages
参数可以是一个包含多轮对话的列表。 - 每条消息是一个字典,包含
role
和content
role="user"
:表示用户输入。role="assistant"
:表示AI的示范回答。
- 在调用
# 3、零样本提示示例
# 导入库并创建客户端
from openai import OpenAI
client = OpenAI()
# 封装通用请求函数
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "格式化以下信息:\n姓名 -> 张三\n年龄 -> 27\n客户ID -> 001"
}
]
)
print(response.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
姓名: 张三
年龄: 27
客户ID: 001
1
2
3
2
3
# 4、小样本提示示例
# 封装通用请求函数
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "格式化以下信息:\n姓名 -> 张三\n年龄 -> 27\n客户ID -> 001"
},
{
"role": "assistant",
"content": "##客户信息\n- 客户姓名:张三\n- 客户年龄:27岁\n- 客户ID:001"
},
{
"role": "user",
"content": "格式化以下信息:\n姓名 -> 李四\n年龄 -> 42\n客户ID -> 002"
},
{
"role": "assistant",
"content": "##客户信息\n- 客户姓名:李四\n- 客户年龄:42岁\n- 客户ID:002"
},
{
"role": "user",
"content": "格式化以下信息:\n姓名 -> 王五\n年龄 -> 32\n客户ID -> 003"
}
]
)
response.choices[0].message.content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'## 客户信息\n- 客户姓名:王五\n- 客户年龄:32岁\n- 客户ID:003'
1
# 四、思维链与分步骤思考
# 1、小样本提示的瓶颈
- 数学与逻辑推理的挑战
- 尽管小样本提示在多数任务中表现优异,但在数学计算、逻辑推理等复杂任务上效果有限。
- 示例:即使提供正确答案的示范,AI仍可能出错(如将奇数相加结果误算为53,实际应为41)。
- 根本原因分析
- AI生成每个Token的时间基本恒定,不会因“需要更多思考”而延长。
- 因此,面对复杂问题时,AI倾向于“跳步”或“猜测”,导致错误累积。
- 单纯的结果示范无法教会AI“如何思考”。
# 2、思维链的核心理念
定义与起源
- 思维链(Chain-of-Thought)由谷歌在2022年提出,是一种引导AI进行分步推理的提示技术。
- 核心思想:让AI像人类一样,通过中间推理步骤逐步解决问题。
工作原理
在小样本提示中,不仅提供输入和最终答案,还展示详细的推理过程。
AI会模仿这种“思考路径”,在生成答案时也输出中间步骤。
示例:
问题:小明有3个苹果,买了5个,吃了2个,还剩几个? 推理步骤: 1. 初始数量:3个 2. 购买后:3 + 5 = 8个 3. 吃掉后:8 - 2 = 6个 答案:6个
1
2
3
4
5
6
# 3、为何思维链更有效?
- 降低认知负荷
- 将复杂任务分解为多个简单步骤,每步只需关注局部信息。
- 类比:学生被点名回答问题时,边说边想比瞬间给出答案更容易成功。
- 减少上下文干扰
- 每个推理步骤聚焦当前任务,避免被无关信息干扰。
- 提高逻辑连贯性和准确性。
- 适用范围广泛
- 不仅限于数学计算,还可用于:
- 常识推理(如时间、因果关系)
- 符号推理(如逻辑谜题)
- 复杂决策分析
- 文本理解与推断
- 不仅限于数学计算,还可用于:
# 4、低成本思维链技巧:Zero-Shot CoT
简单高效的提示词,即使不使用小样本提示,只需在问题后加上:
Let's think step by step.
1
或中文:
让我们来分步骤思考。
1
示例代码
# 导入库并创建客户端
from openai import OpenAI
client = OpenAI()
1
2
3
2
3
不使用思维链提示
# 封装通用请求函数
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "该组中的奇数加起来为偶数:4、8、9、15、12、2、1,对吗?"
},
{
"role": "assistant",
"content": "所有奇数相加等于25。答案为否。"
},
{
"role": "user",
"content": "该组中的奇数加起来为偶数:17、10、19、4、8、12、24,对吗?"
},
{
"role": "assistant",
"content": "所有奇数相加等于36。答案为是。"
},
{
"role": "user",
"content": "该组中的奇数加起来为偶数:15、12、5、3、72、17、1,对吗?"
},
]
)
print(response.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
所有奇数相加等于53。答案为否。
1
# 封装通用请求函数
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "该组中的奇数加起来为偶数:4、8、9、15、12、2、1,对吗?"
},
{
"role": "assistant",
"content": "所有奇数(9、15、1)相加,9 + 15 + 1 = 25。答案为否。"
},
{
"role": "user",
"content": "该组中的奇数加起来为偶数:17、10、19、4、8、12、24,对吗?"
},
{
"role": "assistant",
"content": "所有奇数(17、19)相加,17 + 19 = 36。答案为是。"
},
{
"role": "user",
"content": "该组中的奇数加起来为偶数:15、12、5、3、72、17、1,对吗?"
},
]
)
print(response.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
所有奇数(15、5、3、17、1)相加,15 + 5 + 3 + 17 + 1 = 41。答案为否。
1
使用思维链提示
# 封装通用请求函数
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": "该组中的奇数加起来为偶数:15、12、5、3、72、17、1,对吗?让我们来分步骤思考。"
},
]
)
print(response.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
是的,让我们来分步骤思考这个问题。
首先,我们将奇数从该组中提取出来,这些数字是:15、5、3、17、1。
然后,我们将这些奇数相加:15 + 5 + 3 + 17 + 1 = 41。
最后,我们检查41这个结果是否为偶数。因为41是奇数,所以该组中的奇数加起来不为偶数。
所以,该组中的奇数加起来不为偶数。
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9