构建真正自愈的RAG系统:五层自治架构实战
1. 项目概述:这不是一个“加个重试就叫自愈”的RAG玩具
“Building a Fully Self-Healing RAG System”——这个标题里最危险的词是“Fully”,最被滥用的词是“Self-Healing”,而最容易被忽略的词是“RAG System”本身。我见过太多团队在周会上拍着胸脯说“我们加了fallback链路,RAG已经能自愈了”,结果一上线,用户问“上季度华东区销售冠军是谁”,系统要么返回空,要么胡编一个叫“张伟”的虚构人物,再要么卡死在向量库查相似度那一步,整个API响应时间飙到12秒。这不是自愈,这是把急救包塞进ICU病房门口就宣布病人康复了。
真正的Fully Self-Healing RAG,不是给现有流程打补丁,而是从数据摄入、索引构建、查询路由、响应生成到反馈闭环,每一层都内置可观测性、可诊断性与可恢复性。它得能在无人干预下识别出:是PDF解析器把合同里的“¥500,000”错读成“Y500,000”导致语义断裂?是向量模型在长尾行业术语上嵌入失真?是LLM提示词模板在处理否定句时突然逻辑翻转?还是缓存键设计缺陷让“苹果手机”和“苹果公司”共享同一份过期摘要?这些都不是靠retry(3)或timeout(30s)能解决的。
我过去三年带过7个RAG落地项目,其中4个在第二季度就因“响应不可靠”被业务方叫停。后来我们把所有失败case归类,发现83%的问题根本不在LLM生成层,而在上游的数据链路与中间件决策层。所以这次重构,我们彻底放弃“RAG = Retrieval + LLM”的简化公式,把它拆解成一个五层自治体: 感知层(Sensing)→ 诊断层(Diagnosing)→ 决策层(Deciding)→ 执行层(Acting)→ 学习层(Learning) 。每一层都必须能独立报告健康状态、定位根因、触发修复动作,并把修复效果反哺给其他层。比如当诊断层发现某类法律文书召回率持续低于65%,它不会只告诉运维“向量库可能有问题”,而是直接调用执行层的re-embedding pipeline,用微调后的领域专用嵌入模型对这批文档重做索引,并同步更新缓存策略——整个过程耗时<8.2秒,无需人工介入。
这篇文章不讲概念,不画架构图,只写我们实打实踩出来的每一步:怎么定义“健康指标”才不会被平均值骗?怎么让诊断逻辑既快又准,避免为查一个bug额外增加400ms延迟?怎么设计执行动作的熔断机制,防止自愈行为本身变成DDoS攻击?以及最关键的——怎么让学习层真正记住教训,而不是每次重启后又重复踩同一个坑。如果你正在被RAG的“偶发性失灵”折磨,或者刚被老板问“你们的RAG到底有多可靠”,这篇就是为你写的。
2. 自愈系统的五层架构设计与选型逻辑
2.1 为什么必须是五层,而不是三层或七层?
很多团队一上来就想套用“监控-告警-自愈”的经典运维三段论,结果发现完全失灵。因为RAG的故障不是服务器CPU爆表这种明确信号,而是语义层面的渐进式退化:今天召回的文档相关度下降5%,明天生成答案的事实一致性掉2个百分点,后天缓存命中率莫名升高——这些变化单看都不致命,但叠加起来会让系统在用户无感中滑向不可信。所以我们必须把“感知”和“诊断”拆开:感知层只做轻量、高频、无状态的信号采集(比如每个请求的token级延迟分布、向量相似度直方图、LLM输出的置信度logits),而诊断层则基于多维信号做因果推断(比如发现“高延迟+低相似度+高logits熵值”三者强相关时,才判定为嵌入模型失效)。
至于为什么不是七层?因为我们砍掉了所有无法自动化的环节。比如传统方案里的“人工复核层”和“预案审批层”,在真实业务中只会让自愈延迟从秒级拉长到小时级。我们要求所有决策必须能在200ms内完成,这就倒逼我们把90%的判断逻辑固化进规则引擎+轻量模型,剩下10%交给在线强化学习微调——但那个微调过程本身也必须是自包含的,不能依赖离线训练集群。
2.2 感知层:不采集原始日志,只采集“可行动信号”
很多人以为感知层就是埋点打日志,结果ES里堆了2TB/s的原始trace数据,却找不到一个能直接触发修复的指标。我们的做法很极端: 禁止记录任何原始字段,只允许上报预计算的聚合信号 。比如:
- 不记录
retrieved_docs[0].score,而是上报retrieval_score_percentile_95(当前请求召回文档相似度的95分位值) - 不记录
llm_response_time_ms,而是上报response_latency_bucket(按[0-100ms, 100-300ms, 300-1000ms, >1000ms]四档量化) - 不记录
llm_output_text,而是用本地部署的tiny-bert实时计算output_factuality_score(基于实体共现与知识图谱置信度)
提示:我们用Rust写了轻量信号提取器,单请求开销压到0.8ms以内。如果用Python做同样计算,光序列化JSON就要吃掉3ms——这在自愈系统里是不可接受的延迟。
这套设计带来两个硬收益:一是存储成本降为原来的1/27(从PB级日志到TB级信号),二是所有诊断规则都能用纯SQL写,运维同学不用学PromQL也能写告警。比如检测“语义漂移”的规则就是一句:
SELECT COUNT(*) FROM signals
WHERE ts > NOW() - INTERVAL '5 minutes'
AND retrieval_score_percentile_95 < 0.45
AND output_factuality_score < 0.6
AND response_latency_bucket = '300-1000ms'
HAVING COUNT(*) > 12
只要5分钟内出现12次以上,就触发诊断层深度分析。
2.3 诊断层:用“故障树+贝叶斯网络”替代关键词匹配
早期我们用正则匹配日志里的“timeout”“empty_result”来诊断,结果发现准确率不到37%。因为真实故障往往是组合态的:比如PDF解析错误(导致文本乱码)→ 向量嵌入失真(导致召回偏离)→ LLM强行生成(导致幻觉)→ 用户投诉(触发重试)→ 缓存污染(放大错误)。单点关键词根本抓不住这种链式反应。
现在我们用两套并行机制:
-
静态故障树(Fault Tree Analysis, FTA) :把已知的137种RAG故障预定义为树状结构。比如顶层事件“Answer Unreliable”,其子节点包括“Retrieval Failure”“LLM Hallucination”“Context Truncation”等,每个子节点再展开具体原因(如“Retrieval Failure”下有“Vector DB Timeout”“Embedding Model Drift”“Query Expansion Bug”)。所有叶子节点都绑定可执行的检测脚本。
-
动态贝叶斯网络(Dynamic Bayesian Network, DBN) :对每个新请求,实时构建一个轻量贝叶斯图,节点是感知层信号(如
retrieval_score_percentile_95),边是历史故障数据训练出的条件概率。当某个信号异常时,网络自动计算各故障节点的后验概率,选出Top3最可能根因。
实操心得:DBN的先验概率不能直接用历史故障统计,必须加入“业务权重”。比如金融场景下,“LLM Hallucination”的权重是“Response Latency”的5倍,因为用户宁可等3秒也要答案准确。这个权重要每周根据客服工单重新校准。
2.4 决策层:规则引擎与在线学习的黄金配比
决策层的核心矛盾是:规则太死板,模型太黑盒。我们的解法是“80/20法则”——80%的常见故障用确定性规则处理,20%的长尾问题交给在线学习。
-
规则部分 :用Drools实现,所有规则必须满足“可解释、可回滚、可压测”。比如针对“向量库召回率骤降”的规则:
rule "Vector DB Recall Drop Recovery" when $s: Signal(retrieval_recall_rate < 0.55, ts > (now - 5min), count > 8) then executeAction("reindex_batch", params: ["doc_type": "contract", "model_version": "v2.3"]); logInfo("Triggered reindex for contract docs due to recall drop"); end关键是
executeAction调用前会先跑沙箱环境验证:用100条样本数据测试reindex后召回率是否真能提升到0.7以上,否则拒绝执行。 -
在线学习部分 :用Proximal Policy Optimization(PPO)微调一个轻量决策模型(仅1.2M参数),输入是最近10个请求的信号向量,输出是动作概率分布(如{reindex: 0.62, fallback_to_rulebook: 0.28, escalate_to_human: 0.10})。模型每2小时用新数据增量训练一次,但训练过程本身受熔断保护——如果新模型在验证集上比旧模型差超过3%,自动回滚。
2.5 执行层:所有动作必须带“事务边界”与“效果验证”
最常被忽视的是执行层的可靠性。很多自愈系统在执行reindex时没考虑并发冲突,结果多个请求同时触发reindex,把向量库打挂。我们的所有执行动作都强制遵循ACID原则的变体:
- A(Atomicity) :每个动作封装为原子任务,失败时自动回滚到前一状态。比如reindex动作会先备份原索引元数据,再建新索引,最后原子切换别名。
- C(Consistency) :动作执行前必须通过一致性检查。例如切换缓存策略前,会抽样验证新策略下100个历史query的命中率是否≥85%。
- I(Isolation) :同类动作自动排队,不同类动作可并行。比如reindex和cache_warmup可以并行,但两个reindex必须串行。
- D(Durability) :所有动作结果写入WAL(Write-Ahead Log),即使进程崩溃也能从log恢复。
注意:我们禁用所有“fire-and-forget”式异步调用。每个动作必须返回
ActionResult结构体,包含status(success/failed/partial)、impact_score(0-100)、rollback_cost_ms三个必填字段。监控面板直接消费这些字段,而不是去查数据库状态。
2.6 学习层:不存“经验”,只存“可泛化的修复模式”
很多团队的学习层就是建个MySQL表存“上次XX故障用了XX方案”,结果下次遇到相似故障,发现方案根本不管用——因为没抽象出模式。我们的学习层只存三类东西:
- 故障模式(Failure Pattern) :用DSL描述,比如
[vector_db_timeout] ∧ [retrieval_score_percentile_95 < 0.3] → [embed_model_drift],其中∧表示逻辑与,→表示推导关系。 - 修复模式(Remediation Pattern) :对应故障模式的动作序列,比如
[reindex_batch(doc_type=contract)] → [warmup_cache(query_sample=legal_qa)]。 - 泛化系数(Generalization Score) :每次修复成功后,用Jaccard相似度计算该模式与历史100个模式的匹配度,得分>0.7才入库。
这样当新故障发生时,系统不是找“最像的旧案例”,而是匹配“最匹配的故障模式”,再执行其绑定的修复模式。上周我们遇到一个新问题:医疗问答中“心肌梗死”的召回文档突然混入大量“心肌炎”内容。系统匹配到模式 [disease_name_mismatch] ∧ [semantic_similarity_drop > 0.4] ,自动执行 [fine_tune_embedding_on_disease_pairs] ,22分钟后准确率从51%回升到89%——而这个模式是三个月前从金融场景的“并购”vs“收购”问题中泛化来的。
3. 核心模块的实操实现与关键参数推演
3.1 感知层信号提取器:Rust实现的零拷贝解析
所有信号必须在请求主链路中完成,不能走异步队列(否则诊断就滞后了)。我们用Rust写了 rag-sensor crate,核心是零拷贝解析:
- 对于PDF文本提取:不调用
pdfminer这种Python库,而是用luminancecrate直接内存映射PDF流,用正则跳过图像块,只解析文本操作符(Tj/TJ),提取速度从800ms/页降到47ms/页。 - 对于向量相似度分析:不等完整召回后再计算,而是在FAISS的
IndexIVFFlat.search()返回近似结果时,用SIMD指令批量计算top-k的余弦相似度直方图,开销<0.3ms。 - 对于LLM输出事实性:不用调外部API,而是用蒸馏版
fact-checker-tiny(37MB),输入是query+answer+top3 retrieved doc的拼接,输出是0-1分数。模型用ONNX Runtime GPU推理,单次耗时11ms。
实操细节:
fact-checker-tiny的训练数据来自我们标注的2.3万条医疗/法律/金融QA对,特别强化了否定句(如“未发现转移灶”)、比较级(如“高于平均水平”)、数值范围(如“5-10年”)的识别。普通开源模型在这三类上的F1只有0.42,我们做到0.89。
所有信号最终打包成 SignalBatch 结构体,用 bincode 序列化(比JSON快3.2倍),通过Unix Domain Socket发给诊断服务。压测显示:单节点每秒可处理12,800个SignalBatch,延迟P99<1.4ms。
3.2 故障树的构建与维护:从事故报告到可执行节点
故障树不是一次性设计的,而是从真实事故中生长出来的。我们要求每次线上P1故障的复盘会,必须产出至少一个FTA叶子节点。流程如下:
- 事故报告结构化 :用固定模板填写,必须包含
Root Cause(技术根因)、Trigger Condition(触发条件)、Detection Method(如何发现)、Impact Scope(影响范围)。 - 节点生成规则 :每个
Root Cause生成一个叶子节点,Trigger Condition转为Drools规则的when条件,Detection Method转为感知层信号组合。 - 父子关系推导 :由资深工程师手动建立,但必须通过“反向验证”——即从叶子节点出发,能逻辑推导出父节点的故障现象。
比如一次P1事故:用户问“2023年Q3营收”,返回“2022年Q3营收”。复盘发现根因是 Excel parser misread date cell as string ,触发条件是 cell_format == "custom" && year_cell_value.length() == 4 ,检测方法是 parsed_date_year != expected_year 。这个就生成叶子节点 excel_date_parsing_bug ,其父节点是 data_ingestion_failure ,祖父节点是 answer_unreliable 。
注意:FTA每年大修一次,砍掉使用率<5%的节点,合并相似节点。去年我们删了42个节点,新增29个,其中17个来自LLM生成层的新故障(如prompt injection绕过、token截断导致逻辑断裂)。
3.3 决策规则的压测验证:用混沌工程模拟故障链
规则再完美,不经过混沌测试就是纸上谈兵。我们用 chaos-mesh 在测试环境注入五类故障:
| 故障类型 | 注入方式 | 验证目标 |
|---|---|---|
| 向量库延迟毛刺 | network delay --time 100ms --jitter 50ms |
规则是否触发fallback_to_rulebook |
| 嵌入模型漂移 | 替换embedding模型为故意降质版(dropout=0.8) | 规则是否触发reindex_batch |
| LLM输出幻觉 | 在LLM响应中注入10%的虚构实体 | 规则是否触发fact_check_rerun |
| 缓存雪崩 | 清空全部缓存并突增10倍流量 | 规则是否触发cache_warmup |
| PDF解析乱码 | 修改PDF流中的text operator为随机字节 | 规则是否触发reparse_document |
每次注入后,我们用 k6 跑2000个真实query,检查:
- 自愈成功率(故障被正确识别并修复的比例)
- 误愈率(正常请求被错误干预的比例)
- 干预延迟(从故障发生到动作执行的时间)
实测数据:经过3轮混沌测试,自愈成功率从68%升到94%,误愈率从12%降到0.7%,干预延迟P95从3.2s降到0.87s。关键改进是给所有规则加了“冷静期”(cool-down period):同一类故障24小时内最多触发3次,避免连锁反应。
3.4 执行动作的事务化封装:以reindex_batch为例
reindex_batch 是最常用也最危险的动作。我们把它封装成带事务语义的函数:
pub fn reindex_batch(
doc_type: &str,
model_version: &str,
batch_size: usize // 默认500,可调
) -> ActionResult {
// Step 1: 原子备份元数据
let backup_id = backup_index_metadata(doc_type).unwrap();
// Step 2: 创建新索引(带版本号)
let new_index_name = format!("{}-{}-{}", doc_type, model_version, Uuid::new_v4());
create_vector_index(&new_index_name, model_version).unwrap();
// Step 3: 分批重索引(带进度检查)
let total_docs = get_doc_count(doc_type);
for chunk in (0..total_docs).chunks(batch_size) {
reindex_chunk(doc_type, &new_index_name, chunk).unwrap();
// 每批后验证:抽样10个query,确保新索引召回率≥0.8
if !validate_index_quality(&new_index_name, 10) {
rollback_to_backup(backup_id);
return ActionResult::failed("Index quality check failed");
}
}
// Step 4: 原子切换别名
switch_index_alias(doc_type, &new_index_name).unwrap();
ActionResult::success()
}
关键设计点:
- 进度检查 :每批重索引后强制验证质量,避免全量做完才发现模型有问题。
- 别名切换 :FAISS不支持原生别名,我们用Redis存
{doc_type -> index_name}映射,切换时用SET doc_type new_index_name NX保证原子性。 - 回滚保障 :备份的元数据包含旧索引的HNSW图参数、标量索引配置等,能100%还原。
3.5 学习层的模式泛化:Jaccard相似度的工程实现
模式泛化不是简单算字符串相似度,而是结构化匹配。我们定义故障模式为三元组 (condition, action, context) ,其中:
condition:Drools规则的AST抽象(如LessThan("retrieval_score_percentile_95", 0.45))action:动作类型+参数哈希(如reindex_batch+hash("contract,v2.3"))context:业务域标签(如["legal", "high_precision"])
Jaccard相似度计算为:
similarity = |condition₁ ∩ condition₂| / |condition₁ ∪ condition₂|
+ |action₁ ∩ action₂| / |action₁ ∪ action₂|
+ |context₁ ∩ context₂| / |context₁ ∪ context₂|
工程细节:
condition的交集用AST节点类型+操作符+阈值区间匹配(如LessThan(x,0.45)与LessThan(x,0.48)视为相同,因阈值差异<0.05);action交集只比对类型,参数哈希用于去重;context交集是集合交集。整套计算在内存中完成,单次匹配<0.2ms。
4. 真实故障排查与自愈过程实录
4.1 故障现场:金融问答中“杠杆率”指标突然失真
时间 :2024-03-18 14:22:07
现象 :用户查询“招商银行2023年杠杆率”,返回“12.5%”,但财报原文是“7.3%”。连续17个同类query均出现类似偏差,误差集中在±5%区间。
感知层信号 :
retrieval_score_percentile_95: 0.38(正常>0.62)output_factuality_score: 0.31(正常>0.85)response_latency_bucket:300-1000ms(正常0-100ms)llm_output_entropy: 4.2(正常<2.1)
诊断层输出 (耗时187ms):
Top3 Root Causes:
1. embed_model_drift (posterior_prob=0.92)
- Evidence: low retrieval_score + high entropy + slow response
2. prompt_injection (posterior_prob=0.05)
3. cache_corruption (posterior_prob=0.03)
决策层动作 (耗时42ms):
- 触发
reindex_batch(doc_type="financial_report", model_version="fin-bge-v2.4") - 同时启动
cache_warmup(query_sample=["杠杆率", "资本充足率", "不良贷款率"])
执行层日志 :
[INFO] backup_index_metadata: backup_id=fin-20240318-142207-abc123
[INFO] create_vector_index: name=financial_report-fin-bge-v2.4-xyz789
[INFO] reindex_chunk: processed 500 docs, quality_check_passed=true
[INFO] reindex_chunk: processed 500 docs, quality_check_passed=true
[INFO] switch_index_alias: financial_report -> financial_report-fin-bge-v2.4-xyz789
[INFO] cache_warmup: 12 queries executed, hit_rate=92%
效果验证 (故障后第43秒):
- 第18个query返回正确值“7.3%”
retrieval_score_percentile_95回升至0.71output_factuality_score升至0.93- P95延迟回到89ms
排查心得:这次故障根因是fin-bge-v2.3模型在“杠杆率”这类复合财务术语上嵌入失真。我们事后分析发现,模型训练数据中“杠杆率”92%出现在“资产负债表”上下文,但实际query多来自“风险控制部”场景,语义空间偏移。所以泛化系数高的模式是
[domain_shift] ∧ [term_specific_drift],后续所有金融模型都增加了跨场景术语采样。
4.2 故障现场:医疗问答中“禁忌症”召回文档混入无关内容
时间 :2024-04-02 09:15:33
现象 :查询“阿司匹林禁忌症”,召回文档包含《高血压诊疗指南》全文(与禁忌症无关),且排在第一位。
感知层信号 :
retrieval_score_percentile_95: 0.51(正常>0.68)retrieval_score_std_dev: 0.22(正常<0.08)→ 相似度分布极散query_entity_coverage: 0.33(正常>0.75)→ “阿司匹林”“禁忌症”两个实体只在一个文档中同时出现
诊断层输出 (耗时203ms):
Top3 Root Causes:
1. query_expansion_bug (posterior_prob=0.87)
- Evidence: low entity coverage + high score std_dev
2. vector_db_index_corruption (posterior_prob=0.09)
3. embedding_model_drift (posterior_prob=0.04)
决策层动作 (耗时38ms):
- 触发
fix_query_expansion(query="阿司匹林禁忌症", method="entity_linking") - 同时运行
diagnose_index_health(index="medical_kg")
执行层日志 :
[INFO] fix_query_expansion: added synonyms ["aspirin", "acetylsalicylic_acid"] and constraints ["contraindication"]
[INFO] diagnose_index_health: found 12 corrupted vectors in medical_kg index, repaired
效果验证 (故障后第29秒):
- 召回文档精准匹配《药品说明书-阿司匹林》,相似度0.89
retrieval_score_std_dev降至0.05query_entity_coverage升至0.91
排查心得:原query扩展逻辑是用同义词词典暴力替换,把“阿司匹林”扩成“阿司匹林、拜阿司匹灵、ASA”,但没加语义约束,导致检索“ASA禁忌症”时召回了所有含“ASA”的文档(包括“ASA分级”)。修复后强制要求扩展词必须与原query实体共现于知识图谱三元组中。
4.3 故障现场:法律问答中“连带责任”答案出现事实性幻觉
时间 :2024-04-15 16:44:11
现象 :查询“担保人承担连带责任后能否向债务人追偿”,返回“不能,因担保人自愿承担”,但《民法典》第700条明确规定“可以”。
感知层信号 :
output_factuality_score: 0.28(正常>0.82)retrieval_score_percentile_95: 0.75(正常,说明文档召回没问题)llm_output_entropy: 1.8(正常,说明LLM没胡说)
诊断层输出 (耗时195ms):
Top3 Root Causes:
1. prompt_leakage (posterior_prob=0.94)
- Evidence: high retrieval_score + low factuality + normal entropy
2. context_truncation (posterior_prob=0.04)
3. llm_model_drift (posterior_prob=0.02)
决策层动作 (耗时41ms):
- 触发
rerun_with_stricter_prompt(prompt_version="legal-v3.2-strict") - 同时记录
prompt_leakage事件到学习层
执行层日志 :
[INFO] rerun_with_stricter_prompt: added constraint "cite_exact_article_number_from_retrieved_docs"
[INFO] rerun_with_stricter_prompt: removed ambiguous phrases like "generally speaking"
效果验证 (故障后第17秒):
- 返回“可以,《民法典》第700条”,并附原文截图
output_factuality_score升至0.96
排查心得:原prompt模板有句“请综合法律精神与实务经验回答”,LLM把“法律精神”理解为抽象原则,忽略了必须引用具体法条的要求。新prompt强制要求“所有结论必须对应到检索文档中的确切条款编号”,并用正则校验输出是否含“第XXX条”字样。
5. 部署与运维中的血泪经验
5.1 资源隔离:为什么自愈系统必须独占CPU核心
自愈系统最怕资源争抢。我们曾把诊断服务和RAG API部署在同一K8s Pod,结果当API流量高峰时,诊断服务GC暂停长达1.2秒,导致故障漏检。现在强制要求:
- 感知层:绑定2个物理CPU核心(避免上下文切换)
- 诊断层:绑定4个物理CPU核心(DBN推理需SIMD加速)
- 决策层:绑定1个物理CPU核心(规则引擎对延迟敏感)
- 执行层:绑定2个物理CPU核心(I/O密集型)
- 学习层:绑定GPU(A10G,只用于在线PPO训练)
实测对比:独占核心后,诊断延迟P99从210ms降到87ms,误愈率下降40%。关键是避免了“诊断服务自己成了故障源”的恶性循环。
5.2 版本灰度:如何让自愈逻辑像业务代码一样安全上线
自愈逻辑也是代码,必须灰度发布。我们用三层灰度:
- 实验室灰度 :在离线环境中用10万条历史query回放,验证自愈成功率>95%,误愈率<0.5%。
- 影子灰度 :新规则在生产环境运行但不执行动作,只记录“如果执行会怎样”,持续72小时。
- 流量灰度 :先对0.1%的query执行,监控30分钟,达标后逐步放量到1%→10%→100%。
关键技巧:影子灰度阶段,我们用
diff工具对比新旧规则的决策结果,重点看“旧规则放过、新规则拦截”的case,人工抽检100个,确认都是真阳性。
5.3 成本控制:自愈动作的“经济性评估”机制
自愈不是免费的。一次reindex_batch可能消耗2.3GB显存和8分钟GPU时间,而一次cache_warmup会带来3000QPS的额外负载。所以我们给每个动作打“经济分”:
| 动作 | 成本分 | 收益分 | 净值 |
|---|---|---|---|
| reindex_batch | 85 | 92 | +7 |
| cache_warmup | 42 | 68 | +26 |
| fallback_to_rulebook | 12 | 33 | +21 |
| escalate_to_human | 5 | 18 | +13 |
决策层只执行净值>0的动作,且净值<10的动作需人工二次确认。上周有个case: reindex_batch 净值算出来是-3(因检测到新模型在验证集上表现更差),系统自动降级为 cache_warmup ,避免了无效投入。
5.4 监控告警:不告警“系统宕机”,而告警“自愈能力退化”
传统监控告警“RAG API 5xx>1%”,但自愈系统的目标是让5xx永远≤0.01%。所以我们监控的是自愈系统自身的健康度:
self_healing_success_rate_5m< 90% → P2告警(自愈开始失灵)false_positive_rate_1h> 1% → P3告警(规则太激进)action_execution_latency_p95> 2s → P3告警(执行层瓶颈)learning_layer_pattern_stale_days> 7 → P4告警(学习层没更新)
实操心得:我们把
self_healing_success_rate定义为“被诊断出的故障中,成功修复的比例”,而不是“所有请求中自愈成功的比例”。前者能真实反映系统能力,后者会被海量正常请求稀释。
5.5 团队协作:为什么SRE必须参与RAG需求评审
最大的认知误区是认为“自愈是运维的事”。实际上,90%的自愈能力取决于RAG架构设计。比如:
- 如果向量库没暴露
search_latency_ms指标,诊断层就无法关联延迟与召回率; - 如果LLM服务没返回
logits,就无法计算output_factuality_score; - 如果PDF解析器没提供
confidence_score,就无法判断文本提取是否可信。
所以我们强制要求:所有RAG组件的PR,必须附带 self_healing_interface.md ,声明:
- 暴露哪些感知信号?
- 支持哪些诊断探针?
- 允许哪些执行动作?
- 如何验证动作效果?
血泪教训:曾有个PDF解析器升级后,把
confidence_score从0-1改为0-100,没通知自愈团队。结果诊断层一直以为置信度是100,直到某天所有医疗文档解析失败才暴露——因为新版本把模糊文本的置信度设为0,而旧逻辑认为0是最高置信。现在所有接口变更必须走RFC流程,自愈团队有一票否决权。
6. 后续可扩展方向与个人体会
这个自愈系统上线半年,把RAG的P1故障率从月均4.2次降到0.3次,用户投诉中“答案不准”的占比从67%降到8%。但我知道,这远不是终点。接下来我们正在推进三件事:
第一, 把自愈能力下沉到客户端 。现在所有逻辑都在服务端,但移动端弱网环境下,用户看到“加载中...”10秒,早关App了。我们正在开发WebAssembly版轻量诊断器,能在浏览器里实时分析fetch延迟、缓存命中、甚至用WebGL加速本地向量计算——让自愈在用户感知前就完成。
第二, 构建跨系统故障图谱 。现在只管RAG,但真实业务中,RAG故障常和CRM、ERP系统耦合。比如“客户经理电话号码查不到”,可能是RAG召回失败,也可能是CRM接口
更多推荐



所有评论(0)