跳到主要内容

05-RAG检索增强

核对日期:2026-05-18
官方资料:Retrieval https://docs.langchain.com/oss/javascript/langchain/retrieval;Text splitters https://docs.langchain.com/oss/javascript/integrations/splitters

官方概念

Retrieval 是从外部数据源取回与 query 相关的上下文,RAG 是把检索上下文注入模型生成答案。LangChain 提供 loaders、splitters、retrievers、vector stores、rerankers 等集成,但生产质量取决于数据治理、权限、引用和评测。

机制

本手册离线项目使用 keyword score 代替真实 embedding/vector DB,是为了让权限、引用、冲突、eval 逻辑可本地验证。

TypeScript 写法

对应案例:src/examples/06-rag.ts。综合项目:企业知识库 Agent。

关键点:

  • 检索前做 ACL,不允许“先召回再隐藏”。
  • citation 必须来自命中文档。
  • 低召回时拒答,不编造答案。

可用化任务流

真实 RAG 项目不是“接一个向量库”就结束。建议按下面交付:

步骤要做什么产物验收方式
1. 数据盘点列出文档来源、权限、更新时间、负责人data inventory每个文档有 owner 和 ACL
2. 切分策略按标题、段落、表格、代码块分别定义 chunk 规则chunk policychunk 可追溯到原文
3. 元数据建模保存 docIdchunkIdsourceupdatedAtallowedRolesmetadata schema检索结果可做 ACL 和 citation
4. 索引构建embedding、BM25、hybrid 或 rerankindex job可重复构建,记录版本
5. 查询改写根据意图补充关键词、时间和实体query pipeline改写前后都写 trace
6. 检索与重排先 ACL,再检索或用权限过滤索引retriever跨租户泄露用例为 0
7. 答案生成只允许引用命中文档,低证据拒答answer schemacitation 100% 来自 retrieved docs
8. Eval 回归召回、引用、拒答、冲突、权限eval dataset每次改索引和 prompt 都跑

最小可用 answer schema:

const answerSchema = z.object({
answer: z.string().min(1),
citations: z.array(z.object({
docId: z.string(),
chunkId: z.string().optional(),
title: z.string(),
source: z.string(),
})).min(1),
refused: z.boolean(),
conflicts: z.array(z.string()),
});

RAG 的关键不是让答案“看起来像”,而是让答案能被复核。citation、chunk version、trace 和 eval dataset 是可用性的底座。

检索策略选择

场景推荐策略不适用情况
FAQ、政策、短文档BM25 + embedding hybrid文档极短且关键词稳定时可先 BM25
语义问答embedding retriever + reranker权限复杂但索引不支持 metadata filter 时要谨慎
代码/配置/字段查询keyword / symbol search 优先纯 embedding 可能丢精确 token
多版本制度metadata filter + newest-first rerank只按语义分数排序会引用旧制度
高安全文档per-tenant index 或强 ACL filter共享索引且后过滤风险更高

可运行改造点

文件改造任务验收命令
src/core/rag.ts增加 chunkIdminScore 测试npm test
src/projects/enterprise-kb-agent.ts增加一个过期制度,要求返回 conflictnpm run projects:eval
test/langchain-learning.test.ts增加“无 citation 不允许成功”的断言npm test

RAG Eval 设计

用例类型示例通过标准
正常命中“远程办公一周几天”返回最新政策 citation
权限拒绝普通员工问薪酬审批refused=true 且 citation 为空
低召回问不存在制度拒答,不编造
冲突文档新旧政策都命中conflicts 非空
注入攻击文档或 query 要求忽略系统提示拒答或过滤,不外泄

Python 差异

Python 和 TypeScript 都有 document loader、splitter、vector store 集成,但第三方包覆盖度和 API 名称可能不同。真实项目应按目标语言官方 integration 文档选择包,并锁版本。

工程边界

  • RAG 不能自动解决知识冲突。
  • 长上下文不能替代检索治理。
  • embedding 相似不代表事实正确,仍需引用和回归评测。

常见反模式

反模式后果
把所有文档对所有用户可检索权限泄露
不保存 chunk 版本引用无法复现
只看 Top-1 命中召回不足和冲突文档都被掩盖

练习任务

  1. 修改企业知识库文档角色,确认 ACL 测试变化。
  2. 增加一个过期文档,要求回答优先引用最新文档并提示冲突。
  3. 为 RAG eval 增加“无相关资料必须拒答”的用例。
  4. 给 citation 增加 chunkId,并让测试确认每条引用都能定位到 chunk。
  5. minScore 改低,观察 ACL deny 用例为什么仍不应该泄露薪酬文档。