搜 索

Prompt Engineering:与大模型对话的艺术

  • 5阅读
  • 2025年06月28日
  • 0评论
首页 / AI/大数据 / 正文

前言:提示词的力量

看两个例子:

普通提示词

用户: 写一首诗
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
组件作用示例
角色定义 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

  1. Prompt = 与 AI 沟通的语言:好的提示词 = 好的结果
  2. 结构化是关键:角色 + 任务 + 上下文 + 格式 + 示例
  3. CoT 提升推理:让模型"一步一步思考"
  4. Few-Shot 很有效:给 3-5 个好例子
  5. 迭代优化:不断测试、改进、记录
  6. 建立模板库:积累可复用的优秀 Prompt

下一步学习

  • [ ] LLM 评估:如何衡量效果
  • [ ] 模型部署:生产环境最佳实践
  • [ ] 安全对齐:避免有害输出

参考资料

  1. OpenAI Prompt Engineering Guide
  2. Chain-of-Thought 论文
  3. Tree-of-Thoughts 论文
  4. Anthropic Prompt Library
  5. LangChain Hub - Prompt 分享平台

评论区
暂无评论
avatar