Prompt工程规范
Prompt 编写、版本化与复用管理
规则:所有生产环境使用的 Prompt 必须遵循结构化模板,包含角色、任务、上下文、约束、输出格式五个核心要素。
[Requirement] 生产级 Prompt 必须包含”角色”和”输出格式”两个要素,缺一不可。
[Standard] Prompt 遵循 CRISPE 框架:Capacity(角色)、Insight(背景)、Statement(任务)、Personality(风格)、Experiment(输出要求)。
[Default] 推荐使用以下五段式结构,按顺序书写。
| 段落 | 作用 | 是否必填 | 示例 |
|---|---|---|---|
| 角色 (Role) | 设定 AI 的身份和专业领域 | 必填 | “你是一名资深 Python 后端工程师,精通 FastAPI” |
| 任务 (Task) | 明确要完成的具体目标 | 必填 | “实现一个用户注册接口” |
| 上下文 (Context) | 提供必要的背景信息 | 必填 | “项目使用 FastAPI + SQLAlchemy,现有 User 模型在 src/models/user.py” |
| 约束 (Constraints) | 列出必须遵守的规则和限制 | 必填 | “使用参数化查询、必须包含单元测试、不得硬编码密钥” |
| 输出格式 (Format) | 指定输出的结构和形式 | 必填 | “输出 Python 代码 + 单元测试,代码放在 ```python 块中” |
示例:
【角色】你是一名资深 Python 后端工程师,精通 FastAPI 和 SQLAlchemy,熟悉 RESTful API 设计。
【任务】为现有项目新增"用户注册"接口,包含邮箱唯一性校验和欢迎邮件发送。
【上下文】- 项目框架:FastAPI + SQLAlchemy 2.0- User 模型位置:src/models/user.py,字段:id, email, password_hash, created_at- 邮件服务:src/services/email.py 中的 send_welcome_email(to: str) 函数
【约束】1. 邮箱必须唯一,重复时返回 409 Conflict2. 密码必须使用 bcrypt 哈希,不得明文存储3. 使用依赖注入获取 DB Session4. 必须包含单元测试,覆盖正常/重复邮箱/非法输入三种场景5. 不得硬编码任何密钥或配置
【输出格式】按以下顺序输出:1. 接口实现代码(```python 块)2. 单元测试代码(```python 块)3. 关键设计决策说明(不超过 3 条)反模式:
# 反模式 1:无结构的一句话 Prompt"帮我写个注册接口"
# 反模式 2:缺少约束和输出格式"你是 Python 工程师,帮我实现用户注册,项目用 FastAPI"规则:Prompt 编写遵循”明确、具体、可验证”三原则,使用肯定指令、提供示例、分步骤引导。
[Standard] 优先使用肯定句(“必须做 X”),而非否定句(“不要做 Y”);必须同时给出正例。
[Standard] 对输出质量要求高的场景,使用 Few-shot(提供 1-3 个示例)引导。
[Suggestion] 复杂任务使用 Chain-of-Thought(思维链),要求 AI 先输出推理过程再给结论。
[Caution] 避免在 Prompt 中出现矛盾指令(如”代码要简洁”同时”注释要详细”),需明确优先级。
| 技巧 | 适用场景 | 写法示例 |
|---|---|---|
| 明确角色 | 所有生产级 Prompt | “你是一名有 10 年经验的安全工程师” |
| Few-shot | 输出格式固定、质量要求高 | 给出输入/输出对示例 |
| CoT | 逻辑推理、复杂计算 | “请先分析问题,再给出方案” |
| 分步骤 | 多步骤任务 | “第一步:X;第二步:Y;第三步:Z” |
| 约束清单 | 有明确规则的场景 | “约束:1. … 2. … 3. …” |
| 输出模板 | 需要结构化输出 | “输出 JSON,字段包括:id, name, status” |
| 自我校验 | 高风险任务 | “生成后请自行检查是否满足所有约束” |
示例:
# 使用 Few-shot 的 Prompt从用户评论中提取情感标签,输出 JSON。
示例 1:输入:"这个产品质量很好,物流也快"输出:{"sentiment": "positive", "keywords": ["质量好", "物流快"]}
示例 2:输入:"包装破损,客服态度差"输出:{"sentiment": "negative", "keywords": ["包装破损", "客服差"]}
现在处理:输入:"功能还行,但价格偏贵"输出:反模式:
# 反模式:模糊、无示例、无约束"分析一下这条评论的情感"规则:生产级 Prompt 必须纳入版本控制,每次变更都有明确记录,支持回溯和对比。
[Requirement] 生产环境使用的 Prompt 必须存储在 Git 仓库中,不得只存在于个人电脑或聊天记录中。
[Requirement] Prompt 版本号遵循语义化版本:MAJOR.MINOR.PATCH(破坏性变更升 MAJOR,新增功能升 MINOR,修复升 PATCH)。
[Standard] 每个 Prompt 文件必须包含元数据头:名称、版本、作者、创建日期、最近修改日期、适用模型。
[Default] Prompt 存放在项目 prompts/ 目录下,按业务模块分子目录。
# prompts/user/register_v1.2.0.yaml
name: user_register
version: 1.2.0
author: zhangsan
created_at: 2025-01-15
updated_at: 2025-03-20
model: gpt-4o
description: 用户注册接口生成 Prompt
changelog:
- version: 1.2.0
date: 2025-03-20
change: 增加密码复杂度校验约束
- version: 1.1.0
date: 2025-02-10
change: 增加单元测试输出要求| 变更类型 | 版本号 | 示例 |
|---|---|---|
| 修改输出格式、删除约束 | MAJOR | 1.2.0 → 2.0.0 |
| 新增约束、新增输出字段 | MINOR | 1.2.0 → 1.3.0 |
| 修改措辞、修正错别字 | PATCH | 1.2.0 → 1.2.1 |
反模式:
- Prompt 只存在于某个人的聊天窗口里,其他人无法复用
- 修改 Prompt 不记录版本,出问题无法回滚
- 同一个 Prompt 被复制粘贴到 5 个地方,各版本不一致
规则:可复用的 Prompt 必须抽象为模板,通过变量填充实现复用,避免重复编写。
[Standard] 重复出现 3 次以上的 Prompt 片段,必须抽取为模板或片段库。
[Standard] 模板使用 {{变量名}} 语法标注占位符,运行时由调用方填充。
[Default] 建立团队级 Prompt 片段库,按用途分类:角色定义、约束模板、输出格式模板。
# templates/base_role.yaml
role_template: |
你是一名资深 {{language}} {{role}},
精通 {{framework}},有 {{years}} 年经验。
# templates/code_output.yaml
output_template: |
按以下顺序输出:
1. {{language}} 代码(```{{language}} 块)
2. 单元测试代码
3. 关键说明(不超过 {{max_points}} 条)# 调用时填充变量
from jinja2 import Template
role = Template(open("templates/base_role.yaml").read()).render(
language="Python",
role="后端工程师",
framework="FastAPI",
years=8
)
output = Template(open("templates/code_output.yaml").read()).render(
language="Python",
max_points=3
)| 层级 | 范围 | 存放位置 | 示例 |
|---|---|---|---|
| 团队级 | 全公司通用 | 公共规范仓库 | 角色定义、编码约束 |
| 项目级 | 单个项目 | 项目 prompts/ | 项目特有技术栈约束 |
| 任务级 | 单次任务 | 任务上下文 | 具体功能点的 Prompt |
反模式:
- 每次写 Prompt 都从零开始,不使用已有模板
- 复制粘贴别人的 Prompt 后改两个字就用,不维护原模板
- 模板变量名不统一,同一个含义叫
lang、language、prog_lang
规则:生产级 Prompt 上线前必须经过测试,验证输出质量、稳定性和边界情况。
[Requirement] 上线前必须用至少 5 组测试用例验证 Prompt 输出,覆盖正常、边界、异常三种场景。
[Standard] 对同一 Prompt 连续运行 3 次,输出结构必须一致(允许内容细节有差异)。
[Standard] 建立 Prompt 评测集,每次修改后回归测试,确保不出现退化。
[Suggestion] 使用自动化评测框架(如 promptfoo、OpenAI Evals)进行批量评测。
| 场景类型 | 说明 | 示例用例 |
|---|---|---|
| 正常场景 | 典型输入,验证基本功能 | 合法的用户注册数据 |
| 边界场景 | 极端值、空值、超长输入 | 空邮箱、超长密码、特殊字符 |
| 异常场景 | 非法输入、恶意输入 | SQL 注入字符串、XSS 脚本 |
| 模糊场景 | 输入不完整或有歧义 | 缺少必填字段 |
| 指标 | 定义 | 达标线 |
|---|---|---|
| 格式正确率 | 输出符合指定格式的比例 | ≥ 95% |
| 约束满足率 | 输出满足全部约束的比例 | ≥ 90% |
| 稳定性 | 多次运行结果结构一致的比例 | ≥ 90% |
| 业务正确率 | 输出逻辑正确的比例 | ≥ 95% |
示例:
# Prompt 回归测试示例
import pytest
CASES = [
{"input": {"email": "test@example.com", "password": "Abc12345"}, "expect": "status=201"},
{"input": {"email": "", "password": "Abc12345"}, "expect": "status=422"},
{"input": {"email": "test@example.com", "password": "123"}, "expect": "status=422"},
{"input": {"email": "test@example.com'; DROP TABLE users;--", "password": "Abc12345"}, "expect": "no_sql_injection"},
]
@pytest.mark.parametrize("case", CASES)
def test_register_prompt(case):
prompt = build_register_prompt(case["input"])
output = call_llm(prompt)
assert validate_output(output, case["expect"])反模式:
- Prompt 写好后直接上线,不做任何测试
- 只测正常场景,不测边界和异常
- 修改 Prompt 后不回归测试,导致之前通过的用例失败