LLMNotes

第 13 章:RAG 工程化

zjc 于 2026-01-13 发布

这是《LLM 应用开发 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 一个生产级 RAG 系统不只是“向量库 + 模型”,还包括数据接入、解析、索引、检索、生成、引用、评测、更新、权限、缓存和观测。本章把这些模块串成完整系统。

13.1 总体架构

离线管道
Source -> Parser -> Chunker -> Embedding -> Vector / Search Index

在线链路
User Query
  -> Auth / Rate Limit
  -> Query Understanding
  -> Hybrid Retrieval
  -> Filter / Dedupe
  -> Rerank
  -> Context Builder
  -> LLM
  -> Guardrail / Citation Check
  -> Response

反馈闭环
Logs -> Bad Case -> Dataset -> Eval -> New Version

13.2 数据接入

数据源分类:

类型 示例 同步方式
文件系统 PDF、Word、Markdown 定时扫描或事件
Confluence / Wiki 团队文档 Webhook / API
数据库 商品、订单、工单 CDC 或定时快照
工单系统 历史案例 API 增量拉取
网页 官方文档 受控爬取

接入要求:

  1. 记录源 ID 和版本;
  2. 支持删除和权限同步;
  3. 处理重试和死信;
  4. 任务可幂等;
  5. 状态可观测;
  6. 源数据可重建索引。

13.3 在线请求流程

async def answer(question: str, user: User):
    query = await rewrite_query(question, user.session_id)
    candidates = await retrieve(query, user)
    ranked = await rerank(query, candidates)
    context = build_context(ranked, max_tokens=4000)

    prompt = render_prompt(
        question=question,
        context=context,
        citations=[c.chunk_id for c in ranked],
    )
    answer = await call_llm(prompt)
    verify_citations(answer, context)
    return answer

每一步都要有独立超时、日志和降级策略。

13.4 上下文构造

推荐格式:

以下是参考资料。资料可能不完整,不要使用外部知识补充。

[1] 来源:员工手册 v3 / 考勤 / 远程办公
更新时间:2026-01-10
内容:
远程办公需提前一天在 OA 系统申请。

[2] ...

用户问题:...
回答要求:
1. 优先使用编号小的相关资料;
2. 引用来源编号;
3. 资料冲突时说明差异;
4. 信息不足时明确说明。

构造规则:

  1. 控制 token 预算;
  2. 相邻块可合并;
  3. 表格保留结构;
  4. 无关候选丢弃;
  5. 不把权限字段暴露给模型;
  6. 引用 ID 与 chunk 映射保存在服务端。

13.5 引用与可解释性

答案示例:

{
  "answer": "远程办公需要提前一天在 OA 系统申请。",
  "citations": [
    {"chunk_id": "manual-v3#128", "quote": "提前一天在 OA 系统申请"}
  ],
  "confidence": "medium"
}

服务端校验:

  1. 引用 chunk 是否存在;
  2. 是否属于本次检索结果;
  3. quote 是否真实出现;
  4. 用户是否有权限查看;
  5. 文档是否仍然有效;
  6. 答案与引用是否冲突。

13.6 权限模型

User -> tenant_id -> allowed_doc_types -> roles -> doc ACL

原则:

  1. 检索前确定身份;
  2. 查询携带租户和角色;
  3. 引擎执行硬过滤;
  4. 输出引用再次检查;
  5. 缓存按权限隔离;
  6. 权限变更及时生效;
  7. 管理员调试日志也脱敏。

不能把所有文档都嵌入上下文后让模型“自己判断谁能看”。

13.7 数据新鲜度

场景 策略
政策文档 生效时间、失效时间
产品价格 查询数据库,不做静态 RAG
库存 API 实时查询
官方文档 定时同步和版本比较
工单案例 增量同步

索引要有更新时间,答案可展示资料时间。对强实时数据,RAG 只负责解释规则,数值由服务端查询。

13.8 缓存设计

缓存层级:

内容
语义缓存 规范化问题 + 权限 +索引版本 最终答案
检索缓存 查询 + 过滤 + 索引版本 chunk ID
Embedding 缓存 文本 + 模型 向量

语义缓存要谨慎:

  1. “我的订单”不同用户不能共享;
  2. 时间敏感问题不宜缓存;
  3. 相似不等于等价;
  4. 命中后仍要执行权限检查;
  5. 记录命中率与错误率。

13.9 评测体系

层级 指标
解析 结构准确率、OCR 错误率
切块 边界错误、上下文充分性
召回 Recall@K、MRR
重排 NDCG、Precision@N
生成 Faithfulness、Answer Relevance
引用 Citation Accuracy
工程 延迟、成本、错误率
业务 解决率、人工转接率、用户反馈

线上采样:

自动评分:规则 + 模型评估
人工评审:按风险分层抽样
用户反馈:赞 / 踩 / 修正

13.10 部署与回滚

版本组合:

rag-release-v12
  parser_version = pdf-v4
  chunker_version = heading-v6
  embedding_model = emb-v2
  index_version = idx-20260825
  rerank_model = rerank-v1
  prompt_version = answer-v8
  llm_model = chat-v5

灰度:

  1. 按用户比例;
  2. 按租户;
  3. 按问题类型;
  4. 对比新旧指标;
  5. 保存 trace 可回放;
  6. 出现质量回退立即切回。

13.11 常见故障

现象 处理
检索不到 解析/切块/索引 查 chunk 和向量
检索到但答错 rerank/prompt 查排序和上下文
答案无引用 Prompt/模型 强制 schema
引用错误 映射校验 服务端验证
新旧政策同时出现 数据治理 生效时间过滤
跨租户泄露 权限 硬过滤和测试
成本高 上下文 token 预算和缓存
延迟高 检索/rerank 并行、缩减候选

本章小结

RAG 工程化由离线索引管道、在线问答链路和反馈闭环组成。核心设计点包括数据版本、权限硬过滤、混合召回、重排、上下文预算、引用校验、缓存、评测和灰度回滚。把每一层的状态记录清楚,问题才能被定位和持续优化。

思考题

  1. RAG 离线管道和在线链路分别关注什么?
  2. 为什么引用必须由服务端校验?
  3. 哪些实时数据不应该进入静态索引?
  4. 语义缓存有哪些风险?
  5. 如何设计一次 RAG 版本回滚?