第8章 提示模板(Prompts)开发

93 阅读9分钟

第8章 提示模板(Prompts)开发

前言

提示模板是MCP中最强大的功能——它将专家级的知识、最佳实践和复杂的推理逻辑编码到可复用的模板中。本章讲解如何设计和管理高效的提示模板。


8.1 提示模板的定义与作用

8.1.1 什么是提示模板

graph TB
    A["提示模板 Prompt"] --> B["本质"]
    A --> C["特征"]
    A --> D["价值"]
    
    B --> B1["预定义的提示词"]
    B --> B2["参数化的指令"]
    B --> B3["专家知识的编码"]
    
    C --> C1["参数可变"]
    C --> C2["动态生成"]
    C --> C3["可复用"]
    C --> C4["版本控制"]
    
    D --> D1["标准化输出"]
    D --> D2["质量保证"]
    D --> D3["知识复用"]
    D --> D4["降低成本"]

提示模板的核心定义

提示模板是预定义的、参数化的、可复用的文本模板,用于:

  1. 标准化推理 - 确保一致的分析方法
  2. 知识编码 - 将专家经验转化为通用流程
  3. 质量控制 - 降低LLM输出的变异性
  4. 成本优化 - 减少需要调整的提示词数量

8.1.2 提示模板与工具/资源的区别

graph TB
    A["MCP三大核心功能"] --> B["工具 Tools"]
    A --> C["资源 Resources"]
    A --> D["提示模板 Prompts"]
    
    B --> B1["执行操作"]
    B --> B2["有副作用"]
    B --> B3["返回数据"]
    
    C --> C1["存储数据"]
    C --> C2["持久化"]
    C --> C3["可订阅"]
    
    D --> D1["指导推理"]
    D --> D2["文本生成"]
    D --> D3["无副作用"]
    
    E["关键区别"] --> E1["工具=做什么"]
    E --> E2["资源=在哪里"]
    E --> E3["提示=如何做"]
维度工具资源提示模板
目的执行操作存储数据指导推理
特性有副作用持久化无副作用
复用性
参数化
使用场景数据修改数据访问思路引导

8.2 提示模板的设计原则

8.2.1 清晰性原则

❌ 不清晰的提示模板:
"分析数据并给出建议"

✅ 清晰的提示模板:
"""您是一位资深销售分析师。

任务:分析{period}期间{region}地区的销售数据

分析维度:
1. 销售额趋势变化
2. 产品结构分布
3. 客户群体特征
4. 地区对标表现

输出格式:
- 核心指标摘要(3-5项)
- 关键发现(3-5项)
- 建议和改进措施(3-5项)
"""

清晰性检查清单

  • 角色明确(你是谁?)
  • 任务明确(做什么?)
  • 范围界定(分析什么?)
  • 输出格式定义(如何输出?)
  • 优先级排列(什么最重要?)

8.2.2 一致性原则

# ✅ 一致的模板结构
TEMPLATE_STRUCTURE = """
## 角色定义
{role}

## 背景信息
{context}

## 具体任务
{task}

## 输入数据
{input_data}

## 处理流程
1. {step_1}
2. {step_2}
3. {step_3}

## 输出要求
{output_format}

## 成功标准
{success_criteria}
"""

所有提示模板遵循统一的结构,帮助用户快速理解和应用。

8.2.3 参数化原则

参数分类

graph TB
    A["提示模板参数"] --> B["上下文参数"]
    A --> C["业务参数"]
    A --> D["控制参数"]
    
    B --> B1["role - 角色设定"]
    B --> B2["context - 背景信息"]
    B --> B3["domain - 领域知识"]
    
    C --> C1["entity - 分析对象"]
    C --> C2["period - 时间范围"]
    C --> C3["scope - 分析范围"]
    
    D --> D1["language - 输出语言"]
    D --> D2["style - 风格"]
    D --> D3["detail - 详细程度"]

8.3 提示模板的实现

8.3.1 基础提示模板类

from typing import Dict, Optional, List
from dataclasses import dataclass
from datetime import datetime
import json

@dataclass
class PromptArgument:
    """提示模板参数定义"""
    name: str
    description: str
    type: str  # string, number, boolean, array
    required: bool = True
    default: Optional[str] = None
    enum_values: Optional[List[str]] = None


