前言:提示词的力量
看两个例子:
普通提示词:
用户: 写一首诗
AI: 春风拂面暖阳照,花开满园香气飘。(平淡无奇)优化后的提示词:
用户: 请以李白的风格,写一首关于程序员深夜加班的七言绝句,
要有豪放不羁的气质,结尾要有反转。
AI: 代码千行夜未央,Bug 如山压脊梁。
他年若遂凌云志,敢笑产品需求狂。
(有风格、有主题、有反转)Prompt Engineering(提示词工程) = 设计最优的输入,让大模型输出最好的结果。
graph LR
subgraph 提示词的影响
P1[普通提示词] --> R1[普通结果]
P2[优化提示词] --> R2[优秀结果]
P3[专家提示词] --> R3[惊艳结果]
end
style P3 fill:#4ecdc4
style R3 fill:#4ecdc4
一、Prompt 基础结构
1.1 Prompt 的组成部分
graph TB
subgraph Prompt结构
A[角色设定
Role] --> P[完整 Prompt] B[任务说明
Task] --> P C[上下文
Context] --> P D[输出格式
Format] --> P E[示例
Examples] --> P F[约束条件
Constraints] --> P end
Role] --> P[完整 Prompt] B[任务说明
Task] --> P C[上下文
Context] --> P D[输出格式
Format] --> P E[示例
Examples] --> P F[约束条件
Constraints] --> P end
| 组件 | 作用 | 示例 |
|---|---|---|
| 角色 | 定义 AI 的身份 | "你是一位资深的 Python 开发者" |
| 任务 | 明确要做什么 | "请帮我优化以下代码的性能" |
| 上下文 | 提供背景信息 | "这段代码在处理百万级数据" |
| 格式 | 规定输出形式 | "请用 Markdown 格式输出" |
| 示例 | 展示期望的输出 | Few-shot examples |
| 约束 | 限制和要求 | "代码不超过 50 行" |
1.2 基础 Prompt 模板
BASIC_PROMPT_TEMPLATE = """
## 角色
{role}
## 任务
{task}
## 上下文
{context}
## 要求
{requirements}
## 输出格式
{output_format}
## 输入
{input}
"""
# 示例使用
prompt = BASIC_PROMPT_TEMPLATE.format(
role="你是一位专业的技术文档撰写者,擅长将复杂概念简单化。",
task="请将以下技术概念解释给非技术人员听。",
context="读者是公司的市场部门员工,没有编程背景。",
requirements="""
- 使用生活中的类比
- 避免专业术语
- 控制在 200 字以内
""",
output_format="一段通俗易懂的解释文字",
input="什么是 API?",
)1.3 System Prompt vs User Prompt
# OpenAI API 中的角色区分
messages = [
{
"role": "system", # System Prompt:设定 AI 的行为
"content": """你是一个专业的代码审查助手。
你的职责是:
1. 发现代码中的潜在问题
2. 提供改进建议
3. 解释问题的原因
始终保持友好、专业的态度。"""
},
{
"role": "user", # User Prompt:具体的请求
"content": "请审查以下 Python 代码:\n```python\ndef add(a, b):\n return a + b\n```"
}
]区别:
- System Prompt:定义 AI 的"人格"和行为规范,全局生效
- User Prompt:具体的任务请求,每次对话可能不同
二、核心 Prompting 技术
2.1 Zero-Shot Prompting
不给示例,直接提问:
# Zero-Shot:直接问
prompt = "将以下英文翻译成中文:Hello, how are you?"
# 效果取决于任务复杂度
# 简单任务:效果好
# 复杂任务:可能不稳定2.2 Few-Shot Prompting
给几个示例,让模型学习模式:
# Few-Shot:给示例
prompt = """将英文翻译成中文,保持口语化风格。
示例:
English: What's up?
中文: 怎么了?/ 最近咋样?
English: No worries!
中文: 没事儿!/ 别担心!
English: I'm gonna grab some coffee.
中文: 我去买杯咖啡。
现在翻译这句:
English: Let me think about it.
中文:"""
# 输出: 让我想想。/ 我考虑一下。Few-Shot 最佳实践:
- 示例数量:3-5 个通常足够
- 示例质量:要有代表性,覆盖不同情况
- 示例顺序:从简单到复杂
- 格式一致:所有示例格式相同
2.3 Chain-of-Thought (CoT)
让模型展示推理过程:
# 普通提问
prompt_basic = "小明有 5 个苹果,给了小红 2 个,又买了 3 个,现在有几个?"
# 可能直接给出答案,有时会错
# Chain-of-Thought
prompt_cot = """小明有 5 个苹果,给了小红 2 个,又买了 3 个,现在有几个?
请一步一步思考:"""
# 输出:
# 让我一步一步计算:
# 1. 小明最初有 5 个苹果
# 2. 给了小红 2 个,剩下 5 - 2 = 3 个
# 3. 又买了 3 个,现在有 3 + 3 = 6 个
#
# 所以小明现在有 6 个苹果。Zero-Shot CoT:只需加一句"让我们一步一步思考"
prompt = """复杂问题...
让我们一步一步思考(Let's think step by step):"""2.4 Self-Consistency
多次采样,选择最一致的答案:
import collections
def self_consistency(prompt: str, n_samples: int = 5) -> str:
"""Self-Consistency:多数投票"""
answers = []
for _ in range(n_samples):
# 使用较高的 temperature 增加多样性
response = llm.generate(prompt, temperature=0.7)
answer = extract_final_answer(response)
answers.append(answer)
# 多数投票
counter = collections.Counter(answers)
most_common = counter.most_common(1)[0][0]
return most_common
# 使用
prompt = "某数学问题... 让我们一步一步思考:"
final_answer = self_consistency(prompt, n_samples=5)2.5 Tree-of-Thoughts (ToT)
更复杂的推理,探索多个思路:
graph TB
Q[问题] --> T1[思路1]
Q --> T2[思路2]
Q --> T3[思路3]
T1 --> T1a[展开]
T1 --> T1b[展开]
T2 --> T2a[展开]
T1a --> E1[评估: 好]
T1b --> E2[评估: 差]
T2a --> E3[评估: 中]
E1 --> A[最终答案]
style E1 fill:#4ecdc4
style A fill:#4ecdc4
def tree_of_thoughts(problem: str, breadth: int = 3, depth: int = 3):
"""Tree-of-Thoughts 推理"""
def generate_thoughts(state: str, n: int) -> list:
"""生成多个思路"""
prompt = f"""问题: {problem}
当前状态: {state}
请提出 {n} 个不同的下一步思路:"""
response = llm.generate(prompt)
return parse_thoughts(response)
def evaluate_thought(thought: str) -> float:
"""评估思路的质量"""
prompt = f"""评估以下思路对于解决问题的帮助程度(1-10分):
问题: {problem}
思路: {thought}
只输出分数:"""
score = float(llm.generate(prompt).strip())
return score
# BFS 搜索
current_states = [""]
for d in range(depth):
candidates = []
for state in current_states:
thoughts = generate_thoughts(state, breadth)
for thought in thoughts:
score = evaluate_thought(thought)
candidates.append((state + "\n" + thought, score))
# 保留最好的几个
candidates.sort(key=lambda x: x[1], reverse=True)
current_states = [c[0] for c in candidates[:breadth]]
# 返回最佳路径
return current_states[0]三、高级 Prompting 技术
3.1 ReAct Prompting
结合推理和行动(已在 Agent 篇详细介绍):
REACT_PROMPT = """回答问题时,请按以下格式:
思考: 分析问题,决定下一步
行动: 工具名[参数]
观察: 工具返回结果
... (重复直到得到答案)
答案: 最终答案
可用工具:
- search[query]: 搜索信息
- calculate[expression]: 计算数学表达式
问题: {question}
思考:"""3.2 Prompt Chaining
将复杂任务拆分成多个步骤:
def prompt_chaining(article: str) -> dict:
"""Prompt Chaining 示例:文章分析流水线"""
# Step 1: 提取关键信息
step1_prompt = f"""从以下文章中提取关键信息:
文章: {article}
请提取:
1. 主题
2. 主要观点(列表)
3. 关键人物/组织
4. 时间节点
以 JSON 格式输出:"""
key_info = json.loads(llm.generate(step1_prompt))
# Step 2: 分析情感和立场
step2_prompt = f"""基于以下信息,分析文章的情感和立场:
关键信息: {json.dumps(key_info, ensure_ascii=False)}
请分析:
1. 整体情感(正面/负面/中性)
2. 作者立场
3. 论证强度
以 JSON 格式输出:"""
sentiment = json.loads(llm.generate(step2_prompt))
# Step 3: 生成摘要
step3_prompt = f"""基于以下分析,生成一段 100 字以内的摘要:
关键信息: {json.dumps(key_info, ensure_ascii=False)}
情感分析: {json.dumps(sentiment, ensure_ascii=False)}
摘要:"""
summary = llm.generate(step3_prompt)
return {
"key_info": key_info,
"sentiment": sentiment,
"summary": summary,
}3.3 Least-to-Most Prompting
从简单子问题逐步解决复杂问题:
def least_to_most(complex_question: str) -> str:
"""Least-to-Most: 先分解,再逐步解决"""
# Step 1: 分解问题
decompose_prompt = f"""将以下复杂问题分解为更简单的子问题:
问题: {complex_question}
子问题列表(从简单到复杂):"""
subquestions = llm.generate(decompose_prompt).strip().split("\n")
# Step 2: 逐步解决
context = ""
for sq in subquestions:
solve_prompt = f"""已知信息:
{context}
请回答: {sq}"""
answer = llm.generate(solve_prompt)
context += f"\n问: {sq}\n答: {answer}\n"
# Step 3: 整合最终答案
final_prompt = f"""基于以下解答,回答原问题:
{context}
原问题: {complex_question}
最终答案:"""
return llm.generate(final_prompt)3.4 Directional Stimulus Prompting
给模型一个"方向性提示":
# 普通提示
prompt_basic = "写一个关于创业的故事"
# Directional Stimulus
prompt_ds = """写一个关于创业的故事。
提示词/关键元素:
- 车库创业
- 技术突破
- 资金危机
- 峰回路转
- 上市敲钟
请围绕这些元素展开故事:"""
# 输出会更聚焦、更有结构3.5 Emotion Prompting
加入情感元素,提升效果:
# 研究发现,加入情感表达可以提升 LLM 的表现
# 普通版
prompt_basic = "请帮我检查这段代码的错误。"
# Emotion Prompting
prompt_emotion = """请帮我检查这段代码的错误。
这对我非常重要,因为这是我第一次独立完成的项目,
我真的很希望它能够正常工作。请尽可能仔细地帮我审查。"""
# 另一种方式
prompt_emotion2 = """请帮我检查这段代码的错误。
你的仔细检查将极大地帮助我提升编程水平,我会非常感激!"""四、Prompt 优化策略
4.1 清晰明确
# ❌ 模糊的提示
bad_prompt = "帮我写点东西"
# ✅ 清晰的提示
good_prompt = """请帮我写一封工作邮件,具体要求:
- 收件人:部门经理
- 主题:申请下周一在家办公
- 原因:需要等待家里的装修工人
- 语气:正式但友好
- 长度:100-150字"""4.2 结构化输出
# 要求结构化输出,便于程序解析
prompt = """分析以下用户评论的情感。
评论: "这个产品还不错,但物流太慢了"
请以 JSON 格式输出,包含以下字段:
{
"overall_sentiment": "正面/负面/中性",
"aspects": [
{"aspect": "方面", "sentiment": "情感", "reason": "原因"}
],
"confidence": 0-1之间的置信度
}
只输出 JSON,不要其他内容:"""4.3 使用分隔符
# 使用分隔符区分不同部分
prompt = """请根据以下上下文回答问题。
###上下文###
{context}
###问题###
{question}
###要求###
- 只根据上下文回答
- 如果上下文中没有相关信息,说"无法回答"
- 回答要简洁
###回答###"""4.4 指定输出长度
# 明确长度要求
prompts = {
"简短": "用一句话总结这篇文章",
"中等": "用 100 字左右总结这篇文章",
"详细": "用 300-500 字详细总结这篇文章,包括主要观点和论据",
}4.5 角色扮演
# 设定专业角色,获得更专业的回答
roles = {
"医生": "你是一位有 20 年经验的全科医生,擅长用通俗语言解释医学概念",
"律师": "你是一位资深律师,擅长分析法律问题并给出实用建议",
"教师": "你是一位耐心的老师,擅长用简单例子解释复杂概念",
"程序员": "你是一位 10 年经验的高级工程师,精通代码优化和架构设计",
}
prompt = f"""{roles['程序员']}
请审查以下代码,找出潜在的性能问题和安全漏洞:
{code}
五、实用 Prompt 模板库
5.1 代码相关
CODE_PROMPTS = {
# 代码审查
"review": """作为高级代码审查者,请审查以下代码:
{code}
请从以下方面给出建议:
1. 代码质量和可读性
2. 潜在的 bug
3. 性能优化
4. 安全问题
5. 最佳实践
请用中文回答,给出具体的改进建议和示例代码。""",
# 代码解释
"explain": """请详细解释以下代码的功能:
{code}
要求:
1. 整体功能概述
2. 逐行/逐块解释
3. 关键算法说明
4. 使用场景举例""",
# 代码生成
"generate": """请用 {language} 实现以下功能:
{description}
要求:
1. 代码清晰、有注释
2. 包含错误处理
3. 提供使用示例
4. 说明时间/空间复杂度""",
# Debug
"debug": """以下代码出现了问题:
{code}
错误信息:
{error}
请:
1. 分析错误原因
2. 提供修复方案
3. 解释为什么会出现这个问题
4. 如何避免类似问题""",
}5.2 写作相关
WRITING_PROMPTS = {
# 文章写作
"article": """请写一篇关于"{topic}"的文章。
要求:
- 字数:{word_count}字左右
- 风格:{style}
- 受众:{audience}
- 结构:引言、正文(3个要点)、结论
请确保内容专业、有深度,同时易于理解。""",
# 摘要
"summary": """请为以下内容生成摘要:
{content}
要求:
- 长度:{length}字以内
- 保留关键信息
- 语言简洁
- 客观中立""",
# 改写
"rewrite": """请按照以下要求改写这段文字:
原文:
{original}
改写要求:
- 风格:{style}
- 保持原意
- 语言更{tone}
改写后:""",
# 邮件
"email": """请帮我写一封{type}邮件:
收件人:{recipient}
目的:{purpose}
关键信息:{key_points}
语气:{tone}
邮件内容:""",
}5.3 分析相关
ANALYSIS_PROMPTS = {
# 情感分析
"sentiment": """分析以下文本的情感:
"{text}"
请输出 JSON 格式:
{{
"sentiment": "positive/negative/neutral",
"confidence": 0.0-1.0,
"keywords": ["关键词列表"],
"explanation": "分析解释"
}}""",
# 实体提取
"ner": """从以下文本中提取命名实体:
"{text}"
请提取:
- 人名
- 地点
- 组织
- 时间
- 数字
以 JSON 格式输出:""",
# 分类
"classify": """将以下文本分类到最合适的类别:
文本:"{text}"
可选类别:{categories}
输出格式:
{{
"category": "类别",
"confidence": 0.0-1.0,
"reason": "分类理由"
}}""",
# 关键词提取
"keywords": """提取以下文本的关键词:
"{text}"
要求:
- 提取 {n} 个最重要的关键词
- 按重要性排序
- 输出格式:["keyword1", "keyword2", ...]""",
}5.4 Prompt 管理类
class PromptManager:
"""Prompt 管理器"""
def __init__(self):
self.prompts = {}
self.load_default_prompts()
def load_default_prompts(self):
"""加载默认提示词"""
self.prompts.update(CODE_PROMPTS)
self.prompts.update(WRITING_PROMPTS)
self.prompts.update(ANALYSIS_PROMPTS)
def get(self, name: str, **kwargs) -> str:
"""获取并填充提示词"""
if name not in self.prompts:
raise ValueError(f"Unknown prompt: {name}")
template = self.prompts[name]
return template.format(**kwargs)
def add(self, name: str, template: str):
"""添加新的提示词模板"""
self.prompts[name] = template
def list_prompts(self) -> list:
"""列出所有可用的提示词"""
return list(self.prompts.keys())
# 使用
pm = PromptManager()
# 代码审查
review_prompt = pm.get(
"review",
language="python",
code="def add(a, b): return a + b"
)
# 写邮件
email_prompt = pm.get(
"email",
type="请假",
recipient="直属领导",
purpose="申请下周一到周三的年假",
key_points="需要处理家庭事务",
tone="正式、礼貌",
)六、Prompt 调试与优化
6.1 迭代优化流程
flowchart TB
A[初始 Prompt] --> B[测试]
B --> C{效果满意?}
C -->|否| D[分析问题]
D --> E[调整 Prompt]
E --> B
C -->|是| F[记录最佳版本]
F --> G[边缘测试]
G --> H{鲁棒性OK?}
H -->|否| D
H -->|是| I[完成]
6.2 常见问题与解决
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 输出格式不对 | 格式要求不清晰 | 给出明确的格式示例 |
| 内容不相关 | 任务描述模糊 | 更具体地描述任务 |
| 输出太长/太短 | 没有长度限制 | 明确指定字数范围 |
| 风格不对 | 没有指定风格 | 添加风格描述或示例 |
| 幻觉/编造 | 没有约束 | 加入"只使用提供的信息" |
| 拒绝回答 | 触发安全限制 | 调整措辞,说明正当目的 |
6.3 A/B 测试
import random
from typing import Callable
class PromptABTest:
"""Prompt A/B 测试"""
def __init__(self, llm_client):
self.client = llm_client
self.results = {"A": [], "B": []}
def test(
self,
prompt_a: str,
prompt_b: str,
test_inputs: list,
evaluate_fn: Callable,
) -> dict:
"""运行 A/B 测试"""
for test_input in test_inputs:
# 随机选择版本
version = random.choice(["A", "B"])
prompt = prompt_a if version == "A" else prompt_b
# 生成结果
response = self.client.generate(prompt.format(input=test_input))
# 评估
score = evaluate_fn(test_input, response)
self.results[version].append(score)
# 统计结果
return {
"A": {
"count": len(self.results["A"]),
"avg_score": sum(self.results["A"]) / len(self.results["A"]),
},
"B": {
"count": len(self.results["B"]),
"avg_score": sum(self.results["B"]) / len(self.results["B"]),
},
}
# 使用示例
ab_test = PromptABTest(llm_client)
prompt_a = "总结这篇文章:{input}"
prompt_b = """作为专业编辑,请为以下文章写一段 50 字的摘要,
突出核心观点和关键数据:
{input}
摘要:"""
results = ab_test.test(
prompt_a,
prompt_b,
test_inputs=articles,
evaluate_fn=lambda inp, out: rate_summary_quality(out),
)
print(f"Prompt A 平均得分: {results['A']['avg_score']:.2f}")
print(f"Prompt B 平均得分: {results['B']['avg_score']:.2f}")6.4 Prompt 版本管理
import json
from datetime import datetime
from dataclasses import dataclass, asdict
@dataclass
class PromptVersion:
"""Prompt 版本"""
name: str
version: str
template: str
description: str
created_at: str
performance_score: float = None
notes: str = ""
class PromptVersionControl:
"""Prompt 版本控制"""
def __init__(self, storage_path: str = "prompts.json"):
self.storage_path = storage_path
self.prompts = self.load()
def load(self) -> dict:
"""加载存储的 prompts"""
try:
with open(self.storage_path) as f:
return json.load(f)
except FileNotFoundError:
return {}
def save(self):
"""保存 prompts"""
with open(self.storage_path, 'w') as f:
json.dump(self.prompts, f, ensure_ascii=False, indent=2)
def add_version(self, prompt: PromptVersion):
"""添加新版本"""
key = f"{prompt.name}_v{prompt.version}"
self.prompts[key] = asdict(prompt)
self.save()
def get_latest(self, name: str) -> PromptVersion:
"""获取最新版本"""
versions = [k for k in self.prompts if k.startswith(name)]
if not versions:
return None
latest = sorted(versions)[-1]
return PromptVersion(**self.prompts[latest])
def get_best(self, name: str) -> PromptVersion:
"""获取性能最佳的版本"""
versions = [
PromptVersion(**v)
for k, v in self.prompts.items()
if k.startswith(name) and v.get('performance_score')
]
if not versions:
return None
return max(versions, key=lambda x: x.performance_score)
# 使用
pvc = PromptVersionControl()
# 保存新版本
pvc.add_version(PromptVersion(
name="summary",
version="1.0",
template="总结这篇文章:{input}",
description="基础版摘要提示词",
created_at=datetime.now().isoformat(),
performance_score=0.72,
))
pvc.add_version(PromptVersion(
name="summary",
version="1.1",
template="作为专业编辑,写一段 50 字摘要:{input}",
description="添加角色设定,限制长度",
created_at=datetime.now().isoformat(),
performance_score=0.85,
notes="A/B 测试显示提升明显",
))
# 获取最佳版本
best = pvc.get_best("summary")
print(f"最佳版本: {best.version}, 得分: {best.performance_score}")七、总结
Prompt Engineering 核心要点
mindmap
root((Prompt Engineering))
基础结构
角色
任务
上下文
格式
示例
核心技术
Zero-Shot
Few-Shot
Chain-of-Thought
Self-Consistency
Tree-of-Thoughts
优化策略
清晰明确
结构化输出
使用分隔符
指定长度
角色扮演
工程实践
模板管理
A/B测试
版本控制
迭代优化
关键 Takeaway
- Prompt = 与 AI 沟通的语言:好的提示词 = 好的结果
- 结构化是关键:角色 + 任务 + 上下文 + 格式 + 示例
- CoT 提升推理:让模型"一步一步思考"
- Few-Shot 很有效:给 3-5 个好例子
- 迭代优化:不断测试、改进、记录
- 建立模板库:积累可复用的优秀 Prompt
下一步学习
- [ ] LLM 评估:如何衡量效果
- [ ] 模型部署:生产环境最佳实践
- [ ] 安全对齐:避免有害输出
参考资料
- OpenAI Prompt Engineering Guide
- Chain-of-Thought 论文
- Tree-of-Thoughts 论文
- Anthropic Prompt Library
- LangChain Hub - Prompt 分享平台