微调模型从离线评估到灰度回滚完整原理
训练完成只产生一个候选模型,不产生“可以上线”的结论。微调模型必须证明:目标任务相对基线有足够提升,安全和通用能力没有越过退化门槛,延迟与成本可接受,真实流量中仍然稳定,并且出现问题可以快速、确定地切回已验证版本。
学习目标
完成本页后,你应该能够:
- 设计公平的基础模型与微调模型对照实验。
- 区分训练Loss、离线任务指标、安全硬门槛和线上业务指标。
- 按类别、风险、来源和长度分析结果,而不是只看平均分。
- 结合规则、人工盲评和LLM-as-a-Judge评估开放文本。
- 选择Checkpoint并避免用Test集调参。
- 设计Shadow、Canary、逐步扩流和自动回滚。
- 建立模型、Adapter、数据、Prompt、RAG和推理配置血缘。
- 监控质量漂移、输入漂移、成本和安全事故。
- 区分流量路由回滚、Adapter回滚和业务数据补偿。
- 编写可运行的配对评估与灰度门槛Demo。
一、评估与发布总链路
flowchart TD
A["冻结候选Checkpoint和配置"] --> B["在独立Test运行基线"]
A --> C["在同一Test运行候选模型"]
B --> D["保存配对输出、Usage和耗时"]
C --> D
D --> E["规则、任务指标和人工盲评"]
E --> F["安全与通用回归硬门槛"]
F --> G{"离线是否达标"}
G -->|"否"| H["回到数据、训练或方案"]
G -->|"是"| I["Shadow真实流量"]
I --> J["离线比较但不影响用户"]
J --> K{"Shadow是否达标"}
K -->|"否"| H
K -->|"是"| L["小比例Canary"]
L --> M["监控质量、安全、SLO和成本"]
M --> N{"是否触发回滚"}
N -->|"是"| O["路由切回已验证基线"]
N -->|"否"| P["分阶段扩流"]
P --> Q["持续漂移监控与数据闭环"]二、先冻结评估协议
在看到候选结果前确定:
Test样本清单和摘要
基线与候选模型版本
Prompt、RAG、工具和解码配置
每个指标公式
人工评审Rubric
安全硬门槛
最低业务提升
最大允许延迟和成本退化
统计方法和异常样本处理
上线与回滚条件看到结果后再改评分规则会引入选择偏差。确需修正规则,应生成新评估协议版本,并对基线和候选全部重跑。
三、怎样做公平对比
必须尽量固定:
| 变量 | 要求 |
|---|---|
| 输入 | 同一个sampleId和文本 |
| Prompt | 除适配必需差异外保持一致并记录 |
| RAG | 同一索引、Filter、TopK和召回结果 |
| 工具 | 同一快照或Mock结果 |
| 解码 | Temperature、Top-p、输出上限一致 |
| 重试 | 相同策略并计入成本 |
| 评分 | 同一规则、评审员和盲评流程 |
| 环境 | 记录硬件、引擎、量化和并发 |
微调模型输出更长,可能因最大输出Token更大,而不是模型更好。若必须使用不同配置,应拆开报告影响,不能全部归因于微调。
四、指标按任务选择
4.1 分类
- Accuracy:总体正确率,易受类别不平衡影响。
- Precision:预测为该类时有多少正确。
- Recall:真实该类有多少被找出。
- F1:Precision与Recall调和。
- Macro-F1:每类同等权重,适合不平衡。
- Confusion Matrix:看哪些类别互相混淆。
高风险 P0/P1 类别通常要求单独 Recall 硬门槛,不能被大量普通类平均掉。
4.2 抽取和结构化输出
分层检查:
JSON语法合法
Schema合法
字段级Exact Match/F1
枚举合法
跨字段业务规则
事实正确
权限和敏感字段JSON 能解析不代表金额、日期、类别和权限正确。
4.3 生成任务
评估:事实、完整性、相关性、格式、引用、拒答、风格和安全。ROUGE/BLEU等词面指标只能提供部分信号,表达不同不等于错误。
4.4 工具调用
看工具选择、参数Schema、参数事实、权限、无效调用、重复写入和最终任务成功率,而不是只看最终自然语言。
五、安全指标必须是硬门槛
示例:
| 指标 | 门槛示意 |
|---|---|
| 跨租户泄露 | 0 |
| 明文密钥/PII输出 | 0 |
| 未确认高风险动作 | 0 |
| 禁止内容绕过率 | 不高于基线且满足制度 |
| 应拒答却回答 | 按风险类别设严格上限 |
| Prompt Injection成功率 | 不高于批准阈值 |
总平均分提高不能抵消一次严重越权。门槛应由业务、安全和合规共同批准,不应把本表中的示意数字直接当通用标准。
六、Checkpoint怎样选择
训练可能保存多个Checkpoint:
checkpoint-400:Validation Loss最低
checkpoint-600:Macro-F1最高
checkpoint-800:格式最好但安全回归下降选择流程:
- 用Validation筛选少量候选,不使用Test反复调参。
- 对候选运行任务小评估和安全冒烟。
- 冻结最终候选后,只在Test做正式比较。
- 保存选择理由和被淘汰候选证据。
最后Checkpoint、最低Loss和最佳业务Checkpoint可能不是同一个。
七、人工盲评怎么做
评审员不能看到哪个输出来自基线或候选,随机左右顺序,按固定Rubric评分:
| 维度 | 评分问题 |
|---|---|
| 正确性 | 是否与权威事实一致 |
| 完整性 | 是否覆盖必须点 |
| 边界 | 证据不足时是否澄清/拒答 |
| 可执行性 | 建议是否符合真实流程 |
| 风格 | 是否符合长度和术语规范 |
| 安全 | 是否泄露、越权或危险承诺 |
记录评审员、时间、理由、分歧和仲裁。评审一致性低说明Rubric或任务定义可能模糊。
八、LLM-as-a-Judge的边界
Judge模型可低成本扩大评估,但可能:
- 偏好更长、更流畅的回答。
- 偏好与自身风格相似的输出。
- 被候选答案中的指令注入。
- 不知道企业真实制度。
- 对左右位置有偏差。
治理:隐藏来源、随机顺序、使用结构化Rubric、提供权威参考、交换A/B顺序复评、用人工样本校准Judge,并把安全硬规则交给确定性校验。
九、配对评估和显著性
同一个sampleId同时运行基线与候选,得到配对结果,比比较两个独立平均值更有解释力。
候选赢
持平
候选输
两者都错报告置信区间或Bootstrap等不确定性,尤其小样本差异。0.5%的平均提升可能来自随机波动;同时高风险样本即使数量少,也应单独硬门槛。
十、可运行Demo:配对门槛评估
from dataclasses import dataclass
@dataclass(frozen=True)
class Case:
sample_id: str
category: str
risk: str
baseline_correct: bool
candidate_correct: bool
candidate_safe: bool
baseline_latency_ms: int
candidate_latency_ms: int
def rate(values: list[bool]) -> float:
return sum(values) / len(values) if values else 0.0
def evaluate(cases: list[Case]) -> dict:
baseline_accuracy = rate([case.baseline_correct for case in cases])
candidate_accuracy = rate([case.candidate_correct for case in cases])
unsafe = [case.sample_id for case in cases if not case.candidate_safe]
high_risk = [case for case in cases if case.risk == "HIGH"]
high_risk_recall = rate([case.candidate_correct for case in high_risk])
latency_ratio = (
sum(case.candidate_latency_ms for case in cases)
/ sum(case.baseline_latency_ms for case in cases)
)
metrics = {
"baseline_accuracy": baseline_accuracy,
"candidate_accuracy": candidate_accuracy,
"improvement": candidate_accuracy - baseline_accuracy,
"high_risk_recall": high_risk_recall,
"unsafe_sample_ids": unsafe,
"latency_ratio": latency_ratio,
}
gates = {
"quality": metrics["improvement"] >= 0.02,
"high_risk": metrics["high_risk_recall"] >= 0.95,
"safety": len(unsafe) == 0,
"latency": latency_ratio <= 1.20,
}
return {"metrics": metrics, "gates": gates, "approved": all(gates.values())}
if __name__ == "__main__":
cases = [
Case("s1", "DB", "HIGH", True, True, True, 100, 110),
Case("s2", "NETWORK", "LOW", False, True, True, 100, 105),
Case("s3", "FORMAT", "LOW", True, True, True, 100, 108),
Case("s4", "DB", "HIGH", True, True, True, 100, 112),
]
print(evaluate(cases))示例数据很小,只演示门槛组合,不足以证明统计显著性。真实报告还应按类别、来源、长度和版本分层,并保存每个sampleId输出。
十一、评估产物怎样保存
evaluation-run-id/
├── protocol.yaml
├── baseline-manifest.yaml
├── candidate-manifest.yaml
├── sample-manifest.jsonl
├── paired-outputs.jsonl
├── rule-metrics.json
├── human-review.jsonl
├── safety-report.json
├── latency-cost-report.json
└── decision.md输出可能含敏感数据,应脱敏、限权、加密并设置保留期。不能为了可复现把完整患者信息永久保存在普通日志。
十二、Shadow是什么
Shadow把真实请求复制给候选模型,但用户仍只看到基线结果:
flowchart TD
A["真实请求"] --> B["基线模型返回用户"]
A --> C["异步复制脱敏请求"]
C --> D["候选模型Shadow执行"]
D --> E["保存配对质量、延迟和成本"]
E --> F["不执行候选写操作"]Shadow注意:
- 候选不得重复发送短信、退款或写业务数据。
- 对工具使用Mock、只读或记录不执行模式。
- 复制流量也会产生费用和数据处理风险。
- 异步队列积压不能影响主链路。
- 真实输入需按权限和数据政策处理。
十三、Canary怎样设计
Canary让小部分真实请求使用候选结果。路由应稳定,例如按用户/租户Hash,而不是每次随机,避免同一会话模型来回切换。
扩流示意:
内部用户
→ 1%
→ 5%
→ 10%
→ 25%
→ 50%
→ 100%每一阶段有最小观察时间、最小样本量和停止条件。高风险租户或功能可以更晚进入,不能只看整体错误率。
十四、路由与版本键
一次可复现调用至少记录:
baseModelRevision
adapterVersion/mergedModelVersion
tokenizerRevision
datasetVersion
trainingCodeCommit
checkpoint
promptVersion
RAGIndex/Embedding/RerankVersion
toolSchemaVersion
safetyPolicyVersion
inferenceEngineVersion
quantizationConfig
decodingOptions
experimentId缓存Key也要包含影响答案的版本与权限,避免基线缓存掩盖候选效果或跨版本串答案。
十五、自动回滚看什么
| 维度 | 示例信号 |
|---|---|
| 可用性 | 5xx、超时、OOM、加载失败 |
| 延迟 | TTFT、P95/P99、队列 |
| 质量代理 | JSON失败、Schema失败、拒答突变 |
| 业务 | 人工接管、投诉、任务成功率 |
| 安全 | 敏感输出、越权、危险动作 |
| 成本 | 每请求Token、重试和GPU成本 |
安全硬门槛可立即停止;质量指标可能需要最小样本量避免噪声误回滚。自动回滚策略本身要演练。
十六、回滚不是一个动作
16.1 流量回滚
模型网关将新请求切回基线。它不取消已经运行的长任务,也不撤销已产生的业务写入。
16.2 Adapter回滚
动态加载时切换Adapter版本;要处理正在服务的Batch、缓存和旧会话。合并模型则切换完整镜像/模型版本。
16.3 数据补偿
候选若已经创建错误工单或发送消息,需要按业务记录补偿或人工处置。模型路由回滚不会自动撤销外部世界。
16.4 证据保留
保留事故时间、版本、路由比例、sampleId、脱敏输出、指标和操作记录,避免回滚后现场全部丢失。
十七、线上漂移
17.1 输入漂移
语言、来源、长度、类别和用户群变化。例如新数据库错误码上线,训练集没有覆盖。
17.2 标签/概念漂移
业务规则改变,同样输入对应的新标签不同。继续使用旧模型会稳定地产生过时答案。
17.3 质量漂移
人工接管、纠错、投诉和离线回放变差。还要排除Prompt、RAG、工具和基础设施变化。
监控应使用聚合统计和脱敏特征,避免把完整敏感Prompt长期写入指标系统。
十八、生产Runbook
18.1 Canary质量下降
先冻结扩流,按experimentId比较基线/候选的输入分布、模型/Adapter、Prompt、RAG、工具和解码配置;确认不是路由或缓存串版本。达到门槛立即切回,保留失败sampleId供离线复现。
18.2 延迟突然升高
拆排队、Prefill、Decode、工具和网关;检查候选模型大小、量化、Adapter加载、输出长度、并发和KV Cache。若只是答案变长,TTFT可能正常而总耗时和成本上升。
18.3 Shadow与离线结论相反
检查Test是否泄漏或分布过时、Shadow是否使用相同Prompt/RAG、真实请求是否更长、工具Mock是否不同,以及Judge能否评估新场景。不要只扩大Shadow样本掩盖协议问题。
18.4 回滚后仍有错误输出
检查CDN/应用缓存、异步任务、长连接、Worker、模型进程和多Region配置。配置中心显示基线不代表所有实例已加载基线;按响应中的实际版本标签确认。
18.5 无法判断哪个版本出错
说明血缘和响应元数据缺失。立即补采集实际模型/Adapter/Prompt/RAG/工具/安全版本;不能只依赖发布单推测运行态。
十九、常见误区
平均分提高就能上线
错误。安全、高风险类别和关键业务指标需要独立硬门槛。
LLM Judge分数就是客观事实
错误。Judge存在风格、位置、自偏好和注入偏差,需要人工校准和规则验证。
Shadow没有风险
错误。它会复制真实数据、消耗模型费用,若工具未隔离还可能重复写业务。
回滚模型就恢复全部现场
错误。已执行写操作需要补偿,旧异步任务和缓存也可能继续产生结果。
Test集永远有效
错误。业务和输入会漂移,反复调参也会让Test失去独立性。
二十、面试标准回答
微调模型怎样评估
先冻结独立Test和评估协议,在同一输入、Prompt、RAG、工具、解码和评分规则下配对运行基线与候选;按任务指标、类别和高风险样本比较,并设置安全、通用回归、延迟和成本硬门槛。通过后再做Shadow和Canary,而不是只看Train Loss或几个主观样例。
Shadow和Canary区别
Shadow复制真实请求给候选,但用户仍看到基线结果,候选写工具必须禁用,适合低风险观察真实分布;Canary让小比例用户真正使用候选结果,需要稳定路由、阶段门槛和自动回滚。
为什么回滚不仅是切模型
路由切回只能影响新请求。已经运行的异步任务、缓存和长连接可能继续返回旧版本;候选执行过的工单、消息或其他写操作还需要业务补偿。因此回滚要同时处理流量、进程、任务、缓存和业务数据。
LLM-as-a-Judge有什么风险
Judge可能偏好长答案、特定风格或自身输出,受左右位置和候选注入影响,也未必知道企业事实。应盲化来源、随机顺序、提供Rubric和权威参考、交换位置复评,并用人工样本校准。
二十一、学习验收
不看答案完成:
- 写出基线与候选的公平对比变量。
- 为分类、抽取和生成任务各设计指标。
- 设置质量、安全、回归、延迟和成本门槛。
- 设计人工盲评Rubric和仲裁流程。
- 运行配对评估Demo并制造安全门槛失败。
- 区分Validation选Checkpoint和Test最终验收。
- 设计只读Shadow并证明不会执行写工具。
- 设计按用户Hash稳定的Canary路由。
- 写出一次调用的完整版本矩阵。
- 演练路由、Adapter、异步任务、缓存和业务补偿回滚。
- 设计输入、概念和质量漂移指标。
- 根据失败sampleId还原一次候选事故。
