提示词工程化·免费版
红线
- 不许凭感觉调词:任何改动都要在测试集上验证,记录前后分数。
- 必须有版本号:提示词改动要可回滚。
- 不承诺"万能提示词":效果依赖于模型、场景与数据,只给可测的改进。
- 不引用任何付费端点/专有服务:优先本地/开源方案。
何时使用
- 提示词越写越长、越来越难维护。
- 改了一个词效果变差,却回不去了。
- 多个场景重复写相似提示词,想复用。
- 想把提示词交给团队协作维护。
反触发(不要用):
- 一次性临时用的短提示词 → 不需要工程化。
- 只是想要几个好用的提示词模板 → 直接找模板即可。
职责边界
- 做:模块化拆分、版本管理、测试集设计、改动评估流程。
- 不做:保证效果、替用户写业务逻辑。
主流程
第 1 步:模块化拆分(质检闸 A)
把一整段提示词拆成职责单一的模块:
prompts/
├── _base.md # 角色 + 通用约束(所有场景共用)
├── _output_format.md # 输出格式规范
├── task_summarize.md # 场景:摘要
├── task_extract.md # 场景:信息抽取
└── fewshot/ # 示例库(按需引用)
├── summarize_news.md
└── extract_invoice.md
模块类型:
| 类型 | 内容 | 复用度 |
|---|---|---|
| 基础块 | 角色、语气、通用红线 | 高 |
| 任务块 | 具体要做什么 | 低(场景专属) |
| 格式块 | 输出结构(JSON/Markdown) | 中 |
| 示例块 | Few-shot 样例 | 中(按需选) |
组合方式:
def build_prompt(task, fmt, fewshot=None):
parts = [load("_base.md"), load(f"task_{task}.md"), load(f"_output_format_{fmt}.md")]
if fewshot: parts.append(load(f"fewshot/{fewshot}.md"))
return "\n\n".join(parts)
> 质检闸 A:同一段文字在 3 个以上提示词里重复出现 → 抽成公共模块。
第 2 步:参数化(变量外置)
禁止把具体内容写死在提示词里:
❌ 写死:"请用简洁的语言总结这篇关于人工智能的文章"
✅ 参数化:"请用{{tone}}的语言总结这篇关于{{topic}}的文章"
参数文件:
# params/summarize.yaml
tone: 简洁
topic: 人工智能
max_words: 200
audience: 非技术背景读者
好处:改参数不动提示词,改提示词不动参数;便于批量跑不同配置。
第 3 步:版本管理(质检闸 B)
命名规范:
prompts/v1.2.0/task_summarize.md
prompts/v1.2.1/task_summarize.md
或放在 Git 里(推荐):
git tag prompt-summarize-v1.2.0
每次改动必须记录 CHANGELOG:
## v1.2.1 (2026-09-09)
- 改动:把"简洁"改为"不超过 200 字"
- 原因:v1.2.0 输出长度波动大(50–400 字)
- 测试集分数:78% → 85%
- 副作用:极短输入时略显啰嗦(可接受)
> 质检闸 B:没有 CHANGELOG 的提示词改动 → 视为未记录,回滚时无法定位。
第 4 步:建测试用例集(质检闸 C)
最小 20–30 条,覆盖:
| 类型 | 占比 | 例子 |
|---|---|---|
| 典型 | 60% | 常见长度、常见主题 |
| 边界 | 20% | 极短输入、超长输入、空输入 |
| 异常 | 15% | 含特殊字符、多语言混杂 |
| 对抗 | 5% | 试图让模型违规的输入 |
用例格式:
{
"id": "sum_001",
"input": {"text": "...", "tone": "简洁"},
"expect": {
"must_contain": ["关键词A"],
"must_not_contain": ["原文未提及的内容"],
"max_words": 200,
"format": "markdown"
}
}
第 5 步:自动化评估
分三层,从便宜到贵:
① 规则校验(必做,最便宜)
def check(output, expect):
issues = []
if expect.get("max_words") and count_words(output) > expect["max_words"]:
issues.append("超长")
for kw in expect.get("must_contain", []):
if kw not in output: issues.append(f"缺关键词: {kw}")
if expect.get("format") == "json":
try: json.loads(output)
except Exception: issues.append("JSON 解析失败")
return issues
② LLM 裁判(主观质量)
- 用模型给输出打分(1–5)或做 A/B 二选一
- 裁判必须先校准:用人工标注的 20 条验证裁判与人的一致率 > 80%
③ 人工抽检(最终把关)
- 每次改动后人工看 5–10 条,防止指标好看但实际很糟
> 质检闸 C:改提示词前必须记录当前测试集分数,改完对比。
> 没对比就说"变好了" = 无效改动。
第 6 步:A/B 对比与灰度
对比方法:
1. 同一测试集分别跑 v_old 和 v_new
2. 统计:通过率、平均长度、失败类型分布
3. 对差异大的 case 人工复核
4. 只在"新版本不劣于旧版本"时才上线
灰度:新提示词先给 5–10% 流量,观察真实反馈,再全量。
常见坑
| 坑 | 表现 | 解决 |
|---|---|---|
| 咒语式调词 | 加"深呼吸""你是专家"期待奇迹 | 建测试集,用数据说话 |
| 提示词越来越长 | 从 200 字膨胀到 3000 字 | 模块化 + 删冗余 |
| 示例过多 | 塞 20 个 few-shot,成本高 | 精选 3–5 个典型,或动态检索 |
| 无版本 | 改坏了回不去 | Git 管理 + CHANGELOG |
| 只看单条效果 | 一个 case 好了就上线 | 必须跑测试集 |
| 忽略格式稳定性 | 有时输出 JSON 有时不是 | 格式块 + 校验 + 重试 |
失败降级
- 时间紧 → 至少做到:Git 版本管理 + 10 条冒烟用例 + 规则校验。
- 效果无法量化(创意写作)→ 用 A/B 人工盲评(不告诉评审哪个是新版本)。
- 团队协作混乱 → 先只做模块化拆分和命名规范,测试后补。
依赖
- 无外部依赖。版本管理用 Git,评估脚本用 Python 标准库即可。
- 无需任何付费 API。
致谢
- 原创免费技能,基于公开通用的软件工程实践(版本管理、测试、模块化)
迁移到提示词管理领域,由本技能作者重新组织与本地化撰写。 - 灵感参考社区"Prompt as Code"的公开理念,内容全部原创重写。
- 采用 MIT 许可,不依赖任何专有实现或付费服务。