Prompt Engineering 实战

前言

💡 痛点: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}

请按以下步骤分析:

  1. 首先,理解代码的整体功能是什么
  2. 检查是否存在逻辑错误
  3. 检查是否存在安全问题
  4. 检查性能问题
  5. 检查代码风格和可维护性
  6. 检查测试覆盖情况
  7. 总结:给出修复建议和优先级

逐步推理结果:"""

复制代码
    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}

要求:

  1. 只输出 JSON,不要加额外说明
  2. 确保 JSON 格式正确
  3. 字段名称严格匹配 Schema
  4. 所有字段都是必需

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 | ... |

| ... | ... | ... |

确保:

  1. 表格格式正确

  2. 数据对齐准确

  3. 最少 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 """

你是客服助手。请根据客户消息和规则生成回复。

规则

  1. 客服优先,不推诿
  2. 明确说明处理步骤
  3. 给出时间预期
  4. 提供备选方案
  5. 情绪安抚:共情 + 解决方案

上下文

客户: {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)、评估优化、生产案例。

相关推荐
fastjson_1 小时前
使用 ventoy 安装WinToGo
windows
暗夜猎手-大魔王2 小时前
hermes源码学习4-Prompt 组装
人工智能·prompt
Chase_______2 小时前
【Java杂项】Arrays.asList、List.of 和 new ArrayList:集合可变性避坑
java·windows·list
_Aaron___2 小时前
RAG 多租户知识库:权限隔离不能只靠 Prompt
prompt
qq3621967052 小时前
APK版本选择完全指南——beta/stable/arm64/x86/bundle/universal怎么选?
网络·人工智能
李白你好2 小时前
Burp Suite 自动注入 HTTP Header 的插件
网络·网络协议·http
梁辰兴2 小时前
计算机网络基础:具有集中目录服务器的 P2P 工作方式
服务器·网络·计算机网络·计算机·p2p·计算机网络基础·梁辰兴
艾莉丝努力练剑2 小时前
【Linux网络】网络层IP协议(二):网段划分
linux·运维·服务器·网络·tcp/ip·udp
InHand云飞小白2 小时前
告别有线宽带束缚!5G Wi-Fi 6 CPE赋能企业网络新范式
网络·5g·网络运维·5g路由器·连锁门店·5gcpe·商业联网