Prompt 也是代码,也需要版本管理
2026 年,头部 AI 团队的 Prompt 库已经增长到数千条,涉及数百个应用场景。没有版本管理,Prompt 的变更是灾难性的——“谁改了什么?为什么改?改了之后效果变好了还是变差了?“这些问题无法回答。Prompt 版本管理平台已成为 AI 工程化的基础设施。
一、Prompt 版本管理的核心需求
1.1 与 Git 的异同
| 维度 | 代码 Git | Prompt 版本管理 |
|---|---|---|
| 版本控制 | ✅ 文件差异 | ✅ Prompt 差异 |
| 分支管理 | ✅ 功能分支 | ✅ 实验分支 |
| 代码审查 | ✅ PR | ✅ Prompt 评审 |
| CI/CD | ✅ 自动测试 | ✅ 效果评估 |
| 回滚 | ✅ 任意版本 | ✅ 任意版本 |
| 性能指标 | ❌ 不内置 | ✅ 必须内置 |
| 多环境 | dev/staging/prod | draft/staging/prod |
| A/B测试 | ❌ 不内置 | ✅ 核心功能 |
1.2 平台架构
┌────────────────────────────────────────────┐
│ Web UI / CLI │
├────────────────────────────────────────────┤
│ 版本管理 │ A/B测试 │ 灰度发布 │ 监控面板 │
├────────────────────────────────────────────┤
│ Prompt 存储引擎 │
│ ┌─────────┐ ┌──────────┐ ┌────────────┐ │
│ │版本树 │ │元数据 │ │评估结果 │ │
│ └─────────┘ └──────────┘ └────────────┘ │
├────────────────────────────────────────────┤
│ 集成层 │
│ ┌─────────┐ ┌──────────┐ ┌────────────┐ │
│ │LLM API │ │CI/CD │ │监控系统 │ │
│ └─────────┘ └──────────┘ └────────────┘ │
└────────────────────────────────────────────┘
二、数据模型设计
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Optional, Dict
from enum import Enum
class PromptStatus(Enum):
DRAFT = "draft"
IN_REVIEW = "in_review"
STAGING = "staging"
PRODUCTION = "production"
DEPRECATED = "deprecated"
ARCHIVED = "archived"
class ChangeType(Enum):
CREATED = "created"
MODIFIED = "modified"
PROMOTED = "promoted"
ROLLED_BACK = "rolled_back"
DEPRECATED = "deprecated"
@dataclass
class PromptVersion:
"""Prompt 版本模型"""
id: str
prompt_id: str # Prompt 唯一标识
version: str # 语义化版本号 e.g. "2.3.1"
parent_version: Optional[str] # 父版本
# Prompt 内容
system_prompt: str
user_template: str
variables_schema: Dict # 变量定义
# 元数据
author: str
created_at: datetime
status: PromptStatus
# 变更说明
change_type: ChangeType
change_description: str
# 评估结果
evaluation: Optional[Dict] = None
# {'accuracy': 0.92, 'safety': 0.99, 'latency_ms': 1200, ...}
# 部署信息
deployed_at: Optional[datetime] = None
deployed_by: Optional[str] = None
traffic_percentage: int = 0 # 灰度比例
@dataclass
class PromptBranch:
"""Prompt 分支"""
name: str
base_version: str
head_version: str
purpose: str # 实验目的
created_at: datetime
experiments: List[str] = field(default_factory=list)
@dataclass
class ABTest:
"""A/B 测试配置"""
id: str
prompt_id: str
variants: Dict[str, str] # {'A': 'v2.3.0', 'B': 'v2.3.1'}
traffic_split: Dict[str, int] # {'A': 50, 'B': 50}
start_time: datetime
end_time: Optional[datetime] = None
success_metrics: List[str] # ['accuracy', 'user_satisfaction']
results: Optional[Dict] = None
三、版本控制引擎
class PromptVersionControl:
"""Prompt 版本控制引擎"""
def __init__(self, storage_backend='postgresql'):
self.storage = self._init_storage(storage_backend)
def create_prompt(self, prompt_id: str, system_prompt: str,
user_template: str, author: str,
variables_schema: dict = None) -> PromptVersion:
"""创建新 Prompt"""
version = PromptVersion(
id=self._generate_id(),
prompt_id=prompt_id,
version="1.0.0",
parent_version=None,
system_prompt=system_prompt,
user_template=user_template,
variables_schema=variables_schema or {},
author=author,
created_at=datetime.now(),
status=PromptStatus.DRAFT,
change_type=ChangeType.CREATED,
change_description="初始版本"
)
self.storage.save(version)
return version
def commit(self, prompt_id: str, system_prompt: str = None,
user_template: str = None, author: str = "",
change_description: str = "") -> PromptVersion:
"""提交新版本(类似 git commit)"""
latest = self.storage.get_latest(prompt_id)
new_version = self._increment_version(latest.version,
change_description)
version = PromptVersion(
id=self._generate_id(),
prompt_id=prompt_id,
version=new_version,
parent_version=latest.version,
system_prompt=system_prompt or latest.system_prompt,
user_template=user_template or latest.user_template,
variables_schema=latest.variables_schema,
author=author,
created_at=datetime.now(),
status=PromptStatus.DRAFT,
change_type=ChangeType.MODIFIED,
change_description=change_description
)
self.storage.save(version)
return version
def diff(self, version_a: str, version_b: str) -> dict:
"""比较两个版本的差异"""
va = self.storage.get(version_a)
vb = self.storage.get(version_b)
return {
'system_prompt_diff': self._text_diff(
va.system_prompt, vb.system_prompt),
'user_template_diff': self._text_diff(
va.user_template, vb.user_template),
'version_a': version_a,
'version_b': version_b,
'metadata_changes': {
'author': f"{va.author} → {vb.author}",
'change_type': vb.change_type.value,
}
}
def promote(self, version: str, target_env: str) -> PromptVersion:
"""版本晋升(draft → staging → production)"""
pv = self.storage.get(version)
if target_env == "staging":
pv.status = PromptStatus.STAGING
elif target_env == "production":
# 检查前置条件
if pv.evaluation is None:
raise ValueError("版本未评估,不能上线")
if pv.evaluation.get('safety', 0) < 0.95:
raise ValueError("安全评估未达标")
# 将之前的 production 版本标记为 deprecated
old_prod = self.storage.get_production_version(pv.prompt_id)
if old_prod:
old_prod.status = PromptStatus.DEPRECATED
self.storage.save(old_prod)
pv.status = PromptStatus.PRODUCTION
pv.deployed_at = datetime.now()
pv.traffic_percentage = 100
self.storage.save(pv)
return pv
def rollback(self, prompt_id: str, target_version: str = None) -> PromptVersion:
"""回滚到指定版本"""
if target_version is None:
# 回滚到上一个 production 版本
versions = self.storage.get_version_history(prompt_id)
prod_versions = [v for v in versions
if v.status in [PromptStatus.DEPRECATED]]
if not prod_versions:
raise ValueError("没有可回滚的版本")
target_version = prod_versions[0].version
target = self.storage.get(target_version)
current_prod = self.storage.get_production_version(prompt_id)
if current_prod:
current_prod.status = PromptStatus.DEPRECATED
target.status = PromptStatus.PRODUCTION
target.change_type = ChangeType.ROLLED_BACK
target.deployed_at = datetime.now()
self.storage.save(current_prod)
self.storage.save(target)
return target
def _increment_version(self, current: str, change_desc: str) -> str:
"""语义化版本号递增"""
major, minor, patch = map(int, current.split('.'))
if change_desc.startswith('BREAKING') or '重大修改' in change_desc:
major += 1
minor = 0
patch = 0
elif '新增' in change_desc or '优化' in change_desc:
minor += 1
patch = 0
else:
patch += 1
return f"{major}.{minor}.{patch}"
def _text_diff(self, text_a: str, text_b: str) -> str:
"""生成文本差异"""
import difflib
diff = difflib.unified_diff(
text_a.splitlines(keepends=True),
text_b.splitlines(keepends=True),
fromfile='old', tofile='new'
)
return ''.join(diff)
四、A/B 测试引擎
class PromptABTestEngine:
"""Prompt A/B 测试引擎"""
def __init__(self, version_control: PromptVersionControl,
llm_client, evaluator):
self.vc = version_control
self.llm = llm_client
self.evaluator = evaluator
self.active_tests: Dict[str, ABTest] = {}
def create_test(self, prompt_id: str, variant_a: str,
variant_b: str, traffic_split: dict = None,
duration_days: int = 7) -> ABTest:
"""创建 A/B 测试"""
test = ABTest(
id=self._generate_id(),
prompt_id=prompt_id,
variants={'A': variant_a, 'B': variant_b},
traffic_split=traffic_split or {'A': 50, 'B': 50},
start_time=datetime.now(),
end_time=datetime.now().replace(
hour=datetime.now().hour + duration_days * 24),
success_metrics=['accuracy', 'safety', 'user_satisfaction'],
)
self.active_tests[test.id] = test
return test
def route_request(self, prompt_id: str, user_id: str) -> PromptVersion:
"""路由用户请求到对应的 Prompt 版本"""
import hashlib
# 查找活跃测试
test = self._find_active_test(prompt_id)
if not test:
# 没有测试,返回 production 版本
return self.vc.storage.get_production_version(prompt_id)
# 确定性路由(同一用户总是看到同一版本)
hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16)
bucket = hash_value % 100
cumulative = 0
for variant, percentage in test.traffic_split.items():
cumulative += percentage
if bucket < cumulative:
version = test.variants[variant]
return self.vc.storage.get(version)
return self.vc.storage.get_production_version(prompt_id)
def evaluate_test(self, test_id: str) -> dict:
"""评估 A/B 测试结果"""
test = self.active_tests[test_id]
results = {}
for variant, version in test.variants.items():
pv = self.vc.storage.get(version)
results[variant] = {
'version': version,
'metrics': pv.evaluation or {},
'sample_size': self._get_sample_size(version),
}
# 统计显著性检验
significance = self._statistical_test(
results['A']['metrics'],
results['B']['metrics']
)
test.results = {
'variants': results,
'significance': significance,
'winner': self._determine_winner(results, significance),
'recommendation': self._recommend(test, results, significance)
}
return test.results
def _statistical_test(self, metrics_a: dict, metrics_b: dict) -> dict:
"""统计显著性检验"""
from scipy import stats
results = {}
for metric in ['accuracy', 'safety', 'user_satisfaction']:
if metric in metrics_a and metric in metrics_b:
# 简化:假设已有足够样本
z_stat, p_value = stats.ttest_ind(
[metrics_a[metric]], [metrics_b[metric]]
)
results[metric] = {
'p_value': p_value,
'significant': p_value < 0.05
}
return results
五、CI/CD 集成
class PromptCIPipeline:
"""Prompt CI/CD 管道"""
def __init__(self, version_control, evaluator, safety_checker):
self.vc = version_control
self.evaluator = evaluator
self.safety = safety_checker
def run_pipeline(self, prompt_version: PromptVersion) -> dict:
"""运行完整 CI 管道"""
results = {
'version': prompt_version.version,
'stages': [],
'passed': True,
'blocking_issues': []
}
# Stage 1: 格式检查
stage = self._stage_format_check(prompt_version)
results['stages'].append(stage)
if not stage['passed']:
results['passed'] = False
results['blocking_issues'].append("格式检查未通过")
return results
# Stage 2: 安全扫描
stage = self._stage_safety_scan(prompt_version)
results['stages'].append(stage)
if not stage['passed']:
results['passed'] = False
results['blocking_issues'].append("安全扫描未通过")
return results
# Stage 3: 单元测试
stage = self._stage_unit_test(prompt_version)
results['stages'].append(stage)
if not stage['passed']:
results['passed'] = False
results['blocking_issues'].append("单元测试未通过")
# Stage 4: 回归测试
stage = self._stage_regression_test(prompt_version)
results['stages'].append(stage)
if not stage['passed']:
results['passed'] = False
results['blocking_issues'].append("回归测试未通过")
# Stage 5: 性能评估
stage = self._stage_performance_eval(prompt_version)
results['stages'].append(stage)
# Stage 6: 安全对抗测试
stage = self._stage_adversarial_test(prompt_version)
results['stages'].append(stage)
if not stage['passed']:
results['passed'] = False
results['blocking_issues'].append("对抗测试未通过")
return results
def _stage_format_check(self, pv: PromptVersion) -> dict:
"""格式检查"""
issues = []
# 检查变量引用
for var in pv.variables_schema:
if f"{{{{{var}}}}}" not in pv.user_template:
issues.append(f"变量 {var} 未在模板中使用")
# 检查 Prompt 长度
token_count = self._estimate_tokens(pv.system_prompt)
if token_count > 8000:
issues.append(f"System Prompt 过长:{token_count} tokens")
return {
'stage': 'format_check',
'passed': len(issues) == 0,
'issues': issues
}
def _stage_safety_scan(self, pv: PromptVersion) -> dict:
"""安全扫描"""
issues = self.safety.scan(pv.system_prompt)
return {
'stage': 'safety_scan',
'passed': len(issues) == 0,
'issues': issues
}
def _stage_regression_test(self, pv: PromptVersion) -> dict:
"""回归测试:与 production 版本对比"""
prod = self.vc.storage.get_production_version(pv.prompt_id)
if not prod:
return {'stage': 'regression_test', 'passed': True, 'issues': []}
# 在相同测试集上对比
test_cases = self.vc.storage.get_test_cases(pv.prompt_id)
new_results = [self.evaluator.evaluate(pv, case) for case in test_cases]
old_results = [self.evaluator.evaluate(prod, case) for case in test_cases]
# 检查是否有关键指标下降
new_accuracy = sum(r['correct'] for r in new_results) / len(new_results)
old_accuracy = sum(r['correct'] for r in old_results) / len(old_results)
issues = []
if new_accuracy < old_accuracy - 0.05: # 下降超过5%
issues.append(f"准确率下降:{old_accuracy:.2%} → {new_accuracy:.2%}")
return {
'stage': 'regression_test',
'passed': len(issues) == 0,
'issues': issues,
'metrics': {
'old_accuracy': old_accuracy,
'new_accuracy': new_accuracy
}
}
六、Prompt 注册中心
class PromptRegistry:
"""Prompt 注册中心——生产环境的服务发现"""
def __init__(self, storage):
self.storage = storage
self.cache = {} # 本地缓存
def get_prompt(self, prompt_id: str,
version: str = "latest") -> PromptVersion:
"""获取 Prompt(生产环境调用)"""
cache_key = f"{prompt_id}:{version}"
if cache_key in self.cache:
return self.cache[cache_key]
if version == "latest":
pv = self.storage.get_production_version(prompt_id)
else:
pv = self.storage.get(prompt_id, version)
# 缓存
self.cache[cache_key] = pv
return pv
def invalidate_cache(self, prompt_id: str):
"""缓存失效"""
keys_to_remove = [k for k in self.cache if k.startswith(prompt_id)]
for k in keys_to_remove:
del self.cache[k]
def list_prompts(self, status: PromptStatus = None) -> list:
"""列出所有 Prompt"""
return self.storage.list_all(status)
七、监控与告警
class PromptMonitor:
"""Prompt 监控系统"""
def __init__(self):
self.metrics = {}
def record_usage(self, prompt_id: str, version: str,
latency_ms: float, token_count: int,
success: bool, user_feedback: int = None):
"""记录 Prompt 使用指标"""
key = f"{prompt_id}:{version}"
if key not in self.metrics:
self.metrics[key] = {
'total_calls': 0,
'success_count': 0,
'latency_sum': 0,
'token_sum': 0,
'feedback_sum': 0,
'feedback_count': 0,
'errors': []
}
m = self.metrics[key]
m['total_calls'] += 1
if success:
m['success_count'] += 1
m['latency_sum'] += latency_ms
m['token_sum'] += token_count
if user_feedback is not None:
m['feedback_sum'] += user_feedback
m['feedback_count'] += 1
def check_alerts(self) -> list:
"""检查告警条件"""
alerts = []
for key, m in self.metrics.items():
if m['total_calls'] < 100:
continue
success_rate = m['success_count'] / m['total_calls']
avg_latency = m['latency_sum'] / m['total_calls']
if success_rate < 0.95:
alerts.append({
'prompt': key,
'alert': 'success_rate_low',
'value': success_rate,
'threshold': 0.95
})
if avg_latency > 5000:
alerts.append({
'prompt': key,
'alert': 'latency_high',
'value': avg_latency,
'threshold': 5000
})
return alerts
结语
Prompt 版本管理不是锦上添花,而是 AI 应用从"能用"到"好用"再到"敢用"的必经之路。正如 Git 改变了软件工程一样,Prompt 版本管理平台正在改变 AI 工程的协作方式。投入建设 Prompt 管理平台,是对团队 AI 能力长期投资中回报率最高的一项。
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
