Agent知识学习笔记——03 RAG

知识总结 02:RAG 检索增强

本文以 RAG 知识 为主线,项目代码为佐证(标注为「📌 本项目」)。配套的落地细节、验证数据、踩坑见 01-迭代记录-RAG知识问答.md


一、什么是 RAG

RAG(Retrieval-Augmented Generation,检索增强生成) 是一种让大模型在生成回答前,先从外部知识库中检索相关信息,再结合检索到的内容来生成答案的技术。

它主要解决两个问题:

  • 幻觉:模型不再"凭自身经验瞎说",而是"查完资料再说"。
  • 专业性 / 时效性:让模型能回答训练数据里没有的私有知识、领域知识、最新知识。

一句话抓住本质:

RAG 的核心 = 检索 + 生成。模型回答从「凭记忆答」变成「拿着资料答」。

关键认知:RAG 不改模型本身------不训练、不微调,只是在提问前多做一次检索、把结果塞进上下文。所以它见效快、可随时更新知识(改文档即可),但也天然受限于"检索得准不准"。

📌 本项目:prompt/游戏知识问答.md 里强制"只依据【参考资料】回答,没有就说不知道",就是把"查完资料再说"写成了硬约束。实测问"树枝手镯有什么用"(模型其实知道、但知识库里没写)时,它老实答"知识库里没有",没有用参数知识补位------这就是 RAG 抑制幻觉的直接体现。


二、RAG 的使用场景

RAG 适合那些需要事实性、专业性、时效性知识支撑的场景,让大模型具备"知识更新"和"领域专精"的能力。常见应用:

场景 为什么适合 RAG
企业内部知识库问答 私有资料,模型预训练时没见过
客服 / 产品文档助手 答案必须来自官方文档,且文档常更新
法律 / 医疗 / 金融问答 要求可溯源、不能编,错了代价高
最新资讯 / 实时数据问答 超出模型训练数据的时间截止点
个人知识管理 私人笔记,模型绝无可能知道

📌 本项目属于最后一类:知识库是"杀戮尖塔个人攻略",其中还有一节纯私有的"爬塔口诀",专门用来验证------模型答对它,只可能是检索生效,不可能是预训练记住。

反过来,什么时候不该用 RAG:知识量小到能直接塞进提示词、需要全局理解整个文档集("总结所有文档的共性")、或纯推理/计算任务------这些 RAG 帮不上或属于过度设计。


三、RAG 的整体流程(最核心)

以「用户提问」为分界点,RAG 分为两个阶段:

阶段 时机 做什么 类比
① 构建索引 提问(离线) 把知识库文档变成可检索的向量索引 打地基
② 检索生成 提问(在线) 实时处理问题,检索资料并生成回答 盖房子
复制代码
【① 构建索引 · 离线,只在启动/更新时跑】
  原始文档 →[预处理]→ 干净文本 →[分片]→ chunks →[向量化]→ 向量 →[生成索引]→ 向量库
                                                                              │
────────────────────────  用户提问,分界线  ──────────────────────────────────┤
                                                                              │
【② 检索生成 · 在线,每轮提问都跑】                                             ▼
  用户问题 →[向量化]→ 查询向量 →[相似度检索 Top-K]→ 相关 chunks →[注入上下文]→ 大模型 → 回答

第一步:构建索引(提问前,离线)

对知识库文档做一系列操作:文档预处理 → 文档分片 → 向量化 → 生成索引 。这是后续检索生成的基础,索引质量的好坏,极大影响后续检索效果

四个子环节:

  1. 文档预处理:把原始文档清洗成"只剩语义、没有排版噪声"的干净文本(去掉 markdown 标记、页眉页脚、去重等)。
  2. 文档分片(Chunking):把长文档切成一个个片段(chunk)。检索和注入的最小单位都是 chunk。切太大→混主题、稀释相似度;切太小→缺上下文。
  3. 向量化(Embedding):把每个 chunk 用 embedding 模型转成定长浮点数组。语义越近的文本,向量方向越接近。
  4. 生成索引:把向量存入向量库并建立索引结构,让后续检索不必全量扫描。
