RAG 发布门禁生产实战:Release Manifest、灰度、回滚与审计闭环
把 RAG 的评测报告、变更风险、Hard/Soft Gate、Shadow、Canary、自动暂停和多资产回滚连接成一套可执行、可审计、可恢复的生产发布系统。
RAG 系统的发布经常被误解成一次普通应用部署:
代码合并
→ CI 构建通过
→ 部署新容器
→ 发布完成但一个生产 RAG 版本实际上可能同时改变:
- Query Rewrite Prompt;
- Embedding 模型和向量空间;
- Chunk 策略和索引结构;
- BM25 字段权重;
- RRF、Top-K、阈值和过滤条件;
- Reranker 模型、窗口和
min_score; - Context Pack 顺序与 Token Budget;
- Answer Prompt、Guardrail 和 Citation 规则;
- 模型路由、缓存、价格和超时;
- Tenant、ACL 和数据源授权边界。
代码部署成功,只能证明软件能够启动;它不能证明:
- 正确证据仍然能被召回;
- 高严重度问题没有回归;
- 无权内容没有进入候选、Context 或 Citation;
- P95、P99 和单请求成本仍在预算内;
- 新索引、Prompt、模型和配置可以立即切回;
- 灰度异常时系统知道应该自动暂停,而不是继续扩大流量。
生产级 Release Gate 的目标不是阻止发布,而是把每次变化变成一个有证据、有边界、有 Owner、有暂停条件、有回滚路径的工程动作。
资料快照:本文基于前文已经建立的 RAG 评测、可观测性、Hybrid Search、Reranker、Query Rewriting 与 MySQL→Elasticsearch 一致性设计,核查截至 2026-08-05。文中的阈值和灰度比例是工程示例,应由真实流量、历史基线、业务严重度和合规要求校准。
图 1:RAG 发布不是一次容器替换,而是一条包含评测、风险控制、灰度观察和多资产回滚的发布链路。
一句话结论
一个 RAG 版本只有同时满足下面五个条件,才应该进入生产:
- Release Manifest 足以复现它。
- Baseline 与 Candidate 在同一数据集上完成成对评测。
- 安全和关键能力通过 Hard Gate。
- 灰度阶段有明确的推进、暂停和回滚阈值。
- 旧 Prompt、旧索引、旧模型路由和旧配置仍可立即恢复。
推荐的控制链路是:
Change Request
→ Risk Classification
→ Candidate Build
→ Immutable Release Manifest
→ Offline Paired Evaluation
→ Hard / Soft Gate
→ Shadow
→ Canary 1% / 5% / 10%
→ Full Rollout
→ Online Evaluation
→ Incident / Bad Case
→ Regression Dataset1. 先看完整发布生命周期
图 2:Release Gate 不只存在于 CI。离线评测、Shadow、Canary、持续监控、回滚和坏例回流共同组成完整发布生命周期。
门禁的核心不是“通过或失败”两个结果,而是允许四种决策:
PASS
→ 可以进入下一阶段
CONDITIONAL PASS
→ 带明确风险、Owner 和观察条件进入灰度
PAUSE
→ 停止扩大流量,继续观察或补充样本
BLOCK / ROLLBACK
→ 不允许发布,或立即切回稳定版本2. RAG Release 和代码 Release 有什么不同
代码发布通常围绕:
Build
Test
Deploy
Health Check
Rollback BinaryRAG 发布还需要管理非代码资产:
| 资产 | 变化会影响什么 | 典型回滚 |
|---|---|---|
| Prompt | 答案格式、拒答、引用、工具调用 | 切回 Prompt Version |
| Query Plan | 原始 Query、Rewrite、分解和 Scope | 关闭 Planner 或切回旧版本 |
| Embedding | 向量空间和召回分布 | 切回旧索引与旧模型 |
| Chunk | 检索单位、引用粒度和 Context | Alias 切回旧物理索引 |
| BM25 / RRF | 候选排序和 Recall | 配置路由切回 |
| Reranker | Top-K、延迟和 GPU 成本 | 熔断或切回旧端点 |
| Context Packer | Token、顺序、去重和引用 | 切回旧 Packer 配置 |
| LLM Route | 输出质量、延迟和成本 | 切回稳定模型 Route |
| ACL / Filter | 数据访问边界 | Fail Closed + 回滚规则 |
| Data Source | 覆盖、新鲜度和噪声 | 禁用来源或切回旧快照 |
因此,RAG Release 的发布单元不是一个 Commit,而是:
应用代码 + 索引快照 + 模型身份 + Prompt + 检索配置 + 权限规则 + 评测数据集 + 回滚资产。
3. Release Manifest:先定义“到底发布了什么”
没有 Release Manifest,事故发生后团队通常只知道:
大概是下午发布的;
好像换过 Reranker;
Prompt 应该还是 v7;
索引可能已经切到 v4;
Embedding 用的是哪个 Endpoint 不确定。一份完整 Manifest 可以是:
{
"release_id": "rag-prod-2026-08-05.3",
"created_at": "2026-08-05T18:30:00+08:00",
"owner": "rag-platform",
"change_ticket": "RAG-1842",
"risk_level": "high",
"application": {
"repository": "chicogong/rag-service",
"commit": "abc123def456",
"image": "registry.example.com/rag-service:abc123"
},
"query": {
"classifier_version": "query-classifier-v5",
"planner_prompt_version": "query-plan-v8",
"rewrite_prompt_version": "rewrite-v11",
"scope_compiler_version": "scope-v4"
},
"retrieval": {
"index_alias": "kb_chunks",
"physical_indices": ["kb_chunks_v4"],
"projection_schema_version": 6,
"embedding_model_key": "bge-m3|endpoint-a|rev-20260801",
"bm25_config_version": "bm25-v9",
"rrf_config_version": "rrf-v7",
"top_k": {
"bm25": 80,
"dense": 80,
"fusion": 100
}
},
"rerank": {
"model_key": "bge-reranker-v2-m3|gpu-pool-a|rev-3",
"config_version": "rerank-v10",
"window": 50,
"output_count": 8
},
"context": {
"packer_version": "context-v7",
"token_budget": 6000,
"max_chunks_per_document": 2
},
"generation": {
"prompt_version": "answer-v16",
"model_route": "answer-stable-202608",
"guardrail_version": "guard-v5",
"citation_mapper_version": "citation-v4"
},
"evaluation": {
"datasets": [
"rag-eval-core@2026-08-05.1",
"rag-eval-regression@2026-08-05.7",
"rag-eval-safety@2026-08-05.3"
],
"judge_version": "judge-v11",
"metric_schema_version": "rag-metrics-v6",
"baseline_release_id": "rag-prod-2026-07-29.2",
"report_uri": "artifact://rag-release/rag-prod-2026-08-05.3/report.json"
},
"rollback": {
"target_release_id": "rag-prod-2026-07-29.2",
"runbook": "runbook://rag/release-rollback-v4",
"verified_at": "2026-08-05T17:30:00+08:00"
}
}3.1 Manifest 的三个要求
不可变。
发布后不覆盖原文件,修订应生成新 Release ID。
可解析。
不要只写 Markdown 描述,关键字段必须能被 CI、部署系统和观测系统读取。
可验证。
Manifest 中引用的 Prompt、索引、模型、报告和 Runbook 都必须真实存在。
4. 发布前先做风险分级
图 3:Prompt 文案、检索参数、Reranker、索引、Embedding 和权限规则拥有不同风险。风险越高,所需评测覆盖、审批、灰度和回滚资产越严格。
4.1 风险不是由改动行数决定
下面两个改动可能只差一行配置,但风险完全不同:
answer_temperature: 0.1 → 0.0和:
acl_filter_mode: pre_filter → post_filter后者可能改变无权文档是否进入候选集、Trace 和 Context,属于 Critical 变化。
4.2 建议风险维度
| 维度 | 问题 |
|---|---|
| 影响范围 | 单 Query、单租户、部分流量还是全局 |
| 安全边界 | 是否影响 Tenant、ACL、敏感数据和拒答 |
| 数据变化 | 是否需要重切 Chunk、重建向量或迁移索引 |
| 回滚时间 | 秒级配置切换,还是数小时重建 |
| 模型变化 | 是否改变向量空间、Score 分布或生成行为 |
| 成本变化 | 是否新增模型调用、GPU 或大幅 Token |
| 可观测性 | 新链路是否有完整 Trace 与指标 |
| 历史先例 | 是否存在同类事故或高严重度 Bad Case |
4.3 四级风险
| 等级 | 示例 | 门禁要求 |
|---|---|---|
| Low | 文案、非语义展示、小范围配置 | 基础回归 + 快速灰度 |
| Medium | Top-K、阈值、Query Route、缓存 | Paired Eval + Shadow + Canary |
| High | Reranker、Embedding、Chunk、Index | 全量离线 + 影子流量 + 分段灰度 + 完整回滚 |
| Critical | Tenant、ACL、敏感内容、Guardrail | Safety 100% + 双人审批 + Fail Closed + 零容忍 |
Critical 变化不允许通过 Waiver 抵消安全失败。
5. Change Request 应该包含什么
在运行评测前,变更提出者应回答:
为什么改?
解决哪个 Bad Case 或业务目标?
改动了哪些资产?
预计影响哪些 Query Cohort?
可能退化什么?
如何观察?
如何回滚?
谁是 Owner?推荐 Schema:
change_request:
id: RAG-1842
title: 增加 Reranker Window 以改善多证据问题
owner: retrieval-team
risk_level: high
hypothesis:
problem: 多证据问题正确 Chunk 已进入 RRF Top-50,但未进入 Rerank Window
expected_gain: multi_evidence_context_recall 提升
acceptable_cost: p95 增加不超过 80ms
affected_assets:
- reranker_config
- context_packer
target_cohorts:
- multi_evidence
- policy_comparison
known_risks:
- GPU queue time 增加
- 短 Query 可能无收益
- 长候选文本导致截断比例上升
rollback:
target_release_id: rag-prod-2026-07-29.2
estimated_seconds: 30没有清晰假设的改动,很难设计正确评测,也很难解释上线结果。
6. Candidate Build 需要产生哪些 Artifact
一个候选版本至少产生:
release-manifest.json
change-request.yaml
offline-eval-report.json
offline-eval-report.md
case-level-diff.jsonl
safety-report.json
latency-cost-report.json
index-manifest.json
prompt-bundle/
retrieval-config.json
reranker-config.json
rollback-plan.yaml
approval-record.json建议目录:
Artifact 应有 Hash、创建时间、Owner、Retention 和访问控制。
7. 离线评测必须是 Baseline / Candidate 成对实验
同一批 Case、同一 Scope 和同一时间快照分别运行:
Baseline
Candidate输出:
Improved
Regressed
Unchanged
New Failure
Fixed Bad Case
Judge Inconsistent门禁不能只看两个独立平均值。
7.1 为什么 Case-level Diff 更重要
假设整体 NDCG 上升 2%,但:
高频 FAQ +5%
Critical 权限问题出现 1 次越权平均分不能抵消这次越权。
每个 Case 至少记录:
{
"case_id": "rag_eval_0042",
"severity": "high",
"cohort": "multi_evidence",
"baseline": {
"retrieval_recall_at_20": 0.5,
"faithfulness": 1.0,
"latency_ms": 910
},
"candidate": {
"retrieval_recall_at_20": 1.0,
"faithfulness": 1.0,
"latency_ms": 1040
},
"classification": "improved",
"root_delta": "rerank window 30 → 50"
}7.2 置信区间与 Effect Size
小数据集的 +0.01 可能只是抽样噪声。
评测报告应包含:
- Paired Bootstrap CI;
- 通过率的 Wilson Interval;
- Effect Size;
- 非确定性模型的重复运行方差;
- 高严重度样本的绝对变化。
相关方法见 RAG 评测生产实战。
8. Hard Gate:不能被平均分抵消的规则
Hard Gate 用来保护安全、契约和关键能力。
建议包括:
Unauthorized Retrieval Rate = 0
Unauthorized Context Rate = 0
Unauthorized Citation Rate = 0
Critical Safety Pass Rate = 100%
Invalid Citation ID Rate = 0
Trace Contract Pass Rate = 100%
Schema Validation Pass Rate = 100%
High Severity Regression Count = 0
P99 < Hard Deadline
Rollback Verification = passed8.1 三种 Unauthorized 必须分开
Unauthorized Retrieval
无权内容已经进入候选或 Trace Artifact,即使没有进 Prompt,也可能构成数据暴露。
Unauthorized Context
无权内容进入模型输入,风险更高。
Unauthorized Citation
答案向用户暴露了无权来源或链接。
只检查 Context 不够。
8.2 Fail Closed
如果权限服务、Scope Compiler 或 Policy Engine 异常:
不允许扩大 Scope
不允许跳过 ACL
不允许用缓存中的旧权限继续回答合理降级是拒答、重试或返回明确错误,而不是“尽量回答”。
9. Soft Gate:质量、延迟和成本之间的权衡
Soft Gate 可以允许小幅波动,但必须有解释、Owner 和灰度观察条件。
常见指标:
| 维度 | 指标 |
|---|---|
| Retrieval | Recall@K、MRR、NDCG、Union Recall |
| Context | Precision、Recall、Coverage、Redundancy |
| Answer | Correctness、Faithfulness、Citation Accuracy |
| Behavior | Refusal、Clarification、Degrade Rate |
| Performance | P50、P95、P99、Timeout |
| Cost | Embedding、Rerank、LLM、Artifact Storage |
| Product | 差评率、追问率、人工升级率 |
9.1 不要只设全局阈值
应该按 Cohort 设置:
Exact ID
Error Code
Concept
Multi-evidence
Multi-hop
Temporal
Permission-sensitive
Long Context
No Evidence全局平均值可能掩盖某一类 Query 的明显退化。
10. 一份可执行的 Release Gate 配置
release_gate_version: rag-gate-v5
release:
id: rag-prod-2026-08-05.3
baseline_release_id: rag-prod-2026-07-29.2
risk_level: high
owner: rag-platform
required_artifacts:
- release-manifest.json
- change-request.yaml
- evaluation/summary.json
- evaluation/case-level-diff.jsonl
- evaluation/safety-report.json
- runtime/index-manifest.json
- rollback/rollback-plan.yaml
- rollback/rollback-verification.json
datasets:
- rag-eval-core@2026-08-05.1
- rag-eval-regression@2026-08-05.7
- rag-eval-safety@2026-08-05.3
hard_gates:
unauthorized_retrieval_rate:
max: 0
unauthorized_context_rate:
max: 0
unauthorized_citation_rate:
max: 0
critical_case_pass_rate:
min: 1.0
high_severity_regression_count:
max: 0
invalid_citation_rate:
max: 0
trace_contract_pass_rate:
min: 1.0
schema_validation_pass_rate:
min: 1.0
rollback_verification:
equals: passed
p99_latency_ms:
max: 5000
soft_gates:
evidence_recall_at_10:
max_drop: 0.005
ndcg_at_10:
max_drop: 0.01
context_precision:
max_drop: 0.01
faithfulness:
max_drop: 0.005
citation_accuracy:
max_drop: 0.005
p95_latency_ms:
max_increase_ratio: 0.15
cost_per_request:
max_increase_ratio: 0.10
cohort_gates:
permission_sensitive:
pass_rate:
min: 1.0
exact_id:
hit_at_1:
max_drop: 0
multi_hop:
complete_chain_rate:
max_drop: 0.02
waiver_policy:
allowed_for:
- soft_gate
forbidden_for:
- unauthorized_access
- critical_safety
- invalid_schema
required_approvers: 2
max_valid_hours: 24门禁配置自身也要版本化、评审和测试。
11. Waiver:例外不是绕过门禁
Soft Gate 可能出现合理例外:
Faithfulness 不变
NDCG +4%
P95 +12%
成本 +11%如果业务认为质量收益值得成本增加,可以申请 Waiver。
一份 Waiver 应包含:
waiver:
release_id: rag-prod-2026-08-05.3
gate: cost_per_request
observed: 0.021
threshold: 0.020
reason: 多跳问题完整证据链提升 8.4%
scope: multi_hop_queries_only
expires_at: 2026-08-06T18:00:00+08:00
owner: rag-quality
approvers:
- retrieval-lead
- product-owner
online_guardrail:
cost_per_request_max: 0.024
auto_pause: trueWaiver 必须:
- 有过期时间;
- 有作用 Scope;
- 有在线 Guardrail;
- 有审批记录;
- 不能用于越权、安全和无效契约。
12. Shadow:先用真实请求验证,不影响用户
Shadow 模式将真实生产请求复制给 Candidate:
Shadow 适合验证:
- 真实 Query 分布;
- 新模型延迟与错误;
- Candidate 的空召回和降级率;
- 离线集未覆盖的语言、长度和数据源;
- 真实成本。
12.1 Shadow 的安全要求
Candidate 仍会接触真实数据,因此:
- 使用同样或更严格的 ACL;
- 不允许把输出返回用户;
- Artifact Retention 遵守生产隐私策略;
- 不对外部工具执行写操作;
- 不发送邮件、创建日历或修改业务系统;
- 对高成本模型设置独立预算。
12.2 Shadow 不是完整 A/B
用户看不到 Candidate,所以无法直接测:
- 用户满意度;
- 交互行为;
- 业务转化。
它主要用于技术质量和生产分布验证。
13. Canary 与自动回滚控制环
图 4:稳定版本始终在线,Candidate 逐段放量;每个阶段都拥有推进、暂停和回滚条件。任何 Hard Gate 触发时立即切回已验证资产。
13.1 Canary 的阶段
一个 High Risk 发布可以采用:
Shadow
→ 1%
→ 5%
→ 10%
→ 25%
→ 50%
→ 100%比例不是重点,重点是每一阶段拥有:
最小样本量
最短观察窗口
推进条件
暂停条件
回滚条件
Owner13.2 示例阶段配置
canary:
stages:
- name: shadow
traffic_percent: 0
min_requests: 10000
min_duration_minutes: 30
- name: canary_1
traffic_percent: 1
min_requests: 2000
min_duration_minutes: 30
- name: canary_10
traffic_percent: 10
min_requests: 10000
min_duration_minutes: 60
- name: canary_50
traffic_percent: 50
min_requests: 50000
min_duration_minutes: 120
- name: rollout
traffic_percent: 100
advance_when:
hard_gates_passed: true
high_severity_regressions: 0
p95_latency_ratio_max: 1.15
cost_ratio_max: 1.10
pause_when:
sample_size_insufficient: true
judge_disagreement_rate_max: 0.08
soft_gate_warning_count_max: 2
rollback_when:
unauthorized_access_count_min: 1
critical_failure_count_min: 1
p99_latency_ms_min: 5000
error_rate_ratio_min: 2.013.3 不要只按时间推进
错误做法:
发布 15 分钟没报警
→ 自动从 1% 升到 50%如果 15 分钟内只有几十个目标 Cohort Query,样本不足以判断。
推进应同时满足:
Duration
+
Request Count
+
Cohort Coverage
+
Hard Gate
+
Soft Gate14. Canary 期间应该监控什么
14.1 质量
Empty Retrieval Rate
Evidence Recall Proxy
Citation Coverage
Invalid Citation Rate
Refusal Rate
Clarification Rate
User Negative Feedback
Human Escalation14.2 安全
Unauthorized Retrieval
Unauthorized Context
Unauthorized Citation
Prompt Injection Detection
Sensitive Data Exposure
Cross-tenant Cache Hit14.3 性能
P50 / P95 / P99
Timeout Rate
Queue Time
Embedding Latency
Reranker Latency
LLM Time to First Token
Fallback Rate14.4 成本
Embedding Cost
Rerank Pair Count
Rerank GPU Time
LLM Input / Output Tokens
Cache Read / Write
Artifact Storage
Cost per Successful Answer14.5 分布
按这些维度切分:
Tenant
Language
Query Cohort
Knowledge Base
Data Source
Model Route
Region
Document Type全局平均值可能掩盖某一租户或语言的严重回归。
15. 自动暂停和自动回滚要分开
Pause
停止继续扩大流量,但保留当前 Canary 比例,用于:
- 样本量不足;
- Soft Gate 轻微越界;
- Judge 分歧较大;
- 需要人工检查 Case;
- 指标波动但没有安全问题。
Rollback
立即把所有 Candidate 流量切回稳定版本,用于:
- 任何越权;
- Critical Case 回归;
- 持续错误;
- P99 超硬上限;
- 错误引用或敏感信息暴露;
- 候选资产不可用。
不要因为希望“多看一会”而让 Critical 风险继续暴露。
16. 回滚不是 git revert
RAG 回滚需要同时恢复多种资产。
| 资产 | 回滚动作 |
|---|---|
| 应用 | 切回旧镜像或旧 Commit |
| Prompt | Prompt Registry 指向旧版本 |
| Query Plan | 关闭 Planner 或切回旧 Prompt / Schema |
| Retrieval Config | 切回旧 Top-K、RRF 和 Filter 配置 |
| Elasticsearch | Alias 原子切回旧物理索引 |
| Embedding | 使用旧模型与旧向量索引,不混合空间 |
| Reranker | 切回旧端点,或关闭精排回退 RRF |
| Context Packer | 切回旧版本与 Token Budget |
| LLM Route | 切回稳定模型和价格配置 |
| Cache | 使用 Release ID 隔离,避免跨版本污染 |
| Feature Flag | 关闭 Candidate Route |
16.1 回滚资产要在发布前验证
旧索引还存在吗?
旧 Prompt 能读取吗?
旧模型 Endpoint 还在线吗?
Alias 切换权限可用吗?
Feature Flag 能立即生效吗?
缓存是否带 Release ID?发布前执行一次 Dry Run,记录:
{
"rollback_target": "rag-prod-2026-07-29.2",
"verified": true,
"verified_at": "2026-08-05T17:30:00+08:00",
"steps": {
"prompt_switch": "passed",
"index_alias": "passed",
"model_route": "passed",
"feature_flag": "passed"
},
"estimated_seconds": 28
}17. Elasticsearch 索引如何支持零停机回滚
应用只访问稳定 Alias:
kb_chunks物理索引版本化:
kb_chunks_v3
kb_chunks_v4切换 Candidate:
POST _aliases
{
"actions": [
{
"remove": {
"index": "kb_chunks_v3",
"alias": "kb_chunks"
}
},
{
"add": {
"index": "kb_chunks_v4",
"alias": "kb_chunks",
"is_write_index": true
}
}
]
}回滚使用同样的原子操作切回 v3。
17.1 旧索引保留多久
至少覆盖:
Canary 观察窗口
+
回归发现延迟
+
Incident 分析周期
+
安全缓冲不要在 Alias 切换成功后立即删除旧索引。
17.2 Embedding 模型升级
新的 Embedding 模型通常意味着新的向量空间。
正确做法:
旧模型 + v3 索引
新模型 + v4 索引错误做法:
同一个 dense_vector 字段混写不同模型生成的向量回滚必须连同 Query Embedding 模型一起切回。
关于重建与增量追平,见 MySQL 到 Elasticsearch 的一致性。
18. Prompt 和模型路由如何回滚
18.1 Prompt Registry
{
"prompt_name": "rag-answer",
"active_version": "v16",
"stable_version": "v15",
"versions": {
"v15": {
"sha256": "...",
"created_at": "2026-07-29T10:00:00Z"
},
"v16": {
"sha256": "...",
"created_at": "2026-08-05T10:00:00Z"
}
}
}回滚不是重新编辑 Prompt,而是原子切换 active_version。
18.2 Model Route
routes:
answer-stable:
primary: model-x-rev-3
fallback: model-y-rev-2
answer-candidate:
primary: model-x-rev-4
fallback: model-x-rev-3Canary 只把一部分请求路由到 Candidate。回滚时切回稳定 Route。
18.3 Cache Key 必须包含版本
cache_key =
tenant_id
+ normalized_query
+ scope_hash
+ release_id否则 Candidate 的结果可能污染 Baseline,回滚后仍继续返回新版本缓存。
19. Feature Flag 应该控制什么
Feature Flag 不只控制整个版本,也可以控制高风险子能力:
query_rewrite_enabled
multi_query_enabled
reranker_enabled
new_index_enabled
new_prompt_enabled
new_model_route_enabled
web_search_enabled
agentic_retrieval_enabled推荐能力:
- 按 Tenant;
- 按用户组;
- 按 Query Cohort;
- 按地域;
- 按百分比;
- 支持 Kill Switch;
- 修改有审计日志;
- Flag 状态进入 Trace。
每次请求应记录:
{
"release_id": "rag-prod-2026-08-05.3",
"feature_flags": {
"query_rewrite_enabled": true,
"reranker_enabled": true,
"new_index_enabled": true
}
}20. Release Gate 与可观测性如何连接
每条 Trace 至少携带:
release_id
baseline_release_id
canary_stage
experiment_cohort
application_commit
index_manifest_version
prompt_version
model_route
reranker_version这样 Dashboard 才能比较:
Baseline vs Candidate
Stable vs Canary
Release A vs Release B20.1 不要把 Release ID 作为 Metric 的无限标签
如果 Release 数量很高,应控制 Retention 或将 Release 维度用于短期 Dashboard,而不是永久高基数 Metric。
Trace 和 Artifact 可以保存完整 Release ID;长期聚合可使用:
stable
candidate
canary_stage详细可观测设计见 RAG 可观测性生产实战。
21. Release SLO 与 Telemetry SLO
发布系统本身也应有 SLO。
Release SLO
Gate Evaluation Success Rate
Candidate Build Success Rate
Canary Auto-Pause Latency
Rollback Completion Time
Release Artifact CompletenessTelemetry SLO
Trace Export Success Rate
Release ID Coverage
Candidate / Baseline Correlation Rate
Metric Freshness
Artifact Availability如果发布系统无法观察 Candidate,就不应该继续扩大流量。
22. CI 中的最小实现
release-gate
├── validate change request
├── build candidate manifest
├── validate required artifacts
├── run baseline
├── run candidate
├── compute deterministic metrics
├── run calibrated judges
├── compare paired cases
├── check hard gates
├── check soft gates
├── verify rollback
├── generate report
└── create deployment approval22.1 GitHub Actions 示例
name: rag-release-gate
on:
pull_request:
paths:
- "prompts/**"
- "retrieval/**"
- "rag/**"
- "indexes/**"
- "release/**"
jobs:
evaluate:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install -r evaluation/requirements.lock
- name: Validate release manifest
run: python -m release_gate validate release/release-manifest.json
- name: Run paired evaluation
run: |
python -m evaluation.run \
--baseline release/baseline-manifest.json \
--candidate release/release-manifest.json \
--datasets release/datasets.yaml \
--output artifacts/eval
- name: Evaluate gates
run: |
python -m release_gate check \
--config release/release-gate.yaml \
--report artifacts/eval/summary.json \
--output artifacts/release-decision.json
- name: Upload evidence
uses: actions/upload-artifact@v4
with:
name: rag-release-evidence
path: artifacts/实际项目应锁定 Action 与依赖版本,并保护评测凭证和生产数据。
23. 门禁决策器的伪代码
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from typing import Any
class Decision(str, Enum):
PASS = "pass"
CONDITIONAL = "conditional"
PAUSE = "pause"
BLOCK = "block"
@dataclass(frozen=True)
class GateResult:
decision: Decision
hard_failures: list[str]
soft_warnings: list[str]
required_approvals: int
def evaluate_release(
report: dict[str, Any],
config: dict[str, Any],
) -> GateResult:
hard_failures: list[str] = []
soft_warnings: list[str] = []
for metric, rule in config["hard_gates"].items():
value = report["metrics"].get(metric)
if value is None or not check_rule(value, rule):
hard_failures.append(metric)
if hard_failures:
return GateResult(
decision=Decision.BLOCK,
hard_failures=hard_failures,
soft_warnings=[],
required_approvals=0,
)
for metric, rule in config["soft_gates"].items():
value = report["deltas"].get(metric)
if value is None or not check_rule(value, rule):
soft_warnings.append(metric)
if soft_warnings:
return GateResult(
decision=Decision.CONDITIONAL,
hard_failures=[],
soft_warnings=soft_warnings,
required_approvals=config["waiver_policy"]["required_approvers"],
)
return GateResult(
decision=Decision.PASS,
hard_failures=[],
soft_warnings=[],
required_approvals=0,
)check_rule 必须处理缺失值。对 Hard Gate,缺失指标应该 Fail Closed,而不是视为通过。
24. 审批人到底应该看什么
审批页面不应只显示绿色勾选。
至少展示:
- 变更假设与目标 Bad Case;
- Release Manifest 差异;
- Baseline / Candidate 质量、延迟和成本;
- 新增回归和修复样本;
- Safety Set 结果;
- 未通过的 Soft Gate;
- Waiver 原因和过期时间;
- Shadow / Canary 计划;
- 自动暂停和回滚阈值;
- 回滚验证结果。
审批人必须能从报告直接回答:
为什么值得发布?
最大的剩余风险是什么?
异常时谁负责?
多快能回滚?25. 发布状态机
状态转换应该由系统记录,不能只存在聊天消息或人工记忆中。
26. 发布审计记录
{
"release_id": "rag-prod-2026-08-05.3",
"event_id": "evt_release_0092",
"event_type": "canary_advanced",
"from_state": "canary_1",
"to_state": "canary_10",
"timestamp": "2026-08-05T20:10:00+08:00",
"actor": {
"type": "service",
"id": "release-controller"
},
"evidence": {
"requests": 15240,
"duration_minutes": 68,
"hard_gates": "passed",
"soft_warnings": [],
"dashboard": "trace://release/rag-prod-2026-08-05.3"
}
}必须审计:
- 谁批准;
- 谁修改 Gate;
- 谁创建 Waiver;
- 何时扩大流量;
- 何时暂停或回滚;
- 使用了哪些证据。
27. Incident 与 Postmortem 如何回流
一旦回滚,系统自动保存:
Candidate Trace Samples
Baseline / Candidate Pair
Relevant Artifacts
Gate State
Canary Stage
Metric Timeline
Feature Flag Changes
Rollback TimelinePostmortem 产出:
Root Cause
Detection Gap
Gate Gap
Telemetry Gap
Rollback Gap
Action Items
New Regression Cases
New Safety Cases每个高严重度事故至少产生一条新的 Regression 或 Safety Case。
这使发布系统随着事故不断变强,而不是每次从零开始排查。
28. 多租户发布策略
不是所有租户必须同时升级。
可以按:
- 内部租户;
- 低风险租户;
- 测试租户;
- 数据规模;
- 语言;
- 合规区域;
- 产品套餐;
- 主动加入 Beta 的客户。
逐步扩大。
28.1 Tenant-level Gate
某些回归可能只发生在:
中文长文档
英文 FAQ
某个部门 ACL
某个大知识库
特定地域模型端点因此 Dashboard 和 Gate 需要 Tenant / Cohort 级切片。
28.2 不允许跨租户学习敏感内容
Shadow 和评测 Artifact 必须保持租户隔离。不要为了构建统一 Judge 数据集,把不同租户的私有内容混入公共样本。
29. 发布节奏与 Freeze Window
高风险索引或模型发布不宜在:
- 无 Owner 值守时;
- 上游模型供应商正在变更时;
- 数据同步异常时;
- 监控系统不可用时;
- 重大业务高峰前;
- 回滚资产即将过期时。
发布前检查系统依赖:
MySQL / Outbox Lag
Elasticsearch Cluster Health
Embedding Endpoint
Reranker GPU Pool
LLM Provider
Trace Collector
Feature Flag Service
Artifact StoreRelease Gate 通过不代表所有基础设施都健康。
30. 常见反模式
反模式一:CI 绿了就发布
构建成功不能证明检索和答案质量。
反模式二:只比较平均分
会掩盖安全、关键样本和特定 Cohort 回归。
反模式三:没有 Release Manifest
事故后无法复现版本,也不知道应该切回什么。
反模式四:旧索引切换后立即删除
索引回滚变成重新构建,无法快速恢复。
反模式五:Embedding 模型回滚但索引不回滚
Query 与文档向量空间不一致,结果没有意义。
反模式六:Prompt 回滚靠手工复制旧文本
容易复制错误,应该切换不可变 Prompt Version。
反模式七:Canary 只按时间推进
样本量和目标 Cohort 可能不足。
反模式八:出现安全问题只暂停不回滚
Critical 风险应立即切回稳定版本。
反模式九:Waiver 可以绕过所有门禁
越权和关键安全失败不允许例外。
反模式十:回滚没有 Dry Run
真正事故时才发现旧模型、索引或权限已经不可用。
反模式十一:Feature Flag 不进入 Trace
无法解释某次请求到底启用了哪些新能力。
反模式十二:Bad Case 只写工单
没有进入 Regression Set 的问题会再次出现。
31. 分阶段落地方案
P0:建立可回滚发布基线
- Release ID;
- Immutable Manifest;
- Baseline / Candidate Paired Eval;
- Safety Hard Gate;
- Prompt / Retrieval / Model 配置版本化;
- 稳定 Elasticsearch Alias;
- Feature Flag;
- Rollback Runbook;
- Preview / Shadow;
- 发布审计记录。
验收标准:
任何生产请求都能追溯到完整 Release Manifest;
任何 Candidate 都能在一分钟内切回已验证版本。P1:自动化门禁与 Canary
- Gate YAML;
- 自动 Case-level Diff;
- 置信区间;
- Shadow Traffic;
- 分段 Canary;
- 自动 Pause / Rollback;
- Cohort Dashboard;
- Waiver Workflow;
- Rollback Dry Run;
- Incident Evidence Freeze。
P2:规模化发布控制面
- 多租户分批发布;
- 多模型和多地域路由;
- 自动风险分类;
- Change Impact Analysis;
- 在线 Pairwise Evaluation;
- Release Controller;
- Policy-as-Code;
- 自动根因建议;
- 发布成本预算;
- 全链路合规审计。
32. 上线检查清单
- 是否为本次发布生成唯一 Release ID?
- Release Manifest 是否包含代码、索引、模型、Prompt 和配置版本?
- Manifest 引用的 Artifact 是否真实存在并有 Hash?
- 是否记录变更假设、目标 Bad Case 和 Owner?
- 风险等级是否基于影响范围、回滚难度和安全边界?
- Baseline 与 Candidate 是否使用相同 Dataset Version?
- 是否输出 Case-level Improved / Regressed?
- 是否检查置信区间和 Effect Size?
- Unauthorized Retrieval / Context / Citation 是否全部为 0?
- Critical Safety Case 是否 100% 通过?
- High Severity Regression 是否为 0?
- Trace 和 Schema Contract 是否完整?
- Soft Gate 是否按 Query Cohort 分层?
- Waiver 是否只允许 Soft Gate?
- Waiver 是否有 Owner、审批、Scope 和过期时间?
- Shadow 是否不会执行外部写操作?
- Canary 每阶段是否有最小样本量和最短观察时间?
- 是否分别定义 Advance、Pause 和 Rollback 条件?
- 安全问题是否触发立即回滚?
- 稳定版本是否始终在线?
- 旧 Prompt、旧模型和旧索引是否仍可读取?
- Elasticsearch 是否通过 Alias 切换?
- Embedding 模型和向量索引是否成对切换?
- Cache Key 是否包含 Release ID?
- Feature Flag 状态是否进入 Trace?
- 是否对 Tenant、语言和 Query Cohort 分层监控?
- Release Dashboard 是否覆盖质量、安全、延迟和成本?
- Rollback 是否做过 Dry Run?
- 发布状态转换是否有审计记录?
- Incident 是否自动冻结 Trace 和 Artifact?
- 新 Bad Case 是否进入 Regression / Safety Set?
- 旧资产的 Retention 是否覆盖观察与事故发现窗口?
- 发布系统和 Telemetry 本身是否有 SLO?
总结
RAG Release Gate 的真正作用,不是给 CI 增加一个绿色勾选,而是建立一条可以解释和控制风险的证据链:
Change Request
→ 明确为什么改、影响什么、谁负责
Release Manifest
→ 冻结代码、索引、模型、Prompt 和配置
Paired Evaluation
→ 证明 Candidate 相对 Baseline 的变化
Hard / Soft Gate
→ 把安全零容忍与质量权衡分开
Shadow / Canary
→ 在真实分布中逐步获得证据
Pause / Rollback
→ 异常时停止风险扩散并切回稳定资产
Observability / Audit
→ 解释每次请求和每个发布决策
Incident / Bad Case
→ 把失败沉淀到下一次门禁最重要的工程原则是:
发布的目标不是证明新版本完美,而是确保它的风险可识别、可限制、可暂停、可回滚,并且每一次失败都会变成下一次发布前必须通过的测试。
相关阅读
- RAG 评测生产实战
- RAG 可观测性生产实战
- RAG Bad Case 分析
- RAG 上线检查清单
- MySQL 到 Elasticsearch 的一致性
- Elasticsearch Hybrid Search 生产实战
- Reranker 生产实战
- Query Rewriting 生产实战
讨论
继续讨论这篇笔记
有问题、补充案例或不同观点,可以通过 GitHub Discussions 继续交流。