1. 为什么知识获取管道是 AI Agent 的分水岭
做 AI Agent 开发的人,绕不开一个尴尬的现实:模型本身很聪明,但它对你私有的业务知识一无所知。你问它公司内部的报销流程,它只能给你编一个看起来很像那么回事的答案。这个问题的本质不是模型能力不够,而是知识没有接进来。RAG,也就是检索增强生成,解决的正是这件事——在模型生成答案之前,先从你的知识库里把相关资料捞出来,塞进上下文,让模型基于真实材料回答。
我在过去一年里搭过好几个 Agent 项目,从最朴素的向量检索到后来的混合检索加重排,踩过的坑基本能写一本书。这一篇作为 AI Agent 系列的第四篇,专门聊知识获取管道,也就是 RAG 的基础部分。我会把整个链路的每个环节拆开讲清楚:文档怎么进来、怎么切、怎么变成向量、怎么存、怎么查、怎么把查到的内容喂给模型。适合正在从零搭 Agent 的开发者,也适合已经用过现成 RAG 框架但想搞明白底层原理的人。
先说一个结论:RAG 的效果上限,八成取决于知识获取管道的设计,而不是你换了多大的模型。我见过太多人把精力全花在换模型上,结果检索回来的东西驴唇不对马嘴,再强的模型也救不回来。所以这一篇的重点,是把管道本身讲透。
2. RAG 到底在解决什么问题
2.1 大模型的三道硬伤
要理解 RAG 的价值,得先看清楚大模型本身的局限。第一道硬伤是知识截止。模型的训练数据有明确的时间点,之后发生的事情它一概不知。你问它上个月刚发布的产品政策,它要么说不知道,要么一本正经地胡说。
第二道硬伤是私有知识缺失。你的公司文档、内部 Wiki、客户资料、产品手册,这些东西从来没进过模型的训练集,模型不可能知道。这不是模型的问题,是数据边界的问题。
第三道硬伤是幻觉。模型在不确定的时候倾向于编造一个流畅的答案,而不是承认自己不知道。这在闲聊场景无所谓,但在企业应用里是致命的——用户分不清哪句是真的哪句是编的。
RAG 的思路很直接:既然模型不知道,那我就在它回答之前把相关资料找出来给它看。模型不需要"记住"这些知识,它只需要"读懂"你递给它的材料,然后基于材料作答。这就像开卷考试,考生不需要背下整本书,但需要能快速翻到相关的那一页。
2.2 RAG 和微调的区别在哪
经常有人问,既然要让模型掌握私有知识,为什么不直接微调?这个问题我专门做过对比测试。微调的本质是让模型把知识"内化"到参数里,代价是成本高、更新慢、容易遗忘。你每改一次文档就得重新训一遍,而且微调后的模型可能在其他任务上表现下降,这叫灾难性遗忘。
RAG 则是把知识和模型解耦。知识存在外部库里,模型只负责推理和生成。文档更新了,你只需要重新索引那部分内容,模型完全不用动。这种解耦带来的灵活性,在企业场景里价值巨大。我的经验是:需要模型掌握某种风格、格式、语气,用微调;需要模型掌握事实性知识,用 RAG。两者不冲突,可以叠加使用。
2.3 知识获取管道在 Agent 里的位置
在一个完整的 AI Agent 架构里,知识获取管道是"感知层"的一部分。Agent 接到用户请求后,先判断这个问题需不需要查知识库,需要的话就调用检索管道,把相关资料拉回来,再交给推理层去规划、决策、生成。所以管道不只是"查资料",它是 Agent 决策的输入来源。
这也是为什么我一直强调管道要做得扎实。管道返回的内容质量,直接决定了 Agent 后续所有动作的质量。检索错了,后面全错。这一点在 Agentic RAG 的场景里更明显——Agent 可能会多轮检索、自我反思、调整查询,但如果第一轮检索的基础设施就有问题,多轮也只是在错误的方向上越走越远。
3. 知识获取管道的完整链路拆解
3.1 从原始文档到可检索知识库的全流程
一条完整的知识获取管道,从原始文档到最终能被检索,中间要经过好几个环节。我把它拆成六个阶段:文档加载、文本切分、向量化、存储索引、检索召回、重排精排。每个阶段都有它的门道,任何一个环节偷懒,最终效果都会打折。
文档加载阶段要处理各种格式:PDF、Word、Markdown、HTML、Excel、数据库记录。不同格式的解析难度天差地别。PDF 是最麻烦的,尤其是扫描件和复杂排版,解析出来经常是乱的。文本切分阶段要把长文档切成合适大小的块,块太大检索不精准,块太小上下文不完整。向量化阶段把文本转成稠密向量或稀疏向量。存储索引阶段把向量存进向量数据库并建立索引。检索召回阶段根据用户查询找出候选。重排精排阶段对候选做二次排序,把最相关的排到前面。
这六个阶段里,我踩坑最多的是切分和检索。切分策略选错了,后面怎么调都别扭。检索策略单一了,遇到专业术语就抓瞎。下面逐个展开。
3.2 文档加载:别小看格式解析这一关
很多人觉得文档加载就是读个文件,能有多难。实际做起来,PDF 解析能让你怀疑人生。我处理过一批产品手册,PDF 里全是双栏排版加表格,用默认解析器读出来,文字顺序全乱了,表格内容混进了正文。这种数据喂进管道,检索出来的东西根本没法用。
我的做法是分格式处理。纯文本和 Markdown 直接用,结构清晰。Word 用专门的库解析,保留标题层级。PDF 分两类:文本型 PDF 用解析库提取,扫描型 PDF 得先做 OCR。表格单独抽出来,转成结构化数据。HTML 要清理掉导航栏、广告这些噪音,只留正文。
提示:文档加载阶段一定要做质量抽检。随机抽十几份文档,看看解析出来的文本是不是通顺、有没有乱码、表格有没有错位。这一步花十分钟,能省后面几小时的调试。
还有一个容易被忽略的点:元数据。每份文档都应该带上来源、标题、更新时间、所属分类这些信息。检索的时候可以按元数据过滤,比如只查最近半年的文档,或者只查某个产品线的资料。没有元数据,检索就是盲人摸象。
3.3 文本切分:块大小和重叠度的取舍
文本切分是管道里最需要经验的一环。切分的核心矛盾是:块要足够小,检索才精准;块要足够大,上下文才完整。这个平衡点在哪,取决于你的文档类型和查询特点。
我常用的策略是递归字符切分,按段落、句子、字符逐级降级切分,优先在语义边界处断开。块大小一般设在 500 到 1000 个字符之间,重叠度设在 10% 到 20%。重叠的作用是防止关键信息正好卡在切分边界上被切断。比如一句话被切成两半,前半句在块 A,后半句在块 B,检索时只召回块 A,信息就不完整了。有了重叠,块 B 也会包含前半句,就能补上。
但重叠不是越大越好。重叠太大,块之间重复内容多,检索时容易召回一堆相似的块,浪费上下文窗口。我实测下来,15% 左右的重叠是个比较稳的默认值。
对于结构化文档,比如带标题层级的技术文档,我会用基于标题的切分。按 H1、H2、H3 的层级切,每个小节作为一个块,同时把父级标题拼进块的元数据里。这样检索出来的块自带层级信息,模型能知道这段内容属于哪个章节,理解起来更准。
| 切分策略 | 适用场景 | 块大小建议 | 重叠度 |
|---|---|---|---|
| 递归字符切分 | 通用文本、混合内容 | 500-1000 字符 | 10%-20% |
| 基于标题切分 | 结构化技术文档 | 按小节自然长度 | 视情况 |
| 语义切分 | 长段落、论述性内容 | 按语义单元 | 5%-10% |
| 固定长度切分 | 日志、流水记录 | 256-512 字符 | 0-10% |
3.4 向量化:稠密嵌入与稀疏嵌入的分工
文本切好之后,要转成向量才能做相似度检索。这里有两种主流方式:稠密嵌入和稀疏嵌入。它们各有各的擅长领域,理解它们的区别是做好检索的关键。
稠密嵌入把一段文本压缩成一个固定长度的向量,比如 768 维或 1024 维,每一维都是浮点数。它的优势是能捕捉语义相似性。你搜"如何申请报销",它能召回"费用报销流程说明",即使两句话没有一个字相同。这是因为稠密嵌入在训练时学到了语义空间,意思相近的文本在向量空间里距离也近。
稀疏嵌入则是高维稀疏向量,维度等于词表大小,大部分位置是零,只有出现的词对应的位置有值。它的优势是精确匹配关键词。你搜"SKU-2024-A1",它能精确找到包含这个编号的文档。稠密嵌入对这种专有名词、编号、代码往往力不从心,因为训练时没见过,向量表示不准。
我的实践是两者结合,也就是混合检索。稠密负责语义召回,稀疏负责关键词召回,两路结果融合后排序。这样既能理解"报销"和"费用申请"是一回事,又能精确命中产品编号。实测下来,混合检索的召回率比单用稠密高出不少,尤其是在专业领域。
3.5 存储与索引:向量数据库怎么选
向量存哪里,索引怎么建,这决定了检索的速度和规模。小规模场景,几千到几万条向量,用内存索引就够了,比如 FAISS 这种库,加载快、查询快,不需要额外部署服务。但数据量上到百万级,就得用专门的向量数据库了。
选向量数据库我看几个维度:索引类型、过滤能力、扩展性、运维成本。索引类型决定了查询速度和召回率的平衡,常见的有 HNSW、IVF 这些。过滤能力指的是能不能在向量检索的同时按元数据过滤,比如"在最近半年的文档里找相似的",这个能力在企业场景里很重要。扩展性看能不能水平扩容。运维成本看部署和监控的复杂度。
我个人的选择逻辑是:原型阶段用轻量库快速验证,生产阶段根据数据量和查询量选合适的数据库。不要一上来就上重型方案,也不要数据量大了还硬扛内存索引。有个经验值可以参考:十万条以下用内存索引,十万到千万级用单机向量数据库,千万级以上考虑分布式方案。
3.6 检索召回:从查询到候选集
检索这一步,输入是用户的查询,输出是一批候选文档块。看似简单,其实有很多讲究。最基础的是向量相似度检索,把查询也转成向量,在库里找最相近的 top-k 个块。k 取多少?太小了可能漏掉相关资料,太大了会引入噪音。我一般先取 20 到 50 个候选,后面靠重排来筛。
但直接用用户原始查询去检索,效果往往不好。用户的问法五花八门,可能很口语化,可能信息不全。这时候需要查询改写。比如用户问"那个报销的事咋弄",可以改写成"费用报销的申请流程和所需材料"。改写可以用规则,也可以用模型来做。我试过用模型做查询扩展,把一个问题扩展成几个不同角度的查询,分别检索后合并结果,召回率有明显提升。
还有一种情况是多跳检索。有些问题需要多个文档的信息才能回答,比如"我们公司和 A 供应商的合同里,付款条款是怎么约定的"。这需要先找到合同文档,再在里面定位付款条款。单次检索搞不定,得让 Agent 做多轮检索,每轮基于上一轮的结果调整查询。这就是 Agentic RAG 的雏形。
3.7 重排精排:把最相关的顶上来
召回阶段拿到的候选集,排序往往不够精准。因为向量相似度高不代表真的相关,可能只是用词相近。这时候需要重排,用一个更精细的模型对候选做二次打分。
重排模型通常是交叉编码器,它把查询和每个候选块拼在一起输入模型,输出一个相关性分数。这种方式比向量点积更准,因为它能建模查询和文档之间的交互。代价是计算量大,所以只能用在候选集上,不能用来做全库检索。
我的流程是:向量检索召回 50 个候选,重排模型打分后取前 5 到 10 个,塞进模型的上下文。这样既保证了召回率,又保证了精度。重排这一步对最终效果的影响,比很多人想象的要大。我做过对比,加了重排之后,答案的准确率提升很明显,尤其是那些需要精确匹配的问题。
4. 从零搭一个最小可用的 RAG 管道
4.1 环境准备与依赖选择
理论讲完了,动手搭一个。我用 Python 来演示,因为生态最成熟。核心依赖就几个:文档加载用对应的解析库,切分用文本处理库,向量化用嵌入模型,存储用向量库,检索和重排用相应组件。
嵌入模型的选择上,我建议先用一个通用的开源模型跑通流程,比如 BGE 系列或者 M3E 系列,中文效果都不错。等流程跑通了,再根据业务数据做微调或者换更合适的模型。不要一上来就纠结用哪个模型,先把管道搭起来,有了 baseline 再优化。
向量库我用 FAISS 做演示,因为它轻量、无需部署、API 简单,适合快速验证。生产环境可以换成 Milvus、Qdrant 这类专门的数据库。
pip install langchain langchain-community faiss-cpu sentence-transformers pypdf这套依赖能覆盖文档加载、切分、向量化、存储、检索的完整流程。langchain 提供了很多现成的组件,但我建议你至少把每个环节的输入输出都打印出来看一遍,搞清楚数据是怎么流动的,不要当成黑盒用。
4.2 文档加载与切分的实操代码
先写文档加载。假设我有一批 PDF 和 Markdown 文档放在 data 目录下。
from langchain_community.document_loaders import PyPDFLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter import os def load_documents(data_dir): docs = [] for filename in os.listdir(data_dir): filepath = os.path.join(data_dir, filename) if filename.endswith('.pdf'): loader = PyPDFLoader(filepath) docs.extend(loader.load()) elif filename.endswith('.md') or filename.endswith('.txt'): loader = TextLoader(filepath, encoding='utf-8') docs.extend(loader.load()) return docs def split_documents(docs): splitter = RecursiveCharacterTextSplitter( chunk_size=800, chunk_overlap=120, separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] ) return splitter.split_documents(docs) docs = load_documents("./data") chunks = split_documents(docs) print(f"加载文档 {len(docs)} 份,切分后得到 {len(chunks)} 个块")这段代码里,chunk_size=800和chunk_overlap=120是我常用的默认值,重叠度正好 15%。separators列表的顺序很重要,切分器会优先用靠前的分隔符,也就是优先在段落边界断开,实在不行才在句子、字符级别断。中文文档一定要把中文标点加进去,否则切分器不认识中文句子边界,会切得很碎。
注意:切分完一定要抽几个块看看内容。我见过切分器把一句话从中间切断,或者把表格切得七零八落的情况。切分质量直接决定检索质量,这一步不能偷懒。
4.3 向量化与索引构建
切分完就该向量化了。我用 sentence-transformers 加载一个中文嵌入模型。
from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS embedding_model = HuggingFaceEmbeddings( model_name="BAAI/bge-base-zh-v1.5", model_kwargs={'device': 'cpu'}, encode_kwargs={'normalize_embeddings': True} ) vectorstore = FAISS.from_documents(chunks, embedding_model) vectorstore.save_local("./faiss_index") print("索引构建完成,已保存到本地")这里有个细节:normalize_embeddings=True。归一化之后,向量点积就等于余弦相似度,检索时计算更简单,结果也更稳定。BGE 系列的模型官方推荐开启归一化,我实测下来确实效果更好。
索引构建是一次性的离线操作,文档更新时才需要重建。生产环境里,我会把索引构建做成一个独立的流水线,支持增量更新——新文档进来只索引新的部分,不用全量重建。全量重建在数据量大时非常耗时,我处理过一批几十万块的文档,全量索引跑了好几个小时。
4.4 检索与重排的完整实现
索引建好了,来写检索。先做基础的向量检索,再加混合检索和重排。
def basic_retrieve(query, vectorstore, top_k=5): results = vectorstore.similarity_search_with_score(query, k=top_k) return results query = "报销申请需要哪些材料" results = basic_retrieve(query, vectorstore) for doc, score in results: print(f"分数: {score:.4f}") print(f"内容: {doc.page_content[:100]}...") print("---")基础检索跑通后,加上重排。重排模型我用一个交叉编码器。
from sentence_transformers import CrossEncoder reranker = CrossEncoder("BAAI/bge-reranker-base") def retrieve_with_rerank(query, vectorstore, recall_k=20, top_k=5): candidates = vectorstore.similarity_search(query, k=recall_k) pairs = [[query, doc.page_content] for doc in candidates] scores = reranker.predict(pairs) ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True) return ranked[:top_k]流程是:先用向量检索召回 20 个候选,再用重排模型打分,取前 5 个。重排模型比向量检索慢,但只处理 20 个候选,耗时可接受。这个"粗召回加精排序"的两阶段结构,是工业界 RAG 系统的标准做法。
4.5 把检索结果喂给模型生成答案
最后一步,把检索到的内容拼进提示词,让模型基于这些内容回答。
def generate_answer(query, retrieved_docs, llm_client): context = "\n\n".join([doc.page_content for doc, _ in retrieved_docs]) prompt = f"""基于以下资料回答问题。如果资料中没有相关信息,请明确说明不知道,不要编造。 资料: {context} 问题:{query} 回答:""" response = llm_client.chat(prompt) return response提示词里那句"如果资料中没有相关信息,请明确说明不知道"很关键。不加这句,模型倾向于硬答,哪怕资料里没有相关内容也会编一个。加了之后,模型在资料不足时会老实说不知道,这比编造一个错误答案要好得多。
到这里,一个最小可用的 RAG 管道就跑通了。从文档加载到答案生成,完整链路都覆盖了。你可以拿自己的文档试一下,看看效果。大概率第一版效果一般,这很正常,接下来就是调优的事。
5. 检索效果调优的实战经验
5.1 召回率上不去的排查思路
检索效果不好,先定位是召回的问题还是排序的问题。判断方法很简单:看正确答案在不在召回的前 20 个候选里。如果在,那是排序问题,重排能解决。如果不在,那是召回问题,得从切分、嵌入、查询改写入手。
召回率上不去,我一般按这个顺序排查。先看切分,块是不是太大或太小,关键信息有没有被切断。再看嵌入模型,是不是不适合你的领域,通用模型在专业领域往往表现一般。然后看查询,用户的问法和文档的表述差距大不大,需不需要改写。最后看检索策略,单用稠密是不是不够,要不要加稀疏做混合。
我遇到过一个典型案例:用户搜产品型号,怎么都搜不到。排查发现,稠密嵌入对型号这种专有名词表示不准,因为训练数据里没见过。加上稀疏检索后,型号精确匹配的问题立刻解决了。这就是混合检索的价值。
5.2 混合检索的权重怎么调
混合检索要把稠密和稀疏两路结果融合,融合方式有几种。最简单的是加权求和,给两路各一个权重。权重怎么定?没有标准答案,得根据你的数据特点调。关键词密集的场景,稀疏权重大一些;语义为主的场景,稠密权重大一些。
我用的是倒数排名融合,不直接比分数,而是比排名。每个文档在两路里的排名取倒数相加,得到最终分数。这种方式的优势是不用关心两路分数的量纲差异,鲁棒性更好。实测下来,倒数排名融合在多数场景下表现稳定,不用频繁调参。
| 融合方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 加权求和 | 简单直观 | 需调权重,量纲敏感 | 两路分数可比时 |
| 倒数排名融合 | 鲁棒,无需调参 | 丢失分数信息 | 通用场景 |
| 级联融合 | 精度高 | 实现复杂 | 对精度要求极高时 |
5.3 上下文窗口的分配技巧
检索回来的内容要塞进模型的上下文窗口,但窗口是有限的。塞太多,模型抓不住重点;塞太少,信息不全。我的做法是给检索内容留出窗口的 60% 到 70%,剩下的留给系统提示词、对话历史和模型输出。
如果检索回来的内容超过预算,就得做压缩。压缩有两种思路:一是抽取式,从每个块里挑最相关的句子;二是生成式,用模型把长块摘要成短块。抽取式快但可能不连贯,生成式连贯但慢且可能失真。我一般优先用抽取式,实在不行才上生成式。
还有个技巧是去重。召回的不同块之间可能有大量重复内容,尤其是重叠度设得大的时候。去重能省下不少窗口空间。简单的去重按文本相似度做,相似度超过阈值的只保留一个。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决方法 |
|---|---|---|---|
| 检索不到相关内容 | 切分不当或嵌入模型不匹配 | 检查块内容和嵌入模型 | 调整切分策略,换领域模型 |
| 检索到无关内容 | 块太大或相似度阈值低 | 检查块大小和召回数 | 减小块,提高阈值,加重排 |
| 答案不准确 | 上下文不足或提示词不当 | 检查召回内容和提示词 | 增加召回数,优化提示词 |
| 专有名词搜不到 | 稠密嵌入表示不准 | 测试稀疏检索 | 加混合检索 |
| 响应太慢 | 重排模型大或召回数多 | 检查各阶段耗时 | 减小召回数,换轻量重排 |
| 答案编造 | 提示词没约束 | 检查提示词 | 加"不知道就说不知道"约束 |
这张表是我踩坑踩出来的,基本覆盖了 RAG 管道最常见的几类问题。遇到问题先对号入座,能省不少排查时间。
6. 知识获取管道的进阶方向
6.1 从朴素 RAG 到 Agentic RAG
基础的 RAG 是单向的:查询进来,检索,生成,结束。但真实问题往往需要多轮交互。Agentic RAG 让 Agent 自己决定什么时候检索、检索什么、检索几轮。比如 Agent 可以先检索一次,发现信息不够,再调整查询检索第二次,直到收集到足够的信息才生成答案。
这种模式对管道的要求更高。管道要支持灵活的查询接口,要能返回结构化的检索结果,要能处理多轮检索的状态。我在做 Agentic RAG 时,会把检索做成一个工具,Agent 通过调用工具来检索,而不是把检索硬编码在流程里。这样 Agent 能自主决定检索策略。
6.2 知识图谱与 RAG 的结合
纯向量检索有个天然缺陷:它只能找到相似的文本块,但理解不了实体之间的关系。比如问"张三负责的项目有哪些",向量检索可能找到提到张三的块和提到项目的块,但拼不出完整的关系。知识图谱能补上这块。
GraphRAG 的思路是把文档里的实体和关系抽出来,建成图,检索时既查向量也查图。这样能回答需要多跳推理的问题。代价是构建图谱的成本高,抽取实体关系需要模型,图谱维护也复杂。我的建议是,关系密集型的问题才值得上图谱,普通问答用向量检索就够了。
6.3 本地知识库的部署考量
很多场景要求知识库本地部署,数据不出内网。这时候嵌入模型、向量库、生成模型都得本地化。嵌入模型用开源的小模型,向量库用本地部署的,生成模型用本地推理。整套下来对硬件有要求,尤其是生成模型,显存需求不小。
我的经验是,本地部署优先保证检索质量,生成模型可以适当妥协。因为检索是管道的地基,地基不稳上面全塌。嵌入模型选个领域适配的,向量库选个稳定的,生成模型用能跑起来的就行。等硬件升级了再换更好的生成模型。
6.4 评估与持续迭代
管道搭好不是终点,得持续评估和迭代。评估要有测试集,一批问题和对应的标准答案。每次改动管道,跑一遍测试集,看指标有没有提升。指标主要看召回率、准确率、答案相关性。
我一般会维护一个几十到上百条问题的测试集,覆盖不同类型的查询。每次调整切分、嵌入、检索策略,都跑一遍对比。没有测试集,调优就是盲调,改了半天不知道是变好还是变坏。这个习惯帮我避免了很多次"以为改好了实际改坏了"的情况。
7. 我在实际项目里踩过的坑
说几个具体的坑,都是真金白银换来的教训。第一个坑是切分块太大。早期我图省事,块设成 2000 字符,结果检索出来的块里一半是无关内容,模型被干扰得厉害。后来改成 800,效果立刻好转。块大小这个参数,值得多试几组。
第二个坑是忽略元数据过滤。有次用户搜一个已经下线的产品,检索还是把旧文档翻出来了,因为向量相似度高。后来加了元数据过滤,只查状态为有效的文档,问题解决。元数据不是可有可无的装饰,它是检索精度的重要保障。
第三个坑是重排模型选太大。我用过一个很大的重排模型,精度确实好,但每次检索要好几秒,用户体验很差。后来换了个轻量的,精度略降但速度快了一倍多,综合体验反而更好。模型不是越大越好,要看场景。
第四个坑是提示词没约束。早期提示词写得太宽松,模型经常在资料不足时硬答。加了"资料中没有就说不知道"的约束后,编造的情况大幅减少。提示词是 RAG 的最后一道防线,一定要把约束写清楚。
第五个坑是不做增量更新。有次文档更新了,我忘了重建索引,用户搜到的还是旧内容。后来把索引更新做成自动化的,文档一变就触发增量索引。这种工程细节不注意,会出大问题。
这些坑说到底都是同一个道理:RAG 是个系统工程,每个环节都要认真对待。没有哪个环节是可以随便糊弄的,管道的整体效果取决于最弱的那一环。把每个环节都做扎实,效果自然就上来了。