class PromptTemplate:
    """提示模板基类"""
    
    def __init__(self, name: str, description: str, template: str):
        self.name = name
        self.description = description
        self.template = template
        self.arguments: Dict[str, PromptArgument] = {}
        self.created_at = datetime.now()
        self.version = "1.0.0"
    
    def add_argument(self, arg: PromptArgument):
        """添加参数定义"""
        self.arguments[arg.name] = arg
    
    def validate_arguments(self, **kwargs) -> bool:
        """验证提供的参数"""
        # 检查必需参数
        for name, arg in self.arguments.items():
            if arg.required and name not in kwargs:
                raise ValueError(f"Missing required argument: {name}")
            
            # 检查枚举值
            if arg.enum_values and name in kwargs:
                value = kwargs[name]
                if value not in arg.enum_values:
                    raise ValueError(
                        f"Invalid value for {name}: {value}. "
                        f"Must be one of {arg.enum_values}"
                    )
        
        return True
    
    def render(self, **kwargs) -> str:
        """
        渲染提示模板
        
        Args:
            **kwargs: 模板参数
            
        Returns:
            渲染后的提示词
        """
        # 验证参数
        self.validate_arguments(**kwargs)
        
        # 填充默认值
        for name, arg in self.arguments.items():
            if name not in kwargs and arg.default:
                kwargs[name] = arg.default
        
        # 使用参数渲染模板
        return self.template.format(**kwargs)
    
    def to_dict(self) -> Dict:
        """转换为字典(用于MCP协议)"""
        return {
            "name": self.name,
            "description": self.description,
            "arguments": [
                {
                    "name": arg.name,
                    "description": arg.description,
                    "type": arg.type,
                    "required": arg.required,
                    "default": arg.default,
                    "enum": arg.enum_values
                }
                for arg in self.arguments.values()
            ]
        }

8.3.2 常见提示模板实例

销售分析模板

class SalesAnalysisTemplate(PromptTemplate):
    """销售数据分析提示模板"""
    
    def __init__(self):
        template = """您是一位资深销售分析师,拥有15年的数据分析经验。

## 分析目标
分析 {period} 期间 {region} 地区的销售表现

## 可用数据
- 销售总额:{total_sales}
- 订单数量:{order_count}
- 平均订单值:{average_order_value}
- 同比增长率:{growth_rate}%
- 产品分布:{product_distribution}

## 分析框架
请从以下维度进行分析:

1. **销售趋势分析**
   - 与上期对比(环比)
   - 与去年同期对比(同比)
   - 发展趋势评估

2. **产品结构分析**
   - 各类别销售占比
   - 增长驱动因素
   - 产品竞争力评估

3. **客户洞察**
   - 客户群体特征
   - 消费行为变化
   - 客户满意度信号

4. **地区对标**
   - 与其他地区对比
   - 排名和优劣势
   - 标杆学习机会

## 输出要求
以结构化的方式呈现分析结果:

### 执行摘要
- 最重要的3个指标
- 核心发现
- 风险预警

### 详细分析
[各维度的深入分析]

### 建议措施
1. 短期行动(1-3月)
2. 中期策略(3-6月)
3. 长期规划(6-12月)

### 预期影响
[各项建议的预期结果]

---

分析时要求:
- 深入但不冗长
- 数据驱动
- 可行性强
- 具有商业洞察力
"""
        
        super().__init__(
            name="sales_analysis",
            description="进行销售数据深度分析并提出改进建议",
            template=template
        )
        
        # 添加参数
        self.add_argument(PromptArgument(
            name="period",
            description="分析时间段,如'2025年10月'",
            type="string",
            required=True
        ))
        
        self.add_argument(PromptArgument(
            name="region",
            description="地区代码",
            type="string",
            required=True,
            enum_values=["CN", "US", "EU", "APAC"]
        ))
        
        self.add_argument(PromptArgument(
            name="total_sales",
            description="销售总额(单位:万元)",
            type="number",
            required=True
        ))
        
        # ... 其他参数

8.3.3 高级特性:条件逻辑

class ConditionalPromptTemplate(PromptTemplate):
    """支持条件逻辑的提示模板"""
    
    def render(self, **kwargs) -> str:
        """渲染模板,支持条件渲染"""
        # 基础渲染
        content = self.template.format(**kwargs)
        
        # 条件处理
        if kwargs.get("include_benchmarking", False):
            content += "\n\n## 地区对标分析\n[对标内容]"
        
        if kwargs.get("detail_level", "normal") == "detailed":
            content += "\n\n## 深度分析\n[更详细的分析]"
        
        return content