⚠️ 核心警示:垃圾进,垃圾出(Garbage In, Garbage Out, GIGO)

无论后续检索环节做了多高深的优化,数据源头的质量才是影响最终检索效果的最重要因素。 构建索引时喂进去的是垃圾(乱排版、混主题的大 chunk、脏数据),检索出来的也只能是垃圾。
📌 本项目亲身踩到 GIGO 的两个变体(详见 01 踩坑记录):

  • 切分坏了 :一开始直接用框架的 DocumentSplitters.recursive,它会把相邻小块合并 成主题混杂的大 chunk,导致检索排序失真(问铁甲战士,排第一的竟是静默猎手那段)。改成按 markdown ## 小节切、一节一段才修好。
  • 预处理缺失**加粗**> 这些排版符号原样进向量是噪声。补了清洗后(在早期那份文档上实测),向量化 token 从 736 降到 704;纯符号不带语义,进向量只会稀释相似度。

第二步:检索生成(提问时,在线)

实时处理用户的问题:

  1. 问题向量化 :用同一个 embedding 模型把问题转成查询向量(必须同一模型,否则不在一个向量空间,相似度无意义)。
  2. 相似度检索:在向量库里算查询向量与各 chunk 向量的相似度,取最相似的前 K 个(Top-K)。
  3. 注入上下文:把命中的 chunk 拼进提示词,作为模型回答的"参考资料"。
  4. 生成:模型基于问题 + 参考资料生成回答。

📌 本项目的检索生成链路:EmbeddingStoreContentRetriever(Top-K + 阈值)→ DefaultContentInjector(把命中片段拼成【参考资料】+ 来源文件名)→ 模型流式输出。当前知识库 6 段、Top-K=3。


四、构建索引四环节的两个实测陷阱(📌 本项目)

这两点是抽象知识里不会讲、但真做才会撞到的,单列出来:

陷阱 A:检索分数不是余弦相似度

很多框架(含本项目用的 LangChain4j)返回的"分数"是相关度分数(relevance score),不是原始余弦:

复制代码
relevanceScore = (cosineSimilarity + 1) / 2      // 把余弦的 [-1,1] 线性拉到 [0,1]

没看清这层会把 minScore 阈值调废 :看着"中等"的 0.5,实际是 cos ≥ 0,几乎什么都不过滤。本项目第一版就栽在这里。

陷阱 B:阈值必须贴着"本文档 + 本模型"重新校准

📌 本项目实测(当前知识库):库内提问命中落在 0.744~0.85 ,库外提问(问塞尔达)最高 0.728 ,中间只有约 0.015 的缝隙,因此阈值卡在 0.735

校准方法 :分别问几个库内问题和库外问题,把阈值卡在"库内最低分"与"库外最高分"之间。缝隙极窄,阈值高一点就出现"库里明明有却答不知道"的假拒答。换文档或换 embedding 模型后必须重测,不能抄经验值。
另外两个实测点:① DashScope 的 OpenAI 兼容模式忽略 text_type 参数 ,query 和 document 编出的向量逐位相同(对称编码);② DashScope embeddings 单次请求最多 10 段文本,超了直接 400,靠框架自动分批解决。


五、RAG 的三种范式:Naive / Advanced / Modular

RAG 从"能用"到"好用"再到"可扩展",演化出三代范式。本项目实现的是最基础的 Naive RAG。

5.1 Naive RAG(基础 RAG)------ 📌 本项目就是这一种

最基础、最标准的实现,完整体现"检索 + 生成"的核心思想,不加复杂优化策略。流程简单直观,是理解 RAG 机制的最佳起点:

复制代码
切分 → 向量化 → Top-K 检索 → 注入 → 生成

📌 本项目正是这条最短链路:按 ## 切、text-embedding-v3 向量化、余弦 Top-K、拼进提示词、模型生成。没有混合检索、没有 rerank、没有 query 改写。选它是刻意的------先把 RAG 最本质的一环吃透,再谈优化。

