RAG 知识库实战:把 PDF、网页和内部文档做成可引用问答

知识库

从文档清洗、切分、向量化、召回、重排到引用展示,完整讲清一个企业知识库问答系统怎么做,以及如何减少幻觉和无来源回答。

RAG 是最容易落地的 AI 应用之一。它解决的问题很朴素:模型不知道你的内部资料,也不应该凭空回答,于是先从知识库里找相关片段,再让模型基于片段作答。做好以后,用户可以问“上季度渠道政策有什么变化”“这份合同里付款节点是什么”“新员工报销流程怎么走”,系统给出答案,同时附上引用来源。

办公室文档与知识库管理
办公室文档与知识库管理

适用人群

这篇教程适合企业知识库负责人、开发者、运营团队和咨询团队。只要你的资料分散在 PDF、网页、飞书/Notion 文档、客服 FAQ 或产品手册里,就可以用 RAG 提升检索效率。它不适合处理强实时数据,例如库存、订单、账户余额;这些场景应优先调用数据库或业务 API。

第一步:整理文档来源

不要一上来就把所有文件扔进向量库。先做来源清单:资料类型、负责人、更新频率、权限等级、是否允许进入 AI 系统。企业内部常见文档可以分为四类:制度流程、产品手册、培训资料、项目沉淀。每类文档的更新节奏不同,权限也不同。

建议先选一个边界清楚的集合,例如“客服知识库”或“员工行政制度”,文档数量控制在 50 到 300 篇。范围太大,排查问题会很痛苦。

第二步:清洗与切分

RAG 的质量很大程度取决于切分。PDF 里常见的问题包括页眉页脚重复、表格错位、换行断句、扫描件 OCR 错字。网页里常见的问题是导航栏、广告、相关推荐混入正文。清洗阶段要尽量保留标题层级、段落和表格含义。

切分建议用“语义块”而不是固定字数。比如一个制度条款、一个 FAQ、一个产品功能说明就是一个块。中文场景可以控制在 300 到 800 字之间,太短会丢上下文,太长会影响召回精度。每个块都要带元数据:标题、来源 URL、发布日期、文档类别、权限标签。

文档切分与索引示意
文档切分与索引示意

第三步:向量化与索引

向量化就是把文本块转换成可检索的数值表示。你可以使用 OpenAI、Cohere、Voyage、BGE、Jina 等 embedding 模型。中文知识库要特别测试中文召回效果,不要只看英文榜单。向量数据库可以选择 pgvector、Qdrant、Milvus、Pinecone、Weaviate 等。

最小方案建议用 PostgreSQL + pgvector,部署简单,权限和备份也好管理。如果数据量很大、需要高并发检索,再上专门向量数据库。

第四步:召回、重排与过滤

用户提问后,系统先把问题向量化,召回最相关的 10 到 20 个片段。然后用重排模型或规则把真正相关的片段排到前面。企业场景还要做权限过滤:用户没有权限看的文档,即使相关也不能进入上下文。

这里有个实用技巧:不要只做向量检索。混合检索通常更稳,也就是向量检索加关键词检索。比如用户问“差旅报销发票抬头”,关键词“发票抬头”很重要,纯向量有时会召回“报销流程”但漏掉具体条款。

第五步:提示词与引用

生成答案时,提示词要明确:“只能基于提供的资料回答;如果资料不足,说不知道;每个关键结论必须引用来源。”引用最好映射到文档标题和段落,而不是只给一堆 URL。用户点击引用后,应能跳到原文位置。

一个常见错误是把引用做成装饰:答案写完后再随便附几个来源。正确做法是让每个答案句子都能追到检索片段。这样不仅提升可信度,也方便用户发现知识库过期或缺失的问题。

资料引用与报告核验
资料引用与报告核验

用 LlamaIndex 跑通一个最小 RAG

下面是最小可运行思路:把 docs/ 里的文件读入,建立索引,然后提问。生产环境要加权限、增量更新和引用展示;本地验证先跑通这一步。

mkdir rag-demo
cd rag-demo
npm init -y
npm install llamaindex
mkdir docs
import { VectorStoreIndex, SimpleDirectoryReader } from "llamaindex";

async function main() {
  const documents = await new SimpleDirectoryReader().loadData({
    directoryPath: "./docs",
  });

  const index = await VectorStoreIndex.fromDocuments(documents);
  const queryEngine = index.asQueryEngine();

  const answer = await queryEngine.query({
    query: "报销流程里发票抬头有什么要求?",
  });

  console.log(answer.toString());
}

main();

项目目录建议

rag-demo/
  docs/                 # 原始文档
  scripts/ingest.js      # 文档清洗和入库
  scripts/evaluate.js    # 测试集评估
  src/search.js          # 召回和重排
  src/answer.js          # 生成答案和引用
  data/testset.json      # 真实问题测试集

界面验收图应该长什么样

RAG 教程至少要有三张可核验界面图:文档导入页、检索结果页、带引用答案页。检索结果页必须显示 chunk 标题、来源文档、更新时间和排序分数;答案页必须显示引用编号,并且点击引用能定位到原文段落。只截一个“AI 回答正确”的聊天框没有意义,因为读者看不到召回过程。

常见坑

| 现象 | 应该先查哪里 | 修法 | |------|--------------|------| | 明明有文档却答不知道 | 检索结果前 5 条 | 调整切分,给 chunk 加标题和同义词关键词 | | 答案引用了旧制度 | 文档元数据里的 updatedAt | 检索时按版本过滤,旧文档标记 archived | | 不同部门看到同一答案 | 权限过滤是否在召回前执行 | 先按用户权限过滤文档,再做向量召回 | | 答案很流畅但来源不支持 | 生成提示词和引用映射 | 无引用的句子不展示,或标为“资料不足” | | 表格内容经常答错 | PDF 表格解析结果 | 表格单独转 Markdown 或 CSV,不和正文混切 |

最小权限过滤可以这样写:

function filterByPermission(chunks, user) {
  return chunks.filter((chunk) => {
    if (chunk.visibility === "public") return true;
    return chunk.allowedDepartments?.includes(user.department);
  });
}

上线前检查清单

上线前至少做三轮检查。第一轮检查文档:每份文档是否有标题、来源、更新时间、负责人和权限标签;过期文档是否已经下线;同一制度是否存在多个版本。第二轮检查检索:准备 50 个真实问题,确认正确片段能进入前 5 条召回结果;如果召回不到,先修切分和关键词,不要急着换模型。第三轮检查生成:答案是否引用来源,是否会在资料不足时拒答,是否把“建议”“规定”“经验”混成同一种语气。

对企业团队来说,还要补一项运营机制:谁负责更新知识库,多久复查一次,用户发现答案错误后反馈给谁。没有维护机制的 RAG,刚上线时看起来聪明,三个月后就会变成一台认真引用旧资料的机器。

替代方案

如果资料很少,直接把文档放进模型上下文可能更简单。如果问题需要实时数据,应该用数据库查询或业务 API。如果你的团队没有工程资源,可以先用 Dify、LlamaIndex Cloud、OpenAI 文件检索、Notion AI、飞书知识问答等现成工具验证需求。

小结

RAG 的核心不是“接一个向量库”,而是建设一条可靠的信息链:文档可信、切分合理、召回准确、权限清楚、答案可引用。把这条链打牢,RAG 才能从演示项目变成团队每天愿意用的知识入口。