avatar

一条在知识海洋的咸鱼

这个家伙很懒,啥也没有留下😋

  • Linux
  • OCJP
  • Java核心技术卷
  • J2EE相关标准
  • 深入理解Java虚拟机
  • NIO与SOcket编程技术指南
  • Java多线程编程核心技术
  • Redis开发与运维
  • Spring Cloud Alibaba 微服务原理与实践
  • DevOps
  • Docker
  • MySQL必知必会
  • AI自学路线
  • Spring Boot 编程思想(核心篇)
  • 首页
主页 15 RAG 原理
文章

15 RAG 原理

发表于 昨天 更新于 最近
作者 Administrator
38~49 分钟 阅读

RAG 原理

RAG 的核心是先从知识库检索相关内容,再把检索结果作为上下文交给大模型回答,从而减少模型胡编,并让模型能回答私有文档里的问题。

[TOC]

RAG 是什么

RAG,全称是 Retrieval-Augmented Generation。

中文一般翻译为“检索增强生成”。

拆开看:

Retrieval:检索  
Augmented:增强  
Generation:生成  

普通聊天是:

用户问题  
 -> 大模型  
 -> 回答  

RAG 是:

用户问题  
 -> 检索知识库  
 -> 找到相关文档片段  
 -> 把片段和问题一起给大模型  
 -> 回答  

重点是:

RAG 不是训练模型,而是在模型回答前给它补充上下文。

为什么需要 RAG

大模型有几个天然限制:

不知道你的私有文档  
不知道公司内部数据  
知识可能过期  
容易编造不存在的细节  
上下文窗口有限  
不能直接翻完整资料库  

RAG 的作用是把外部知识接进来。

比如你上传了:

产品手册  
合同条款  
接口文档  
公司制度  
课程笔记  
项目 README  

用户问:

这个系统的上传文件大小限制是多少?  

RAG 会先检索相关片段,再让模型基于片段回答。

这样回答就不完全依赖模型记忆。

RAG 和普通 Chat 的区别

普通 Chat:

用户:接口超时是多少?  
模型:根据已有知识猜一个答案  

RAG:

用户:接口超时是多少?  
系统:检索项目文档  
文档片段:连接超时 3 秒,读取超时 30 秒  
模型:根据片段回答  

区别在这里:

普通 Chat:模型直接回答  
RAG:模型基于检索上下文回答  

所以 RAG 的质量不只取决于模型。

还取决于:

文档质量  
解析质量  
切片质量  
Embedding 质量  
检索质量  
Prompt 质量  
引用来源  

RAG 基本流程

完整流程可以分成两条线。

先看整体图:

graph TD;  
 A["用户上传文档"] --> B["解析文本"];  
 B --> C["清洗文本"];  
 C --> D["文档切片"];  
 D --> E["生成 chunk Embedding"]; E --> F["存入向量数据库"];  
 G["用户提问"] --> H["问题生成 Embedding"]; H --> I["向量检索相关 chunk"]; I --> J["拼接上下文"];  
 J --> K["大模型生成回答"];  
 K --> L["返回答案和来源"];  
 F -. "提供检索数据" .-> I;  

第一条是入库流程:

上传文档  
 -> 解析文本  
 -> 清洗文本  
 -> 文档切片  
 -> 生成 Embedding -> 存入向量数据库  

入库流程图:

graph LR;  
 A["上传文档<br/>PDF / DOCX / MD / TXT"] --> B["解析文本<br/>Parser"];  
 B --> C["清洗文本<br/>Cleaner"];  
 C --> D["文档切片<br/>Chunker"];  
 D --> E["生成 Embedding<br/>Embedding Model"]; E --> F["写入向量库<br/>Vector Store"];  
 F --> G["保存 metadata<br/>文件名 / 页码 / chunkIndex"];  

第二条是问答流程:

用户提问  
 -> 问题生成 Embedding -> 向量检索相关 chunk -> 拼接上下文  
 -> 大模型生成回答  
 -> 返回答案和来源  

问答时序图:

sequenceDiagram  
 participant U as 用户  
 participant WEB as 前端页面  
 participant API as RAG API 服务  
 participant EMB as Embedding 服务  
 participant VS as 向量数据库  
 participant PROMPT as Prompt 组装器  
 participant LLM as 大模型服务  
  
 U->>WEB: 输入问题并点击发送  
 WEB->>API: POST /rag/chat,提交 question API->>API: 生成 requestId,记录请求日志  
 API->>EMB: 调用 Embedding 服务生成问题向量  
 EMB-->>API: 返回问题向量  
 API->>VS: 用问题向量检索 topK chunks VS-->>API: 返回相关 chunks 和来源 metadata API->>API: 过滤权限和低相关度结果  
 API->>PROMPT: 传入 question、chunks 和回答规则  
 PROMPT-->>API: 返回最终 Prompt API->>LLM: RAG API 服务调用大模型生成回答  
 LLM-->>API: 返回模型回答  
 API->>API: 组装 answer、sources 和 traceId API-->>WEB: 返回答案和来源  
 WEB-->>U: 展示回答和引用来源  

本节先理解原理。

后面会逐步做数据库、上传、解析、清洗、切片和 Embedding。

核心组件

一个 RAG 系统至少有这些组件:

Document:原始文档  
Parser:文档解析器  
Cleaner:文本清洗器  
Chunker:切片器  
Embedding Model:向量模型  
Vector Store:向量库  
Retriever:检索器  
Prompt:问答提示词  
LLM:生成模型  
Source:来源信息  

不要把 RAG 只理解成“向量数据库”。

向量数据库只是其中一部分。

如果文档解析和切片做得差,向量库再强也救不了。

最小组件关系图:

graph TD;  
 DOC["Document<br/>原始文档"] --> PARSER["Parser<br/>文档解析器"];  
 PARSER --> CLEANER["Cleaner<br/>文本清洗器"];  
 CLEANER --> CHUNKER["Chunker<br/>切片器"];  
 CHUNKER --> EMB1["Embedding Model<br/>生成 chunk 向量"];  
 EMB1 --> STORE["Vector Store<br/>保存 chunk + metadata + embedding"];  
 QUESTION["用户问题"] --> EMB2["Embedding Model<br/>生成问题向量"];  
 EMB2 --> RETRIEVER["Retriever<br/>检索 topK chunks"]; STORE --> RETRIEVER; RETRIEVER --> PROMPT["Prompt<br/>上下文 + 问题 + 规则"];  
 PROMPT --> LLM["LLM<br/>生成回答"];  
 LLM --> SOURCE["Answer + Source<br/>答案和来源"];  

Document 和 Chunk

Document 是原始文档。

比如:

合同.pdf  
项目说明.docx  
README.md  
接口文档.txt  

Chunk 是文档切出来的小片段。

比如一份 20 页 PDF,可能切成:

chunk 1:标题和第一段  
chunk 2:第二段到第三段  
chunk 3:接口说明  
...  

为什么要切片?

因为:

模型上下文有限  
向量检索需要较小片段  
整篇文档太大不方便匹配  
用户问题通常只对应部分内容  

Chunk 太大:

检索不精准  
上下文浪费  
模型容易抓不到重点  

Chunk 太小:

上下文断裂  
答案缺少前后关系  
检索结果碎片化  

所以后面会重点讲切片。

Embedding 是什么

Embedding,中文一般翻译为“向量表示”。

它会把文本变成一串数字。

比如:

"什么是 RAG?"  
 -> [0.12, -0.03, 0.88, ...]  

语义相近的文本,向量距离通常更近。

例如:

"文件上传限制是多少?"  
"最大文件大小是多少?"  

这两个句子字面不完全一样,但语义相近。