8.4 提示模板的参数化与动态生成

8.4.1 参数注入

class ParameterizedPromptTemplate(PromptTemplate):
    """支持复杂参数注入的提示模板"""
    
    def render(self, **kwargs) -> str:
        """渲染模板,支持参数的高级处理"""
        
        # 1. 参数验证与转换
        processed_args = self._process_arguments(kwargs)
        
        # 2. 参数补充(生成派生参数)
        enriched_args = self._enrich_arguments(processed_args)
        
        # 3. 模板渲染
        return self.template.format(**enriched_args)
    
    def _process_arguments(self, kwargs: Dict) -> Dict:
        """处理参数(验证、转换、清理)"""
        processed = {}
        
        for name, arg in self.arguments.items():
            value = kwargs.get(name, arg.default)
            
            # 类型转换
            if arg.type == "number" and isinstance(value, str):
                value = float(value)
            
            processed[name] = value
        
        return processed
    
    def _enrich_arguments(self, args: Dict) -> Dict:
        """
        从基础参数生成派生参数
        
        例如:从时间范围生成"分析周期描述"
        """
        enriched = args.copy()
        
        # 示例:从period生成description
        if "period" in args:
            period = args["period"]
            if "month" in period.lower():
                enriched["period_desc"] = f"{period}的月度数据"
            elif "quarter" in period.lower():
                enriched["period_desc"] = f"{period}的季度数据"
        
        return enriched

8.4.2 动态提示生成

class DynamicPromptGenerator:
    """动态生成提示模板"""
    
    def __init__(self):
        self.templates: Dict[str, PromptTemplate] = {}
    
    def generate_context_aware_prompt(self, context: Dict) -> str:
        """
        根据上下文智能生成提示
        
        Args:
            context: 包含用户背景、任务类型、数据规模等信息
            
        Returns:
            生成的提示词
        """
        # 1. 分析上下文
        user_level = context.get("user_level", "intermediate")  # beginner/intermediate/expert
        task_complexity = context.get("complexity", "medium")  # simple/medium/complex
        data_volume = context.get("data_volume", "small")  # small/medium/large
        
        # 2. 选择合适的提示策略
        prompt_parts = []
        
        # 根据用户级别调整指令复杂度
        if user_level == "beginner":
            prompt_parts.append(self._get_beginner_instructions())
        elif user_level == "expert":
            prompt_parts.append(self._get_expert_instructions())
        
        # 根据任务复杂度调整分析深度
        if task_complexity == "complex":
            prompt_parts.append(self._get_detailed_analysis_steps())
        
        # 根据数据量调整处理方式
        if data_volume == "large":
            prompt_parts.append(self._get_data_sampling_instructions())
        
        # 3. 组合生成最终提示
        return "\n\n".join(prompt_parts)
    
    def _get_beginner_instructions(self) -> str:
        """初级用户的指导"""
        return """## 分析指引
这个分析帮您理解数据的基本模式。

按以下步骤进行:
1. 首先观察整体趋势
2. 然后对比变化
3. 最后给出简单建议
"""
    
    def _get_expert_instructions(self) -> str:
        """专家级用户的指导"""
        return """## 深度分析框架
进行多维度分析,包括:
1. 统计显著性检验
2. 因果关系分析
3. 对标企业对比
4. 预测模型建议
"""
    
    def _get_detailed_analysis_steps(self) -> str:
        """详细的分析步骤"""
        return """## 分析步骤
1. 数据清洗与预处理
2. 描述性统计分析
3. 趋势与周期性分析
4. 异常值检测
5. 深层因素探讨
6. 对标与基准对比
7. 预测与建议
"""
    
    def _get_data_sampling_instructions(self) -> str:
        """大数据处理指导"""
        return """## 大数据处理
由于数据量大,建议:
1. 采样关键子集进行深度分析
2. 计算汇总统计指标
3. 聚焦异常和关键数据点
"""

8.5 提示模板的管理与版本控制

8.5.1 模板库管理

