RAG 不是向量数据库教程

很多人第一次做 RAG,会从向量数据库开始。

选 pgvector、Pinecone、Milvus、Qdrant,读 quick start,把文档切成 chunk,生成 embedding,写入库里,然后对用户问题做相似度搜索。看起来系统已经有了:用户问问题,系统检索文档,模型基于文档回答。

但上线后问题很快出现:

  • 用户问得很具体,检索却命中一堆泛泛而谈的段落。
  • 文档里明明有答案,模型却说不知道。
  • 答案看似正确,但引用来源点进去不是那一段。
  • 用户无权访问的文档被检索进上下文。
  • 文档更新后,旧答案仍然被召回。
  • 相似度分数很高,但内容和问题没什么关系。

这些问题不是“换一个向量数据库”就能解决的。

RAG 的核心不是向量数据库,而是把外部知识变成模型可使用上下文的一整套工程系统。向量数据库只是其中一个存储与召回组件,就像数据库不是一个完整 Web 应用,Redis 也不是一个完整实时协作系统。

RAG 到底解决什么问题

RAG 是 Retrieval Augmented Generation,检索增强生成。

它解决的问题不是“让模型学会你的文档”,而是“在回答某个问题时,把相关、可信、允许访问的资料带进模型上下文”。

这句话里有几个关键词。

相关:不是任意相似内容,而是能回答当前问题的证据。

可信:不是用户上传的任意文字都同等可靠,文档可能过期、重复、冲突或来自低可信来源。

允许访问:模型不能看见用户无权访问的知识。权限过滤必须在模型调用前完成。

带进上下文:RAG 最终仍然受上下文窗口、Prompt 结构、引用格式、输出要求和模型能力影响。

所以 RAG 更像前端工程里的“数据请求 + 状态选择 + 权限控制 + 组件渲染”。数据库查询只是其中一步。真正影响体验的是整条链路。

为什么会被误解成向量数据库教程

因为最容易被演示的部分就是向量检索。

一个最小 Demo 通常长这样:

  1. 读取一批文档。
  2. 按固定长度切片。
  3. 调 embedding API 得到向量。
  4. 写入向量数据库。
  5. 用户问题也生成向量。
  6. 做 top-k 相似度搜索。
  7. 把搜索结果拼进 Prompt。
  8. 调模型生成答案。

这个流程很适合 demo,但它省略了生产系统里最麻烦的部分:文档质量、结构解析、元数据、权限、版本、检索调试、重排、上下文预算、引用、评估和监控。

前端工程师可以把它类比成“只讲 fetch,不讲应用状态”。

fetch('/api/user') 不等于能做好用户中心。真实系统还要处理 loading、error、cache、权限、并发、空状态、重试、分页、乐观更新、埋点和 UI 一致性。

同样,会 vector search 不等于能做好 RAG。

RAG 工程流程

一个完整 RAG 系统至少有两条链路:文档入库链路和问答检索链路。

入库链路决定“系统里有什么知识,以及这些知识是否可被正确召回”。问答链路决定“这次用户问题拿到了哪些证据,以及模型如何使用这些证据”。

很多 RAG 问题发生在入库阶段,却在回答阶段才暴露。比如 PDF 解析把页眉页脚混进正文,后面再怎么调 Prompt 都很难稳定;比如 chunk 没有保留标题层级,检索命中了正文却丢了语义位置;比如没有文档版本,过期资料和新资料同时被召回。

向量数据库在 RAG 里负责什么

向量数据库通常负责三件事。

第一,存储 embedding。每个 chunk 会对应一个向量,用于语义相似度搜索。

第二,执行近似最近邻搜索。用户问题向量进来后,数据库返回相似度最高的一批 chunk。

第三,配合 metadata 做过滤。比如只查某个租户、某个知识库、某个文档类型、某个语言或某个权限范围。

这些都很重要,但它们不是 RAG 的全部。

向量数据库通常不负责:

  • 判断文档是否解析正确。
  • 判断 chunk 是否语义完整。
  • 判断问题是否需要改写。
  • 判断检索结果是否真的能回答问题。
  • 判断用户是否应该看到某个答案。
  • 判断多个文档冲突时该信哪一个。
  • 判断答案是否忠实于证据。
  • 判断引用是否准确。

如果把这些都交给“相似度分数”,系统就会非常脆弱。

RAG 工程流程应该怎么拆

从工程视角看,RAG 可以拆成六个阶段。

阶段目标关键产物
文档准备把原始资料变成可处理文本文本、结构、来源、版本
知识建模让每段知识有身份和边界document、chunk、metadata、permission
索引构建让知识可被召回embedding、关键词索引、metadata 索引
查询处理把用户问题转成检索任务query rewrite、filter、intent
上下文组装把证据变成模型输入ranked chunks、citations、token budget
质量闭环判断系统是否变好traces、eval cases、指标、反馈

对前端工程师来说,最值得建立的意识是:RAG 不是一个后端黑盒。它会直接影响界面设计。

例如:

  • 搜索命中的文档要不要展示给用户?
  • 引用来源能不能点击定位到原文?
  • 回答失败时是展示“没有找到资料”,还是让用户重新选择知识库?
  • 用户上传文档后,是否需要显示解析和索引进度?
  • 权限变化后,已有对话里的引用是否仍然可见?
  • 调试模式里是否展示检索 query、chunk 分数和 rerank 结果?

这些都是产品体验的一部分,不是数据库选型能回答的问题。

一个可用 RAG 系统需要哪些模块

