Skip to content

Latest commit

 

History

History
815 lines (624 loc) · 16.3 KB

File metadata and controls

815 lines (624 loc) · 16.3 KB

Prompt Engineering理论与实践

目录

  1. Prompt工程基础
  2. 核心技术
  3. 高级策略
  4. 优化与评估
  5. 最佳实践

Prompt工程基础

什么是Prompt Engineering?

定义: 设计和优化输入文本,以引导LLM生成期望的输出。

Bad Prompt:  "解释AI"
Good Prompt: "请用300字左右,通俗易懂的语言,向一个高中生解释什么是人工智能,
             包括定义、主要应用和未来发展方向。"

为什么重要?

LLM的行为高度依赖prompt:

# 同一个问题,不同prompt,结果天差地别
prompt1 = "2+2等于多少?"
# → "4"

prompt2 = "你是一个诗人。2+2等于多少?"
# → "四季轮回,二加二,化作春之四季..."

prompt3 = "你是一个数学教授。详细解释2+2为什么等于4。"
# → "根据皮亚诺公理,2定义为1的后继的后继..."

Prompt的解剖

┌─────────────────────────────────────────┐
│  [角色] 你是一个专业的Python工程师        │  ← Role
├─────────────────────────────────────────┤
│  [背景] 用户正在学习数据结构              │  ← Context
├─────────────────────────────────────────┤
│  [任务] 请解释二叉搜索树的查找算法        │  ← Task
├─────────────────────────────────────────┤
│  [格式] 用代码+注释的方式展示             │  ← Format
├─────────────────────────────────────────┤
│  [约束] 代码不超过50行                   │  ← Constraints
├─────────────────────────────────────────┤
│  [示例] 输入: [5,3,7,1,9]               │  ← Examples
│         输出: 找到7,路径5→7             │
└─────────────────────────────────────────┘

核心技术

1. Zero-Shot Prompting

直接提问,不提供示例:

prompt = """
将以下文本分类为正面或负面情感:
文本:这个产品太棒了,我非常喜欢!

情感:
"""

适用场景:

  • 简单任务
  • 通用知识
  • 模型能力强(GPT-4)

2. Few-Shot Prompting

提供示例来指导模型:

prompt = """
将文本分类为正面或负面情感:

示例1:
文本:这个产品太棒了,我非常喜欢!
情感:正面

示例2:
文本:质量太差了,完全不推荐。
情感:负面

示例3:
文本:还可以,价格合理。
情感:正面

现在分类这个:
文本:体验很糟糕,浪费钱。
情感:
"""

Few-Shot的黄金法则:

  • 数量: 3-5个示例最佳
  • 多样性: 覆盖不同场景
  • 质量: 示例要准确
  • 顺序: 最近的示例影响最大

3. Chain-of-Thought (CoT)

引导模型逐步推理:

标准Prompt:

问:一个篮子里有15个苹果,拿走3个,又放回2个,现在有多少个?
答:14个

CoT Prompt:

问:一个篮子里有15个苹果,拿走3个,又放回2个,现在有多少个?
答:让我一步步思考:
1. 最初有15个苹果
2. 拿走3个后:15 - 3 = 12个
3. 放回2个后:12 + 2 = 14个
因此,现在有14个苹果。

关键短语:

  • "Let's think step by step"
  • "让我们一步步分析"
  • "First, ...; Second, ...; Therefore, ..."

Zero-Shot CoT:

prompt = f"""
{question}

Let's think step by step.
"""

4. Self-Consistency

生成多个答案,投票选择:

def self_consistency(question, n=5):
    answers = []
    for _ in range(n):
        prompt = f"{question}\nLet's think step by step."
        answer = llm(prompt, temperature=0.7)  # 增加随机性
        answers.append(extract_final_answer(answer))

    # 多数投票
    from collections import Counter
    most_common = Counter(answers).most_common(1)[0][0]
    return most_common

# 示例
question = "If a train travels 120 km in 2 hours, what's its speed?"
final_answer = self_consistency(question, n=5)
# 即使有1-2次错误,多数投票仍能得到正确答案