class PromptTemplateLibrary:
    """提示模板库"""
    
    def __init__(self):
        self.templates: Dict[str, Dict[str, PromptTemplate]] = {}
        self.version_history: Dict[str, List[Dict]] = {}
    
    def register_template(self, category: str, template: PromptTemplate):
        """注册模板"""
        if category not in self.templates:
            self.templates[category] = {}
        
        self.templates[category][template.name] = template
        
        # 记录版本历史
        if template.name not in self.version_history:
            self.version_history[template.name] = []
        
        self.version_history[template.name].append({
            "version": template.version,
            "timestamp": datetime.now().isoformat(),
            "description": "Template registered"
        })
    
    def get_template(self, category: str, name: str) -> Optional[PromptTemplate]:
        """获取模板"""
        return self.templates.get(category, {}).get(name)
    
    def list_templates(self, category: str = None) -> List[Dict]:
        """列出模板"""
        if category:
            templates = self.templates.get(category, {})
        else:
            templates = {}
            for cat_templates in self.templates.values():
                templates.update(cat_templates)
        
        return [
            {
                "name": t.name,
                "description": t.description,
                "version": t.version,
                "arguments": len(t.arguments)
            }
            for t in templates.values()
        ]
    
    def update_template(self, category: str, template: PromptTemplate, 
                       change_description: str):
        """更新模板"""
        old_version = None
        
        if category in self.templates and template.name in self.templates[category]:
            old_version = self.templates[category][template.name].version
        
        # 自动升级版本号
        if old_version:
            template.version = self._increment_version(old_version)
        
        self.register_template(category, template)
        
        # 记录变更
        self.version_history[template.name][-1]["description"] = change_description
    
    def _increment_version(self, version: str) -> str:
        """版本号递增"""
        parts = version.split(".")
        parts[-1] = str(int(parts[-1]) + 1)
        return ".".join(parts)

8.5.2 模板复用与组合

class CompositePromptTemplate(PromptTemplate):
    """组合模板:由多个子模板组成"""
    
    def __init__(self, name: str, description: str):
        super().__init__(name, description, "")
        self.sub_templates: List[PromptTemplate] = []
    
    def add_sub_template(self, template: PromptTemplate, position: str = "end"):
        """添加子模板"""
        if position == "end":
            self.sub_templates.append(template)
        elif position == "start":
            self.sub_templates.insert(0, template)
    
    def render(self, **kwargs) -> str:
        """渲染组合模板"""
        rendered_parts = []
        
        for template in self.sub_templates:
            # 每个子模板只使用它需要的参数
            sub_kwargs = {
                k: v for k, v in kwargs.items()
                if k in template.arguments
            }
            rendered_parts.append(template.render(**sub_kwargs))
        
        return "\n\n---\n\n".join(rendered_parts)


# 使用示例
def create_comprehensive_analysis_prompt():
    """创建综合分析提示"""
    composite = CompositePromptTemplate(
        "comprehensive_analysis",
        "综合数据分析模板"
    )
    
    # 添加多个子模板
    composite.add_sub_template(SalesAnalysisTemplate())
    composite.add_sub_template(RiskAssessmentTemplate())
    composite.add_sub_template(RecommendationTemplate())
    
    return composite

本章总结

核心概念关键点
定义预定义、参数化、可复用的文本模板
设计原则清晰性、一致性、参数化
参数分类上下文参数、业务参数、控制参数
参数化验证、转换、补充、派生
动态生成上下文感知的智能生成
版本管理语义版本号、变更记录
模板复用组合模板、模板库
质量保证验证规则、枚举约束

常见问题

Q1: 提示模板与系统提示有什么区别? A: 系统提示是固定的行为指令,提示模板是参数化的可复用指引。模板更灵活。

Q2: 提示模板是否会增加LLM的token消耗? A: 是的,但能通过规范化和复用减少调整需求,总体成本通常降低。

Q3: 如何评估提示模板的质量? A: 通过一致性、准确率、完成度、用户反馈等指标评估。

Q4: 可以在提示模板中嵌入其他提示吗? A: 可以。组合模板支持多层嵌套。

Q5: 提示模板与Few-shot示例的关系? A: 提示模板定义结构,Few-shot示例是具体例子,常配合使用。


实战要点

✅ 推荐做法

  • 设计清晰的参数化结构
  • 提供详细的参数说明
  • 创建模板变体库
  • 定期收集用户反馈
  • 建立版本管理制度
  • 编写模板使用指南

❌ 避免的做法

  • 不要过度参数化
  • 不要忽视输出格式定义
  • 不要缺乏版本管理
  • 不要忘记参数验证
  • 不要把所有逻辑都放在提示中
  • 不要设计过于复杂的模板

延伸阅读


下一章预告:第9章将讲述如何开发MCP客户端——包括连接管理、工具发现、异步处理等关键内容。