ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent知识库实战:从文档解析到RAG检索的完整链路

Agent知识库实战:从文档解析到RAG检索的完整链路 知识库这个东西我前前后后搭过不下十套。最早那会儿我也觉得不就是把文档往向量库里一塞接个模型就完事了结果上线第一天就被打脸——用户问报销标准是多少AI 一本正经地编了个每天补贴 800 元而真实文件里写的是 150 元。那一刻我才明白知识库的核心难点从来不是存进去而是查得准。散落一地的 PDF、Word、Excel、网页、聊天记录怎么变成 AI 真能查、查得对、答得稳的东西这里面每一步都有坑。这篇就聊聊 Agent 系列第三篇的主角——知识库。我会从为什么大多数人的知识库是废的讲起把文档解析、切分策略、向量化、检索召回、重排、以及和 Agent 的联动这一整条链路拆开讲透。不管你是刚接触 RAG 的新手还是已经踩过几轮坑的老手都能从里面找到能直接抄作业的东西。关键词就那几个Agent、智能体、知识库、RAG、MCP我们一个一个落地。1. 为什么你搭的知识库AI 查了等于没查1.1 一个真实的翻车现场先讲个我自己的案例。去年帮一个做企业服务的团队搭内部知识库资料大概 3000 多份包含产品手册、FAQ、合同模板、历史工单。第一版我用的是最朴素的方案把所有文件转成纯文本按 500 字一刀切丢进向量库用户提问就做相似度检索取 Top 3 塞给模型。上线测试的时候问客户要求退款超过 30 天怎么处理AI 回答得头头是道但引用的是一份两年前的旧政策。而最新政策明明就在库里只是它被切成了三段关键的那句超过 30 天需走特殊审批流程正好卡在两段的交界处检索时两段都没被完整召回。这就是典型的存进去了但查不出来。问题不在模型在于整条链路的每一环都在丢信息解析丢格式、切分丢上下文、检索丢精度、拼装丢重点。很多人以为知识库是个存储问题其实它是个信息保真问题。1.2 知识库和普通搜索的本质区别有人会问那我直接用全文检索比如 Elasticsearch 的关键词匹配不就行了为什么非要搞向量、搞 RAG这里要讲清楚一个核心差异。关键词检索匹配的是字面向量检索匹配的是语义。用户问怎么退钱文档里写的是申请退款流程关键词检索可能匹配不上但向量检索能识别出退钱和退款是一回事。但反过来向量检索也有软肋。用户问2024 年 Q3 的营收数据向量检索可能给你召回一堆营收季度相关的段落但具体是哪个季度、哪一年它不一定分得清。所以真正好用的知识库从来不是二选一而是混合检索——关键词负责精确匹配数字、专有名词、编号向量负责语义理解同义、近义、口语化表达。我一般会这么配先用关键词召回一批候选再用向量召回一批候选两路结果合并去重最后用重排模型统一打分排序。这套组合拳下来召回率能比单路提升 30% 以上。1.3 判断你的知识库是否合格的三个硬指标在动手之前先给你三个自测标准达不到的话后面做得再花哨也是白搭召回率用户问的问题正确答案所在的文档片段有没有被检索出来这个指标低于 85%说明解析或切分有问题。准确率检索出来的 Top 3 里有多少是真正相关的低于 70%说明检索策略或向量模型需要换。答案忠实度AI 生成的回答有没有超出检索到的内容去编这个靠提示词和引用约束来控制。这三个指标里召回率是地基。召回都召不回来后面重排、生成全是空中楼阁。我见过太多人一上来就纠结用哪个大模型结果连文档都没解析干净纯属本末倒置。2. 文档解析别让格式成为信息的第一道漏斗2.1 不同格式的解析难度天差地别知识库的原料五花八门但解析难度完全不是一个量级。我按经验给你排个序从易到难格式类型解析难度主要坑点推荐工具方向纯文本 / Markdown低编码问题、换行混乱直接读取注意 UTF-8Word (.docx)中表格、页眉页脚、批注python-docx、docx2txtPDF文字版中高分栏、表格、页眉页脚PyMuPDF、pdfplumberPDF扫描版高需要 OCR识别率不稳PaddleOCR、通用 OCR 服务Excel中多 sheet、合并单元格openpyxl、pandas网页 / HTML中正文提取、广告噪声readability、trafilatura图片高图文混排、图表理解多模态模型辅助我踩过最深的坑是 PDF。很多 PDF 看着是文字其实是图片扫描件你直接提取文本会得到一堆乱码或者空白。判断方法很简单用 pdfplumber 提取一下如果字符数远小于预期基本就是扫描件得上 OCR。2.2 PDF 解析的实战细节PDF 解析我推荐PyMuPDFfitz打底pdfplumber处理表格。为什么这么配PyMuPDF 速度快、对文字版 PDF 的文本提取质量高pdfplumber 虽然慢但它对表格的识别和坐标定位更准。一个关键细节页眉页脚必须去掉。很多 PDF 每页顶部都有公司名、底部有页码这些内容如果不去掉会被切进每个片段里严重干扰检索。我的做法是统计每页前两行和后两行的重复率重复率超过 80% 的就判定为页眉页脚直接剔除。import fitz # PyMuPDF def extract_pdf_text(pdf_path): doc fitz.open(pdf_path) pages [] for page in doc: # 按块提取保留段落结构 blocks page.get_text(blocks) # blocks 格式: (x0, y0, x1, y1, text, block_no, block_type) text_blocks [b[4] for b in blocks if b[6] 0] pages.append(\n.join(text_blocks)) doc.close() return pages注意get_text(blocks)这个参数它比默认的get_text()保留了更多版面信息段落不会被揉成一坨。这个细节很多人不知道但效果差别很大。2.3 表格和图片最容易被忽略的信息载体表格是知识库里信息密度最高的部分也是最容易被解析毁掉的部分。一份报价单解析成纯文本后可能变成产品A 100 产品B 200行列关系全丢了AI 根本看不懂。我的处理策略是表格单独提取转成 Markdown 表格或结构化 JSON作为一个独立片段存储并在片段开头加上以下是一张表格描述的是 XX这样的说明。这样检索到表格时AI 能明确知道这是结构化数据。图片的话如果知识库场景涉及图表、流程图、产品图建议用多模态模型生成图片描述把描述文本存进向量库。纯文本模型是看不见图片的你不做这一步图片就等于没存。提示解析阶段的目标不是提取所有文字而是保留所有语义。宁可多花时间做结构化也不要把信息揉成一团。3. 切分策略切得好检索就成功了一半3.1 为什么固定长度切分是个陷阱回到开头那个翻车案例罪魁祸首就是固定长度切分。按 500 字一刀切看起来整齐实际上把语义切碎了。一句话被切成两半前半段在片段 A后半段在片段 B检索时两段都召不全AI 自然答不对。固定长度切分的问题在于它假设字数相等 信息量相等但现实是一段 200 字的政策条款信息量可能顶得上一段 2000 字的背景介绍。用同一把尺子量必然出问题。3.2 语义切分的三种落地方式我现在用的切分策略是语义优先长度兜底具体分三层第一层按文档结构切。Markdown 的标题、Word 的 Heading、PDF 的章节标题这些都是天然的语义边界。优先按这些边界切能保证每个片段是一个完整的语义单元。第二层按段落和句子切。结构边界内部再按段落切段落太长超过 800 字再按句子切。句子边界用标点符号。判断别用固定字数。第三层重叠窗口兜底。相邻片段之间保留 10%~15% 的重叠内容。比如片段 A 是 1~500 字片段 B 就从 450 字开始。这样即使边界判断有误关键信息也不会完全丢失。def semantic_chunk(text, max_len800, overlap100): # 先按段落切 paragraphs text.split(\n\n) chunks [] current for para in paragraphs: if len(current) len(para) max_len: current para \n\n else: if current: chunks.append(current.strip()) # 处理超长段落 if len(para) max_len: for i in range(0, len(para), max_len - overlap): chunks.append(para[i:i max_len]) current else: current para \n\n if current: chunks.append(current.strip()) return chunks3.3 片段大小到底设多少合适这个问题我被问过无数次。我的经验值是中文 300~800 字英文 200~500 词。为什么是这个区间太小低于 200 字单个片段信息量不足检索时容易召回一堆碎片AI 拼不出完整答案。太大超过 1000 字片段里混入太多无关内容向量表示会被稀释检索精度下降。但这不是死规定。FAQ 类内容可以切小一点一问一答200~300 字政策文档、技术手册可以切大一点500~800 字。核心原则是一个片段应该能独立回答一个完整的问题。你切完之后自己读一遍如果读不懂说明切错了。3.4 给片段加上上下文标签这是我强烈推荐的一个技巧在每个片段前面加上它所属的文档标题、章节路径。比如一个片段原本是超过 30 天需走特殊审批流程加上标签后变成【文档退款政策 V3.2】【章节三、特殊场景处理】 超过 30 天需走特殊审批流程……这么做有两个好处一是检索时标签里的关键词也能参与匹配提升召回二是 AI 生成答案时能知道这段话的出处引用更准确。实测下来加了上下文标签的片段答案准确率能提升 15% 左右。4. 向量化与检索让 AI 真正理解你的资料4.1 向量模型怎么选向量模型Embedding Model决定了文本被映射成什么样的向量直接影响检索质量。选型时看三个维度中文能力、维度大小、推理速度。我的建议是中文场景优先选中文优化过的模型别直接用英文模型硬套。维度方面768 维和 1024 维是主流维度越高表达能力越强但存储和计算成本也越高。中小企业知识库768 维基本够用。还有一个容易被忽略的点查询和文档要用同一个模型。有人图省事文档用一个模型查询用另一个结果向量空间对不上检索全是噪声。这个错误我见过不止一次。4.2 混合检索的具体实现前面说了混合检索这里给个可落地的思路。核心是两路召回 分数归一化 融合排序def hybrid_search(query, top_k10): # 第一路向量检索 query_vec embed(query) vector_results vector_db.search(query_vec, top_ktop_k) # 第二路关键词检索BM25 keyword_results bm25_index.search(query, top_ktop_k) # 分数归一化后融合 scores {} for rank, doc in enumerate(vector_results): scores[doc.id] scores.get(doc.id, 0) 1 / (rank 60) for rank, doc in enumerate(keyword_results): scores[doc.id] scores.get(doc.id, 0) 1 / (rank 60) # 按融合分数排序 ranked sorted(scores.items(), keylambda x: x[1], reverseTrue) return ranked[:top_k]这里的1 / (rank 60)是RRFReciprocal Rank Fusion的经典公式60 是个经验常数。它的好处是不用关心两路检索的分数尺度差异只看排名融合起来很稳。4.3 重排检索质量的最后一道闸混合检索召回 Top 10 之后别急着塞给模型。加一道重排Rerank用专门的交叉编码器模型对这 10 个候选重新打分取 Top 3。为什么需要重排因为向量检索是粗筛它把查询和文档分别编码成向量再算相似度速度快但精度有限。重排模型是精筛它把查询和文档拼在一起输入模型能捕捉更细粒度的语义关系精度高但速度慢。所以标准做法是向量粗筛 Top 50重排精筛 Top 5。实测数据加了重排之后Top 3 的准确率能从 65% 提升到 85% 以上。这一步的性价比极高强烈建议加上。4.4 检索结果怎么拼给模型检索到片段后怎么组织进提示词也有讲究。我的模板是这样的你是一个严谨的知识库助手。请仅根据以下参考资料回答问题 如果资料中没有相关信息请明确说资料中未提及不要编造。 参考资料 [1] 【文档退款政策 V3.2】超过 30 天需走特殊审批流程…… [2] 【文档客服手册】特殊审批需由主管签字…… 用户问题客户要求退款超过 30 天怎么处理关键点有三个编号引用方便追溯、明确约束禁止编造、资料在前问题在后模型对末尾内容更敏感。这套模板能显著降低幻觉率。5. 知识库与 Agent 的联动从能查到会用5.1 知识库不是终点是 Agent 的工具很多人把知识库当成一个独立的问答系统其实在 Agent 架构里知识库是 Agent 的一个工具Tool。Agent 根据用户意图决定要不要调用知识库、调用几次、用什么查询词。举个例子用户问帮我对比一下 A 产品和 B 产品的退款政策。Agent 会先拆解意图发现需要查两次知识库A 的政策、B 的政策分别检索再对比生成。这种多轮检索、动态决策的能力是单纯的知识库问答做不到的。5.2 通过 MCP 把知识库标准化接入MCPModel Context Protocol是现在 Agent 生态里很火的一个协议它的价值在于把工具接入标准化。以前你给每个 Agent 框架写一套知识库对接代码换个框架就得重写。有了 MCP知识库封装成一个 MCP Server任何支持 MCP 的 Agent 都能直接调用。一个知识库 MCP Server 通常暴露这几个能力search_knowledge(query, top_k)检索知识库get_document(doc_id)获取完整文档list_collections()列出知识库集合这样 Agent 只需要知道有个工具能查知识库不用关心底层用的是哪个向量库、哪个模型。解耦做得干净维护成本大幅下降。5.3 查询改写让 Agent 自己优化检索词用户的口语化提问直接拿去检索往往效果不好。比如用户问那个退钱的事儿咋弄直接检索可能召回一堆无关内容。这时候可以让 Agent 先做查询改写原始查询那个退钱的事儿咋弄改写后退款流程 申请条件 所需材料改写后的查询关键词更明确检索命中率明显提升。这个改写动作可以由 Agent 自动完成也可以用一个轻量模型专门做。我一般会在 Agent 的提示词里加一句在调用知识库前先把用户问题改写成适合检索的关键词组合。5.4 多轮对话中的知识库上下文管理多轮对话里用户会省略上下文。比如第一轮问退款政策是什么第二轮问那超过 30 天呢。第二轮如果直接检索超过 30 天可能召回一堆不相关的内容。正确做法是把历史对话和当前问题合并改写变成退款政策 超过 30 天怎么处理再检索。这个细节决定了多轮场景下的体验。我见过不少知识库单轮表现很好一到多轮就崩问题就出在没做上下文合并。6. 上线之后那些只有跑起来才会暴露的问题6.1 检索日志是最好的优化依据知识库上线不是终点是起点。我强烈建议记录每一次检索的完整日志用户原始问题、改写后的查询、召回的片段 ID、重排后的分数、最终生成的答案、用户反馈。有了这些日志你才能知道哪些问题召回失败了哪些片段从来没被召回过可能是冗余哪些查询改写效果差我一般每周看一次日志把召回失败的 case 挑出来反推是解析问题、切分问题还是检索问题。这个迭代循环比任何理论优化都管用。6.2 增量更新与版本管理知识库不是一次建完就完事的。文档会更新、会新增、会作废。这里有两个坑坑一更新后旧向量没删。文档改了新向量加进去了旧向量还在检索时新旧混在一起AI 可能引用旧内容。解决办法是给每个片段打上doc_id和version更新时先按doc_id删除旧片段再插入新片段。坑二没有版本追溯。用户问最新的政策是什么你得能区分哪个是最新版本。我的做法是在片段元数据里存effective_date和version检索时可以按时间过滤或者让 Agent 优先选最新版本。6.3 权限控制别让所有人都能查所有东西企业知识库一定要做权限。销售能看的、HR 能看的、财务能看的范围完全不同。如果检索时不带权限过滤销售可能查到财务的薪酬数据这是重大事故。实现方式是在片段元数据里存access_level或department检索时根据当前用户的身份加过滤条件。向量库一般支持元数据过滤在检索请求里带上filter{department: sales}就行。这一步千万别省。6.4 效果评估别靠感觉要靠数据最后说评估。很多人优化知识库全靠感觉好像好了一点这不行。你得有一套评估集准备 50~100 个真实问题每个问题标注正确答案所在的文档片段。每次改动后跑一遍评估集看召回率和准确率的变化。这套评估集不用很复杂一个 Excel 就行问题、标准答案片段 ID、当前召回结果、是否命中。跑一次几分钟但能让你清楚地知道每次改动是进步还是退步。我见过太多人凭感觉调参数越调越差就是因为没有评估基准。7. 我踩过的几个典型坑你可以直接绕开7.1 坑一以为向量库能存一切刚开始我以为向量库是万能的什么都能往里塞。后来发现结构化数据比如订单号、金额、日期用向量检索效果极差。用户问订单 12345 的状态向量检索可能召回一堆订单状态相关的通用说明就是找不到那个具体订单。正确做法是结构化数据走数据库查询非结构化数据走向量检索。Agent 根据问题类型决定调用哪个工具。这也是为什么 Agent 架构比单纯知识库更强——它能路由到正确的数据源。7.2 坑二忽略文档的时效性知识库里最危险的不是查不到而是查到了过期的。一份 2022 年的政策和 2024 年的政策向量相似度可能很高检索时都召回了AI 分不清哪个是现行的。解决办法有两个一是在片段里显式标注生效日期让 AI 能看到二是检索时按时间加权新文档分数更高。我一般两个都做双保险。7.3 坑三提示词里没做无答案处理用户问的问题知识库里根本没有相关内容这时候 AI 应该老实说不知道而不是硬编一个答案。但很多提示词没做这个约束模型就会尽力而为地编。我的提示词里必加一句如果参考资料中没有能回答问题的内容请直接回复根据现有资料无法回答该问题不要尝试推测或编造。这一句话能挡掉大部分幻觉。7.4 坑四切分时把表格切碎了前面提过表格的问题这里再强调一次。表格如果被当普通文本切分行列关系全丢。我的做法是表格整体作为一个片段不参与常规切分并且转成 Markdown 格式存储。如果表格特别大超过 2000 字按行切分但每一段都要带上表头。| 产品 | 价格 | 退款期限 | |------|------|---------| | A | 100 | 30天 | | B | 200 | 15天 |这样即使只召回表格的一部分AI 也能看懂列的含义。8. 一套可以直接抄的最小可用方案8.1 技术栈选型如果你现在要从零搭一套我给你一套经过验证的最小方案环节选型理由文档解析PyMuPDF pdfplumber python-docx覆盖主流格式质量稳定切分自研语义切分结构段落重叠比现成库更可控向量模型中文优化的 Embedding 模型中文场景必备向量库支持元数据过滤的向量数据库权限和版本管理需要关键词检索BM25精确匹配兜底重排交叉编码器 Rerank 模型精度提升明显Agent 接入MCP Server 封装标准化、可复用8.2 落地顺序建议别想着一次做完所有事按这个顺序来先跑通单文档拿一份 PDF走完解析→切分→向量化→检索→生成全流程确认链路通。再加混合检索和重排单路检索效果不够时加这两样。再做权限和版本企业场景必须做个人场景可以缓。最后接 Agent 和 MCP让知识库从问答升级到工具。每一步都跑评估集确认有提升再进下一步。这样出问题容易定位不会一锅乱炖。8.3 一个容易被忽略的收尾细节最后分享一个我踩过的小坑片段 ID 的生成方式。早期我用随机 UUID结果每次重建索引同一个片段的 ID 都变了导致评估集里的标注全部失效没法对比前后效果。后来改成基于内容哈希生成 ID比如hash(doc_id chunk_index content)只要内容不变ID 就不变。这样重建索引后评估集还能用迭代效率高了很多。这个细节很小但影响很大做评估的同学一定要注意。知识库这件事说到底是个工程活不是模型活。模型再强喂进去的是垃圾出来的还是垃圾。把解析做干净、把切分做合理、把检索做精准、把约束做严格这四件事做到位一个中等规模的模型也能撑起很好用的知识库。反过来模型再顶级前面几环漏了照样答非所问。我这些年最大的体会就是别急着换模型先把数据链路捋顺。
返回列表