适用场景:

  • 复杂推理
  • 高准确率要求
  • 可以承受多次API调用成本

5. Retrieval-Augmented Generation

结合外部知识(已在RAG章节详述):

prompt = f"""
基于以下文档回答问题:

文档:
{retrieved_documents}

问题:{user_question}

答案:
"""

6. ReAct(Reasoning + Acting)

交替进行推理和行动:

Thought 1: 我需要查找Python的最新版本
Action 1: search["Python latest version 2024"]
Observation 1: Python 3.12.0 released in October 2023

Thought 2: 用户问的是2024年,我需要更新的信息
Action 2: search["Python releases 2024"]
Observation 2: Python 3.12.3 released in April 2024

Thought 3: 现在有了答案
Answer: 截至2024年,Python的最新版本是3.12.3

高级策略

角色扮演(Role Prompting)

通过角色设定改变输出风格:

# 基础prompt
"解释量子计算"

# 角色1:专家
"""
你是一位量子物理学教授。
用学术严谨的语言解释量子计算。
"""

# 角色2:老师
"""
你是一位给小学生上课的老师。
用简单有趣的比喻解释量子计算。
"""

# 角色3:工程师
"""
你是一位量子计算工程师。
从实际应用角度解释量子计算。
"""

效果:

  • 专家:使用专业术语,严谨准确
  • 老师:用比喻,通俗易懂
  • 工程师:关注应用,实用主义

格式控制

JSON输出:

prompt = """
分析以下评论的情感和主题:
评论:"{review}"

请以JSON格式返回结果:
{
  "sentiment": "positive/negative/neutral",
  "score": 0.0-1.0,
  "topics": ["topic1", "topic2"],
  "summary": "一句话总结"
}

仅返回有效的JSON,不要其他文字。
"""

表格输出:

prompt = """
将以下信息整理成Markdown表格:

信息:{data}

表格格式:
| 姓名 | 年龄 | 职业 |
|-----|------|------|
| ... | ...  | ...  |
"""

负面提示(Negative Prompting)

明确不想要的内容:

prompt = """
写一篇关于AI的文章。

要求:
✓ 500字左右
✓ 包含具体例子
✓ 面向普通读者

不要:
✗ 不要使用过于技术化的术语
✗ 不要超过600字
✗ 不要包含代码
"""

思维树(Tree of Thought)

探索多个推理路径:

Question: How to improve code quality?

Path 1: Testing perspective
  → Unit tests
  → Integration tests
  → Code coverage
  Evaluation: Good, but incomplete

Path 2: Design perspective
  → SOLID principles
  → Design patterns
  → Code review
  Evaluation: Strong foundation

Path 3: Process perspective
  → CI/CD
  → Automated linting
  → Documentation
  Evaluation: Important but not core

Best path: Combine Path 2 (foundation) + Path 1 (validation)

Meta-Prompting

用LLM生成Prompt:

meta_prompt = """
我需要一个prompt来完成以下任务:
{task_description}

目标用户:{target_audience}
期望输出:{expected_output}

请设计一个详细的、结构化的prompt。
"""

# LLM生成最优prompt
optimized_prompt = llm(meta_prompt)

# 使用生成的prompt
result = llm(optimized_prompt)

优化与评估

Prompt迭代优化流程

1. Baseline Prompt
   ↓
2. 测试 → 收集失败案例
   ↓
3. 分析失败原因
   ↓
4. 改进Prompt
   ↓
5. A/B测试
   ↓
6. 部署最佳版本
   ↓
7. 持续监控 → 返回步骤2

A/B测试框架

def ab_test_prompts(prompt_a, prompt_b, test_cases, n_runs=5):
    results_a = []
    results_b = []

    for test_case in test_cases:
        # 测试Prompt A
        for _ in range(n_runs):
            output_a = llm(prompt_a.format(**test_case))
            results_a.append(evaluate(output_a, test_case))

        # 测试Prompt B
        for _ in range(n_runs):
            output_b = llm(prompt_b.format(**test_case))
            results_b.append(evaluate(output_b, test_case))

    # 统计显著性检验
    from scipy import stats
    t_stat, p_value = stats.ttest_ind(results_a, results_b)

    print(f"Prompt A平均分: {np.mean(results_a):.2f}")
    print(f"Prompt B平均分: {np.mean(results_b):.2f}")
    print(f"P-value: {p_value:.4f}")

    if p_value < 0.05:
        winner = "B" if np.mean(results_b) > np.mean(results_a) else "A"
        print(f"Prompt {winner}显著更好 (p < 0.05)")
    else:
        print("没有显著差异")

