先抛一个问题你手上正在搭的 Agent能回答多少超出训练数据的问题我想大多数人都卡在同一个地方。大模型的记忆是死的训练完之后就固定在某个时刻了私有文档、实时业务数据、公司内部知识它一概不知道。这也是《走进 AI Agent》系列走到第四篇必然要面对的问题光有规划能力和工具调用还不够Agent 得有稳定的知识来源。这一篇我们聊知识获取管道也就是 RAG 基础。RAG 的全称是 Retrieval-Augmented Generation检索增强生成思路很简单让大模型在回答问题之前先去一个外挂的知识库里检索相关资料把它当作参考材料再组织答案。这篇文章会从原理讲到最小可用实现再聊分块、检索调参和实战避坑适合正在从 0 到 1 搭 Agent、打算把本地知识库接进 LLM 的朋友。1. 为什么 Agent 需要一个知识获取管道1.1 大模型原生能力的三个短板我见过太多人第一版 Agent 就是把大模型接个提示词就上线了结果一问到具体业务数据就哑火。这不是模型不够聪明而是它天生有短板而且这个短板在纯对话场景里不容易暴露一旦接入业务数据就会被放大。第一个短板是训练数据的时间截止。模型训练完知识就固化了任何之后发生的事它都不知道。你问它昨天新发布的产品参数它只会按训练集里的旧信息编一个答案。第二个短板是私有数据不可见。公司内部文档、个人笔记、本地 ERP 里的订单记录这些内容大模型的训练语料里没有它再强大也无从知晓。第三个短板是幻觉。它不知道但又要回答时会非常流畅地编造内容语气越笃定越危险。比如你问某型号设备支持的电压范围它可能根据行业常识猜一个值完全不管实际产品规格。所以要建一套能让 Agent 实时、准确地获取知识的管道而不是指望模型记住一切。RAG 就是这种管道最常见的基础形态它能直接弥补上面三个短板知识可以更新、可以看到私有数据、生成时还有原文参考幻觉被大幅压缩。1.2 RAG 要解决的核心问题知识割裂与时效性如果只是把文档喂给模型很多人第一反应是微调但微调的实际体验很痛苦成本高、周期长而且知识一变就要重新调。RAG 的价值在于把“知识存储”和“模型能力”解耦。模型还是那个模型知识库可以随时替换、更新、扩展。这一步解决的是知识割裂问题——散落在 PDF、网页、数据库、wiki 里的信息经过清洗和索引进入同一个可检索管道模型在回答问题前能统一访问。拿一个我真实接触过的业务场景举例。某团队的本地 ERP 里有上千个 SKU 的产品信息销售经常在小群问“某型号供电电压是多少”以前只能打开系统慢慢翻。后来他们做了一个简单的 RAG 管道把 ERP 导出的产品手册清洗成纯文本按段落分块后向量化销售提问时先用检索拿到对应规格段落再交给模型生成答案。准确率一下子上来了而且产品参数更新后重新走一遍索引就能生效。这就是“检索增强生成”的直观收益。从架构上看知识获取管道处在 Agent 的中间层上游对接各种数据源下游把处理后的候选内容交给生成模块。它虽然叫“RAG 基础”但对于整个 Agent 来说是最值得先打扎实的一环。没有它Agent 只能是一个会聊天但不懂业务的聊天机器人。1.3 什么时候暂时不需要 RAG也不是啥项目都要上 RAG。如果 Agent 只回答通用常识、不涉及实时数据也不涉及私有内容那直接调用大模型反而更简单延迟低、成本低。RAG 会引入索引构建、检索调优、上下文组装这些额外复杂度纯闲聊场景用不上。还有一种情况是知识高度稳定、格式又极度统一比如固定版本的设备操作说明书且答案就是原文某页某段。这种情况可以先用规则或微调原型对比成本微调一旦成功推理时很省心但遇到内容更新就要重来维护成本并不低。我的判断标准很简单知识的更新频率越高、来源越杂RAG 的收益就越大反过来如果知识一年都不动倒是可以评估更简单的方案。这个思路能让团队避免在架构上过度设计。2. RAG 基础原理三阶段流水线2.1 索引阶段把文档变成可检索的向量理解 RAG可以先把它想象成一个图书管理员你不是直接把整本书塞给读者而是先把书拆成段落、贴上标签、编入检索目录。读者提问时管理员快速检索目录抽出最相关的几页递过去。索引阶段就是在建设这个“检索目录”。具体要做的事包括加载文档、解析格式、清洗噪声、分块、向量化。加载与解析阶段把 PDF、Word、Markdown、HTML 变成结构化的纯文本清洗阶段去掉页眉页脚、水印、乱码和无关导航分块阶段决定知识的最小存储单位向量化阶段则把每个文本块用 embedding 模型映射成一个稠密向量。为什么要向量化因为文本本身没法直接计算相似度但向量可以。语义相近的句子在向量空间里的距离会更近比如“如何退款”和“怎么申请退款”虽然字面不同向量却很接近。这样用户提问时我们可以计算问题向量和每个文本块向量的相似度快速找出语义相关的候选内容。索引阶段还要给每个块打上元数据比如来源文档、页码、更新时间这能让后续检索支持按字段过滤也方便生成答案时标注引用来源。2.2 检索阶段向量检索、混合检索与重排检索阶段是 RAG 的核心目标是尽可能把真正有用的上下文找出来。最基础的做法是向量检索把用户问题转成向量跟向量库里的所有块向量算相似度取 Top K。相似度度量常见的是余弦相似度或内积向量库一般会封装好但你得知道自己用的哪个因为 score 阈值含义不一样。向量检索擅长语义理解但遇到精确匹配时有硬伤。比如一个产品型号“ABC-1024”分词后语义向量可能把它理解成“ABC 公司 1024 个产品”召回结果就乱。更稳妥的做法是混合检索向量检索负责语义召回BM25 这类关键词检索负责精确匹配两边结果合在一起再用 RRFReciprocal Rank Fusion或重排模型统一排序。重排Rerank是我强烈建议加的一层。典型的策略先用计算成本低的检索召回 2050 条候选再用一个交叉编码器模型对候选做精排取前 35 条交给生成。重排能够把真正相关的内容提到最前面同时排除噪声。代价是多一次模型推理但命中率收益通常非常明显。在很多真实项目里加不加重排答案质量的差别肉眼可见。2.3 生成阶段上下文组装与输出控制检索到的内容不是直接丢给模型就完事组装方式非常影响最终答案。首先要按相关度排序并限制数量控制最终塞进 prompt 的 token 总量。其次要让模型显式区分“上下文”和“用户问题”避免上下文成为错误引导。比如在 system prompt 里写清楚只根据提供的上下文回答上下文里没有的信息直接回答不知道不要编造。还需要控制生成 token 上限。很多 RAG 翻车案例是模型太啰嗦把整段知识库内容当成答案复述了一遍。给 max_tokens 设一个合理值比如 300600能逼它输出要点。另外如果业务要求答案可追溯可以在 prompt 中让模型在回答末尾引用来源编号例如“根据文档 A 第 3 节”这样用户能快速核对也方便后期排查错误答案。到这里你会发现RAG 的三阶段其实是在模拟人类查资料作答的过程先建目录再找资料最后写回答。理解了这个逻辑后面所有调参都不难。举一个具体的参数例子假如 top_k5每条 chunk 512 token那进入上下文的检索内容约 2560 token再加上 prompt 模板和问题总 token 数在 3k 左右非常安全。但如果 top_k20同样 chunk 大小一条回答就可能消耗 10k token成本和对模型上下文窗口的要求都会变高所以这些环节要一起设计。3. 从零实现一个最小可用的 RAG 管道3.1 技术选型框架与组件的取舍先别急着写代码想清楚用什么搭。目前 RAG 生态已经非常成熟Python 方向比较主流的是 LangChain 和 LlamaIndex。LangChain 的优点是和 Agent 生态结合紧密如果你想在下一篇里把 RAG 接入 Agent 的规划循环它最顺手。LlamaIndex 的强项则在于文档加载和索引抽象处理多格式文档更省心。Java 方向可以用 Spring AI 或 langchain4j尤其适合企业里已经有 Spring 技术栈的团队甚至可以结合 Spring Cloud 把 RAG 封装为内部服务。另一个值得关注的是 Agentscope 2.0 提出的 RAG as Service把检索能力平台化减少重复造轮子。向量数据库的选择也很重要。本地实验可以用 Chroma 或 FAISS零部署成本数据量上了千万级、要求高并发再考虑 Milvus 或 Qdrant。Elasticsearch 也能做向量检索而且同时支持 BM25 混合检索很多传统团队喜欢它因为可以沿用已有运维经验。下面是一个简单的选型参考方案优势适合场景LangChain与 Agent 生态结合紧密资料多Python 快速原型Agent 接入LlamaIndex文档加载和索引能力强复杂文档结构、本地知识库Spring AI langchain4jJava 技术栈统一企业级 Java 应用Agentscope 2.0 RAG as Service平台化、服务化不想重复造轮子的团队我的建议是小项目不要一上来就追新框架先用最成熟的一条链路把端到端打通再看短板在哪。比如先用 LangChain OpenAI Embedding Chroma 跑通之后发现中文效果不好再把 embedding 换成开源的 bge-m3发现检索不准再加重排。技术选型不是一步到位的RAG 的优化是持续调出来的。3.2 分块参数怎么定chunk_size、overlap 与计算示例分块是整个管道里最容易被低估的环节。分得太小一个完整知识点被截断检索只能拿到片段分得太大向量表达变得模糊而且会把无关内容一起送进上下文。假设原始文档大约 10000 个 token你把 chunk_size 设为 512overlap 设为 50那么每滑一步是 462 个 token最终块数约等于 ceil((10000 - 512) / 462) 1算出来大概是 22 块。这个公式可以帮你快速估算索引成本和上下文开销实际中还要按 tokenizer 的统计为准。为什么需要 overlap因为一段话可能在句子中间被切断比如上一块的末尾是“但是”下一块的开头才是“价格较高”没有 overlap 的话语义就断了。overlap 给前后块保留一小段交集相当于在书页之间留了一行提示让模型能连贯理解。通常 overlap 设为 chunk_size 的 10%20%比如 512 的块用 5080 的 overlap。具体取值看数据类型FAQ 通常 256 以内就够因为单个问答本身独立技术文档我习惯用 512如果文档段落较长且结构复杂可以放宽到 800 并配合重排。记住分块参数不是拍脑袋定的要用真实问题做评估后面我会讲 hit rate。3.3 向量化模型选择embedding 模型决定检索质量的上限。中文场景我常用的有 bge-m3、bge-small-zh、m3e-base国外闭源的有 text-embedding-3-small 等。bge-m3 支持中英文混合和多粒度文本效果均衡本地部署也不算太慢是很多中文项目的首选。如果你只需要轻量本地部署bge-small-zh 能省不少资源。闭源模型的优势是开箱即用、维护省心但数据要过 API对隐私要求高的企业会有顾虑。维度方面也要心里有数。同样是文本向量有的 256 维有的 1024 维、2048 维维度越高通常表达越精细但存储和计算成本也越高。向量库索引类型也会影响查询性能。更关键的一个铁律是索引文本和查询文本必须用同一个 embedding 模型。注意索引和查询必须使用同一个 embedding 模型升级模型后一定要重建索引否则检索结果会直接废掉。我见过不少项目文档索引时用模型 A查询时换成了模型 B维度都不一致检索结果自然惨不忍睹。升级 embedding 模型时一定要重建索引不能只改查询端。3.4 检索调优top_k、score 阈值与 hit rate接下来是最有工程味道的部分怎么知道检索到底准不准。业界常用 hit rate 作为指标意思是准备一批真实问题每个问题标注出它应该在知识库中对应的文档或 chunk。对每个问题用检索器取 Top K如果结果包含标注的那条就算命中。最终 hit rate 命中问题数 / 总问题数。这个指标不直接等于答案质量但它是 RAG 的地基检索都召回不了生成再强也没用。调优路径通常是先固定 top_k 为 5然后扫 chunk_size 的候选值比如 256、512、800画一条 hit rate 曲线确定 chunk_size 后再调 top_k从 5 到 50 观察变化。与此同时要留意向量库返回的相似度分数分布。某些距离度量下阈值不要设置得太激进否则会把有效 chunk 过滤掉。如果命中率一直上不去优先怀疑分块与文档清洗而不是急着加大模型。评估逻辑可以用伪代码表示def eval_hit_rate(qa_pairs, retriever, top_k): hits 0 for query, gold_doc_ids in qa_pairs: candidates [d.doc_id for d in retriever.retrieve(query, top_k)] if any(doc_id in gold_doc_ids for doc_id in candidates): hits 1 return hits / len(qa_pairs)假设 qa_pairs 里每个元素包含问题字符串和正确答案的文档 id 列表retriever.retrieve 返回候选片段列表判断候选里有任何一个命中就算成功。这样跑一轮离线测试就能量化调整效果比人工看一两个例子靠谱得多。3.5 完整流程串联伪代码与调用链把前面模块串起来一个最小可用管道大概长下面这样。我用伪代码写你可以迁移到任何框架。docs load_documents(data/) chunks split_documents(docs, chunk_size512, overlap50) vectors embed_documents(chunks, modelbge-m3) index build_vector_index(vectors, chunks, metadatachunks.metadata) query 某产品支持的最大工作电压是多少 candidates_brute hybrid_search(index, query, top_k20) candidates_ranked rerank(query, candidates_brute, top_k5) prompt assemble_prompt(query, candidates_ranked) answer generate(prompt)这个链路看起来简单但每一步都有隐藏决策。比如 load_documents 需要处理表格和扫描件embed_documents 的批大小会影响内存和速度hybrid_search 里的权重需要调rerank 模型也要选。实际工程中我习惯先用简单的封装跑通确认数据质量再逐步把每一步替换成更优实现。这样建设出来的 RAG 管道后面接 Agent 规划循环也很自然。4. 实战中常见的坑与排查思路4.1 召回为空或命中率低先查数据再查检索RAG 上线后最常遇到的问题是“模型说不知道或者答非所问”。很多人第一反应是换大模型其实问题多半在检索。先确认索引里确实有数据比如直接看向量库的计数确认 chunk 数量和文档字数对得上。再确认查询和索引用的是同一个 embedding 模型这个错误很常见也最隐蔽。接着用最简单的方式验证把问题里的关键词语直接文本搜索看原始文档能否匹配。如果文本搜索都匹配不到那是数据缺失或清洗问题不是检索问题如果能匹配到但向量检索召不回才是分块或向量化的问题。我常用的排查顺序是数据 → 分块 → 检索 → 重排 → 生成一层层缩小范围。比如先打印检索到的候选 chunk看内容是否相关如果候选里相关 chunk 排在很后面说明重排或融合策略有问题如果候选里根本没有相关片段问题在上游。这个顺序能省下大量试错时间。4.2 上下文超限与截断策略与控制另一个高频问题是报告“context length exceeded”。如果模型上下文窗口是 8k而检索内容动辄 10k直接爆掉。解决方案不是盲目减小 top_k而是要对进入上下文的内容做预算。先设定一个总 token 预算比如 4000再按相关性从高到低往里塞直到预算用尽。每条 chunk 也可以先做裁剪或摘要只保留包含关键信息的部分。网上很多模板是把所有候选拼一起这在真实场景里很快就会翻车。我习惯在调用大模型之前先做一个 token 统计函数超出预算就把最靠后的 chunk 砍掉同时提醒用户“部分内容因长度限制被省略”。这种兜底逻辑在 RAG 服务化的时候非常重要。另外不同模型对输出长度和总上下文也有不同要求需要结合具体模型的 API 文档来设定。4.3 知识更新后不生效版本管理与重建索引很多项目文档更新了但 Agent 回答的还是旧信息查半天发现索引没有重建。RAG 管道的索引不会自动跟随文件变化除非你实现监听逻辑。最简单的做法是记录每个文档的哈希定时或触发式检查内容变化就重新加载、分块、embedding 该文档的 chunks并更新对应索引。生产环境最好给索引加一个版本字段或数据时间戳这样排查答案来源时能知道是哪个版本的数据参与了检索。我见过一个团队把索引重建脚本放在手工工具里结果每次更新文档都靠运维手动执行漏一次就产生错误答案。后来用户反馈才发现流程断了。自动化更新不是可选项是 RAG 稳定性的基本要求。这部分可以在基础设施里通过消息队列消费文件变更事件来做也可以先用简单的轮询脚本但一定要闭环。4.4 多源异构文档清洗PDF表格、扫描件、网页最后一块硬骨头是清洗。文档来源多样PDF 里最常见的坑是表格被文本流读碎比如单元格顺序错乱、表头和内容分离直接分块后向量检索基本命中不准确。我的经验是先做版面解析把表格转成 Markdown 或 HTML 结构再分块。扫描件需要先 OCR但 OCR 之后的版面分析和顺序恢复同样重要否则原文顺序错乱会让分块语义不连贯。网页内容要先清理导航、页脚、广告和脚本代码只保留正文文本最好再用正文提取算法。工具层面unstructured、LlamaParse、PyMuPDF 都能处理一部分但没有任何工具能通吃所有文件。你需要针对自己的文档类型建立清洗流水线并在清洗后人工抽检几篇确认文本顺序、表格结构、特殊字符都正常。记住一句话清洗错误会被后续的检索和生成成倍放大越早投入越省钱。处理完的数据也最好存一份标准化后的原文方便排查和重新分块。5. 从基础 RAG 走向 Agentic RAG 与 GraphRAG5.1 Agentic RAG把检索变成 Agent 决策的一部分基础 RAG 是一条直线用户问一句检索一次生成一次。它适合简单的“问—答”场景但真实业务问题往往需要多个步骤。比如用户问“过去一周销售额下降是什么原因”RAG 需要同时检索销售数据、产品变更记录、市场活动文档还要区分哪些信息是事实、哪些是结论。这时候把 RAG 嵌进 Agent 的决策循环里模型不再只是做一次检索而是会规划先查哪个库、需要调用什么工具、检索结果不够就换个关键词再查一次。这就是 Agentic RAG。我在实践中最直观的感受是Agentic RAG 把“检索策略”从固定规则变成模型推理的一部分也可以把具体的检索动作封装成 Skill让 Agent 按需调用。同一个问题在不同语境下可能需要不同的分块粒度、不同的知识库、不同的查询关键词。Agent 可以尝试多种检索路径并交叉验证最终答案的质量比单次检索高出一截。当然它带来的代价是延迟和 token 成本显著上升调试复杂度也高了。所以我的建议是先把基础 RAG 调稳再逐步把决策交给 Agent而不是一开始就上高复杂度的多跳检索。5.2 GraphRAG 与 Ontology RAG解决知识割裂的两种路线如果基础向量 RAG 的核心瓶颈是“多跳关系”那 GraphRAG 是当前很热的一种解法。它先把文档里的实体、关系抽取出来构造成知识图谱再在图上做检索和路径推理。比如“A 公司收购 B 公司后B 的产品线归谁负责”传统向量 RAG 可能只能找到收购新闻这条片段但 GraphRAG 可以通过实体关联把“A—收购—B—包含—产品线”这条路径串起来回答更完整。与 GraphRAG 相关的是 Ontology RAG它在知识库之上定义了概念、属性和关系的一张“语义地图”。检索时可以用本体对查询做改写或过滤例如用户问“iOS 上能用的支付方式”如果本体已经定义了 App 支持的操作系统属性和支付集成关系检索可以精准地过滤无关 PC 端文档。这个领域早期也被称为“ontology rag”或“llm wiki 本体”本质上是让知识库的语义结构参与检索。这些方案都能缓解“知识割裂”但工程复杂度比基础 RAG 高不少通常适用于知识关系复杂、跨域查询要求高的业务。5.3 RAG 工程化的最后一公里评估、监控与成本说一千道一万RAG 的工程落地靠的是持续评估和监控。离线阶段我建议每个项目都维护一份包含几十条真实问题的评测集问题、答案、来源文档 id 都标好。每次调整分块参数、换 embedding 模型、加重排都跑一遍 hit rate 和答案质量评测用数据说话不要凭感觉。线上阶段要记录每次查询的检索命中文档、消耗 token 数、生成耗时定期回看失败案例。把这些数据沉淀下来RAG 管道才不是碰巧能跑而是可以被不断改进的。成本方面embedding 大文档、重排模型、大模型生成都会带来开销。批量场景可以把 embedding 在离线阶段预先算好缓存在线检索只计算查询向量能省下大头。重排可以用小模型做第一遍粗排不行再上大模型精排。这些细节积累起来效果差别很大。最后分享一点个人体会。我见过不少团队把 RAG 想得很玄一上来就对比各种高级架构结果基础的数据清洗和分块都还没做好。我的建议是先用最土的方案把管道跑通把文档清洗、分块、检索评估这一套基本功练扎实再根据业务复杂度逐步引入 Agent 决策、图结构、本体模型。这个顺序能帮你少走很多弯路也能让 Agent 真正拥有可持续更新的知识来源。