为什么需要版本管理
Prompt 迭代的痛点:
v1:你是客服。回答问题。
→ 用户嫌太简短
v2:你是客服。详细回答,分点列出。
→ 效果好,用了一周
v3:你是客服。详细回答,分点,加表情符号。
→ 上线后发现 AI 疯狂加 emoji,体验崩坏
→ 想回 v2,但 v2 的内容早被覆盖,找不到了
三个缺失:
- 没有历史:改一版丢一版,无法回退
- 没有对比:不知道 v3 比 v2 改了啥、效果差多少
- 没有回滚:出问题只能紧急手改,改出新 bug
模板复用 让 Prompt 可复用,A/B 测试 让迭代有数据支撑,版本管理让这一切可追溯、可回滚——这是 Prompt 工程化的收尾一环。
版本管理四要素
要素 1:版本号
用语义化版本(SemVer):
MAJOR.MINOR.PATCH
v2.1.0
│ │ │
│ │ └─ PATCH:修 bug、调措辞(不破坏行为)
│ └─── MINOR:加变量、加示例(向后兼容)
└───── MAJOR:破坏性变更(改输出格式/改角色/改规则)
例:
v1.0.0 初版
v1.0.1 修了个错别字
v1.1.0 加了 {{style}} 变量
v2.0.0 从"自由回答"改成"分点输出"(破坏性)
v2.0.1 分点数从 3 改成 5
要素 2:变更记录
每版改了啥,一句话说清:
id: customer-service/qa
version: 2.1.0
date: 2026-08-18
author: zhang
change_type: MINOR
change: 加 {{tone}} 变量,支持语气切换
reason: 不同渠道需要不同语气
metrics:
satisfaction: 78 → 82 # 满意度提升
before: |
你是客服。问题:{{q}}
after: |
你是客服。语气:{{tone}}。问题:{{q}}
要素 3:效果指标
每个版本记录关键指标,方便对比:
v1.0.0 满意度 72% 准确率 85%
v1.1.0 满意度 75% 准确率 86%
v2.0.0 满意度 80% 准确率 83% ← 准确率降了
v2.0.1 满意度 81% 准确率 84%
v2.1.0 满意度 82% 准确率 85%
一看就知道 v2.0.0 换格式后准确率掉了,可针对性优化。这与 A/B 测试 的指标体系一致。
要素 4:回滚机制
出问题时快速回到上一稳定版:
回滚触发条件:
- 满意度跌 > 10%
- 准确率跌 > 5%
- 格式合规率 < 90%
- 用户投诉激增
回滚流程:
1. 触发告警
2. 自动切回上一稳定版(v2.0.1)
3. 通知负责人
4. 排查 v2.1.0 问题
5. 修复后重新灰度
三种管理方案
方案 1:文件管理(轻量)
适合小团队 / Prompt 少。
prompts/
├── customer-service/
│ ├── qa.v1.md # v1
│ ├── qa.v2.md # v2
│ ├── qa.v2.1.md # v2.1
│ ├── qa.current.md # 当前版(指向最新)
│ └── changelog.yml # 变更记录
优点:简单、Git 友好、可 diff。 缺点:版本多了文件爆炸、查询不便。
方案 2:数据库管理(中等)
适合 Prompt 多、需要查询统计。
CREATE TABLE prompts (
id VARCHAR PRIMARY KEY, -- customer-service/qa
version VARCHAR, -- 2.1.0
content TEXT, -- 模板正文
variables JSON, -- 变量定义
change_log TEXT, -- 变更说明
metrics JSON, -- 效果指标
status VARCHAR, -- stable/canary/deprecated
created_at TIMESTAMP,
UNIQUE(id, version)
);
查询:
-- 取当前稳定版
SELECT * FROM prompts
WHERE id = 'customer-service/qa' AND status = 'stable'
ORDER BY created_at DESC LIMIT 1;
-- 对比两版 diff
SELECT content FROM prompts WHERE id = '...' AND version IN ('2.0.0', '2.1.0');
优点:查询强、可统计、可灰度。 缺点:要建表、要维护。
方案 3:Prompt 注册中心(重度)
适合大团队 / 多应用复用。
Prompt Registry(类似微服务注册中心)
├── 版本管理
├── 灰度发布
├── A/B 路由
├── 效果监控
├── 权限管理
└── API 调用
应用通过 API 拉取:
template = registry.get("customer-service/qa", version="2.1.0")
prompt = template.render(q="怎么退货")
优点:全功能、跨应用。 缺点:开发成本高。
建议:5 个模板以下用方案 1,20 个以下用方案 2,再多用方案 3。
版本管理器实现
import json
from datetime import datetime
from pathlib import Path
from typing import Any
import semver # pip install semver
class PromptVersionManager:
def __init__(self, store_path: str):
self.store = Path(store_path) # 存储 JSON 文件
self.store.mkdir(exist_ok=True)
def save_version(self, prompt_id: str, content: str,
variables: dict, change: str,
change_type: str = "PATCH") -> str:
"""保存新版本"""
# 取当前最新版本号
latest = self.get_latest(prompt_id)
if latest:
new_ver = self._bump(latest["version"], change_type)
else:
new_ver = "1.0.0" # 初版
record = {
"id": prompt_id,
"version": new_ver,
"content": content,
"variables": variables,
"change": change,
"change_type": change_type,
"date": datetime.now().isoformat(),
"status": "canary", # 新版先灰度
"metrics": {},
}
# 写入
file = self.store / f"{prompt_id.replace('/', '_')}_{new_ver}.json"
file.write_text(json.dumps(record, ensure_ascii=False, indent=2))
return new_ver
def get_version(self, prompt_id: str, version: str = None):
"""取指定版本,默认取 stable"""
if version:
return self._load(prompt_id, version)
# 取 stable
return self.get_stable(prompt_id)
def get_stable(self, prompt_id: str):
"""取当前稳定版"""
all_v = self._list_versions(prompt_id)
for v in sorted(all_v, key=lambda x: x["date"], reverse=True):
if v["status"] == "stable":
return v
return None
def promote(self, prompt_id: str, version: str):
"""灰度版晋升为稳定版"""
rec = self._load(prompt_id, version)
# 旧 stable 降级
old = self.get_stable(prompt_id)
if old:
old["status"] = "deprecated"
self._write(old)
# 新版升 stable
rec["status"] = "stable"
self._write(rec)
return f"promoted {version} to stable"
def rollback(self, prompt_id: str):
"""回滚到上一稳定版"""
all_v = self._list_versions(prompt_id)
stables = [v for v in all_v if v["status"] in ("stable", "deprecated")]
stables.sort(key=lambda x: x["date"])
if len(stables) < 2:
return "no version to rollback"
# 当 stable 降回 deprecated,上一 deprecated 升 stable
current = stables[-1]
current["status"] = "deprecated"
self._write(current)
previous = stables[-2]
previous["status"] = "stable"
self._write(previous)
return f"rollback: {current['version']} → {previous['version']}"
def diff(self, prompt_id: str, v1: str, v2: str):
"""对比两版"""
a = self._load(prompt_id, v1)
b = self._load(prompt_id, v2)
return {
"content_changed": a["content"] != b["content"],
"variables_changed": a["variables"] != b["variables"],
"change_log": b["change"],
}
def _bump(self, ver: str, change_type: str) -> str:
v = semver.Version.parse(ver)
if change_type == "MAJOR":
return str(v.bump_major())
elif change_type == "MINOR":
return str(v.bump_minor())
else:
return str(v.bump_patch())
def _load(self, pid, ver):
file = self.store / f"{pid.replace('/', '_')}_{ver}.json"
return json.loads(file.read_text())
def _write(self, record):
file = self.store / f"{record['id'].replace('/', '_')}_{record['version']}.json"
file.write_text(json.dumps(record, ensure_ascii=False, indent=2))
def _list_versions(self, pid):
prefix = pid.replace("/", "_")
files = list(self.store.glob(f"{prefix}_*.json"))
return [json.loads(f.read_text()) for f in files]
# 使用
mgr = PromptVersionManager("./prompt_store")
# 保存初版
v1 = mgr.save_version("cs/qa", "你是客服。问题:{{q}}",
{"q": {"required": True}}, "初版", "MAJOR")
# 加变量(MINOR)
v2 = mgr.save_version("cs/qa", "你是客服。语气:{{tone}}。问题:{{q}}",
{"q": {"required": True}, "tone": {"default": "礼貌"}},
"加语气变量", "MINOR")
# 灰度测试通过,晋升稳定
mgr.promote("cs/qa", v2)
# 出问题,回滚
mgr.rollback("cs/qa")
灰度发布流程
新版别全量上,先小流量试:
v2.1.0 发布流程:
1. save_version → status=canary(灰度)
2. 灰度路由:10% 流量走 v2.1.0,90% 走 v2.0.1
3. 观察 24h:
- 满意度 ≥ v2.0.1? → 加到 30%
- 再观察 24h:
- 仍 ≥? → 50%
- 再 24h:
- 仍 ≥? → 100%,promote 为 stable
- 跌了? → 停灰度,回 v2.0.1
4. 任何阶段跌 > 10% → 自动回滚
灰度路由实现:
import random
def route_prompt(prompt_id, stable_ver, canary_ver, canary_ratio=0.1):
if random.random() < canary_ratio:
return get_version(prompt_id, canary_ver) # 10% 灰度
return get_version(prompt_id, stable_ver) # 90% 稳定
回滚决策树
新版上线后监控指标:
│
├─ 指标正常(≥ 旧版)
│ └─ 继续灰度 / 全量
│
├─ 指标微跌(< 5%)
│ ├─ 可接受 → 观察更久
│ └─ 不可接受 → 停灰度,保留版本待优化
│
└─ 指标大跌(≥ 10%)或 出现故障
├─ 自动回滚到上一 stable
├─ 通知负责人
└─ 归档问题版本,禁止再灰度
常见坑点
坑 1:变量与版本不匹配
v2.0.0 依赖 {{tone}} 变量
回滚到 v1.0.0(没有 tone 变量)
→ 调用方仍传 tone → 报错
解决:调用方也记录所用版本,回滚时调用方同步回退。
坑 2:模型升级破坏旧版
Prompt v2.1.0 在 GPT-4o 上效果好
OpenAI 升级到 GPT-4o-2026
同版本 Prompt 效果变了 → 不知道是 Prompt 还是模型的问题
解决:版本记录里锁定模型版本 model: gpt-4o-2026-08。
坑 3:并发改冲突
A 改了 v2.1.0,B 也改了 v2.1.0
两人都存,后存覆盖先存
解决:加锁或用乐观锁(版本号校验)。
坑 4:只记成功不记失败
只存"好版本",不存"试过但差的版本"
→ 下次有人又试同样的改法,重复踩坑
解决:失败版本也存,标记 status: deprecated, reason: 满意度跌,避免重蹈覆辙。
与其他技巧的关系
小结
版本管理的核心思想:Prompt 是资产,不是一次性文本。
- 版本号 → 知道现在用哪版
- 变更记录 → 知道改了啥为啥改
- 效果指标 → 知道这版好不好
- 回滚机制 → 出问题能快速止血
- 灰度发布 → 新版不全量冒险
至此,Prompt 工程化四件套集齐:模板复用(定义)→ A/B 测试(验证)→ 版本管理(沉淀)→ 评估(监控)。你的 Prompt 从"个人手艺"正式走向"团队工程资产"。