Embedding 可以帮助系统找出相关文档片段。

Vector Store 是什么

Vector Store,中文可以理解为“向量存储”或“向量数据库”。

它负责存:

chunk 文本  
chunk metadata  
chunk embedding  

然后根据问题向量做相似度搜索。

常见选择:

pgvector  
Milvus  
Qdrant  
Weaviate  
Chroma  
Elasticsearch dense_vector  

本路线先以 PostgreSQL + pgvector 为主。

原因是:

容易本地启动  
和业务数据库接近  
SQL 好理解  
后续能加 metadata 过滤  
适合学习阶段  

Retriever 是什么

Retriever,中文可以理解为“检索器”。

它负责把用户问题变成检索结果。

最小逻辑:

用户问题  
 -> 生成问题向量  
 -> 向量库相似度搜索  
 -> 返回 topK chunks  

topK 表示返回最相关的前 K 条。

比如:

topK = 4  

表示拿 4 个相关片段给模型。

检索器后面还可以加:

metadata 过滤  
关键词检索  
混合检索  
重排序  
权限过滤  

本节先理解最小检索。

RAG Prompt

RAG 的 Prompt 通常包含:

角色说明  
回答规则  
检索上下文  
用户问题  
无法回答时的兜底  
引用来源要求  

示例:

你是一个知识库问答助手。  
请只根据给定的上下文回答问题。  
如果上下文中没有答案,请回答“根据已上传资料无法确定”。  
不要编造上下文之外的信息。  
  
上下文:  
{context}  
  
用户问题:  
{question}  

这条规则很重要:

如果上下文中没有答案,不要编造  

否则 RAG 也会变成普通 Chat。

来源信息

RAG 项目最好返回来源。

比如:

{  
 "answer": "上传文件大小限制是 20MB。",  
 "sources": [ { "documentName": "接口文档.md",  
 "chunkIndex": 3, "page": 2 } ]}  

来源的作用:

用户能核对  
开发能排查  
减少胡编风险  
方便后续做引用跳转  

如果只返回答案,不返回来源,很难判断答案是否可信。

最小 RAG 伪代码

先看整体伪代码:

question = "文件上传大小限制是多少?"  
  
query_vector = embedding_model.embed_query(question)  
  
chunks = vector_store.similarity_search(  
 query_vector, top_k=4,)  
  
context = "\n\n".join(chunk.text for chunk in chunks)  
  
prompt = f"""  
请只根据上下文回答问题。  
  
上下文:  
{context}  
  
问题:  
{question}  
"""  
  
answer = llm.invoke(prompt)  

真实项目会多很多细节。

但主线就是这几个步骤。

项目边界

本节要先确定项目边界。

建议第一个 RAG Demo 只做:

上传 PDF / DOCX / MD / TXT解析成纯文本  
切成 chunk生成 embedding存 pgvector根据问题检索 topK模型基于上下文回答  
返回来源  

先不做:

复杂权限  
多租户  
图片 OCR表格结构化抽取  
多模态检索  
知识图谱  
自动评测平台  
大规模分布式索引  

边界越清楚,第一版越容易跑通。

RAG 失败的常见原因

常见问题:

文档解析丢内容  
页眉页脚干扰太多  
chunk 切得太碎  
chunk 切得太大  
embedding 模型不适合中文  
topK 太少  
检索结果没有来源  
Prompt 没要求基于上下文回答  
上下文太长导致重点被稀释  
没有处理“找不到答案”  

排查顺序:

先看原文是否解析正确  
再看 chunk 是否合理  
再看检索结果是否相关  
最后看模型回答是否遵守上下文  

不要一出问题就换模型。

RAG 的很多问题在模型之前就已经发生了。

排查流程图:

graph TD;  
 A["RAG 回答效果差"] --> B{"原文解析正确吗?"};  
 B -- "否" --> B1["修复 Parser<br/>检查 PDF / DOCX / Markdown 解析结果"];  
 B -- "是" --> C{"chunk 合理吗?"};  
 C -- "否" --> C1["调整切片策略<br/>chunk size / overlap / 按标题切分"];  
 C -- "是" --> D{"检索结果相关吗?"};  
 D -- "否" --> D1["优化检索<br/>embedding 模型 / topK / metadata 过滤 / 混合检索"];  
 D -- "是" --> E{"Prompt 约束清楚吗?"};  
 E -- "否" --> E1["强化 Prompt<br/>要求基于上下文回答并返回来源"];  
 E -- "是" --> F{"来源足够支撑答案吗?"};  
 F -- "否" --> F1["补充资料或扩大检索范围"];  
 F -- "是" --> G["再检查模型输出<br/>是否需要更强模型或人工校验"];  

常见问题

RAG 是不是微调

不是。

微调会改变模型参数。

RAG 不改变模型参数,只是在回答时提供外部上下文。

RAG 能保证答案一定正确吗

不能。

RAG 只能提高可追溯性和事实相关性。

仍然需要:

好的文档  
好的切片  
好的检索  
好的提示词  
必要的人工校验  

文档要不要全部塞给模型

不要。

应该先检索,再只放相关片段。

否则上下文太长、成本高、噪声大。

为什么要返回来源

因为 RAG 的可信度来自“答案能回到资料”。

没有来源,用户只能相信模型。

有来源,用户可以核对。

练习清单

完成几件事情:

能解释 RAG 是什么  
能画出入库流程  
能画出问答流程  
能解释 Document 和 Chunk能解释 Embedding能解释 Vector Store能解释 Retriever能写一个 RAG Prompt能说明 RAG 和普通 Chat 的区别  
能列出第一版项目边界  

建议目录:

ai-agent-study  
├── docs  
│   └── rag-principle.md  
├── java  
│   └── rag-api  
└── python  
 └── rag-service  

小结

本节的结论:

RAG 的本质是“先检索,再生成”,不是让模型凭空记住你的资料。

入库链路:

文档  
 -> 解析  
 -> 清洗  
 -> 切片  
 -> Embedding -> 向量库  

问答链路:

问题  
 -> 检索 chunk -> 拼上下文  
 -> 模型回答  
 -> 返回来源  

后面会按这条链路逐步实现。

参考资料

  • LangChain RAG
  • Spring AI RAG
  • LangChain Semantic Search
AI自学路线
AI
许可协议: 
分享

相关文章

6月 10, 2026

15 RAG 原理

RAG 原理RAG 的核心是先从知识库检索相关内容,再把检索结果作为上下文交给大模型回答,从而减少模型胡编,并让模型能回答私有文档里的问题。RAG 原理RAG 是什么为什么需要 RAGRAG 和普通 Chat 的区别RAG 基本流程核心组件Document 和 ChunkEmbedding 是什么V

6月 10, 2026

14 阶段交付

阶段交付 阶段交付的核心不是继续加新功能,而是把前面做过的聊天、流式输出、Tool Calling、FastAPI 和 Java/Python 联调整理成一个能启动、

6月 9, 2026

13 Java + Python 联调

Java + Python 联调Java + Python 联调的核心是让 Spring Boot 负责业务入口,让 FastAPI 负责 AI 能力,并用统一协议、超时、重试和日志把两边稳定连接起来。Java + Python 联调为什么要 Java 调 Python联调目标Python 侧接口统

下一篇

上一篇

14 阶段交付

最近更新

  • 15 RAG 原理
  • 14 阶段交付
  • 13 Java + Python 联调
  • 12 LangGraph 基础
  • 11 LangChain 基础

热门标签

java基础 微服务 maven Spring Tomcat DDD Linux Linux基础 SQL基础 数据结构算法

目录

©2026 一条在知识海洋的咸鱼. 保留部分权利。

使用 Halo 主题 Chirpy