提示词工程

Python

# 一、什么构成了一个好的提示?

与大语言模型高效沟通的核心——提示(Prompt)

# 1、什么是提示工程?

  • 提示的定义
    • 提示是我们输入给AI的问题或指示,是AI生成回应的基础。
  • 提示的重要性
    • 高质量的提示能显著提升AI的理解能力、执行效率和输出准确性。
  • 提示工程的本质
    • 研究如何优化与AI的沟通方式,核心在于提示的设计与迭代优化

# 2、OpenAI官方推荐的七大提示工程原则

  1. 使用最新模型
  2. 指令前置 + 分隔符
  3. 具体、详细、描述性强
  4. 提供输出格式示例
  5. 先零样本,后小样本
  6. 要求具体明确,避免空洞
  7. 正向引导,明确应做之事

# 原则一 —— 使用最新模型

  • 模型版本演进
    • 早期模型如 text-ada, text-babbage, text-curie, text-davinci 主要用于文本补全。
    • 当前主流为擅长对话的 GPT-3.5 TurboGPT-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的具体语法细节

  • 键值对规则
    • 键必须是字符串,并且需要用双引号 " " 包围。
    • 值可以是字符串、数字、布尔值、数组或对象。
    • 每个键值对之间用逗号 , 分隔。
  • 数据类型的注意事项
    • 字符串:必须用双引号包围,单引号无效。
    • 数字:整数或浮点数均可。
    • 布尔值truefalse,注意区分大小写,与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
[{'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
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 参数可以是一个包含多轮对话的列表。
    • 每条消息是一个字典,包含rolecontent
      • 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
姓名: 张三
年龄: 27
客户ID: 001
1
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
'## 客户信息\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. 初始数量:32. 购买后:3 + 5 = 83. 吃掉后: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

不使用思维链提示

# 封装通用请求函数
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
所有奇数相加等于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
所有奇数(1553171)相加,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
是的,让我们来分步骤思考这个问题。

首先,我们将奇数从该组中提取出来,这些数字是:1553171。

然后,我们将这些奇数相加:15 + 5 + 3 + 17 + 1 = 41。

最后,我们检查41这个结果是否为偶数。因为41是奇数,所以该组中的奇数加起来不为偶数。

所以,该组中的奇数加起来不为偶数。
1
2
3
4
5
6
7
8
9
最近修改于: 2025/8/18 01:22:39
和宇宙温柔的关联
房东的猫