前言
💡 痛点:LLM 回答不够准确?输出格式不稳定?复杂任务总是遗漏关键点?
🎯 解决方案:Prompt Engineering --- 精确的提示工程设计,让 LLM 发挥最大潜力。
#mermaid-svg-RtgUMXek1MyjXw3X{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RtgUMXek1MyjXw3X .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RtgUMXek1MyjXw3X .error-icon{fill:#552222;}#mermaid-svg-RtgUMXek1MyjXw3X .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RtgUMXek1MyjXw3X .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RtgUMXek1MyjXw3X .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RtgUMXek1MyjXw3X .marker.cross{stroke:#333333;}#mermaid-svg-RtgUMXek1MyjXw3X svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RtgUMXek1MyjXw3X p{margin:0;}#mermaid-svg-RtgUMXek1MyjXw3X .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RtgUMXek1MyjXw3X .cluster-label text{fill:#333;}#mermaid-svg-RtgUMXek1MyjXw3X .cluster-label span{color:#333;}#mermaid-svg-RtgUMXek1MyjXw3X .cluster-label span p{background-color:transparent;}#mermaid-svg-RtgUMXek1MyjXw3X .label text,#mermaid-svg-RtgUMXek1MyjXw3X span{fill:#333;color:#333;}#mermaid-svg-RtgUMXek1MyjXw3X .node rect,#mermaid-svg-RtgUMXek1MyjXw3X .node circle,#mermaid-svg-RtgUMXek1MyjXw3X .node ellipse,#mermaid-svg-RtgUMXek1MyjXw3X .node polygon,#mermaid-svg-RtgUMXek1MyjXw3X .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RtgUMXek1MyjXw3X .rough-node .label text,#mermaid-svg-RtgUMXek1MyjXw3X .node .label text,#mermaid-svg-RtgUMXek1MyjXw3X .image-shape .label,#mermaid-svg-RtgUMXek1MyjXw3X .icon-shape .label{text-anchor:middle;}#mermaid-svg-RtgUMXek1MyjXw3X .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RtgUMXek1MyjXw3X .rough-node .label,#mermaid-svg-RtgUMXek1MyjXw3X .node .label,#mermaid-svg-RtgUMXek1MyjXw3X .image-shape .label,#mermaid-svg-RtgUMXek1MyjXw3X .icon-shape .label{text-align:center;}#mermaid-svg-RtgUMXek1MyjXw3X .node.clickable{cursor:pointer;}#mermaid-svg-RtgUMXek1MyjXw3X .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RtgUMXek1MyjXw3X .arrowheadPath{fill:#333333;}#mermaid-svg-RtgUMXek1MyjXw3X .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RtgUMXek1MyjXw3X .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RtgUMXek1MyjXw3X .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RtgUMXek1MyjXw3X .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RtgUMXek1MyjXw3X .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RtgUMXek1MyjXw3X .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RtgUMXek1MyjXw3X .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RtgUMXek1MyjXw3X .cluster text{fill:#333;}#mermaid-svg-RtgUMXek1MyjXw3X .cluster span{color:#333;}#mermaid-svg-RtgUMXek1MyjXw3X div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RtgUMXek1MyjXw3X .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RtgUMXek1MyjXw3X rect.text{fill:none;stroke-width:0;}#mermaid-svg-RtgUMXek1MyjXw3X .icon-shape,#mermaid-svg-RtgUMXek1MyjXw3X .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RtgUMXek1MyjXw3X .icon-shape p,#mermaid-svg-RtgUMXek1MyjXw3X .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RtgUMXek1MyjXw3X .icon-shape .label rect,#mermaid-svg-RtgUMXek1MyjXw3X .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RtgUMXek1MyjXw3X .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RtgUMXek1MyjXw3X .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RtgUMXek1MyjXw3X :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 高手
角色 + 上下文 + 格式 + 示例 + 约束
精确输出: 可执行的完整代码
菜鸟
问: 写个代码
答: 写了一堆泛泛的
为什么需要 Prompt Engineering?
| 问题 | 效果 | 解决 |
|---|---|---|
| 输出格式乱 | ❌ JSON 缺字段 | ✅ 结构化提示 + 示例 |
| 推理错误 | ❌ 算错数学题 | ✅ Chain-of-Thought |
| 遗漏指令 | ❌ 只回答了部分问题 | ✅ 清单式提示 |
| 幻觉严重 | ❌ 编造不存在的事实 | ✅ Few-shot + 约束 |
一、Prompt 核心要素
1.1 六大要素
python
# ===== Prompt 要素框架 =====
from typing import List, Optional, Dict, Any
from dataclasses import dataclass, field
@dataclass
class PromptElement:
"""Prompt 要素"""
pass
@dataclass
class SystemMessage(PromptElement):
"""系统角色设定"""
content: str
def format(self) -> str:
return f"系统: {self.content}"
@dataclass
class Context(PromptElement):
"""上下文信息"""
content: str
def format(self) -> str:
return f"背景信息:\n{self.content}"
@dataclass
class Instruction(PromptElement):
"""明确指令"""
steps: List[str]
def format(self) -> str:
steps = "\n".join([f"{i+1}. {s}" for i, s in enumerate(self.steps)])
return f"请按以下步骤执行:\n{steps}"
@dataclass
class Examples(PromptElement):
"""Few-shot 示例"""
pairs: List[Dict[str, str]]
def format(self) -> str:
parts = ["示例:"]
for i, pair in enumerate(self.pairs, 1):
parts.append(f"\n示例{i}:")
parts.append(f"输入: {pair['input']}")
parts.append(f"输出: {pair['output']}")
return "\n".join(parts)
@dataclass
class Constraints(PromptElement):
"""约束条件"""
rules: List[str]
def format(self) -> str:
rules = "\n".join([f"- {r}" for r in self.rules])
return f"约束:\n{rules}"
@dataclass
class OutputFormat(PromptElement):
"""输出格式要求"""
format_spec: str
def format(self) -> str:
return f"输出格式:\n{self.format_spec}"
class PromptBuilder:
"""Prompt 构建器"""
def __init__(self):
self.elements: List[PromptElement] = []
def add_system(self, content: str) -> "PromptBuilder":
self.elements.append(SystemMessage(content))
return self
def add_context(self, content: str) -> "PromptBuilder":
self.elements.append(Context(content))
return self
def add_instruction(self, steps: List[str]) -> "PromptBuilder":
self.elements.append(Instruction(steps))
return self
def add_examples(self, pairs: List[Dict[str, str]]) -> "PromptBuilder":
self.elements.append(Examples(pairs))
return self
def add_constraints(self, rules: List[str]) -> "PromptBuilder":
self.elements.append(Constraints(rules))
return self
def add_output_format(self, format_spec: str) -> "PromptBuilder":
self.elements.append(OutputFormat(format_spec))
return self
def build(self) -> str:
"""构建最终 Prompt"""
return "\n\n".join([e.format() for e in self.elements])
def clear(self) -> "PromptBuilder":
self.elements.clear()
return self
# ===== 使用示例 =====
builder = PromptBuilder()
prompt = (builder
.add_system("你是资深的 Python 工程师,擅长编写高质量的代码。")
.add_context("项目是一个 RESTful API 服务")
.add_instruction([
"分析需求",
"设计接口",
"编写完整的实现代码",
"添加类型注解",
"添加错误处理"
])
.add_examples([
{
"input": "用户注册接口",
"output": "POST /api/users + 输入校验 + 密码加密"
}
])
.add_constraints([
"使用 FastAPI 框架",
"Python >= 3.10",
"包含单元测试"
])
.add_output_format("返回完整的 Python 代码文件,包含 import 和 main 入口")
.build()
)
二、角色提示
2.1 角色定义
python
# ===== 角色提示框架 =====
class RolePrompt:
"""角色提示管理器"""
ROLES = {
"expert": {
"system": "你是一个世界级的专家,拥有 20 年从业经验。",
"tone": "专业、精准、深入"
},
"teacher": {
"system": "你是一个耐心的老师,擅长用简单的语言解释复杂概念。",
"tone": "通俗易懂、循序渐进"
},
"mentor": {
"system": "你是资深的技术导师,不仅给答案还给方法论。",
"tone": "指导性、启发性"
},
"debugger": {
"system": "你是一个资深调试专家,善于追查 Bug 根因。",
"tone": "逻辑严谨、分步分析"
},
"architect": {
"system": "你是一个系统架构师,关注整体设计而非细节实现。",
"tone": "宏观、结构化"
},
"reviewer": {
"system": "你是一个代码审查专家,严格遵循最佳实践。",
"tone": "批判性、建设性"
}
}
@staticmethod
def create_role_prompt(role: str, task: str) -> str:
"""创建角色提示"""
role_config = RolePrompt.ROLES.get(role, RolePrompt.ROLES["expert"])
prompt = f"""你是[角色],请以该角色的方式完成以下任务。
[角色设定]
{role_config['system']}
语气风格:{role_config['tone']}
[任务]
{task}
[要求]
1. 始终保持角色身份
2. 以角色的专业视角分析问题
3. 输出风格符合角色设定"""
return prompt
三、Few-shot 与 Zero-shot
3.1 Zero-shot
python
# ===== Zero-shot Prompt =====
ZERO_SHOT_EXAMPLES = {
"分类": """
对以下文本进行分类,类别为: 技术、生活、娱乐、教育、其他
文本:量子计算将如何改变现代社会?
分类:技术
""",
"提取": """
从以下文本中提取所有日期。
文本:该计划将于2024年3月15日开始,第一阶段在6月底完成。
日期:2024-03-15, 2024-06-30
"""
}
# ===== Few-shot Prompt =====
FEW_SHOT_EXAMPLES = {
"情绪分析": """
文本:今天天气真好!
情绪:积极
文本:这个产品太差了,我再也不会买。
情绪:消极
文本:会议定在下午三点。
情绪:中性
文本:这部电影还不错,但是结局有点遗憾。
情绪:混合
文本:{input_text}
情绪:
"""
}
class ShotTypeSelector:
"""选择最适合的提示策略"""
@staticmethod
def should_use_few_shot(task_type: str, complexity: int = 5) -> bool:
"""判断是否需要 Few-shot"""
# 复杂度 > 7 或需要精确格式输出时使用 Few-shot
return complexity > 7 or task_type in ["分类", "提取", "格式化"]
@staticmethod
def optimal_shot_count(task_type: str) -> int:
"""Few-shot 最佳示例数量"""
shot_counts = {
"分类": 3, # 每个类别至少1个
"提取": 2, # 2个足够
"生成": 1, # 1个示例 + 详细指令
"推理": 2, # 2个 CoT 示例
"翻译": 1, # 1个示例
"总结": 2 # 2个不同长度的示例
}
return shot_counts.get(task_type, 2)
四、Chain-of-Thought 推理
4.1 CoT 策略
python
# ===== Chain-of-Thought =====
class ChainOfThought:
"""CoT 推理引擎"""
COT_TEMPLATES = {
"standard": "让我们一步步思考。\n\n{question}\n\n逐步推理:\n1.",
"few_shot": """
问题:小明有10个苹果,给了小红3个,又买了5个,现在有多少个?
推理:10 - 3 = 7,7 + 5 = 12
答案:12
问题:{question}
推理:""",
"tree": """
分析以下问题,列出所有可能的解决路径,选择最优方案。
问题:{question}
路径树:
1.
2.
3.
评估各路径后,最优方案是:""",
"reversed": """
从目标出发反向推导所需步骤。
目标:{goal}
反向推理:
- 要实现目标,需要先完成:...
- 要完成这个,需要先:...
- 最终需要的初始条件:...
"""
}
@staticmethod
def chain_of_thought(question: str, template: str = "standard") -> str:
"""生成 CoT Prompt"""
template_content = ChainOfThought.COT_TEMPLATES.get(
template, ChainOfThought.COT_TEMPLATES["standard"]
)
return template_content.format(question=question)
@staticmethod
def self_consistency(
question: str,
n_attempts: int = 3,
llm_client=None
) -> List[str]:
"""Self-Consistency: 多次生成取最优"""
if not llm_client:
return []
results = []
for i in range(n_attempts):
prompt = f"""用不同的推理路径解决以下问题。尽量使用不同的方法。
问题: {question}
第{i+1}种方法:"""
result = llm_client.generate(prompt)
results.append(result)
return results
# ===== CoT 实际场景示例 =====
class CodeReviewWithCoT:
"""用 CoT 做代码审查"""
def __init__(self, llm_client):
self.llm = llm_client
def review_code(self, code: str, language: str = "Python") -> str:
"""分步审查代码"""
prompt = f"""你是一个资深代码审查专家。请分步骤审查以下 {language} 代码。
代码:
```{language}
{code}
请按以下步骤分析:
- 首先,理解代码的整体功能是什么
- 检查是否存在逻辑错误
- 检查是否存在安全问题
- 检查性能问题
- 检查代码风格和可维护性
- 检查测试覆盖情况
- 总结:给出修复建议和优先级
逐步推理结果:"""
return self.llm.generate(prompt)
---
## 五、结构化输出
### 5.1 JSON 模式
```python
# ===== 结构化输出 =====
import json
from typing import List, Optional
from dataclasses import dataclass
from enum import Enum
class StructuredPrompt:
"""结构化输出 Prompt 模板"""
@staticmethod
def json_output(
schema: dict,
instruction: str,
context: str = ""
) -> str:
"""生成 JSON 输出 Prompt"""
schema_str = json.dumps(schema, indent=2, ensure_ascii=False)
prompt = f"""{instruction}
{context}
请严格按照以下 JSON Schema 输出结果:
```json
{schema_str}
要求:
- 只输出 JSON,不要加额外说明
- 确保 JSON 格式正确
- 字段名称严格匹配 Schema
- 所有字段都是必需
JSON 输出:
"""
return prompt
@staticmethod
def markdown_table(
headers: List[str],
instruction: str,
data_description: str
) -> str:
"""生成 Markdown 表格 Prompt"""
header_line = "| " + " | ".join(headers) + " |"
sep_line = "| " + " | ".join(["---"] * len(headers)) + " |"
prompt = f"""{instruction}
{data_description}
请按以下 Markdown 表格格式输出:
{header_line}
{sep_line}
| 数据1 | 数据2 | ... |
| ... | ... | ... |
确保:
-
表格格式正确
-
数据对齐准确
-
最少 5 行数据"""
return prompt
===== 实际场景:智能客服 =====
class CustomerServicePrompt:
"""客服系统 Prompt"""
@staticmethod
def classify_and_route() -> str:
"""分类 + 路由 Prompt"""
schema = {
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["售后", "物流", "退换货", "投诉", "咨询"]
},
"priority": {
"type": "string",
"enum": ["紧急", "高", "中", "低"]
},
"sentiment": {
"type": "string",
"enum": ["愤怒", "不满", "中性", "满意"]
},
"summary": {"type": "string"},
"suggested_reply": {"type": "string"},
"needs_escalation": {"type": "boolean"},
"department": {
"type": "string",
"enum": ["客服", "技术", "物流", "财务"]
}
},
"required": [
"category", "priority", "sentiment",
"summary", "needs_escalation", "department"
]
}
return StructuredPrompt.json_output(
schema=schema,
instruction="分析以下客户消息,分类并给出处理建议。",
context="客户消息:{customer_message}"
)
@staticmethod
def generate_reply_with_rules() -> str:
"""带规则的回复生成"""
return """
你是客服助手。请根据客户消息和规则生成回复。
规则
- 客服优先,不推诿
- 明确说明处理步骤
- 给出时间预期
- 提供备选方案
- 情绪安抚:共情 + 解决方案
上下文
客户: {customer_message}
历史: {chat_history}
分类: {category}
优先级: {priority}
回复格式
共情
{理解客户情绪}
问题确认
{确认客户问题}
解决方案
{具体步骤 + 时间节点}
备选方案
{如果方案A不行,方案B}
结束语
{友好的收尾}
"""
---
## 六、高级技巧
### 6.1 提示链
```python
# ===== 提示链 =====
from typing import List, Callable
class PromptChain:
"""提示链:将复杂任务分解为多个简单步骤"""
def __init__(self, llm_client):
self.llm = llm_client
self.steps: List[dict] = []
self.context: Dict[str, Any] = {}
def add_step(
self,
name: str,
prompt_template: str,
output_key: str,
parser: Optional[Callable] = None
) -> "PromptChain":
"""添加一步"""
self.steps.append({
"name": name,
"prompt": prompt_template,
"output_key": output_key,
"parser": parser
})
return self
def execute(self, initial_input: str) -> Dict[str, Any]:
"""执行整个链"""
results = {"input": initial_input}
for step in self.steps:
# 填充模板
prompt = step["prompt"].format(**results)
# 调用 LLM
raw_output = self.llm.generate(prompt)
# 解析
if step["parser"]:
parsed = step["parser"](raw_output)
else:
parsed = raw_output
results[step["output_key"]] = parsed
self.context[step["name"]] = parsed
return results
# ===== 实际场景:生成技术博客 =====
class BlogGeneratorWithPromptChain:
"""用提示链生成技术博客"""
def __init__(self, llm_client):
self.chain = PromptChain(llm_client)
self._build_chain()
def _build_chain(self):
"""构建提示链"""
self.chain \
.add_step(
name="outline",
prompt_template="""
你是一个技术博客作者。请根据以下主题生成博客大纲。
主题: {input}
大纲格式:
- 引言(说明问题背景和读者收获)
- 第1部分:
- 第2部分:
- ...
- 总结
""",
output_key="outline"
) \
.add_step(
name="introduction",
prompt_template="""
根据以下主题和大纲,编写博客的引言部分。
主题: {input}
大纲: {outline}
要求:
1. 500字以内
2. 说明痛点
3. 预告解决方案
4. 吸引读者继续阅读
""",
output_key="introduction"
) \
.add_step(
name="main_content",
prompt_template="""
根据以下信息编写博客正文(不含引言和总结)。
主题: {input}
大纲: {outline}
引言: {introduction}
要求:
1. 包含代码示例
2. 步骤清晰可执行
3. 有实际案例
4. 2000字以上
""",
output_key="main_content"
) \
.add_step(
name="conclusion",
prompt_template="""
根据以下内容编写博客总结部分。
主题: {input}
正文摘要: {main_content[:500]}
要求:
1. 300字以内
2. 总结要点
3. T行动建议
4. 引导读者尝试
""",
output_key="conclusion"
) \
.add_step(
name="full_blog",
prompt_template="""
将以下各部分组合成完整的博客文章。
引言: {introduction}
正文: {main_content}
总结: {conclusion}
输出完整的 Markdown 格式文章。
""",
output_key="full_blog"
)
def generate_blog(self, topic: str) -> str:
"""生成博客"""
result = self.chain.execute(topic)
return result["full_blog"]
6.2 思维树
python
# ===== Tree of Thoughts =====
class TreeOfThoughts:
"""思维树:探索多条推理路径"""
def __init__(self, llm_client, max_depth: int = 3, branch_factor: int = 3):
self.llm = llm_client
self.max_depth = max_depth
self.branch_factor = branch_factor
def solve(self, problem: str) -> Dict[str, Any]:
"""使用思维树解决问题"""
def evaluate_state(state: str, depth: int) -> float:
"""评估状态的可行性"""
prompt = f"""评估以下推理步骤对解决以下问题的可行性,给出 0-1 的评分。
问题: {problem}
当前推理: {state}
深度: {depth}/{self.max_depth}
评分标准:
- 1.0: 完全正确,接近答案
- 0.7: 方向正确,有希望
- 0.5: 不确定,需要更多探索
- 0.3: 不太对,但可能有用
- 0.0: 完全错误
只输出评分(一个数字):"""
response = self.llm.generate(prompt)
try:
return float(response.strip())
except ValueError:
return 0.5
def generate_branches(state: str, depth: int) -> List[str]:
"""生成下一步分支"""
prompt = f"""针对以下问题和当前推理状态,生成 {self.branch_factor} 种不同的下一步推理方向。
问题: {problem}
当前推理状态:
{state}
当前深度: {depth}
请生成 {self.branch_factor} 种不同的、合理的下一步推理。每个方向用一行,序号开头:"""
response = self.llm.generate(prompt)
branches = [
line.split(".", 1)[-1].strip()
for line in response.split("\n")
if line.strip() and (line[0].isdigit() or line.startswith("-"))
]
return branches[:self.branch_factor]
# BFS 搜索
queue = [("", 0, 0.5)] # (state, depth, score)
best_state = ""
best_score = 0
while queue:
state, depth, parent_score = queue.pop(0)
if depth >= self.max_depth:
if parent_score > best_score:
best_score = parent_score
best_state = state
continue
branches = generate_branches(state, depth)
for branch in branches:
new_state = f"{state}\n{branch}" if state else branch
new_depth = depth + 1
score = evaluate_state(new_state, new_depth)
queue.append((new_state, new_depth, score))
# 按评分排序,优先探索高评分路径
queue.sort(key=lambda x: -x[2])
# 限制搜索宽度
queue = queue[:5]
return {
"problem": problem,
"solution": best_state,
"score": best_score
}
6.3 ReAct 模式
python
# ===== ReAct: Reasoning + Acting =====
class ReActPrompt:
"""ReAct 提示模板"""
@staticmethod
def react_pattern(tools_description: str) -> str:
"""生成 ReAct 模式 Prompt"""
return f"""你是可以调用工具解决问题的智能助手。请遵循 Thought → Action → Observation 循环。
可用工具:
{tools_description}
## 循环格式
Thought: 分析当前状态,思考下一步需要做什么
Action: 选择要调用的工具和参数
Observation: 工具返回的结果
## 示例
Question: 北京今天的天气怎么样?
Thought: 我需要查询北京的天气信息
Action: get_weather(city="北京")
Observation: 北京今天 25°C,晴
Thought: 已获取天气信息,可以回答用户
Answer: 北京今天 25°C,天气晴朗。
## 开始
Question: {{question}}
"""
# ===== 实际场景:数据分析助手 =====
class DataAnalysisReAct:
"""数据分析 ReAct 助手"""
def __init__(self, llm_client, available_functions: dict):
self.llm = llm_client
self.functions = available_functions
self.history = []
def analyze(self, question: str, max_steps: int = 10) -> str:
"""执行数据分析"""
tools_desc = "\n".join([
f"- {name}: {func.__doc__}"
for name, func in self.functions.items()
])
prompt_template = ReActPrompt.react_pattern(tools_desc)
current_prompt = prompt_template.format(question=question)
for step in range(max_steps):
response = self.llm.generate(current_prompt)
if "Answer:" in response:
return response.split("Answer:", 1)[-1].strip()
if "Action:" in response:
action_line = [l for l in response.split("\n") if "Action:" in l][0]
action_text = action_line.split("Action:", 1)[-1].strip()
# 解析工具调用
tool_name = action_text.split("(")[0].strip()
tool_result = self._execute_tool(action_text)
current_prompt += f"\n{response}\nObservation: {tool_result}"
self.history.append({
"step": step,
"thought": response,
"action": action_text,
"observation": tool_result
})
return "抱歉,无法在指定步骤内解决问题。"
def _execute_tool(self, action_text: str) -> str:
"""执行工具调用"""
import re
match = re.match(r"(\w+)\((.+)\)", action_text)
if not match:
return "Error: 无效的工具调用格式"
tool_name = match.group(1)
args_str = match.group(2)
if tool_name not in self.functions:
return f"Error: 工具 {tool_name} 不存在"
try:
# 简单的参数解析(实际项目用 ast.literal_eval)
args = {}
if args_str:
for arg in args_str.split(","):
k, v = arg.split("=", 1)
args[k.strip()] = v.strip().strip('"\'')
result = self.functions[tool_name](**args)
return str(result)
except Exception as e:
return f"Error: {str(e)}"
七、评估与优化
7.1 Prompt 质量评估
python
# ===== Prompt 评估 =====
from typing import List, Tuple
class PromptEvaluator:
"""Prompt 质量评估"""
EVALUATION_DIMENSIONS = {
"clarity": "提示是否清晰、无歧义",
"specificity": "是否足够具体",
"constraints": "约束条件是否明确",
"examples": "示例是否相关且充分",
"format": "输出格式要求是否明确",
"context": "背景信息是否充分",
"role": "角色设定是否合适"
}
@staticmethod
def evaluate_prompt(prompt: str) -> Dict[str, float]:
"""评估 Prompt 质量(模拟评估)"""
scores = {}
# 1. 清晰度:是否有明确的目标
if "请" in prompt or "要求" in prompt:
scores["clarity"] = 0.8
else:
scores["clarity"] = 0.3
# 2. 指令具体性:是否有具体步骤
if "步骤" in prompt or "1." in prompt:
scores["specificity"] = 0.9
else:
scores["specificity"] = 0.4
# 3. 约束条件
if "约束" in prompt or "不能" in prompt or "只" in prompt:
scores["constraints"] = 0.8
else:
scores["constraints"] = 0.2
# 4. 示例
if "示例" in prompt or "例如" in prompt:
scores["examples"] = 0.9
else:
scores["examples"] = 0.3
# 5. 格式要求
if "格式" in prompt or "JSON" in prompt or "Markdown" in prompt:
scores["format"] = 0.9
else:
scores["format"] = 0.3
# 6. 上下文
if "背景" in prompt or "context" in prompt.lower():
scores["context"] = 0.8
else:
scores["context"] = 0.4
# 7. 角色
if "你是" in prompt or "角色" in prompt:
scores["role"] = 0.9
else:
scores["role"] = 0.1
return scores
@staticmethod
def optimize_prompt(
prompt: str,
score_threshold: float = 0.6
) -> List[str]:
"""给出优化建议"""
scores = PromptEvaluator.evaluate_prompt(prompt)
suggestions = []
for dim, score in scores.items():
if score < score_threshold:
suggestion_map = {
"clarity": "添加明确的目标描述,使用「请」「要求」等引导词",
"specificity": "分解为具体步骤,使用编号列表",
"constraints": "添加约束条件:长度限制、禁止内容、必须包含的元素",
"examples": "添加 Few-shot 示例,输入输出对",
"format": "指定输出格式:JSON/Markdown/纯文本,附上 Schema",
"context": "补充背景信息:项目上下文、用户画像、前置条件",
"role": "添加角色设定:你是谁、以什么身份回答"
}
suggestions.append(suggestion_map.get(dim))
return [s for s in suggestions if s]
# ===== A/B 测试 =====
class PromptABTest:
"""Prompt A/B 测试"""
def __init__(self, llm_client):
self.llm = llm_client
def compare_prompts(
self,
prompt_a: str,
prompt_b: str,
test_cases: List[str],
criteria: List[str]
) -> Dict[str, Any]:
"""比较两种 Prompt 的效果"""
results = {"a": [], "b": []}
for case in test_cases:
result_a = self.llm.generate(prompt_a.format(input=case))
result_b = self.llm.generate(prompt_b.format(input=case))
results["a"].append({"input": case, "output": result_a})
results["b"].append({"input": case, "output": result_b})
return results
八、生产案例
8.1 智能客服 Prompt 系统
python
# ===== 生产案例:智能客服 =====
class CustomerServicePromptSystem:
"""智能客服 Prompt 系统"""
def __init__(self, llm_client):
self.llm = llm_client
self.classifier_prompt = CustomerServicePrompt.classify_and_route()
self.reply_prompt = CustomerServicePrompt.generate_reply_with_rules()
def handle_customer(self, message: str) -> Dict[str, Any]:
"""处理客户消息"""
# 1. 分类
classification = self.llm.generate(
self.classifier_prompt.format(customer_message=message)
)
# 2. 生成回复
category = json.loads(classification).get("category", "咨询")
reply = self.llm.generate(
self.reply_prompt.format(
customer_message=message,
chat_history="",
category=category,
priority="中"
)
)
return {
"classification": classification,
"reply": reply,
"timestamp": "2024-06-09T14:00:00"
}
九、总结
最佳实践
| 原则 | 说明 | 示例 |
|---|---|---|
| 明确角色 | 设定身份和语气 | "你是资深 Python 工程师" |
| 分解任务 | 复杂任务拆解为步骤 | CoT、提示链 |
| 提供示例 | Few-shot 优于 Zero-shot | 输入输出对 |
| 约束条件 | 明确限制和禁忌 | "只输出 JSON" |
| 输出格式 | 指定期望格式 | JSON Schema |
| 迭代优化 | A/B 测试验证效果 | PromptEvaluator |
反模式
| ❌ 错误做法 | ✅ 正确做法 |
|---|---|
| "写个代码" | "用 Python FastAPI 写一个用户注册接口" |
| "分析这个" | "分析以下数据,找出去年 Q4 的销售趋势" |
| 无输出格式 | 指定 JSON 格式和字段定义 |
| 一次性复杂任务 | 分解为提示链 |
本文涵盖 Prompt Engineering 完整技术栈:要素框架、角色提示、Few-shot/Zero-shot、CoT、结构化输出、高级技巧(提示链/思维树/ReAct)、评估优化、生产案例。