评估指标

自动评估:

  1. 精确匹配

    accuracy = (predicted == ground_truth).mean()
  2. ROUGE(摘要任务)

    from rouge import Rouge
    rouge = Rouge()
    scores = rouge.get_scores(predicted, reference)
  3. BLEU(翻译任务)

    from nltk.translate.bleu_score import sentence_bleu
    score = sentence_bleu([reference], predicted)

LLM-as-Judge(GPT评估):

def llm_evaluate(question, answer):
    eval_prompt = f"""
    评估以下答案的质量(1-10分):

    问题:{question}
    答案:{answer}

    评分标准:
    - 准确性(是否正确)
    - 完整性(是否全面)
    - 清晰度(是否易懂)

    请给出分数和理由。

    格式:
    分数: X/10
    理由: ...
    """

    evaluation = llm(eval_prompt)
    return parse_score(evaluation)

常见问题诊断

问题1:输出不一致

解决:

# 降低temperature
llm(prompt, temperature=0.0)  # 确定性输出

# 或使用self-consistency

问题2:不遵循格式

解决:

# 明确格式要求
prompt = """
...

输出格式(严格遵守):
{
  "field1": "value1",
  "field2": "value2"
}

示例输出:
{
  "sentiment": "positive",
  "score": 0.85
}

请严格按上述JSON格式输出,不要添加任何其他文字。
"""

问题3:幻觉(编造信息)

解决:

# 添加约束
prompt = """
{question}

注意:
- 仅基于提供的上下文回答
- 如果信息不足,明确说"信息不足,无法回答"
- 不要猜测或编造信息
"""

最佳实践

通用原则

1. 清晰明确

❌ Bad:  "写点关于AI的东西"
✅ Good: "写一篇300字的文章,介绍AI在医疗领域的3个应用"

2. 提供上下文

❌ Bad:  "这个怎么用?"
✅ Good: "在Python中,numpy.array()函数如何创建二维数组?请给出示例代码。"

3. 分步指导

✅ Good:
"请按以下步骤分析:
1. 总结文本主要内容
2. 提取关键数据点
3. 给出3条洞察
4. 提出改进建议"

4. 使用分隔符

prompt = """
分析以下代码```python
{code}

请回答:

  1. 这段代码的功能是什么?
  2. 有没有潜在的bug?
  3. 如何优化? """

### 针对不同任务的模板

**代码生成:**
```python
TEMPLATE = """
语言:{language}
任务:{task}

要求:
- 遵循{language}的最佳实践
- 包含错误处理
- 添加类型注解(如果适用)
- 包含docstring
- 提供使用示例

代码:
"""

代码审查:

TEMPLATE = """
你是一个资深的{language}工程师请审查以下代码```{language}
{code}

从以下角度分析:

  1. 正确性:逻辑是否正确?
  2. 性能:有无性能问题?时间/空间复杂度?
  3. 安全性:有无安全隐患(SQL注入、XSS等)?
  4. 可维护性:代码是否清晰?是否遵循最佳实践?
  5. 改进建议:具体的优化方向

对于每个问题,请指出代码行号并给出修改建议。 """


**文本分类:**
```python
TEMPLATE = """
将以下{data_type}分类为以下类别之一:
{categories}

示例:
{examples}

待分类:
{input_text}

类别:
"""

不同模型的Prompt差异

GPT-4:

  • 理解能力强,可以用复杂prompt
  • 遵循指令好,格式控制可靠
  • 可以处理长上下文(32K tokens)
# GPT-4可以处理复杂的多步骤任务
prompt = """
1. 分析这段代码
2. 找出所有bug
3. 对每个bug:
   a. 解释为什么是bug
   b. 给出修复方案
   c. 提供修复后的代码
