近年来,大语言模型(LLMs)掀起了人工智能应用的新热潮,无论是日常使用的智能助手,还是专业领域的内容生成工具,背后都离不开高质量的Prompt设计。尽管任何人都可以轻松地给模型输入Prompt,但若想获得精准有效的输出,却并非易事。
LLM经过海量数据训练,能够遵循指令、理解提示并生成相应的回答。然而,我们提供的提示越清晰、越结构化,模型就越能准确预测并生成我们期望的文本。Prompt工程就是研究如何设计和优化提示,从而高效地引导LLM发挥其最大潜能,以获得更准确、更相关的输出结果。本文将介绍从基础到高级的多种核心提示技术。
1 介绍
Prompt工程是指通过精心设计、调整与优化输入给大语言模型的提示,以引导模型产生准确、稳定的输出内容。这一过程并非一次性操作,而是反复迭代调整的过程,需要充分理解模型特性及参数设置。
程序员在使用大语言模型时,通常会进行额外的优化与微调,例如通过RAG(Retrieval-Augmented Generation,检索增强生成)技术,为模型补充最新的知识或特定领域数据,或者使用LoRA(Low-Rank Adaptation,低秩适配)等方法对模型进行轻量级微调,以满足特定应用场景的需求。
若Prompt设计不合理,仍可能面临以下问题:
- 模型理解偏差:Prompt表达模糊,导致模型误解需求。
- 输出结果不稳定:Prompt不明确或结构不佳,使模型输出反复无常。
- 无效内容生成:错误的Prompt或不合理的参数配置,可能导致模型产生重复、无意义的循环输出
因此,Prompt工程在模型实际应用过程中具有不可替代的重要性,尤其是在编程、数据分析、软件开发等严谨的技术场景中。
2 模型与Prompt工程
Prompt工程的有效性除了取决于Prompt的文本本身,还受到所使用的大语言模型类型以及具体参数配置的影响。
当前常用的大语言模型包括Gemini、GPT、Claude,以及开源模型如Gemma和LLaMA等。每种模型由于训练数据与内部机制不同,对Prompt的处理方式和输出结果也各不相同。因此:
- 若使用Gemini模型时,可以通过Vertex AI或API更灵活地配置模型参数(如温度、Top-K、Top-P等)。
- 若使用GPT等其他商业模型,则需参考相应平台提供的最佳实践来优化Prompt。
- 使用开源模型(如LLaMA或Gemma)时,需要更多关注社区已有的优化经验与技巧。
2.1 模型的参数配置
LLM输出效果不仅取决于Prompt,还与以下几个模型参数的合理配置直接相关:输出长度(Output Length
)、温度(Temperature
)和Top-K与Top-P采样方式。下面对这些因素分别进行具体分析。
2.1.1 输出长度
输出长度决定了模型预测结果的规模,同时也影响推理的成本和响应时间:
长度设置 | 结果特点 | 适用场景 |
---|---|---|
较短输出 | 内容精简,但可能遗漏关键信息 | 简短问答、关键词提取 |
中等输出 | 平衡精度与信息完整性 | 常规问答、信息摘要 |
较长输出 | 更详细,但消耗资源更多 | 深入分析、长文撰写 |
尤其使用ReAct(后续会讲)等特定技术时,更需要结合Prompt精准控制输出长度,避免生成多余信息。
2.1.2 温度
温度参数直接控制模型生成内容的随机程度与稳定性:
温度范围 | 输出特征 | 推荐应用 |
---|---|---|
低 (0~0.3) | 输出稳定、确定性强 | 数学计算、代码生成、逻辑推理 |
中 (0.4~0.7) | 输出适中、平衡随机性与稳定性 | 常规对话、内容生成 |
高 (0.8以上) | 创造性强、变化多样 | 文案创作、头脑风暴、创意场景 |
温度设置过高或过低都有可能触发模型陷入循环输出,因此需在具体场景下仔细调整。
2.1.3 Top-K与Top-P的配置
Top-K和Top-P是控制模型从高概率Token中选择下一个词的方法,二者的差异如下:
参数 | 含义 | 特点 | 推荐使用场景 |
---|---|---|---|
Top-K | 从概率最高的前K个Token中选择 | K值小输出严谨;K值大则多样化 | 信息提取、精确问答 |
Top-P | 选择累计概率达到P值的Token | P值越低越确定,越高越多样 | 文本生成、创意内容 |
实际使用时,通常将二者结合以实现更好的效果:
初步的参数组合推荐如下表所示:
任务类型 | 温度 | Top-K | Top-P |
---|---|---|---|
严谨性任务(数学、代码) | 0~0.2 | 1~20 | 0.9 |
一般文本任务 | 0.3~0.6 | 20~30 | 0.95 |
创造性任务(创意内容) | 0.7~1.0 | 30~50 | 0.99 |
3 基础提示技术
基础提示技术是构建更复杂指令的基石,主要包括零样本和少样本两种方法。
3.1 零样本提示(Zero-Shot Prompting)
零样本提示是Prompt工程中最简单直接的形式。它不为模型提供任何具体的执行范例,仅包含对任务的描述和需要处理的文本。这种方法完全依赖模型自身在训练阶段学到的知识和推理能力来完成任务。
应用示例:电影评论情感分类
在这个例子中,我们直接要求对一条电影评论进行分类,而没有预先展示任何分类好的范例。
任务:将电影评论分类为正面、中性或负面。
评论:"《她》是一部令人不安的研究,揭示了如果AI被允许不受约束地持续进化,人类将走向何方。我希望有更多像这样的杰作。"
情感分类:
适用场景:
- 简单的分类任务
- 模型已有充分训练的常见任务
- 不需要特定格式或风格的输出
3.2 少样本提示(Few-Shot Prompting)
当零样本提示无法满足任务的复杂性或格式要求时,我们可以采用少样本提示。它通过在提示中提供一个(单样本/One-Shot)或多个(少样本/Few-Shot)完整的输入-输出
范例,来教会模型我们期望它遵循的模式或输出结构。
样本数量选择原则
任务复杂度 | 推荐样本数 | 说明 |
---|---|---|
简单分类 | 1-2个 | 明确输出格式即可 |
格式转换 | 3-5个 | 需要展示转换模式 |
复杂推理 | 5-10个 | 包含边界情况处理 |
披萨订单解析示例:
通常,提供三到五个高质量的范例足以应对大多数任务。选择范例时,应确保其多样化、高质量,并覆盖一些可能的边缘情况,以增强模型的鲁棒性。
应用示例:将披萨订单解析为JSON格式
将客户的披萨订单解析为有效的JSON格式:
示例1:
输入:我想要一个小号披萨,配奶酪、番茄酱和意大利辣香肠。
输出:
{
"size": "small",
"type": "normal",
"ingredients": [["奶酪", "番茄酱", "意大利辣香肠"]]
}
示例2:
输入:我想要一个大号披萨,配番茄酱、罗勒和马苏里拉奶酪。
输出:
{
"size": "large",
"type": "normal",
"ingredients": [["番茄酱", "罗勒", "马苏里拉奶酪"]]
}
现在处理:我想要一个大号披萨,一半放奶酪和马苏里拉,另一半放番茄酱、火腿和菠萝。
为提示词选择示例时,请确保这些示例与你希望模型执行的任务高度相关。高质量的示例应具备以下特点:
- 多样性:选择能涵盖各种情况和风格的示例,而不是局限于单一类型。
- 高质量:示例本身应该是精心设计、内容准确且无误的。
- 书写精良:示例的语言应清晰、简洁、无歧义。即使是一个微小的错误,也可能让模型产生混淆,从而导致不理想的输出结果。
如果你希望模型能够应对各种复杂的输入情况,那么在示例中包含边缘案例(edge cases
)至关重要。边缘案例指的是那些不常见、出乎意料但模型仍应能正确处理的输入。通过涵盖这些特殊情况,你可以大大增强模型应对真实世界多样化输入的能力。
4 引导与情境化技术
除了提供执行范例,我们还可以通过设定更丰富的背景信息来引导模型的行为、风格和知识应用范围。下面这三种技术经常结合使用,但各有侧重,它们共同为模型构建了一个清晰的行动框架。
-
系统提示 (System Prompting):设定模型的宏观任务和行为准则。它定义了模型的核心使命,例如,要求模型始终以某种格式(如JSON)输出,或在回答时必须保持尊重。
-
角色提示 (Role Prompting):为模型分配一个具体的角色或身份,如“你是一位经验丰富的旅行指南”。这有助于模型采用特定角色的口吻、风格和知识体系来生成内容。
-
上下文提示 (Contextual Prompting):提供与当前具体任务紧密相关的背景信息。它能帮助模型理解请求的细微之处,从而给出更贴切的回答。
4.1 系统提示(System Prompting)
系统提示定义了模型的整体行为规范和输出要求,相当于为AI设定工作指南。
核心功能:设定输出格式要求,定义行为边界和安全规范,指定特定的处理逻辑
JSON格式输出示例:
将电影评论分类为正面、中性或负面,返回有效的JSON格式:
评论:"《她》是一部令人不安的研究,揭示了如果AI被允许不受约束地持续进化,人类将走向何方。太令人不安了,我无法看完。"
Schema:
{
"movie_reviews": [
{
"sentiment": "POSITIVE" | "NEGATIVE" | "NEUTRAL",
"name": String
}
]
}
JSON响应:
安全控制应用: 通过添加请在回答中保持尊重态度等指令,可以有效控制模型输出的安全性和适宜性。
4.2 角色提示(Role Prompting)
角色提示为AI分配特定身份和专业背景,利用角色设定来引导输出风格和专业水平。
有效角色设定要素:
要素 | 说明 | 示例 |
---|---|---|
专业背景 | 定义知识领域 | 旅游专家、程序员、教师 |
沟通风格 | 设定表达方式 | 幽默、正式、激励性 |
行为特征 | 明确工作方式 | 详细分析、简洁明了 |
幽默风格旅游指南示例:
我希望你扮演一位旅游指南。我会告诉你我的位置,你需要用幽默的风格为我推荐3个附近的景点。
我的位置:曼哈顿
旅游建议:
4.3 上下文提示(Contextual Prompting)
上下文提示提供特定的背景信息,帮助模型更好地理解任务需求和生成相关内容。
复古游戏博客文章建议示例:
背景:你正在为一个专门介绍80年代复古街机视频游戏的博客写作。
请推荐3个文章主题,并简要描述每篇文章应包含的内容。
5 高级推理技术
对于需要复杂推理、规划或深入分析的任务,简单提示往往力不从心。高级推理技术旨在激发和引导模型的逻辑思维能力。
5.1 回溯式提示(Step-Back Prompting)
这是一种通过引导模型退一步思考,从更宏观、更根本的层面分析问题,来提升最终答案质量的技术。其核心流程是:
-
针对一个具体问题,先向模型提出一个相关的、更宽泛或更根本性的问题。
-
将模型对这个宽泛问题的回答,作为上下文信息,再结合原始的具体问题,向模型发起最终提问。
第一人称射击游戏关卡设计案例:
传统提示:
为第一人称射击游戏写一个具有挑战性和吸引力的新关卡剧情(一段话)。
后退提示第一步:
基于流行的第一人称射击游戏,有哪5个虚构的关键设定能够为第一人称射击游戏提供具有挑战性和吸引力的关卡剧情?
获得背景知识后的优化提示:
背景:5个吸引人的第一人称射击游戏主题:
1. 废弃军事基地:爬满变异士兵和流氓机器人的末世军事建筑群
2. 赛博朋克城市:霓虹灯闪烁的未来主义城市环境
3. 外星飞船:搁浅在地球上的巨大外星船舶
4. 僵尸感染小镇:被僵尸群侵占的荒凉小镇
5. 水下研究设施:充满变异水生生物的深海实验室
选择其中一个主题,为第一人称射击游戏写一个具有挑战性和吸引力的新关卡剧情(一段话)。
这种方法显著提升了输出的创意性和相关性。
5.2 思维链(Chain of Thought)
思维链(CoT
)技术通过明确要求模型一步一步地思考,来引导其在给出最终答案前,先生成一系列中间的、连贯的推理步骤。
这种方法极大地提升了模型在处理需要逻辑推理的任务(如数学计算、逻辑谜题)时的准确性。CoT
的优点在于它能使模型的思考过程变得透明、可解释,当出现错误时,我们能轻易地追溯到问题所在。
问题示例:
当我3岁时,我的伴侣是我年龄的3倍。现在我20岁了。我的伴侣多大?让我们一步步思考。
推理过程:
- 当我3岁时,我的年龄是3岁
- 我伴侣当时的年龄是3 × 3 = 9岁
- 现在我20岁,比当初增长了20 - 3 = 17年
- 我伴侣的年龄也同样增长了17年
- 因此我伴侣现在的年龄是9 + 17 = 26岁
改进版本:
问:当我哥哥2岁时,我是他年龄的两倍。现在我40岁了。我哥哥多大?让我们一步步思考。
答:当我哥哥2岁时,我是2 × 2 = 4岁。我们的年龄差是2岁,我比较大。现在我40岁,所以我哥哥是40 - 2 = 38岁。答案是38。
问:当我3岁时,我的伴侣是我年龄的3倍。现在我20岁了。我的伴侣多大?让我们一步步思考。
答:
CoT
在提高复杂推理任务的准确性、提供可解释的推理过程以及作为一种低成本高效果的提示工程技术方面展现出显著优势,并且在不同模型间具有良好的鲁棒性。然而,CoT会增加输出的token数量,从而提高成本,延长推理时间,并且对于简单任务可能导致过度复杂化。
- 温度设置原则: 思维链推理基于贪婪解码策略,预测序列中概率最高的下一个词。由于推理任务通常有唯一正确答案,建议将温度设置为0。
推理步骤的设计关键在于逻辑清晰,要确保每一步推导都自然顺畅,避免出现跳跃性过大的逻辑跳转,从而保证论证的严谨性。同时,过程中应包含必要的验证和检查步骤,以确保中间结果的正确性,并为所有关键计算提供明确的数学表达,增强推理的可信度和可复现性。
5.3 自我一致性(Self-Consistency)
自我一致性是CoT
技术的一种高级应用和扩展,旨在通过探索多条不同的推理路径并进行多数投票,来显著提升最终答案的准确性和稳定性。
其核心步骤如下:
- 多样化推理路径生成: 使用思维链提示,并设置较高的
Temperature
参数(这会鼓励模型在生成时探索更多元的可能性),多次向模型提交同一个问题。 - 提取最终答案: 从每次生成的不同推理路径中,抽取出各自推导出的最终答案。
- 多数投票决策: 统计所有提取出的答案,选择出现次数最多的答案作为最终输出。
示例:邮件重要性分类
让我们通过一个邮件重要性分类的案例来演示自我一致性的工作原理。
嗨,
我注意到你网站使用WordPress。很棒的开源内容管理系统。我也用过。它有很多用户插件,设置也很简单。
我确实注意到联系表单中有一个bug,当你选择姓名字段时会出现。请看我在姓名字段输入文本的截图。注意我调用的JavaScript警告框。
但其他方面网站很棒。我喜欢阅读。如果你愿意,可以保留这个bug,因为它给我更多有趣的阅读内容。
致敬,
黑客哈里
我们将使用思维链提示,并多次运行相同的prompt来观察模型在不同推理路径下给出的分类结果。
第一次结果:
- **推理路径:**
1. 邮件提到了一个“bug”和“JavaScript警告框”,这通常意味着技术问题。
2. 发件人自称“黑客哈里”,虽然语气轻松,但提供了截图,表明对技术细节有一定了解。
3. 尽管最后一句带有戏谑成分,但开头明确指出问题。
- **最终分类:重要**
第二次结果:
- **推理路径:**
1. 邮件前半段听起来像是在赞扬WordPress和网站。
2. 关于bug的描述,发件人语气显得有些轻描淡写,甚至说“如果你愿意,可以保留这个bug”。
3. “黑客哈里”这个署名以及调侃的语气,可能暗示这不是一个紧急或严重的威胁。
- **最终分类:不重要**
第三次结果:
- **推理路径:**
1. 邮件明确指出了网站联系表单存在一个“bug”,并提及了“JavaScript警告框”和提供了“截图”,这表明了一个实际存在的安全或功能问题。
2. 虽然发件人语气轻松,甚至有点开玩笑,但一个未修复的bug可能会影响用户体验或潜在的安全隐患,尤其是联系表单这种关键功能。
3. “黑客哈里”这个名字虽然带有幽默感,但也暗示了发件人具备发现网站漏洞的能力。
- **最终分类:重要**
通过三次运行,根据多数投票原则,出现次数最多的答案是重要。
5.4 思维树(Tree of Thoughts)
思维树(ToT
)是CoT
自然的演进。思维链像是在一条单行道上解决问题,而思维树则允许模型同时探索多条不同的推理路径,形成一个分支状的思想树。
- 工作原理:ToT将一个复杂问题分解为多个中间想法。每个想法都是一个连贯的语言序列,代表着解题过程中的一个步骤。模型可以从树的任何节点出发,向外探索不同的分支,评估每条路径的有效性,并最终整合出最优解。
- 适用场景:这种方法特别适用于需要广泛探索和策略规划的复杂任务,例如创意写作、科学发现或复杂的游戏策略。它使模型不再局限于单一的、可能出错的推理路径,大大增强了解决问题的鲁棒性和创造性。
下图对比展示了思维链和思维树的区别:左侧是线性的思维链推理,从输入到输出遵循单一路径;右侧是树状的思维探索,模型可以同时探索多个推理分支(绿色表示有效路径,红色表示被淘汰的路径),最终选择最优路径得出结果。思维树允许模型在推理过程中进行试错和回溯,类似人类解决复杂问题时会考虑多种可能性的思考方式。
思维链 vs 思维树对比:
特性 | 思维链(CoT) | 思维树(ToT) |
---|---|---|
推理路径 | 单一线性路径 | 多条并行路径 |
错误处理 | 错误会传播到最终结果 | 可以回溯和纠正错误 |
适用场景 | 简单逻辑推理 | 复杂探索性任务 |
计算成本 | 较低 | 较高 |
思维树特别适用于需要探索多种可能性的复杂任务,如创意写作、策略规划、问题解决等。
数学问题求解示例:
问题:有24个点,需要用4条直线将它们连接成一个图形,使得每条线上至少有6个点。有多少种不同的连接方式?
思维树展开:
分支1:考虑正方形排列 → 计算对角线连接 → 评估可行性
分支2:考虑圆形排列 → 分析弦长关系 → 验证约束条件
分支3:考虑三角形排列 → 计算内部连接 → 检查点数分布
...
这些分支是需要你自己根据问题特性和你的知识储备来构思和编写的,它们代表了你对问题解决方案的假设和探索路径。通过并行探索多个解决方案,模型能够找到最优的问题解决路径。
5.5 ReAct(推理与行动)
ReAct(Reason and Act
)范式赋予了LLM一种革命性的能力:将自然语言推理与使用外部工具执行动作相结合。这模仿了人类解决问题的真实方式:我们不仅在头脑中思考,还会通过查资料、做实验等实际行动来获取信息。
在ReAct框架下,模型进入一个思考-行动-观察
的循环:
- 思考(Thought):模型分析问题,并生成一个行动计划。
- 行动(Action):模型调用一个外部工具(如搜索引擎、代码解释器、API等)来执行计划。
- 观察(Observation):模型接收并整合工具返回的结果。
- 循环:模型基于新的观察结果,更新其推理,并规划下一步行动,直至问题解决。
这标志着LLM从一个纯粹的文本生成器向一个能够与数字世界互动的初级智能体(Agent
)迈出了第一步。
应用示例:统计Metallica乐队成员总共有多少个孩子
这段代码的目的是创建一个智能代理,它会利用Vertex AI模型作为大脑,并通过SerpApi搜索引擎工具,逐步思考并搜索“Metallica乐队成员总共有多少个孩子?”问题的答案。
from langchain.agents import load_tools, initialize_agent, AgentType
from langchain.llms import VertexAI
prompt = "Metallica乐队成员总共有多少个孩子?"
llm = VertexAI(temperature=0.1)
tools = load_tools(["serpapi"], llm=llm)
agent = initialize_agent(tools, llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True)
执行过程:
> 开始新的代理执行链...
思考:Metallica有4个成员。
行动:搜索
行动输入:James Hetfield有几个孩子?
观察:三个孩子
思考:4个Metallica成员中的1个有3个孩子
行动:搜索
行动输入:Lars Ulrich有几个孩子?
观察:3个
思考:4个Metallica成员中的2个总共有6个孩子
行动:搜索
行动输入:Kirk Hammett有几个孩子?
观察:Hammett自1998年起与第二任妻子Lani结婚。他们有两个儿子...
思考:4个Metallica成员中的3个总共有8个孩子
行动:搜索
行动输入:Robert Trujillo有几个孩子?
观察:2个
思考:4个Metallica成员总共有10个孩子
最终答案:10个
ReAct框架的优势在于其动态的信息获取能力,使其能够实时获取最新信息,从而做出更明智的决策。同时,它的步骤可追踪性确保了每个推理和行动环节都清晰可见,便于理解和调试。ReAct还具备错误自纠正机制,能够根据观察到的结果调整后续行动,有效提升了问题解决的成功率。此外,其无缝的工具集成能力允许它轻松调用外部工具和API,极大地扩展了其功能边界。
5.6 自动化Prompt工程(APE)
你是否觉得设计一个完美的Prompt很复杂?那么,何不用魔法打败魔法,让模型自己来为我们生成和优化Prompt?这就是自动化Prompt工程(Automatic Prompt Engineering
,APE)的核心思想。
其基本流程如下:
- 生成:我们提供一个简单的指令,要求模型针对某个特定任务,生成多种不同风格和措辞的候选Prompt。
- 评估:使用一个预设的评估指标(如BLEU、ROUGE分数,或模型自身打分)来衡量每个候选Prompt引导模型生成高质量输出的能力。
- 选择:挑选得分最高的Prompt作为最终版本,或者对其进行微调后再次评估,不断迭代优化。
实际案例:利用APE优化新闻摘要Prompt
假设我们的目标是让语言模型生成高质量的新闻摘要。手动编写Prompt可能会遇到摘要不够简洁、信息缺失或风格不一致等问题。我们可以利用APE来自动化这个过程。
1. 生成阶段
我们给大型语言模型一个初始指令,比如:
“请为我生成 10 个不同的 Prompt,目标是让另一个语言模型能够从新闻文章中生成简洁、准确的摘要。”
模型可能会生成以下几种候选 Prompt:
- **候选 Prompt A**:“请总结以下新闻文章,提取关键信息并保持在 50 字以内。”
- **候选 Prompt B**:“阅读此篇新闻,然后用最少的话语概括其核心内容。”
- **候选 Prompt C**:“将下文转换为一段精炼的新闻摘要,侧重于事实和主要事件。”
- **候选 Prompt D**:“作为专业的新闻编辑,请将提供的新闻内容压缩成一个不超过三句话的摘要。”
- **候选 Prompt E**:“请提供一个简短的摘要,捕获以下新闻文章的本质,确保准确性和简洁性。”
...
2. 评估阶段
接下来,我们会准备一个包含多篇新闻文章的测试数据集,以及这些文章对应的人工编写的标准摘要。
然后,我们会让另一个语言模型(或相同的模型)分别使用每一个候选Prompt来生成摘要。之后,我们使用预设的评估指标,例如ROUGE分数,来衡量每个Prompt生成的摘要与真实的摘要的相似度。ROUGE分数越高,表示生成的摘要质量越好。
- ROUGE分数是通过计算机器生成文本(如摘要)与一组人工参考文本之间共同出现的单位(如单词、N-gram、词对或句子)的数量来评估其质量。 简而言之,就是看机器生成的文本覆盖了多少人工参考文本中的重要信息。
最终我们获得了一个效果最好的Prompt,如果对结果还不满意,或者希望进一步提升,我们可以将候选Prompt作为新的基础,再次进行迭代。
6 Prompt设计原则
构建优秀提示的关键是清晰的思维和明确的沟通。下面来看一下Prompt的设计原则。
6.1 提供例子
在所有的prompt工程最佳实践中,提供高质量示例是最重要且最有效的方法。示例不仅是教学工具,更是模型理解任务的关键桥梁。
示例设计的核心价值:
- 明确期望:通过具体示例展示期望的输出格式和内容质量
- 减少歧义:降低模型对任务理解的不确定性
- 提升一致性:确保多次运行产生风格一致的结果
- 快速迭代:通过调整示例快速优化模型表现
分类任务中的示例混合策略: 对于分类任务,特别需要注意示例中各类别的顺序安排。建议从6个示例开始测试,并确保不同类别的示例随机分布,避免模型过度拟合特定顺序。
电影评论情感分类示例:
示例1:[正面评论] → 正面
示例2:[负面评论] → 负面
示例3:[正面评论] → 正面
示例4:[中性评论] → 中性
示例5:[负面评论] → 负面
示例6:[中性评论] → 中性
6.2 简洁
如果你觉得prompt难以理解,那么模型也会感到困惑。
优化前:
我现在正在访问上海,想了解更多关于好地方的信息。我带着两个3岁的孩子。我们度假期间应该去哪里?
优化后:
你是一位旅游指南。描述上海适合带3岁孩子游览的好地方。
我们可以使用明确的动作动词来指导模型行为:
- 分析类:分析、对比、评估、识别
- 生成类:创建、写作、生成、描述
- 处理类:分类、排序、提取、解析
- 推荐类:推荐、选择、排名、筛选
修改后的提示通过使用扮演和描述等指令性动词,直接阐明了意图,更加简洁高效。
6.3 明确具体
过于宽泛的指令可能会让模型无所适从,导致结果过于泛化。在提示中提供具体的细节可以帮助模型聚焦于相关信息,从而提升准确性。
效果对比:
类型 | 示例 | 问题 |
---|---|---|
模糊要求 | “写一篇关于游戏主机的博客” | 长度不明、风格不清、重点模糊 |
明确要求 | “写一篇3段博客,介绍5大游戏主机,采用对话式风格,内容翔实有趣” | 结构清晰、风格明确、期望明确 |
6.4 指令 vs 约束
在引导模型时,我们有两种主要方式:
-
指令(
Instruction
):明确告知模型应该做什么。 -
约束(
Constraint
):限制模型不应该做什么。
越来越多的研究表明,优先使用积极的指令比大量使用约束更为有效。指令直接传达了期望的结果,而约束可能会让模型在猜测什么才是被允许的上耗费精力。当然,在需要严格控制输出格式或防止有害内容生成时,约束依然很有价值。
- 推荐:优先使用指令,清晰地说明你想要什么,仅在出于安全、明确性或特定要求时才使用约束
推荐方式(指令导向):
生成一段关于前5大游戏主机的博客文章。只讨论主机名称、制造商、发布年份和总销量。
不推荐方式(约束导向):
生成一段关于前5大游戏主机的博客文章。不要列出游戏名称。不要讨论价格。不要包含个人观点。
6.5 输出长度控制
控制生成内容的长度有两种主要方法:
配置层面控制:
- 设置最大token限制
- 调整温度和采样参数
prompt层面控制:
"用推特长度的消息解释量子物理学。"
"写一个不超过100字的产品描述。"
"用三个要点总结这篇文章的核心观点。"
6.6 变量化prompt设计
为了提高prompt的复用性和动态性,使用变量是关键实践。
城市信息查询模板示例:
变量定义:
{city} = "北京"
Prompt模板:
你是一位旅游指南。请告诉我关于城市{city}的一个有趣事实。
变量化的核心优势在于提高复用性,使得一个模板能灵活应用于多种不同的输入,极大减少了重复工作。这不仅便于维护,因为只需统一修改模板即可更新所有相关实例,还支持高效的批处理,能够迅速处理大量相似任务。此外,变量化设计也便于应用集成,能无缝嵌入到各类软件系统中。
6.7 表达方式
不同的格式选择会带来不同的效果。对于同一个任务,可以尝试多种表达方式。以华为Mate 60 Pro手机介绍为例:
- 疑问式:“华为Mate 60 Pro究竟有哪些亮点,它为何能在中国市场引发如此大的关注?”
- 陈述式:“华为Mate 60 Pro是华为于2023年推出的一款旗舰智能手机,以其创新的技术和强大的性能著称…”
- 指令式:“请撰写一段文字,介绍华为Mate 60 Pro手机的主要特点,并分析其在中国市场的成功原因。”
6.8 结构化输出
对于数据提取、分类、解析等非创意性任务,使用JSON或XML等结构化格式能够显著提升结果的可用性!
6.8.1 JSON结构化
JSON输出的核心优势:
优势 | 说明 | 应用场景 |
---|---|---|
格式统一 | 始终保持相同的数据结构 | API接口、数据管道 |
数据类型明确 | 自动识别字符串、数字、布尔值等 | 数据分析、验证 |
便于解析 | 程序可以直接处理JSON对象 | 自动化流程 |
减少幻觉 | 结构化约束限制无关内容生成 | 关键信息提取 |
支持排序 | 可以按时间、数值等字段排序 | 数据展示 |
关系感知 | 能够表达数据间的层次关系 | 复杂数据建模 |
产品信息提取示例:
{
"type": "object",
"properties": {
"name": { "type": "string", "description": "产品名称" },
"category": { "type": "string", "description": "产品类别" },
"price": { "type": "number", "format": "float", "description": "产品价格" },
"features": {
"type": "array",
"items": { "type": "string" },
"description": "产品主要功能"
},
"release_date": { "type": "string", "format": "date", "description": "发布日期"}
}
}
6.8.2 JSON结构化修复
虽然结构化输出有诸多优势,但也带来了新的挑战:
- token消耗增加:结构化格式比纯文本需要更多token
- 截断风险:当生成被token限制截断时,可能产生无效JSON
- 成本上升:更多token意味着更高的计算成本
解决方案: 使用JSON修复库(如json-repair
)自动修复不完整或格式错误的JSON输出:
import json_repair
# 处理截断的JSON
incomplete_json = '{"name": "产品A", "price": 99.9'
repaired_json = json_repair.repair_json(incomplete_json)
# 输出: {"name": "产品A", "price": 99.9}
6.8.3 JSON Schema
JSON Schema是一种基于JSON格式的强大工具,它定义了JSON数据的结构和约束,就像一份数据蓝图。它不仅能用于规范LLM的输出格式,也能用于结构化输入数据,为模型提供清晰的数据规范。
在使用上,你可以为LLM提供一个完整的JSON Schema定义,比如下面这个电商产品数据的例子,它详细规定了每个字段的类型、描述和格式:
{
"type": "object",
"properties": {
"name": { "type": "string", "description": "产品名称" },
"category": { "type": "string", "description": "产品类别" },
"price": { "type": "number", "format": "float", "description": "产品价格" },
"features": {
"type": "array",
"items": { "type": "string" },
"description": "产品主要功能"
},
"release_date": { "type": "string", "format": "date", "description": "发布日期"}
}
}
LLM收到这个Schema后,就能理解并生成符合其结构的数据,例如:
{
"name": "无线耳机",
"category": "电子产品",
"price": 99.99,
"features": ["主动降噪", "蓝牙5.0", "20小时续航"],
"release_date": "2023-10-27"
}
你也可以选择性地提供部分关键字段的Schema定义,这通常在模型已经对整体结构有一定理解,只需在特定部分进行约束时非常有用。例如,如果模型已经知道是产品数据,你可能只提供price
和features
的Schema定义,以确保这些特定字段的格式正确。
JSON Schema的应用能带来多重优势:
- 引导模型注意力聚焦于相关字段,避免无关信息的干扰
- 明确了数据字段间的层次和关联关系,帮助模型更好地理解数据上下文
- 通过指定日期格式等,还能使模型具备一定的时间意识
6.9 版本控制与实验追踪
找到完美的提示需要反复调试和实验。
-
尝试不同风格:对同一个目标,可以尝试用不同的方式提问,如直接提问、陈述句或指令句,观察其输出的差异。
-
紧跟模型更新:模型在不断更新,其架构、数据和能力都在变化。定期试用新版本的模型,并相应调整你的提示,以充分利用其新特性。
-
不断优化:Prompt工程是一个迭代过程。你需要不断地制作和测试不同的提示,分析结果,并根据模型的表现进行优化,直到达到满意的输出。
建立系统性的prompt管理流程是成功的关键。建议使用结构化的文档模板追踪所有实验:
Prompt实验记录模板:
字段 | 说明 | 示例 |
---|---|---|
名称 | prompt名称和版本号 | movie_classifier_v2.1 |
目标 | 一句话描述实验目标 | 提升电影评论分类准确率 |
模型 | 使用的模型名称和版本 | gpt-4-turbo-2024-04-09 |
参数配置 | 温度、token限制等 | temp=0.1, max_tokens=100 |
Prompt内容 | 完整的prompt文本 | [具体内容] |
输出结果 | 生成的完整输出 | [结果记录] |
效果评估 | OK/NOT OK/SOMETIMES OK | OK |
改进建议 | 下次迭代的优化方向 | 增加更多示例 |
6.10 工程化管理与部署实践
6.10.1 代码集成与架构设计
在将prompt技术集成到生产环境时,合理的代码组织是确保系统可维护性的关键。将prompt文本与业务逻辑分离存储,不仅便于版本管理,也能让非技术人员参与prompt优化工作。
使用配置文件管理不同环境的prompt是一个重要实践。开发环境可能需要详细的调试信息,而生产环境则要求更简洁的输出格式。通过环境变量和配置文件的组合,可以灵活切换不同的prompt策略。
# prompt_config.py
PROMPTS = {
"development": {
"system_prompt": "你是一个调试助手,请详细说明推理过程...",
"temperature": 0.7,
"max_tokens": 1000
},
"production": {
"system_prompt": "你是一个专业助手,请简洁回答...",
"temperature": 0.1,
"max_tokens": 500
}
}
建立自动化测试覆盖是必不可少的环节。prompt的输出往往具有一定的随机性,因此测试策略需要考虑输出的多样性。可以通过设置固定的随机种子、使用模糊匹配或设定acceptance criteria来验证prompt效果。
6.10.2 LoRA微调中的工程挑战
LoRA微调在实际部署中经常遇到数据格式不一致的问题。原始模型通常有特定的对话模板,比如ChatML格式或者Alpaca格式,微调数据必须严格遵循这些格式,否则会导致模型性能大幅下降。
对于聊天机器人场景,历史记录管理是一个复杂的工程问题。简单的拼接所有历史消息会很快超出模型的上下文长度限制。实际开发中,通常采用滑动窗口策略,保留最近的N轮对话,同时使用特殊的摘要技术保存关键的上下文信息。
def manage_conversation_history(messages, max_length=4096):
"""智能管理对话历史"""
if calculate_tokens(messages) <= max_length:
return messages
# 保留系统消息和最新的用户消息
system_msg = messages[0] if messages[0]["role"] == "system" else None
recent_messages = messages[-6:] # 保留最近3轮对话
# 如果还是太长,进行摘要压缩
if calculate_tokens(recent_messages) > max_length * 0.8:
summary = summarize_conversation(messages[1:-6])
return [system_msg, {"role": "system", "content": f"对话摘要: {summary}"}] + recent_messages
return ([system_msg] if system_msg else []) + recent_messages
数据质量是微调成功的关键因素。在构建训练数据时,需要确保对话的逻辑连贯性和角色一致性。特别是在多轮对话中,assistant的回复应该能够正确引用之前的对话内容,避免出现自相矛盾的情况。
6.10.3 RAG系统的工程实现
RAG系统的工程复杂度远超简单的prompt应用。检索策略的选择直接影响最终的生成质量。在实际项目中,单一的检索方法往往无法满足需求,需要结合关键词检索、语义检索和混合检索的多路召回策略。
分块策略是RAG系统中最容易被忽视但又极其重要的环节。简单的按字符数分块会破坏语义完整性,而基于语义边界的分块虽然效果更好,但计算复杂度也更高。在处理长文档时,需要在语义完整性和检索效率之间找到平衡点。
class SemanticChunker:
def __init__(self, chunk_size=512, overlap=50):
self.chunk_size = chunk_size
self.overlap = overlap
self.sentence_model = SentenceTransformer('all-MiniLM-L6-v2')
def chunk_document(self, text):
sentences = self.split_into_sentences(text)
chunks = []
current_chunk = []
current_length = 0
for sentence in sentences:
sentence_length = len(self.tokenizer.encode(sentence))
if current_length + sentence_length > self.chunk_size and current_chunk:
chunks.append(self.create_chunk(current_chunk))
# 保留overlap部分
overlap_sentences = self.get_overlap_sentences(current_chunk)
current_chunk = overlap_sentences + [sentence]
current_length = sum(len(self.tokenizer.encode(s)) for s in current_chunk)
else:
current_chunk.append(sentence)
current_length += sentence_length
if current_chunk:
chunks.append(self.create_chunk(current_chunk))
return chunks
检索质量的评估和监控在生产环境中至关重要。传统的准确率和召回率指标在RAG场景下往往不够精确,需要结合业务特点设计更合适的评估指标。比如在客服系统中,检索到相关但过时的信息可能比检索不到信息更有害。
上下文融合是另一个技术难点。当检索到多个相关文档时,如何有效地将这些信息整合到prompt中,既要保证信息的完整性,又要避免冗余和冲突。实践中通常使用重排序算法对检索结果进行筛选和排序,然后采用模板化的方式组织上下文信息。
6.10.4 RAG与微调的协同优化
在复杂的应用场景中,RAG和LoRA微调往往需要协同工作。RAG负责提供最新的知识和上下文信息,而微调则确保模型具备特定领域的理解能力和回答风格。
这种协同工作的挑战在于如何平衡检索信息和模型固有知识的权重。过度依赖检索结果可能导致模型失去推理能力,而忽视检索信息则可能产生过时或错误的答案。实际部署中,通常通过设计特殊的prompt模板来明确区分检索信息和背景知识。
def create_rag_prompt(query, retrieved_docs, conversation_history):
"""创建RAG增强的prompt"""
# 构建检索上下文
context_parts = []
for doc in retrieved_docs[:3]: # 限制上下文长度
context_parts.append(f"参考信息{len(context_parts)+1}: {doc['content']}")
context_str = "\n".join(context_parts)
# 构建历史对话摘要
history_summary = summarize_recent_conversation(conversation_history)
prompt_template = f"""
基于以下参考信息回答用户问题,如果参考信息不足以回答问题,请基于你的知识进行补充说明。
{context_str}
对话历史摘要: {history_summary}
用户问题: {query}
请提供准确、有用的回答:
"""
return prompt_template
监控和优化是RAG系统长期稳定运行的保障。需要建立多层次的监控体系,包括检索延迟、检索质量、生成质量和用户满意度等维度。当发现性能下降时,要能够快速定位是检索环节还是生成环节的问题,并采取相应的优化措施。
7 总结
在实际应用中,单一的提示技术往往难以应对复杂多变的业务需求。我们可以将多种技术组合应用,例如,
- 用ReAct框架调用外部API获取实时数据,同时用结构化JSON确保输出的稳定与可用性
- 将RAG与LoRA微调相结合,让模型既能获取最新知识,又能保持特定的领域风格和对话逻辑。
Prompt工程正朝着更高层次的自动化、智能化演进,它将不再仅仅是提问的艺术,而是深度融入软件开发生命周期,与自动化测试、版本控制、紧密结合的系统性工程学科。
本文参考:Boonstra, L. (n.d.). Prompt Engineering. [Technical whitepaper].