本节聚焦 RAG 系统中最常见且最难彻底根除的问题:幻觉(Hallucination)与答案质量不稳定。我们从“数据 -> 检索 -> 生成 -> 约束 -> 观测”五个层面构建一个可迭代、可量化、可回溯的质量提升闭环,并列出最小可实施集(MVP Hardening)与进阶增强策略。
质量问题分层模型
层级 | 典型症状 | 根因类别 | 优先级 |
---|
语料层 | 过时 / 不覆盖 | 内容缺失、未标准化 | 高 |
切块层 | 回答引用不聚焦 | 语义边界错误、块过长 | 高 |
检索层 | 召回偏题 / 噪音多 | topK 不当 / 无重排 | 高 |
生成层 | 编造事实 / 结构混乱 | 指令不明确 / 上下文冗余 | 中 |
约束层 | 回答可信度不可判 | 缺乏引用验证 / 置信评估 | 中 |
观测层 | 问题反复出现 | 缺乏指标、无反馈分类 | 高 |
语料与预处理
- 内容标准化:统一术语、别名映射(K8s→Kubernetes),移除噪声(版权声明、导航、空段)。
- 时效控制:新增
lastReviewed
字段,定期巡检排序优先级。 - 元数据增强:为每段添加
source
, section
, lang
, version
, hash
。 - 变更检测:文件内容 Hash 变化 → 触发增量嵌入与旧向量 upsert。
切块策略(Chunking)
维度 | 建议 | 说明 |
---|
长度 | 300500 中文字符 / 200400 tokens | 平衡语义完整与召回精度 |
边界 | 标题、列表、段落、代码块对齐 | 避免句子截断导致语义丢失 |
重叠 | 0 或 50~80 tokens(跨段依赖时) | 防止跨界引用缺失 |
内容压缩 | 可选生成“摘要向量” | 面向概念型问答二次召回 |
检索与重排
- 向量检索:主召回(余弦相似度 topK=8 或 5~10 动态)。
- 语义重排:交叉编码器或 API rerank 过滤并排序前 15→5。
- 混合检索:向量 + BM25(关键词)合并去重 → rerank。
- 语义分类路由:对“定义类/步骤类/比较类”设不同 topK。
- 过滤策略:最小相似度阈值 + 结果跨度(同文档合并)。
相似度阈值示例
const MIN_SIMILARITY = 0.70; // 低于则拒答
def filter(results) {
return results.filter(r => r.score >= MIN_SIMILARITY);
}
提示工程(Prompt Engineering)
结构化模板:
System: 你是...(角色 + 边界 + 拒答条件)
Context: \n[doc1] 内容...\n[doc2] 内容...
Instruction: 基于上方上下文回答用户问题。不得编造。若无充分依据输出 REFUSE 模板。
Format: 1) 直接回答 2) 若引用多来源,按 [1][3] 标注 3) 末尾追加“引用”部分。
Language: 复用用户语言。
引用编号要求模型输出可验证结构,后续可做自动校验。
生成约束与后处理
机制 | 目标 | 实现要点 |
---|
引用完整性校验 | 避免无依据陈述 | 检测 [\d+] 是否至少出现一次 |
引用存在性核验 | 防止伪造引用 | 解析引用编号 → 对应上下文块 ID 是否存在 |
事实回查(可选) | 高风险场景再验证 | 对生成句子提取三元组再向量对比 |
置信度打分 | 分级展示 | 组合 avgSim , maxSim , coverage |
降级策略 | 防止误导 | 低置信度 → 输出安全模板 + 建议追问 |
去重与合并 | 减少重复句 | 基于 Jaccard / 余弦阈值 0.85 去重 |
监控与指标
指标 | 描述 | 采集方式 |
---|
similarity_dist | 前 K 相似度分布 | 检索阶段收集 |
citation_count | 回答引用块数量 | 生成后解析 |
citation_match_rate | 引用命中率 | 引用编号 ↔ 检索块集合 |
refusal_rate | 拒答占比 | 答案模板分类 |
followup_rate | 用户追问率 | 会话日志序列分析 |
hallucination_flags | 人工标注幻觉数 | 反馈面板 |
反馈闭环
- 采样失败会话:topK 全部低相似度 / 引用缺失 / 人工标注幻觉。
- 分类标签:
NO_RECALL
BAD_RERANK
PROMPT_FAIL
OVERGEN
NEED_CONTENT
。 - 修复动作:
- NO_RECALL → 语料扩充或召回 topK ↑
- BAD_RERANK → 调整 rerank 模型 / 特征
- PROMPT_FAIL → 修改指令模板
- OVERGEN → 限制输出长度 + 强制格式
- NEED_CONTENT → 添加文档并增量嵌入
最小可实施集(MVP Hardening)
类别 | 措施 | 成本 | 影响 |
---|
检索 | 动态 topK + 相似度阈值 | 低 | ↓噪音 ↑精准 |
生成 | 结构化 Prompt + 引用编号 | 低 | ↑可追溯 |
约束 | 引用存在性与最少 1 条校验 | 低 | ↓幻觉 |
观测 | 记录相似度分布 & 引用统计 | 低 | ↑可诊断 |
反馈 | 手工标注 20 个失败会话 | 中 | 建立迭代基础 |
进阶增强
- Rerank 模型自蒸馏:用高成本模型离线重排 → 训练轻量 cross-encoder。
- 检索多样性:MMR 或基于覆盖率的去冗余,避免高度相似块挤占上下文窗口。
- 语义图谱:对实体/关系做结构化抽取 → 支撑精确对齐与回答验证。
- 答案自我反思链:第一轮输出 → 反思检查(引用/逻辑/漏洞)→ 第二轮修订。
- 统一评分服务:集中计算质量指标并回写日志,用于 Dashboard 与报警。
实现起步代码片段
function buildPrompt(blocks: RetrievedBlock[], question: string, lang: string) {
const context = blocks.map((b, i) => `[doc${i+1}] ${b.text}`).join('\n');
return `System: 你是严谨的技术问答助手...\nContext:\n${context}\nInstruction: 基于上述内容回答:${question}`;
}
function validateAnswer(answer: string, blockCount: number) {
const cited = new Set([...answer.matchAll(/\[(\d+)\]/g)].map(m => Number(m[1])));
const valid = [...cited].every(n => n >=1 && n <= blockCount) && cited.size > 0;
return { cited: [...cited], valid };
}
小结
通过分层拆解、结构化提示、引用约束、可观测指标与反馈闭环,RAG 幻觉控制成为一条“工程化运营”路径,而非一次性调参。建议先实施最小集,再按优先级迭代增强,以持续压缩幻觉发生概率并提升答案可信度。