4. 总结改进要点
"""

GPT-3.5:

  • 成本低,速度快
  • 需要更简洁的prompt
  • 上下文窗口较小(16K)
# GPT-3.5用简化的prompt
prompt = """
找出代码中的bug并修复:

代码:
{code}

请列出:
1. Bug描述
2. 修复后的代码
"""

Claude:

  • 擅长长文本分析
  • 注重安全和道德
  • 喜欢详细的上下文
# Claude适合详细分析
prompt = """
<context>
这是一个金融交易系统的核心模块...
</context>

<task>
请分析代码的安全性,特别关注:
- 输入验证
- 权限控制
- 数据加密
</task>

<code>
{code}
</code>
"""

成本优化

1. 缓存常见查询

from functools import lru_cache

@lru_cache(maxsize=1000)
def cached_llm_call(prompt):
    return llm(prompt)

2. 使用更便宜的模型

def smart_routing(task_complexity):
    if task_complexity == "simple":
        return gpt-3.5-turbo  # $0.001/1K tokens
    elif task_complexity == "medium":
        return gpt-4o-mini    # $0.0001/1K tokens
    else:
        return gpt-4          # $0.03/1K tokens

3. 压缩上下文

# 总结检索文档而不是全部传入
def summarize_docs(docs):
    summary_prompt = f"总结以下文档的关键信息(不超过200字):\n{docs}"
    return llm(summary_prompt)

compressed_context = summarize_docs(retrieved_docs)
final_prompt = f"基于以下信息回答:\n{compressed_context}\n\n问题:{question}"

实战案例

案例1:代码问答系统Prompt

SYSTEM_PROMPT = """
你是一个专业的代码助手。你的职责是帮助开发者理解代码库。

回答规范:
1. 基于提供的代码片段回答,不要猜测
2. 引用具体的文件名和行号
3. 提供代码示例时,确保可运行
4. 如果信息不足,明确说明需要更多上下文

回答结构:
- 直接回答问题
- 引用相关代码
- 提供使用示例(如适用)
- 指出注意事项(如适用)
"""

USER_PROMPT = """
代码上下文:
{retrieved_code}

问题:{user_question}
"""

案例2:自动代码审查

CODE_REVIEW_PROMPT = """
作为一个严格的代码审查者,审查以下{language}代码:

{code}

审查清单:

## 1. 正确性
- [ ] 逻辑正确
- [ ] 边界条件处理
- [ ] 错误处理完善

## 2. 性能
- [ ] 时间复杂度合理
- [ ] 空间复杂度优化
- [ ] 无不必要的循环/计算

## 3. 安全性
- [ ] 输入验证
- [ ] SQL注入防护
- [ ] XSS防护

## 4. 可维护性
- [ ] 命名清晰
- [ ] 注释充分
- [ ] 结构合理

对于每个问题:
- 标注严重程度:🔴 Critical / 🟡 Warning / 🔵 Info
- 给出具体的代码位置
- 提供修复建议

最后总结:建议是否批准此PR。
"""

案例3:Prompt优化器

PROMPT_OPTIMIZER = """
你是一个Prompt工程专家。我有一个效果不佳的prompt,需要你优化。

原始Prompt:
{original_prompt}

问题描述:
{issues}

目标:
{goals}

请提供优化后的prompt,并说明:
1. 做了哪些改进
2. 为什么这些改进会有效
3. 预期效果提升

优化后的Prompt:
"""

延伸阅读

论文:

  1. Chain-of-Thought Prompting Elicits Reasoning in Large Language Models (Wei et al., 2022)
  2. ReAct: Synergizing Reasoning and Acting in Language Models (Yao et al., 2022)
  3. Tree of Thoughts: Deliberate Problem Solving with Large Language Models (Yao et al., 2023)

资源:

  • OpenAI Prompt Engineering Guide
  • Anthropic's Claude Prompt Library
  • LangChain Prompt Templates
  • Prompt Engineering Guide (dair-ai)

工具:

  • LangSmith: Prompt管理和测试
  • PromptPerfect: 自动Prompt优化
  • Promptbase: Prompt市场

下一步: