全文约6000字,预计需要25-30分钟阅读。
引言
核心定义:
Prompt Engineering(提示词工程)是一种设计输入的实践,目的是从大语言模型中获得可靠、高质量的输出。
背景 :
日常与AI的对话逐渐增多,很多时候AI不会输出令人满意的答案,可以通过Prompt Enginnering来优化提示词来让AI输出令人满意的答案。
Prompt Engineering这一方面与日常生活需要比较相关,涉及的技术含量也比较少,但实用性较强。
本文根据Anthropic给的Prompt Engineering官方文档,结合我自身的理解,总结了一下相应的六个核心原则(主要涉及方法),后续会总结相关的常见问题的提示词模板。
工作原理:"为什么需要Prompt Engineering?" :
大模型本身相当于一个巨大的数学函数,通过提示词和上文来预测下一个词(token),不同的提示词会导致输出质量有很大的差异(PS.相同的提示词也会输出不同的回答)。
Prompt Engineering核心目标是让AI准确理解意图,获得稳定、高质量的输出。
Prompt Engineering准备:
- 明确个人需求: 需求拆解:明确任务目标/输出格式/成功标准
makefile
示例:一个与代码审查相关的任务
Prompt:
任务:(要求大模型做什么) 代码审查助手
成功标准:(判断什么是好的输出)
- 准确识别出潜在bug(准确率>90%)
- 给出具体的代码行号
- 提供可行的修复建议
- 输出格式为JSON,便于程序解析 # 输出格式
- 建立评估方法:
定性问题(文章创作、绘图...):是否符合个人要求/格式是否正确/信息是否完整;
定量问题(数学题、代码...): 用标准答案来判断。 - 准备初始草稿Prompt: 从一个简单版本开始迭代优化
scss
V1 (基础版) → 测试 → 发现问题
↓
V2 (改进版) → 测试 → 发现新问题
↓
V3 (优化版) → 测试 → 反复修改,直到达成目标or得到理想的输出
🚨 重要提醒:Prompt Engineering不能解决所有问题
diff
✅ 适用场景(可以解决的问题):
- AI理解错了任务意图
- 输出格式不符合要求
- 输出质量不稳定
- 缺少关键信息
❌ 不能解决的问题:
- 模型本身的知识边界(xxx年之后的新闻)
- 需要外部工具(计算器、搜索引擎、数据库)
主要内容
下面基于Anthropic的Prompt Engineering官方教程的总结。
文档主要分为三部分: 六大核心原则+ 高级技巧 + 提示词示例/模板
这里主要主要涉及六大核心原则,后续会对应六个核心原则总结一下常见问题的模板。
六大核心原则:
- 清晰直接(Be Clear and Direct)
- 使用示例(Few-shot)
- 展示推理过程(Chain of Thought)
- 使用XML标签(Use XML Tags)
- 设定角色(Give a Role)
- 预填充(Prefill Response)
1. 清晰直接(Be Clear and Direct)
⭐核心原则:给出详细、具体的指令,清晰直接比委婉礼貌更有用。
vbnet
'要点: 详细>简洁, 明确>礼貌, 具体>抽象'
❌错误示例 -> ✅ 好的提示词
1.指令太模糊
bad: 帮我看看这段代码 (粗略/广泛/礼貌)
good:
分析这段代码的性能瓶颈:
<code>
代码
</code>
请输出:
1.时间、空间复杂度分析
2.性能瓶颈所在具体行
3.优化建议(改进后的代码+建议)
Tips: 准确描述任务(不需要加请帮我...委婉礼貌的词,直接说明需要求): [动作] + [对象] + [具体要求] + [输出格式]
e.g. 生成 Python单元测试 要求使用Pytest框架...(其他具体要求) 输出可以直接运行的.py文件
2.依赖隐含假设(默认AI知道某些常识or你自己下意识认为的知识)
bad: 写一个排序函数
good: 用Python3.10编写一个排序函数, 要求:...(具体要求:输入/输出/算法/边界情况处理/库函数限制等等)
Tips: 不要根据个人情况(如我最近在学python,默认AI也会用python输出结果所以给一个模糊的指令), 要自行提供上下文信息or情景。
3.语言过于委婉
bad: 能不能帮我看一下这个JSON,如果方便的话,能否提取一下用户信息,不过如果太麻烦就算了..
× 客套话太多(占用token且无用); 如果...假设会让AI不确定是否执行
good:
从以下JSON中提取所有用户信息:
<json>{...}</json>
输出格式:
{
"users": [
{"id": 1, "name": "张三", "email": "..."},
...
]
}
只输出JSON,不要其他文字。
Tips: 去掉客套,直接说明具体的需求。
其他技巧:
- 使用"否定指令"来明确边界: "不要包含...", "不要使用..."
- 分层次的清晰度: 复杂任务(概述->给出细节)
- 用具体数字来代替"适当"、"合理"成都词: "列出主要特征" -> "列出3-5个最重要的特征"
实战案例: 从模糊 -> 清晰直接(clear and direct):
-
初始prompt(模糊):
为这个API写文档
-
V1(添加基本需求):
css
为这个REST API写文档,包括端点、参数、响应格式
- V2(添加具体细节):
diff
为以下REST API编写文档:
<api_code>
{{CODE}}
</api_code>
文档要求:
- 格式:Markdown
- 每个端点包含:URL、HTTP方法、描述、参数表格、响应示例
- 参数表格列:名称、类型、必填/可选、描述
- 响应示例包括成功和常见错误情况
- 最终版本(完全清晰):
ps: 用了XML标签,在后续第四个重要原则会讲到。
markdown
为以下REST API生成OpenAPI 3.0格式的文档:
<api_implementation>
{{CODE}}
</api_implementation>
<project_context>
这是一个用户管理服务的API
基础URL:https://api.example.com/v1
认证方式:Bearer Token
</project_context>
文档结构要求:
1. API概述(1-2句话说明用途)
2. 认证说明
3. 端点列表,每个端点包含:
- 路径和HTTP方法
- 简短描述
- 请求参数(路径/查询/body)
- 请求示例(curl命令)
- 响应格式(JSON schema)
- 响应示例(200成功、400错误、401未授权)
- 可能的错误码列表
输出格式:
使用Markdown,代码块要指定语言类型
curl示例要包含完整的headers
JSON要格式化(缩进2空格)
示例端点文档格式:
GET /users/{id}
获取指定用户的详细信息
**参数**
| 名称 | 位置 | 类型 | 必填 | 描述 |
|------|------|------|------|------|
| id | path | int | 是 | 用户ID |
个人心得:
scss
Prompt写的第一步是要清晰直接,不要用日常客套语言来向AI提问,直接说明需求。
基本思路:
任务目标(总体说明要干什么) + 具体需求(从哪几个角度来分析问题,完成任务)
+ 输出格式(以什么形式输出) + 约束条件(不要用什么方法,不要包含什么...)
要写出好的清晰直接的Prompt,可能要对所提的任务有一个比较系统的了解。
e.g. 比如分析这段代码, [具体要求] 只有本身知道从哪几个角度出发(如时间、空间复杂度分析/性能瓶颈所在具体行/优化建议)才能写出好的Prompt。
对此解决方法有:
一是直接询问AI可以从哪几个角度来分析你的这个任务,然后根据具体需求添加到Prompt再次提问;
二是可以根据个人常问问题(代码生成/文档生成/总结文章)套用网上总结的好的Prompt模板来提问。
2. 使用示例(Few-shot)
⭐核心原则:给AI看具体的示例比解释抽象的规则更有效
scss
最有效: Few-shot Learning(少样本学习) = 通过提供2-5个具体示例,让AI理解你期望的输出格式。
❌ 抽象规则: AI需要"理解"和"推理"
✅ 具体示例: AI直接"模式匹配"
设计好的示例的技巧:
sql
1. 示例具有代表性
示例:一个有关"加减乘除"的问题:
bad prompt: good prompt:
输入:"1+1" → 输出:"2" 输入:"1+1" → 输出:"2"
输入:"2+2" → 输出:"4" 输入:"(3+5)*2" → 输出:"16"
输入:"10/2+3" → 输出:"8"
现在计算:"(3+5)*2-7"
*坏的示例只给了+的情况,好的示例给了+,-,*,/以及括号的情况,更具代表性*
2. 展示边界情况
示例:给出邮箱(可能非法)让AI提取出正确的邮箱
bad prompt: # 只展示了正确情况,没展示哪些情况不合法无法提取(边界)
输入:"联系我:john@example.com"
输出:"john@example.com
good prompt:
输入:"联系我:john@example.com"
输出:"john@example.com"
输入:"没有邮箱"
输出:null
输入:"多个邮箱:a@test.com 和 b@test.com"
输出:["a@test.com", "b@test.com"]
输入:"无效格式:invalid@@test"
输出:null
3. 示例格式一致(整齐)
good prompt:
输入:"修复了登录bug"
输出:"fix(auth): resolve login issue"
输入:"新增用户头像功能"
输出:"feat(user): add avatar upload feature"
输入:"更新文档"
输出:"docs: update README"
现在处理:[...]
4. (2)-(5)个示例最佳(少样本):
2-3个示例: 大多数情况最佳(格式统一)[代表性例子+展示边界情况]
4-5个示例: 复杂任务或展示变化
其他技巧:
- 渐进式示例(难度递增): 示例中有递进的顺序(可以通过打分如: 9分->6分->5分->3分-> -1分 -> -3分)
- 对比示例(展示好与坏的示例): 分别展示正确与错误的例子
- 带解释的示例: 示例中带有评分+理由,让AI学习打分标准
- 变体示例(复杂): 展示多种错误相应的情况
个人心得:
scss
在有好的示例的情况下,在提示词中加入示例可以让AI更准确地理解意图并输出高质量、稳定的回答。
重点在于在相关问题学习中积累好的示例:具有代表性的示例、边界情况的示例、正反对比的实例、带解释(打分+理由)的示例。同时,示例的格式一致更利于AI的学习和理解。
对于自己经常提问的相关领域,日常学习过程中总结积累好的示例。
3. 展示推理过程(Chain of Thought)
⭐核心原则: 让AI展示推理过程,而不是直接给出答案。
markdown
CoT, 即思维链 = 要求AI再给出最终答案前,展示自己的"思考过程"
将复杂的问题拆成小步骤,每步都可以验证,减少"直接错误"。 适用于复杂推理、代码调试、多步决策、因果分析等逻辑性比较强、比较复杂的任务。
*特别简单的问题不要使用CoT, 可能会导致简单问题复杂化甚至出错*
CoT实现方法:
python
1. 隐式CoT(最简单):
只需要在写好的提示词最后加一句: "让我们一步步思考" / "请逐步分析"
2. 显式CoT(结构化):
明确地告诉AI按照那几个特定步骤思考(需要自己对该问题有一定的分析思路)。
Prompt:
分析这段代码地性能问题。请按照以下步骤:
1. 识别代码的功能
2. 分析代码时间复杂度
3. 找出性能瓶颈
4. 提出优化方案
<code>
# 具体代码粘贴
</code>
3. Few-shot + CoT:
通过给一个具体例子来展示思考过程。
Prompt:
诊断代码bug。请参考以下示例的思考方式:
示例:
<code>
def get_first(items):
return items[0]
</code>
思考过程:
1. 功能:获取列表第一个元素
2. 假设:items不为空
3. 潜在问题:如果items为空列表?
4. 测试:get_first([]) → IndexError
5. 结论:缺少空列表检查
现在诊断下列这段代码:
<code>
def calculate_average(numbers):
total = sum(numbers)
return total / len(numbers)
</code>
其他技巧:
- 不同身份/多角度分析: +一句类似的话*"从以下角度分析:开发者角度/性能角度/维护角度"*
- 假设-验证技巧: +一句类似的话*"使用假设验证方法,步骤:推出3个可能的假设->对每个假设提供验证方法->给出最可能的原因->提供测试方案"*
- 对比技巧: 对比上述两种方法,分析优劣。 按照具体的对比维度(比如代码可以从:可读性/性能/溢出风险/适用场景...)
- 逆向推理:这段代码应该实现'某个功能',但是失败了,失败案例:<具体给出>. 请逆向推理: 预期正确行为->实际发生了什么->哪一行导致了问题,为什么->如何修复。
实战案例:
常用CoT的相关任务(数学推理/代码调试/系统决策设计/安全漏洞分析...)
markdown
1. 代码调试:
❌bad prompt:这段代码有bug吗?
⬇
✅good prompt:
分析这段代码潜在问题。请逐步检查:
1. 函数的预期行为
2. 输入验证
3. 可能的运行时错误
4. 边界情况
2. 系统设计决策:
bad prompt: 我应该用Redis还是Memcached做缓存?
good prompt: 设计思路(需求[选项]+分步骤按照多个维度来分析)
我需要为一个电商网站选择缓存方案,候选是Redis和Memcached。
需求背景:
- 缓存用户会话、商品信息、购物车
- 预计并发1万用户
- 需要持久化(防止重启丢失)
- 未来可能需要排行榜功能
请按以下维度分析:
1. 我的具体需求
2. 两者的关键差异
3. 针对我的场景的优劣
4. 最终推荐
个人心得:
scss
CoT适合于逻辑性比较强(一步一步推理)、比较复杂的问题,过于简单的问题不用使用CoT(甚至可能会导致出错)。
写出好的CoT的提示词需要自身对相关问题有一定的分析方式和思路,比如代码调试这一块,需要知道可以从函数预期行为、时间空间复杂度、可能出现的错误、边界情况等几个角度出发。
可以多多参考相关问题的好的CoT模板,或者自己在日常学习中多总结自己相关领域的思维链或者分析思路模板。
e.g.常设设计的问题: 代码调试/数学、物理等理科题推导/做技术决策问题
4. 使用XML标签(Use XML Tags)
⭐核心原则: 使用XML标签结构化复杂的输入和输出
css
XML标签是用类似HTML的标签包裹不同类型的内容,可以理解为以一种标准化的格式来写Prompt,这样可以让AI更加清晰的区分:
指令vs数据; 不同类型的数据; 输入vs输出格式.
XML标签适用于: 有多个输入源、复杂嵌套数据、指令和数据混合、明确输出格式等复杂的输入。
本质上是将复杂输入用一种标准形式写,让AI更好理解需求。
XML标签写法:
xml
# 基本语法:
1.最基本的结构:
<tag_name>
具体内容
</tag_name>
# 用<name>表示开始, </name>表示结束,name可以自行命名类似与具体内容的概况or标题1
2. 自闭合标签: 只带标题无内容(可以让AI从这方面自行考虑)
<tag_name/>
3. 带属性的标签: 相关内容的参数
<tag_name attribute="value">
内容
</tag_name>
# Claude 推荐的好的标签命名:
1. 小写字母 + 用下划线分割,如:user_feedback
2. 或者驼峰命名法,如:userFeedback
3. 描述性: 标签名要概括性说明具体内容或者说明内容类型
4. 一致性: 同一个prompt中标签风格要统一
!!! 简单的问题不需要使用XML来复杂化、标签注意要闭合、不要过度嵌套标签。
其他技巧:
xml
- 嵌套标签来表示层级:类似与分层(用空格来表示大小)
e.g.
<project>
<module name="auth">
<file name="login.py">
<function name="authenticate">
<issue severity="high">
缺少SQL注入防护
</issue>
</function>
</file>
</module>
<module name="api">
...
- 使用带属性的标签,可以添加一些附加信息
- 强制AI以XML标记输出格式:
加上这句话:
你的输出必须严格遵循这个格式:
<required_output_format>
<analysis>
<summary>一句话总结</summary>
<issues>
<issue priority="high|medium|low">
<description>问题描述</description>
<location>行号或函数名</location>
<suggestion>修复建议</suggestion>
</issue>
</issues>
<overall_score>1-10分</overall_score>
</analysis>
</required_output_format>
- 注意XML中不要带指令性文字。
XML中<> </>之间内容会标记为数据,而指令内容比如:分析/忽略...指令要写在XML格式之后的部分。
实战案例:
xml
# 多步骤处理问题
Prompt(带XML版本):
对以下技术文档进行翻译处理: # 指令语句不需要带<>
<source_text lang="zh-CN"> # 带属性
Python是一种高级编程语言,具有简洁的语法和强大的功能。
它广泛应用于Web开发、数据分析、人工智能等领域。
</source_text>
# 分步骤操作 step1.2.3(XML格式)
<processing_steps>
<step id="1" name="translate">
翻译为英文,保持技术术语准确
</step>
<step id="2" name="review">
检查翻译质量:
- 术语准确性
- 语法正确性
- 自然流畅度
</step>
<step id="3" name="format">
格式化为技术文档风格:
- 每句独立一段
- 专业术语使用斜体
</step>
</processing_steps>
# 输出格式
<output_format>
<step_outputs>
<step_1_translation>...</step_1_translation>
<step_2_review>...</step_2_review>
<step_3_formatted>...</step_3_formatted>
</step_outputs>
</output_format>
个人心得:
scss
使用XML标签方法在处理[有多种不同类型输入][需要区分指令和数据][数据之间有层级关系][有输出格式要求]等输入需求有明显的优势。
实际上可以认为是用一种更标准的格式来输入,<></>来包含数据,标签命名需要与具体内容相关,带有描述性(简单易懂).
XML标签适用于与其他方法组合使用,如Few-shot(<example>来显示示例)、 CoT(用XML格式了分步骤step1.2.3)
5.设定角色(Give a Role)
⭐核心原则:通过角色设定来影响AI的行为和输出风格
sql
角色设定(Role Prompting) = 让AI扮演某个特定角色,让它从角色的视角思考和回答。
System Prompt *vs* User prompt
- System Prompt:对话开始前,给AI设定的"身份"和"行为规则"
在整个对话生效、用户通常看不到、优先级高(通常是调用API时设置)
- User Prompt:在对话中对AI的设定
如,在对话Prompt中直接说明:
你是一位资深Python开发者, 请审查以下代码:
<code>...
PS.这里的给定角色设定通常是在对话中根据特殊需求给定的设定(属于User prompt)
角色设定的要素:
bash
!!! 核心原则是要设定要具体详细+清晰(特别要针对所问问题专业对口)
1. 专业领域 + 技能专长 设定(一定要详细)
"角色和技能一定要清晰具体,角色要和任务相匹配"
❌ 坏例子:你是一个工程师。
✅ 好例子:你是一位有10年经验的后端工程师,专注于分布式系统和微服务架构。 # 具体到工作经验和工作的细分领域
❌ 坏例子:你懂数据科学。
✅ 好例子:你是数据科学家,擅长机器学习模型调优和特征工程。你熟悉Python、scikit-learn、Pytorch # 精细到技能和擅长相关库
2. 沟通风格
"风格不要抽象,要具体来描述,最好可以用示例来展示"
❌ 坏例子:你要友好一点。
✅ 好例子:你是一位友善的技术导师,善于用简单的类比解释复杂概念。你的回答简洁但完整,面向初学者。
3. 工作目标
"目标清晰具体,目标与角色设定相匹配"
❌ 坏例子:你要帮助别人。
✅ 好例子:你是代码审查专家,目标是帮助团队提高代码质量。你会指出潜在bug、性能问题和可维护性问题。
其他技巧:
- 多重角色: 设计不同的角色从不同视角来分析问题。 e.g.对于一个API设计,可以从"开发者","安全专家","运维工程师"...多个角度分析评估
- 角色+约束:在设定角色后约束角色的行为,比如写代码只能用Python标准库、保证代码通俗易懂...
- 负面角色: 告诉AI不要成为什么, 正反对比加强AI身份认识。
个人心得:
scss
角色设定,特别是User Prompt,我们在日常对话中也经常使用。在面对比较复杂的问题(例如:让AI带你深入学习某个领域/让AI调试代码or写一段相关代码),一个合适的角色设定比较重要。
角色设定的根本原则是要清晰具体,具体阐述这个角色的身份、技能、沟通风格以及工作目标(最好可以通过示例来具体展示)。
总结or直接套用好的角色模板来进行相同领域的学习(比如写代码/做规划/审查评估)效果比较好。
6. 预填充(Prefill Response)
⭐核心原则: 预填充的输出开头,精确的控制格式和内容
ini
Prefill = 在API调用中,预先填写AI回复的开头几个字,强制AI按照指定格式继续输出。
通常是在API调用中使用,等于你先预设值好AI输出的前几个字,然AI接着你设定好的内容往下输出。
Prefill实现方式(API调用):
ini
# API调用(常用) ⭐
import anthropic
client = anthropic.Anthropic(api_key="your-key")
response = client.messages.create(
model="clade-3-5-sonnet-20241022", # 选择调用的模型
max_tokens=1024, # 最大上下文
messages=[
{
"role": "user",
"content": "将以下文本分类为:正面、负面、中性\n\n文本:这个产品还不错。" # 相当于输入的内容,网页版对话中写的Prompt
}
{
"role": "assistant",
"content": "分类:" # AI的输出, 与填充了 "分类:"
}
]
)
# 这样会强制AI输出是从"分类:..."开始
# 不使用Prefill, 可能输出:"好的,让我来分析一下。这个评价是正面的。"
# 使用Prefill,输出:"分类:正面..."
erlang
网页版对话可以实现预填充类似的效果(只是模拟,但不能实现真正的Prefill)。
网页版本质上是通过Prompt引导AI按照特定格式输出,但是AI仍然可能加前言or不完全按照预填充格式输出。
核心区别:
真正的Prefill(API):
- 强制AI从指定内容开始
- AI"认为"是自己输出的开头
- 100%格式一致性
模拟Prefill(网页版Prompt技巧):
- 通过prompt引导AI输出
- AI仍然可能加前言
- 约85-95%格式一致性
总结:
erlang
六大核心原则:
- 清晰直接
- 2-5个示例
- 展示推理过程
- 使用XML标签
- 角色设定
- 预填充
首先最重要的是prompt要清晰直接,要详细地描述自己的需求,按照以下格式:
任务目标(总体说明要干什么) + 具体需求(从哪几个角度来分析问题,完成任务) + 输出格式(以什么形式输出) + 约束条件(不要用什么方法,不要包含什么...)
来详细具体的写明自身的需求。而后可以通过:
示例(Few-shot): 展示好的例子;
思维链(CoT):对于复杂的问题展示推理过程
XML标签: 复杂的输入用XML格式让输入分层次更清晰
角色设定: 设定具体的的角色来对应内容
预填充:API调用时强制输出格式。
上述方法可以根据需要选择多个一起混用,Prompt Engineering核心原则介绍如上,总这是一门偏实践的技术,重要的是在实际与大模型对话时可以通过上述的技巧获得自己满意(高质量,稳定)的回答。
后续会对应六个核心方法总结常问问题的的模板,感谢观看。