最小可用的 RAG 系统通常包含这些模块。

Document Store 保存原始文档、解析文本、版本、来源、所有者、租户、权限和同步状态。不要只保存 chunk,否则后续很难重新切分、重新索引和追踪来源。

Parser and Cleaner 负责把 PDF、网页、Markdown、Office 文档变成结构化文本。它要处理页眉页脚、目录、脚注、表格、代码块、重复导航和乱码。

Chunker 负责切分文本。好的 chunk 不只是固定字符长度,而要尽量保留标题、段落、列表、表格和代码块的语义完整性。

Embedding Worker 负责批量生成 embedding,并处理重试、限流、幂等和版本更新。embedding model 变化时,通常需要重新索引。

Retriever 负责召回候选内容。它可能同时使用向量搜索、关键词搜索、元数据过滤和 query rewrite。

Reranker 负责在候选 chunk 中重新排序。向量召回更像粗筛,rerank 更像精排。

Context Assembler 负责把最终证据放进 Prompt。它要控制 token 预算、去重、排序、引用编号和冲突提示。

Answer Generator 负责生成答案,并约束模型只基于给定证据回答。不足时应该明确说证据不足。

Trace and Eval 负责记录每次运行的 query、召回内容、分数、上下文、引用和答案质量。没有 trace,RAG 就很难调试。

RAG 和普通搜索的区别

RAG 不是搜索框的替代品。

搜索通常返回文档列表,让用户自己阅读和判断。RAG 会把检索结果交给模型,由模型综合生成一个回答。它减少了用户阅读成本,也带来了新的风险:模型可能误读证据、合并不该合并的信息、忽略冲突,或者在证据不足时补全细节。

所以 RAG 要比搜索多几层约束:

  • 必须保留引用来源。
  • 必须区分“资料中没有”与“模型不知道”。
  • 必须能解释答案来自哪些片段。
  • 必须评估答案是否忠实于证据。
  • 必须防止把无关片段拼进上下文。

如果业务只需要用户找到文档,搜索可能更合适。如果业务需要基于多个片段生成一段可执行答案,RAG 才有价值。

RAG 和长上下文的区别

长上下文模型让我们可以一次塞进更多资料,但它没有消灭 RAG。

长上下文解决的是“模型能看多少”,RAG 解决的是“模型应该看什么”。

如果把整个知识库都塞进长上下文,你仍然会遇到成本、延迟、权限、噪音、冲突、时效和可观测性问题。上下文越长,模型越可能忽略中间信息,也越难解释答案到底参考了哪一段。

长上下文可以降低部分检索压力,比如用户只问一个已打开文档时,直接把文档放进上下文可能足够。但在企业知识库、帮助中心、法规库、代码库这类多文档场景中,RAG 仍然需要负责筛选、排序、引用和评估。

面向前端的体验设计

RAG 的用户体验不能只展示一个回答气泡。

一个成熟的文档问答界面通常需要:

  • 知识范围选择:当前文档、某个文件夹、整个知识库、多个数据源。
  • 索引状态:上传中、解析中、索引中、可提问、索引失败。
  • 引用展示:答案里的引用编号、来源标题、页码、段落定位。
  • 证据预览:用户能看到模型依据了哪些片段。
  • 失败状态:没有命中资料、权限不足、资料冲突、系统繁忙。
  • 反馈入口:答案有用、无用、引用错误、资料过期。
  • 调试信息:面向内部用户展示 query、scores、rerank、token usage。

前端在这里不只是“消费后端答案”。它要帮助用户理解模型看到了什么、没看到什么、为什么这么回答,以及如何修正上下文。

常见坑

第一个坑:只看 top-k 分数。

相似度高不等于能回答问题。标题、表格、否定句、时效条件和权限信息都可能被向量相似度弱化。生产系统通常需要 keyword search、metadata filter、rerank 和人工评估一起工作。

第二个坑:固定长度切分所有文档。

固定长度简单,但会切断标题、列表、表格和代码块。对技术文档、合同、规范、FAQ 来说,结构往往比长度更重要。

第三个坑:不保存来源和版本。

如果 chunk 只有文本和向量,后面就很难展示引用、定位原文、删除旧版本和解释答案来源。每个 chunk 都应该能追溯到 document id、版本、位置、标题路径和权限。

第四个坑:检索后再想权限。

权限应该参与检索条件,至少要在模型调用前完成过滤。不要把无权内容放进上下文,再靠 Prompt 要求模型不要泄露。

第五个坑:把 RAG 失败归因给模型。

模型回答不好,可能是解析错、切分差、没召回、召回噪音、上下文超预算、Prompt 冲突或引用丢失。没有 trace 时,团队很容易盲目换模型。

第六个坑:没有 RAG Eval。

RAG 至少要分别评估 retrieval 和 answer。检索有没有找到证据,答案有没有忠实使用证据,是两个问题。

小结

RAG 不是向量数据库教程。

向量数据库解决的是“如何按向量相似度召回候选片段”,而 RAG 要解决的是“如何把可信、相关、允许访问的知识变成模型可用上下文,并生成可追溯答案”。

对前端工程师来说,理解 RAG 的价值不在于记住某个数据库 API,而在于建立完整链路意识:文档如何进入系统,知识如何被切分和索引,问题如何被检索,证据如何被组装,引用如何展示,失败如何解释,质量如何评估。

只有把 RAG 当作工程系统,而不是向量搜索 demo,才有可能做出真正可用的知识问答产品。