Naive RAG 的天生短板(也正是后两代要解决的):

  • 纯向量检索对专有名词弱("树枝手镯""灵动步法"这类词,关键词匹配其实更稳)。
  • 用户口语和文档措辞差距大时,召回会掉。
  • Top-K 是"粗排",可能混入相关度不高的噪声片段。

5.2 Advanced RAG(进阶 RAG)

在 Naive RAG 基础上引入混合检索与各种优化策略 ,让召回更准、回答更稳。目前企业生产环境用得最多的范式。 常见增强手段:

手段 作用
混合检索(Hybrid Retrieval) 结合关键词检索(BM25/ES)与向量检索,取长补短,提升精确度
重排序(Re-ranking) 对召回结果用更精的模型做语义相关性打分再重排,过滤噪声,"精筛选"
上下文压缩(Context Compression) 对长文本做摘要 / 关键信息提取,降低上下文压力
多轮记忆(Conversation Memory) 支持多轮对话,让模型理解上下文语义
问题重写(Query Rewriting) 把用户原始 Query 改写成语义更完整、信息更丰富的检索条件

Advanced RAG 是让 RAG 从"能用"变"好用"的关键阶段。
📌 对本项目而言,收益最大的一项是混合检索 ------本项目文档全是"主宰/灵动步法/雷暴"这类专有名词,恰是向量检索的软肋,BM25 能明显补强。这是当前最该补的下一步(见 01 待办)。

5.3 Modular RAG(模块化 RAG)

较新的工程化 形态,强调把 RAG 流程的各组件解耦为可独立配置、替换、组合的模块 ,通过配置或编排灵活拼装。相比 Naive 的"单流程"、Advanced 的"多优化",Modular 更强调可扩展性、灵活性、可维护性。典型模块划分:

模块 职责
查询转换模块(Query Transformation) 对原始查询改写、扩展、分解
检索模块(Retrieval) 从知识库/外部源检索候选,支持向量/关键词/混合等多种策略
重排序模块(Re-ranking) 基于语义相关性对候选再排序
上下文构建模块(Context Builder) 筛选、拼接、压缩检索结果,给模型最优上下文
生成模块(Generation) 大模型执行答案生成
后处理模块(Post-processing) 事实校验、格式优化、引用标注
路由模块(Routing) 按任务类型动态选择模块组合

这种"积木式"设计可针对不同任务自由组装,例如:安全情报场景加时效性筛选、法律/医疗场景加事实校验、长文档场景加上下文压缩。

Modular RAG 的优势

  • 每个模块可单独优化/升级,不必重构整个系统。
  • 模块间标准化接口交互,职责清晰,便于多人协作与版本管理。
  • 支持多源异构数据(联网、知识图谱、API)、动态路由与复杂逻辑组合。

Modular RAG 让 RAG 从"好用"走向"可扩展",代表企业级、系统化 RAG 的未来方向。
📌 一个有意思的连接点:本项目用的 LangChain4j,其 DefaultRetrievalAugmentor 已经把链路拆成了 QueryTransformer(查询转换)/ QueryRouter(路由)/ ContentAggregator(聚合重排)/ ContentInjector(上下文构建)四个可插拔组件 ------这就是 Modular 思想的雏形。本项目目前只替换了 ContentInjector(换成中文注入模板),其余全用默认值。也就是说,从 Naive 走向 Advanced/Modular,在本项目里就是逐个填上这几个扩展点。

三种范式对比

Naive RAG Advanced RAG Modular RAG
定位 能用 好用 可扩展
核心 检索 + 生成 多种优化策略 组件解耦 + 编排
检索 纯向量 Top-K 混合检索 + 重排 可插拔多策略
复杂度
适用 学习 / 原型 / 小知识库 企业生产主流 大型系统 / 多任务
📌 本项目 ✅ 就是这一档 差混合检索/rerank/query改写 框架已备扩展点,未填

六、本项目落地对照(📌 代码为辅)

