ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RAG实战:AI Agent知识获取管道搭建与调优指南

RAG实战:AI Agent知识获取管道搭建与调优指南 把AI Agent系列写到第四篇终于要碰最硬核、也最容易翻车的环节——知识获取管道。前面几篇聊了Agent的规划、工具调用和记忆但真正跑业务的Agent总会撞上一个现实模型参数里的知识是“上一个训练周期”的知识它不知道你刚更新的业务文档也不知道你们公司内部的知识库。RAGRetrieval-Augmented Generation检索增强生成就是给Agent补上“知识外挂”的标准做法在模型回答之前先从外部知识库检索出一批相关资料再把“问题资料”一起交给模型让它基于证据回答。这套管道不解决所有问题但它是让Agent从“嘴强王者”变成“能干活”的基础设施。这篇文章会把RAG最基础的链路完整拆一遍并给出可以直接参考的落地代码、参数选型与排查清单适合刚入门Agent开发、或已经跑通Demo但对效果不满意的朋友。先说结论别急着上重编排、多跳推理、知识图谱先把“切分—向量化—检索—生成”这四个环节的每个参数吃透后面的一切才有意义。1. RAG在Agent架构里的角色远不止“加个知识库”1.1 Agent为什么必须有知识获取管道Agent应用和纯聊天机器人最大的区别在于它要朝着一个目标去行动需要调用工具、做规划、跟外部系统打交道。但不管怎么流转最终给用户的那段回复都依赖“当前这个模型脑子里的知识”。问题是模型参数里的知识在训练完成那一刻就冻结了它记不住昨天更新的产品手册也没读过你上传的几百份PDF。这时候如果硬让模型回答它就只能“编”。Agent圈里这种现象特别常见任务规划头头是道一旦涉及具体业务数据就开始一本正经地胡说八道比如把退货政策的截止日期说错把内部审批流程的负责人搞混。根本原因不是模型不够聪明而是知识获取环节是断的。所以RAG要承担的角色是给Agent接一条“外挂记忆”通路。在模型生成之前先从一个受控的知识源里把相关资料捞出来塞进上下文再让模型基于这些材料作答。这样回答不仅更新鲜还能给出依据用户问“你怎么知道的”你可以直接把原文片段甩过去。还有一个经常被拿来对比的方案是微调。RAG和微调不是二选一但适用场景明显不同RAG适合频繁更新的知识、私有文档、需要引用溯源的任务微调适合改变模型的说话风格、领域术语习惯、固定格式输出。实际项目里混合方案也不少见——先用RAG解决“内容对不对”再用微调解决“说法像不像”。但在Agent这个语境下知识获取管道是必选课因为Agent要操作的业务知识总是在变你不可能每次业务更新都去重新微调模型。1.2 “知识获取”本身就该是一条管道很多人第一次接触RAG以为就是“开个向量数据库问一句查一下”。真做起来会发现从原始文档到模型能用的一段上下文中间隔着好几个环节文件采集、格式清洗、语义切分、向量化、索引存储、检索召回、上下文组装。任何一个环节做得糙最终效果都会塌。这也是为什么我坚持把它叫“知识获取管道”而不是“知识库”。管道强调的是流程可控、每段可测。比如切分大了召回太粗切分小了一条完整信息被撕碎embedding模型和你的文档语言不匹配召回率直接腰斩检索到的chunk不加清洗就直接塞给模型模型很容易淹没在噪声里。管道思维还能帮你做效果归因。线上问答效果变差了你是该怀疑新上传的文档还是该怀疑切分参数又或者是embedding模型被动过只要每个环节都有单独的日志和评估指标问题定位就是分钟级的事。这是我带RAG项目时最深的体会。给工具链做个简单对比基于常见实践手动拼接脚本做Demo没问题但一旦文档量过万、问题类型变多必须有“阶段划分和指标埋点”。先用简单链路跑通再逐步替换某个环节比如把固定切分换成语义切分把单路向量检索换成BM25向量混合检索。上了Agentic RAG后管道里会多出“决策”环节但基础数据层仍然是这条管道。2. RAG基础链路拆解索引、检索、生成2.1 文档处理与切分chunk_size不是随便填的所有知识获取管道都从原始文档开始。第一步是把它变成纯文本PDF要解决扫描版还是文字版HTML要去掉标签表格要决定保留原样还是转成Markdown。这一步看起来琐碎但特别影响后续质量——很多PDF里的表格被简单拼成一行文字后检索到了也读不出含义。清洗完就要切分。常见的切分策略有三种固定长度切分、按标点/段落的递归切分、语义切分。固定长度简单粗暴但容易把一句话从中间腰斩递归切分RecursiveCharacterTextSplitter先按段落、再按句子、再按换行去切尽量让每个chunk在语义上完整语义切分更进一步用embedding判断句子之间相似度在意思变化的地方断开。chunk_size和chunk_overlap这两个参数是新手最容易拍脑袋填的地方。我见过有人无脑填256也有人填2000。关键要看两个约束一是chunk内部语义要完整二是多个chunk拼起来的上下文长度不能超过模型窗口。向量维度方面不管用bge-m31024维还是其他768维模型chunk大小影响的不是向量维度而是向量库的规模和检索颗粒度。更关键的是token估算假设一个512字的中文块经过主流大模型分词后大约消耗300到450个token那么8K上下文的窗口模型最多只能吃下10个chunk左右再算上给答案留的空间top_k不能拍脑袋设太高。我自己的经验是中文场景从chunk_size512、chunk_overlap48~64起步跑一轮评测集看命中率再上下调整。如果文档本身是学术论文、产品手册这种段落清晰的递归切分往往比固定长度好不少如果是聊天记录这种碎片文本固定长度反而更省心。2.2 向量化与索引embedding选型与向量库切分完每个chunk要变成向量。这里有个常见的认知误区embedding模型不是“随便下载一个英文模型就能用”。中文场景如果你用的是纯英文训练的text-embedding-ada-002当然这里只是举例反映问题对中文长句的语义区分度会差很多。更适合中文的方案包括bge系列、m3e、text2vec、gte等开源模型或者直接用国产商业模型API。选型时重点看三个指标检索评测集上的召回率、向量维数影响存储成本、CPU/GPU推理延迟。向量库这边按部署复杂度从小到大排方案部署形态适合规模特点FAISS内存索引单机/原型轻量上手快Chroma本地文件型小团队验证持久化方便Milvus分布式服务生产环境横向扩展强Qdrant独立服务中等规模元数据过滤强Elasticsearch已有集群扩展存量ES用户复用已有设施选型另一个关键点是metadata。每个chunk在入库时除了向量和原文最好还带上来源、章节、更新时间、权限标识等字段。这样检索时既能按时间过滤也能按来源过滤还方便做权限隔离。很多人忽略metadata出了问题只能把整个索引重建非常被动。还有一个低级错误必须提醒建索引和线上查询必须用同一个embedding模型。我见过不止一个项目建索引时图省事用模型A线上查询时换了模型B向量空间完全不一致检索效果直接崩溃。这个问题在日志里很隐蔽因为系统不会报错但hit_rate会掉到不忍直视。2.3 检索与生成融合召回、重排、上下文组装向量化只是给检索做准备真正的核心动作发生在查询那一刻。一个具体的流程是把用户query用同一个embedding模型转成向量然后在向量库里做相似度搜索常见度量有余弦相似度、内积和欧氏距离。返回的chunk不能直接全塞给模型要经过几道处理。第一道是召回先取一个稍大的候选集合比如top_k20保证“正确答案在里面”的概率。第二道是重排用一个rerank模型比如bge-reranker系列或基于cross-encoder对候选chunk重新打分把最相关的几个放最前。重排对效果提升非常明显因为向量检索的相似度排序未必对应“真正有用的顺序”。第三道是上下文组装。这里要处理几个细节去掉明显重复或冲突的chunk重复信息会让模型无所适从。用清晰的模板拼接chunk比如每条前面加“【资料3】来源产品手册_第2章”方便模型引用。如果chunk数量多要做一个简单的去噪过短的、跟query相关性明显偏低的小块可以丢弃。组装完成后最终把这个“问题资料”模板交给大模型。生成阶段的建议也要写进prompt只能基于提供的上下文回答资料里没有的信息要明确说不知道不能自己编。这一点在4.2还会展开但本质上属于“上下文工程”的一部分检索质量和prompt约束缺一不可。3. 最小可用RAG管道从0到1跑通全程3.1 环境准备与依赖选型下面给的是我自己用着比较顺的一套最小组合适合在一台普通开发机上把流程跑通Python 3.10、一个本地大模型Ollama拉起的qwen2.5:7b、一个embedding模型BAAI/bge-m3、向量库用FAISS编排用LangChain的轻量API。不建议上来就引入复杂的RAG框架因为那样你看不清每一步到底在发生什么。依赖大致如下实际装的时候注意版本兼容以官方文档为准。pip install langchain langchain-community langchain-text-splitters pip install sentence-transformers faiss-cpu pip install ollama如果你所在团队不允许直接用第三方编排框架也可以不用LangChain直接把加载、切分、embedding、存FAISS、检索、拼接prompt这些步骤写成普通函数。最小实现反而更可控出问题好排查。3.2 核心实现让Agent学会查内部手册我用一个具体场景来说明公司内部的IT支持手册包含设备申请流程、网络故障排查、软件安装规范等几十个文档。目标是做一个Agent员工问“忘记密码怎么办”它必须先检索手册再给出流程并且标注摘自哪里。下面是完整的最小实现前面加载和切分是给“离线构建索引”用的from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS from langchain.chains import RetrievalQA # 1. 加载并清洗文档这里是本地txt文件 loader TextLoader(it_manual.txt, encodingutf-8) docs loader.load() # 2. 切分先按段落再按句子中文加了标点分隔 splitter RecursiveCharacterTextSplitter( chunk_size512, chunk_overlap48, separators[\n\n, \n, 。, , , , , , ] ) chunks splitter.split_documents(docs) # 3. 向量化并写入FAISS索引 embedding HuggingFaceEmbeddings(model_nameBAAI/bge-m3) vector_store FAISS.from_documents(chunks, embedding) vector_store.save_local(faiss_index) # 4. 构建检索问答链QA环节使用本地模型 from langchain_community.llms import Ollama qa RetrievalQA.from_chain_type( llmOllama(modelqwen2.5:7b), retrievervector_store.as_retriever(search_kwargs{k: 4}), chain_typestuff, ) resp qa.invoke(员工忘记密码应该按什么步骤重置) print(resp[result])先说几个注释里没写的坑。第一HuggingFaceEmbeddings首次运行会下载模型权重如果是内网环境记得提前把模型文件拷到本地仓库。第二FAISS.save_local之后加载用FAISS.load_local同时传embedding对象否则取向量时没人帮你做query向量化。第三Ollama要在后台先拉好模型并且把服务跑起来url默认是localhost:11434不需要额外配置。这个chain_typestuff的意思是把检索到的chunk直接拼成一个长文本塞进prompt。好处是简单缺点是chunk一多容易超窗口所以k先别调太大。等后面需要处理更多资料时再换成map_reduce或refine策略。3.3 效果评估与参数调优先定义“什么是答得好”很多团队跑通上面的代码看到能回答就开始欢呼。我通常建议先别高兴准备一套评测问题集再说。RAG最核心的评估指标叫hit_rate命中率它衡量的是对于一批有标准答案的问题检索结果top_k里有没有包含“正确答案所在的chunk”。可以这么算假设你有20个测试问题每个问题都人工标注了它在文档中的正确答案段落IDchunk_id。跑一次检索看top_k返回的chunk_id列表里是否包含标注的chunk_id。如果20个问题里有16个的答案被召回那么hit_rate80%。别小看这个数50%和80%的差距往往就是召回策略和切分参数的差距。基于评测集我一般这样调参提高hit_rate加大chunk_overlap、把切分策略改成递归优先或换成更合适中文领域的embedding模型。降低噪声如果top_k返回一堆无关片段检查chunk_size是不是太小以及embedding模型是否和文档领域匹配。回答不准确先看hit_rate是不是过了60%~70%如果召回本身很差调生成侧的prompt几乎没有意义。回答太长/超窗口降低k或改成“先重排再取前3”。4. 常见问题排查与避坑实录4.1 检索空召回或命中率低先查这五个地方检索命中低是RAG项目里出现频率最高的问题而且八成不是向量库的锅。我按概率从高到低列出排查顺序切分是否合理。整段怼进去检索出来一大块看似相关实际证据被淹没切太碎问题里的关键实体被切开检索更找不到。query与文档的语言表达是否一致。用户口语问“密码丢了咋办”文档里写的是“重置密码申请流程”如果只用向量相似度可能反而匹配不上。解决方式是做query改写或者同时做关键词命中BM25。embedding模型是否匹配。直接用英文模型处理中文或是用通用模型处理高度垂直的法律/医疗文本都会导致语义偏差。top_k太小。有些问题答案分散在多个chunk里只取2~3个很容易漏。索引数据本身脏。重复文档、旧版本覆盖新版本、乱码内容都会把正确的chunk挤下去。排查时可以临时打印检索出来的chunk原文手工比对“既然你没召回到正确答案那到底召回到了什么”这个动作能快速告诉你问题出在切分、embedding还是query处理上。4.2 生成侧幻觉严重prompt和管道都要管RAG项目里的“幻觉”并不总是模型的错。如果你检索到的资料里根本没提“审批需要3天”但模型还是回答了3天那问题十有八九出在prompt没有把“只允许基于资料回答”写死或者上下文里夹带了不少无关信息模型自己“脑补”了出来。一个比较稳的prompt模板大概是这样的你是一个知识库问答助手。你需要严格基于下方提供的资料片段回答问题。 规则 1. 只在资料片段能支撑答案时回答。 2. 资料中没有的信息直接说“资料中未找到相关内容”不要猜测。 3. 回答末尾列出参考来源编号。 资料片段 【资料1】来源it_manual.txt_第3章 内容... 【资料2】来源it_manual.txt_第8章 内容... 用户问题{question}另外生成参数建议把temperature调低一些0.1~0.3之间。对一些“必须按流程来”的任务模型创造欲太强不是好事。还有一个很容易被忽略的点如果多个chunk里同时存在互相矛盾的信息模型也很容易混乱。这种情况不能只靠prompt约束要在检索阶段就通过metadata过滤掉过期版本。4.3 知识更新、去重与多知识库管理上线之后遇到的麻烦往往是知识维护。业务文档一个月更新三次之前的索引还留在向量库里检索时旧文档的chunk会和新文档打架。可靠的思路是给每个索引加版本号或更新时间字段更新时对同一来源的旧chunk做软删除而不是不断叠加。多知识库管理也需要提前想好按部门建多个索引query进入前先路由到对应知识库或者用一个索引但靠metadata过滤。比如“市场部员工手册”和“研发部应急预案”放在一个向量库没问题但检索时用filter字段限定部门范围效果通常比全库搜要好很多。还有一个很多人会忽略的坑权限隔离。如果知识库里有些文档只有部分人能看到向量库本身不做权限控制。开放RAG服务接口时一定要在检索环节把用户权限传进去做metadata过滤否则很容易出现越权检索。这个看起来是工程问题但出一次就是事故。5. 从基础RAG到Agentic RAG进阶方向与实际建议5.1 把“检索”变成一个决策动作基础RAG的流程是一条固定的流水线query进来检索生成。Agentic RAG最大的不同是把“检索”本身变成Agent可以决策的动作。Agent不再每次都检索而是先判断这个问题自己能不能回答也不能只检索一次它可能先模糊搜一下再根据返回的chunk判断是继续检索细化还是换一个检索工具或者干脆调用一个业务API拿数据。这一转变听起来很美但我对团队的劝告一直是不要为了概念而概念。Agentic RAG适合两类场景一是问题链路特别长的多跳问答比如“上个季度华南区哪款产品退货率最高”中间需要聚合多次查询结果二是检索工具很多、需要自动选路的时候比如既有API又有文档库又有表格。如果只是一问一答式的知识库问答固定管道反而更快、更可控。5.2 知识图谱、GraphRAG和本体什么时候该上再往后走会看到两个高频词GraphRAG和本体RAG。它们的共同点是把知识组织成“实体—关系”结构而不是一堆孤立的chunk。优点是回答“谁和谁有关”“某个流程依赖哪些环节”这类关系型问题时候准确率更高代价是构建图谱的成本远高于向量化不是所有项目都值得上。我的判断标准很简单如果你的用户问题里充满“A公司收购了B公司后原B公司的产品线怎么处理”这类关系链条可以考虑实体抽取构建图谱如果大部分问题是“某个政策怎么执行”“某个参数的默认值是多少”先把向量RAG做好收益更大。5.3 落地顺序与最后建议最后说点实际的。我经手的RAG项目里最失败的不是没做Agentic而是没建立评测集就开始调参数最后所有人都在凭感觉说“效果好像好了一点”。所以我强烈建议你按这个顺序做先收集20~50条真实业务问题人工标注答案和chunk_id。跑通最基础的索引—检索—生成。用hit_rate评估检索环节调到可接受水平。再做生成侧的prompt优化检查回答有没有依据。最后考虑query改写、重排、多知识库路由这些进阶策略。等基础稳定后再考虑把检索封装成一个Agent的工具让规划链路去决定何时检索、检索几轮。至于GraphRAG、知识图谱这些重武器等你的场景里出现关系推理需求时再上也不迟。我自己的体会是RAG这个方向最大的分水岭不是算法复杂度而是你能不能把自己的知识库管得明明白白。数据质量差再牛的检索模型也救不回来数据干净、分层合理哪怕只用最基础的向量检索效果也能让业务方满意。这也是为什么我一直强调“知识获取管道”——它值得你像对待在线业务一样仔细梳理每个环节。
返回列表