阶段 环节 本项目实现 类 / 方法
构建索引 加载 FileSystemDocumentLoader + TextDocumentParserrag-docs/*.mdDocument RagConfig.loadDocuments
构建索引 预处理 弱化 markdown 标记,保留标题文字与列表内容 RagConfig.normalizeMarkdown
构建索引 分片 ## 二级标题切,一节 = 一段 RagConfig.splitBySection
构建索引 向量化 text-embedding-v3,1024 维,自动分批(≤10) OpenAiEmbeddingModel
构建索引 生成索引 灌进 InMemoryEmbeddingStore knowledgeStore
检索生成 检索 余弦相似度 Top-K + 阈值 EmbeddingStoreContentRetriever
检索生成 注入 命中片段拼进【参考资料】+ 文件名 DefaultContentInjector
检索生成 生成 提示词强约束"只依据资料回答" prompt/游戏知识问答.md
全程 可观测 打印命中片段+分数 / 打印注入后的完整上下文 LoggingContentRetriever / ChatContextLogger

⚠️ 关于"生成索引"这一环的诚实说明:本项目用的 InMemoryEmbeddingStoreO(N) 暴力线性扫描,没有真正的 ANN 索引 (无 HNSW/IVF),且进程退出即丢。8 段规模下建索引收益为负,这样最简单。上万段以上才需要 pgvector / Milvus 这类真正的向量数据库,那时"生成索引"才名副其实(用 HNSW 图把检索降到近似 O(log N))。


七、RAG 与 Function Calling / MCP 的关系(本项目三个模块)

三个模块解决三件正交的事,可叠加、互不替代:

模块 解决的问题 给模型多了什么 改模型吗
Prompt + Function Calling 让模型做事 一个可调用的动作(工具)
MCP 让工具脱离宿主进程 工具从哪来、在哪执行(协议层)
RAG 让回答有据可依 一段问题相关的资料(上下文)

共同点:三者都不改模型本身,都是在"喂给模型的输入"上做文章。

📌 本项目工程上也复用同一套骨架:RAG 形态开关用 ObjectProvider<RetrievalAugmentor>,与 MCP 那轮的 ObjectProvider<ToolProvider> 完全同构------Bean 在不在决定走哪条分支,原有逻辑一行不删。且 RAG 形态刻意不挂工具:知识问答不需要"做事",挂着只是白烧 token。


八、需要内化的三件事

  1. RAG 分两阶段:构建索引在提问前(预处理→分片→向量化→生成索引),检索生成在提问时(问题向量化→Top-K 检索→注入→生成);GIGO 说的是第一阶段质量决定一切。
  2. 三种范式是一条演化线:Naive(检索+生成,能用)→ Advanced(混合检索+重排+改写,好用)→ Modular(组件解耦+编排,可扩展)。本项目是 Naive,往上走就是逐个填检索/重排/改写这些扩展点。
  3. RAG 不改模型,只改上下文------和 Function Calling / MCP 一样都在模型输入侧做文章,三者正交可叠加;RAG 的效果上限由"检索准不准"决定,而检索准不准的根子在构建索引的质量(GIGO)。
相关推荐
IT古董2 小时前
【MES学习笔记系列】MES 厂商与产品对比
笔记·学习
libokaifa2 小时前
从零手搓一个 GPT:只用 Python 标准库,写一个会起名的字符级模型
ai编程
火云牌神2 小时前
前后端分离:约束 AI 分工,避免接口耦合与职责错乱
人工智能·系统架构·ai编程·前后端分离·vibecoding
嘶哈哈哈2 小时前
# 异构十电机机架数学建模:从单电机力矩到受约束控制分配
笔记
呱呱巨基2 小时前
Linux 查找命令
linux·笔记·学习·查找命令
刘立军3 小时前
领域驱动设计:给 AI 划定上下文边界,告别“大泥球”代码
架构·ai编程·领域驱动设计
岛雨QA3 小时前
Claude Code国内无障碍接入 DeepSeek使用指南
ai编程·claude·deepseek
zhangrelay4 小时前
ROS 2 Lyrical 第4章 URDF机器人建模与Gazebo Garden仿真
linux·笔记·学习·ubuntu·机器人·ros2
Dave1205464 小时前
AI Agent学习 Day14:LangGraph进阶 —— 条件分支、Tool Node与Memory持久化
人工智能·学习