ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

TypeScript 构建 AI Agent 知识获取管道:RAG 从切分到检索的工程实践

TypeScript 构建 AI Agent 知识获取管道:RAG 从切分到检索的工程实践

1. 为什么知识获取管道是 AI Agent 从玩具走向工具的分水岭

做 AI Agent 开发的人,大概都经历过这样一个阶段:Demo 跑得飞起,一旦接入真实业务数据就开始胡言乱语。你问它公司内部的报销标准,它给你编一个看起来很像那么回事的数字;你让它查某个产品的技术参数,它把两个型号的参数混在一起说得头头是道。这不是模型不够聪明,而是它压根不知道你的数据长什么样。

知识获取管道要解决的就是这个问题。它的核心任务只有一句话:在 Agent 需要做决策或生成回答之前,把正确、相关、最新的知识送到模型面前。听起来简单,但真正落地时会发现,从数据源接入、文档切分、向量化、索引构建到检索排序,每一步都有大量需要做决策的地方,而这些决策直接决定了最终回答的质量。

RAG(检索增强生成)是目前构建知识获取管道最主流的技术路线。它的基本思路不复杂:把知识库里的文档转成向量存起来,用户提问时把问题也转成向量,然后找最相似的文档片段,连同问题一起塞给大模型生成回答。但"基本思路不复杂"和"工程上能跑通"之间,隔着一条很宽的河。

这篇文章面向的是正在用 TypeScript 构建 AI Agent、准备给 Agent 接入知识库的开发者。我会从零开始拆解 RAG 管道的每个环节,重点讲清楚每个环节为什么这样设计、有哪些容易踩的坑、以及在 TypeScript 技术栈下怎么落地。文章不会只给你一个"Hello World"级别的示例,而是会覆盖从文档处理到检索优化的完整链路,让你看完之后能直接在自己的项目里复现。

提示:本文假设你已经对 AI Agent 的基本概念有了解,知道什么是工具调用、什么是 Agent 循环。如果你还没接触过 Agent 开发,建议先补一下基础概念再来看这篇。

2. RAG 管道的四个核心环节与数据流转逻辑

2.1 从原始文档到可检索知识块的完整链路

一条完整的 RAG 管道,数据要经过四次形态变化。理解这四次变化,比记住任何代码都重要。

第一次变化发生在数据接入层。你的知识可能来自 Markdown 文件、PDF、数据库表、API 返回的 JSON,甚至是网页抓取的内容。这一层的任务是把这些异构数据统一成纯文本加元数据的格式。元数据包括来源、标题、创建时间、所属分类等,这些信息在后续检索和过滤时会派上大用场。

第二次变化发生在切分层。原始文档往往很长,直接整篇向量化会导致检索粒度太粗。你需要把文档切成大小合适的块(chunk),每个块独立向量化。切分策略直接决定了检索的精度和召回率,这是整个管道里最容易被低估的环节。

第三次变化发生在向量化层。每个文本块通过嵌入模型转换成一个高维向量,这个向量捕捉了文本的语义信息。向量化之后,文本块和它的向量、元数据一起存入向量数据库。

第四次变化发生在检索层。用户提问时,问题被同样的嵌入模型转成向量,然后在向量数据库中查找最相似的若干个块。这些块经过排序和过滤后,作为上下文注入到提示词中。

这四次变化对应四个核心环节:接入、切分、向量化、检索。每个环节都有独立的优化空间,而且上游环节的问题会向下游传导。比如切分粒度太粗,检索时就会召回大量无关内容;元数据没保留好,检索时就没法做过滤。

2.2 为什么不能把整篇文档直接塞给模型

有人可能会想:现在大模型的上下文窗口都很大了,直接把整个知识库塞进去不就行了,何必搞这么复杂?

这个想法在两种情况下会碰壁。第一种是知识库规模稍大一点,比如几百篇文档,总 token 数轻松超过百万,即使上下文窗口够大,推理成本和延迟也会高到无法接受。第二种是知识库更新频繁,每次更新都要重新构造完整的上下文,这在工程上不可行。

更重要的是,即使上下文窗口装得下,模型对长上下文的注意力也是不均匀的。大量实验表明,当上下文中包含大量无关信息时,模型对关键信息的提取能力会显著下降。RAG 的价值不仅在于节省 token,更在于把模型的注意力聚焦在真正相关的信息上。

2.3 TypeScript 技术栈下的模块划分

在 TypeScript 项目里,我习惯把 RAG 管道拆成四个独立的模块,每个模块有清晰的输入输出接口:

  • Loader 模块:负责从各种数据源读取原始内容,输出统一的Document对象数组,每个对象包含content和metadata。
  • Splitter 模块:接收Document数组,输出Chunk数组,每个 chunk 包含切分后的文本和继承自父文档的元数据。
  • Embedder 模块:接收文本数组,输出向量数组。这个模块要处理批量请求、重试、速率限制等问题。
  • Retriever 模块:接收查询文本,输出排序后的相关 chunk 数组。内部可能包含向量检索、关键词检索、重排序等多个子步骤。

这种模块化设计的好处是每个环节都可以独立替换和测试。比如你想从 OpenAI 的嵌入模型换成开源的 BGE 模型,只需要改 Embedder 模块的实现,其他部分不受影响。

3. 文档切分:RAG 管道里最容易被做坏的一步

3.1 固定长度切分的三个致命问题

大多数 RAG 教程教你的第一种切分方式是固定长度切分:每 500 个字符切一刀,或者每 200 个 token 切一刀。这种方式实现简单,但在真实场景下会带来三个严重问题。

第一个问题是语义断裂。一个完整的论述可能被从中间切开,前半段在一个 chunk 里,后半段在另一个 chunk 里。检索时如果只召回了前半段,模型看到的就是一个不完整的论述,很容易产生误解。

第二个问题是噪声引入。固定长度切分不考虑文档的自然结构,可能把标题和正文切在一起,也可能把两个不相关的段落切在同一个 chunk 里。这些噪声会稀释 chunk 的语义信号,降低检索精度。

第三个问题是元数据丢失。固定长度切分通常只保留最基础的元数据,比如来源文件。但文档内部的层级信息,比如这段文字属于哪个章节、哪个小节,往往在切分时就丢掉了。这些层级信息在检索时其实很有价值,可以用来做上下文扩展或结果过滤。

3.2 递归字符切分的实现与参数调优

递归字符切分是目前最实用的通用切分策略。它的思路是:先尝试用最大的分隔符切分,如果切出来的块还是太大,就用更小的分隔符继续切,直到所有块都在目标大小以内。

在 TypeScript 里,你可以用 LangChain.js 的RecursiveCharacterTextSplitter,也可以自己实现。核心逻辑是维护一个分隔符优先级列表,比如["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],从高优先级到低优先级依次尝试。

参数调优方面,有几个经验值可以参考。chunkSize设置在 500 到 1000 个字符之间比较合适,具体取决于你的文档类型和嵌入模型。技术文档可以小一点,因为概念密度高;叙述性文档可以大一点,因为需要更多上下文才能理解。chunkOverlap设置在chunkSize的 10% 到 20% 之间,目的是保证被切断的语义在相邻 chunk 中有重叠,减少信息丢失。

但递归字符切分也不是万能的。它对格式规整的文档效果好,对格式混乱的文档效果一般。如果你的文档有明确的 Markdown 标题层级,更好的做法是按标题切分,把每个小节作为一个独立的 chunk,同时把标题路径作为元数据保留下来。

3.3 按文档结构切分:Markdown 标题与代码块的处理

对于 Markdown 文档,我强烈建议按标题层级切分。具体做法是解析 Markdown 的 AST,找到所有标题节点,然后以标题为边界切分内容。每个 chunk 的元数据里记录完整的标题路径,比如["第三章", "3.2 节", "3.2.1 小节"]。

这样做的好处是检索时可以利用标题路径做过滤。比如用户问的是"第三章里的某个概念",你可以只在前三章的 chunk 里检索,大幅缩小搜索范围。另外,标题路径本身也是很好的语义信号,可以在向量化时把标题拼接到 chunk 内容前面,增强语义表达。

代码块的处理需要特别小心。代码块不能被从中间切断,否则检索出来的代码片段无法运行。在切分时要把代码块视为原子单元,如果代码块本身超过了chunkSize,要么单独成块,要么按函数或类切分。同时,代码块的元数据里要标注语言类型,方便后续做语法高亮或过滤。

3.4 切分质量的验证方法

切分做完之后,怎么知道切得好不好?我常用的方法是抽样检查加检索测试。

抽样检查就是随机抽取 20 到 30 个 chunk,人工看一遍,检查有没有语义断裂、有没有噪声混入、元数据是否完整。这个步骤很枯燥,但能发现很多自动化指标发现不了的问题。

检索测试是构造一批查询,看检索结果是否合理。具体做法是准备 10 到 20 个问题,每个问题你心里有一个标准答案所在的文档位置,然后看检索器返回的 top-5 结果里有没有包含这个位置。这个指标叫 hit rate,是衡量 RAG 管道质量最直接的指标之一。

注意:切分策略没有绝对的最优解,只有最适合你数据特征的解。不要迷信任何教程里的固定参数,一定要用自己的数据做验证。

4. 向量化与索引构建:选型、批处理与成本控制

4.1 嵌入模型选型的四个考量维度

选嵌入模型不能只看排行榜上的分数,要结合你的实际场景综合考虑四个维度。

语言支持是第一个维度。如果你的知识库主要是中文,就要选中文语义理解能力强的模型。很多在英文榜单上排名很高的模型,中文表现其实一般。目前中文场景下表现比较稳定的有 BGE 系列、M3E 系列,以及一些商业 API 提供的中文优化版本。

维度与存储成本是第二个维度。嵌入向量的维度从 384 到 3072 不等,维度越高,向量数据库的存储和检索成本越高。对于大多数场景,768 到 1024 维已经足够,没必要追求最高维度。

推理方式是第三个维度。商业 API 调用简单,但按 token 计费,数据量大的时候成本可观,而且有网络延迟和速率限制。本地部署的模型一次性投入算力,后续边际成本低,但需要自己处理模型加载、批处理、GPU 显存管理等问题。

领域适配是第四个维度。通用嵌入模型在通用语料上表现好,但在法律、医疗、金融等专业领域可能不够精准。如果预算允许,可以用领域数据对模型做微调,或者选择在相关领域预训练过的模型。

4.2 批量向量化的并发控制与错误重试

向量化是一个 I/O 密集型操作,尤其是调用远程 API 时。如果不做并发控制,要么串行执行慢得让人抓狂,要么并发太高被限流。

我的做法是用一个带并发上限的任务队列。在 TypeScript 里可以用p-limit这个库,设置并发数为 5 到 10,具体取决于 API 的速率限制。每个批次处理 100 到 500 个文本块,批次太大容易超时,批次太小则请求次数过多。

错误重试是必须的。网络抖动、API 临时不可用、速率限制触发,这些都会导致请求失败。重试策略建议用指数退避,第一次失败等 1 秒,第二次等 2 秒,第三次等 4 秒,最多重试 3 到 5 次。如果连续失败,就把这批数据记录下来,等全部处理完之后再单独重试。

还有一个容易被忽略的点是幂等性。如果你的向量化任务中途失败需要重跑,要确保已经处理过的数据不会被重复处理。做法是在向量数据库里用文档 ID 加 chunk 索引作为唯一键,插入时做 upsert 而不是 insert。

4.3 向量数据库的选型对比与本地开发方案

向量数据库的选型要考虑数据规模、查询延迟、过滤能力、运维成本等因素。下面是我用过的几种方案对比:

方案适用规模过滤能力运维成本典型场景
内存向量库万级以下弱极低本地开发、Demo
SQLite 扩展十万级中等低单机应用、小团队
专用向量数据库百万到十亿级强中等生产环境、中大型项目
云托管服务弹性强低快速上线、不想运维

本地开发阶段,我建议用内存向量库或者 SQLite 扩展,启动快、零配置、方便调试。等数据量和查询量上来了,再迁移到专用向量数据库。迁移时要注意不同数据库的相似度计算方式可能不同,余弦相似度和内积相似度的结果会有差异,需要重新校准阈值。

4.4 索引更新策略:全量重建还是增量更新

知识库不是一成不变的,新文档会加入,旧文档会修改或删除。索引更新策略直接影响系统的可用性和数据一致性。

全量重建最简单,把所有文档重新切分、向量化、写入。缺点是耗时耗资源,数据量大时可能几小时都跑不完,而且重建期间检索服务不可用。

增量更新只处理变化的文档。做法是给每个文档记录内容哈希,定期扫描数据源,只对哈希变化的文档重新处理。删除文档时,根据文档 ID 删除对应的所有 chunk。这种方式效率高,但实现复杂度也高,需要处理好文档版本管理和并发写入的问题。

我的建议是:数据量小、更新频率低时用全量重建,简单可靠;数据量大、更新频繁时用增量更新,但要做好监控和回滚机制。

5. 检索策略:从向量相似度到混合检索的演进

5.1 纯向量检索的语义漂移问题

纯向量检索的核心假设是:语义相似的文本在向量空间里距离近。这个假设在大多数情况下成立,但有两种情况会失效。

第一种是专有名词和缩写。比如你问"ABC 协议的端口号是多少",向量检索可能召回一堆讲其他协议的内容,因为"ABC"这个词在嵌入模型训练语料里可能很少出现,模型无法准确捕捉它的语义。但关键词检索可以精确匹配"ABC",直接找到包含这个词的文档。

第二种是否定和条件查询。比如你问"哪些型号不支持蓝牙",向量检索可能召回一堆讲支持蓝牙的型号,因为"蓝牙"这个词的语义权重很高,而"不支持"这个否定语义在向量空间里很难表达。

这两种情况说明,纯向量检索在精确匹配和逻辑运算方面有天然短板。实际生产系统里,纯向量检索的 hit rate 往往在 60% 到 80% 之间,剩下的 20% 到 40% 就是这些短板造成的。

5.2 关键词检索与向量检索的互补逻辑

关键词检索(比如 BM25 算法)基于词频和逆文档频率计算相关性,擅长精确匹配和稀有词查询。它的短板是无法理解同义词和语义相似性,你搜"电脑"它不会返回"计算机"的文档。

向量检索和关键词检索的优缺点是互补的。向量检索擅长语义匹配,关键词检索擅长精确匹配。把两者的结果融合起来,可以显著提升召回率。这就是混合检索的基本思路。

融合的方法有几种。最简单的是加权求和,给向量检索和关键词检索的分数各分配一个权重,比如 0.7 和 0.3,然后按加权分数排序。更精细的做法是 Reciprocal Rank Fusion(RRF),它不依赖原始分数,只依赖排名,对不同检索器的分数尺度不敏感,鲁棒性更好。

5.3 重排序模型在管道中的位置与价值

混合检索解决了召回问题,但召回的结果里仍然可能有很多不相关的。重排序(Rerank)的作用是对召回结果做精细排序,把最相关的排到最前面。

重排序模型通常是交叉编码器(Cross-Encoder),它把查询和文档拼接在一起输入模型,直接输出相关性分数。这种方式比向量检索的双编码器(Bi-Encoder)精度高很多,但计算量大,无法对全量文档做检索,只能对召回结果做重排。

在管道里的位置是:向量检索和关键词检索各召回 top-20,合并去重后得到 30 到 40 个候选,然后用重排序模型对这 30 到 40 个候选打分,取 top-5 作为最终上下文。这个流程在实测中能把 hit rate 从 70% 左右提升到 90% 以上。

重排序模型的选型要考虑语言支持和推理速度。中文场景下,BGE-Reranker 系列是比较稳妥的选择。推理速度方面,如果候选集是 30 到 40 个,用 GPU 推理延迟通常在 100 毫秒以内,可以接受。

5.4 元数据过滤与查询改写

元数据过滤是在检索前缩小搜索范围的手段。比如用户问的是"2024 年的销售政策",你可以在检索时加上时间过滤条件,只搜 2024 年之后的文档。这能大幅减少无关结果,提升检索精度。

查询改写是在检索前优化查询文本的手段。用户的原始提问可能很口语化,或者包含指代和省略。查询改写可以把"那个东西怎么用来着"改写成"XX 功能的使用方法",让检索更精准。

查询改写的实现方式有几种。最简单的是用大模型做改写,把用户问题连同对话历史一起发给模型,让它输出一个更适合检索的查询。更复杂的方式是生成多个查询变体,分别检索后合并结果,这叫多查询检索(Multi-Query Retrieval)。

提示:元数据过滤和查询改写都是"锦上添花"的优化,不要一开始就上。先把基础的切分、向量化、混合检索跑通,有了 baseline 之后再逐步加这些优化,才能准确衡量每个优化的收益。

6. 把管道串起来:TypeScript 实现中的工程细节

6.1 管道编排与错误传播

把四个模块串起来的时候,错误处理是最容易出问题的地方。一个常见的错误是:向量化阶段某个批次失败了,但管道没有正确传播这个错误,导致后续检索时发现数据不完整,但不知道哪里出了问题。

我的做法是给每个阶段定义明确的错误类型,并且在管道入口处做统一的错误收集。比如LoadError、SplitError、EmbedError、RetrieveError,每个错误携带上下文信息,比如失败的文档 ID、批次索引、原始错误信息。管道执行时,如果某个阶段出错,记录错误但继续处理其他数据,最后汇总报告。

这样做的好处是,一次执行可以处理尽可能多的数据,而不是遇到第一个错误就中断。对于批量处理场景,这能大幅提升效率。

6.2 缓存策略:嵌入缓存与检索缓存

嵌入计算是 RAG 管道里最耗时的环节之一。如果同一段文本被多次向量化,就是纯粹的浪费。加一层嵌入缓存可以显著提速。

缓存的键可以用文本内容的哈希,值是对应的向量。缓存可以放在内存里,也可以持久化到磁盘或 Redis。内存缓存适合开发阶段,持久化缓存适合生产环境,因为服务重启后缓存不会丢失。

检索缓存是另一层优化。如果两个用户问了相似的问题,检索结果可能高度重叠。缓存查询向量到检索结果的映射,可以避免重复的向量检索和重排序计算。但检索缓存的失效策略要设计好,知识库更新后要及时清理相关缓存。

6.3 可观测性:日志、指标与追踪

RAG 管道上线之后,你需要知道它运行得好不好。可观测性包括三个层面:日志、指标、追踪。

日志记录每个阶段的输入输出摘要,比如加载了多少文档、切分了多少 chunk、向量化了多少文本、检索返回了多少结果。日志级别要可配置,开发时用 debug 级别看细节,生产时用 info 级别看概况。

指标是聚合后的量化数据,比如平均切分耗时、向量化成功率、检索平均延迟、hit rate 等。这些指标可以接入监控系统,设置告警阈值。

追踪是记录单个请求的完整链路,从用户提问到最终回答,每个阶段的耗时和中间结果都记录下来。这对于排查"为什么这个问题的回答质量差"这类问题非常有用。

6.4 一个可复用的管道类设计

基于上面的讨论,我通常会设计一个RAGPipeline类,把四个模块组合起来,对外暴露ingest和query两个方法。

ingest方法接收数据源配置,依次执行加载、切分、向量化、索引写入,返回处理报告。query方法接收查询文本和可选的过滤条件,执行查询改写、混合检索、重排序,返回最终的上下文块数组。

这个类的构造函数接收四个模块的实例,支持依赖注入。这样在测试时可以用 mock 模块替换真实模块,在生产时可以用真实模块。模块之间的接口要定义清楚,用 TypeScript 的 interface 来约束,保证替换实现时不会破坏管道。

7. 实测中遇到的五个典型问题与排查思路

7.1 检索结果总是差一点:从切分粒度开始排查

检索结果不理想时,我的排查顺序是:先看切分,再看嵌入,最后看检索策略。

切分问题的典型表现是:检索到的 chunk 内容不完整,或者包含大量无关内容。排查方法是把检索到的 chunk 打印出来,人工看一遍。如果 chunk 明显被切断,就调整chunkSize和chunkOverlap。如果 chunk 里混入了标题、页眉、页脚等噪声,就在切分前做数据清洗。

嵌入问题的典型表现是:语义相似的查询和文档,向量距离却很远。排查方法是构造几个已知相关的查询-文档对,计算它们的向量相似度,看是否在合理范围内。如果相似度普遍偏低,可能是嵌入模型不适合你的语言或领域,需要换模型。

检索策略问题的典型表现是:相关文档在候选集里,但排名很靠后。排查方法是看召回结果和重排序结果的对比,如果召回里有但重排后没了,说明重排序模型有问题;如果召回里就没有,说明召回策略需要调整。

7.2 向量化成本失控:批量大小与模型选择的权衡

向量化成本主要来自 API 调用费用或 GPU 算力消耗。控制成本的手段有几个。

批量大小要合理。批量太小,请求次数多,每次请求的固定开销占比高;批量太大,单次请求 token 数多,可能触发 API 的最大 token 限制。我的经验是每批 100 到 200 个文本块,每个块 500 到 1000 字符,这样单次请求的 token 数在 5 万到 20 万之间,大多数 API 都能接受。

模型选择要匹配场景。如果只是做语义搜索,中等维度的模型就够了,没必要用最高维度的。如果预算紧张,可以考虑本地部署开源模型,一次性投入 GPU 算力,后续边际成本几乎为零。

缓存要充分利用。开发阶段反复调试时,嵌入缓存能省下大量重复计算。生产环境如果知识库更新不频繁,缓存命中率会很高。

7.3 中文分词的坑:嵌入模型与关键词检索的配合

中文没有天然的空格分隔,关键词检索需要先分词。分词的粒度直接影响 BM25 的效果。分得太细,单个字或词的信息量不足;分得太粗,匹配精度下降。

我常用的中文分词方案是 jieba 或者 nodejieba,支持自定义词典。对于专业领域的术语,要把它们加入自定义词典,避免被切碎。比如"检索增强生成"如果不加词典,可能被切成"检索""增强""生成"三个词,匹配时就会丢失这个术语的整体语义。

嵌入模型方面,中文场景要选在中文语料上训练过的模型。有些模型虽然支持多语言,但中文表现明显弱于英文。选型时要用中文数据做实际测试,不要只看模型卡上的多语言支持声明。

7.4 检索延迟优化:从索引结构到缓存层级

检索延迟直接影响用户体验。优化手段从底层到上层依次是:索引结构、检索算法、缓存。

索引结构方面,向量数据库通常支持多种索引类型,比如扁平索引、IVF 索引、HNSW 索引。扁平索引精度最高但速度最慢,HNSW 索引速度快但精度略有损失。数据量小时用扁平索引,数据量大时用 HNSW。

检索算法方面,混合检索的两路召回可以并行执行,用Promise.all同时发起向量检索和关键词检索,总延迟取决于较慢的那一路,而不是两路之和。

缓存方面,查询向量缓存和检索结果缓存都能显著降低延迟。对于高频查询,缓存命中时延迟可以降到毫秒级。

7.5 知识库更新后的检索不一致

知识库更新后,有时会出现新旧数据混在一起、检索结果不一致的问题。这通常是索引更新策略的问题。

如果是全量重建,要确保重建期间检索服务要么暂停,要么指向旧索引,重建完成后再切换。切换时要用原子操作,避免部分请求走新索引、部分走旧索引。

如果是增量更新,要处理好文档的增删改。新增文档直接插入,修改文档先删旧 chunk 再插新 chunk,删除文档根据 ID 删除所有相关 chunk。这些操作要保证原子性,避免出现"旧 chunk 已删、新 chunk 未插"的中间状态。

还有一个容易忽略的点是嵌入模型的版本一致性。如果更新时换了嵌入模型,新旧向量就不在同一个向量空间里,相似度计算会完全失效。换模型时必须全量重建索引,不能增量更新。

8. 从基础 RAG 到 Agentic RAG 的演进方向

基础 RAG 管道跑通之后,下一步的优化方向是让检索变得更智能、更自适应。这就是 Agentic RAG 的思路:把检索本身也交给 Agent 来决策。

具体来说,Agentic RAG 会让 Agent 根据问题类型决定检索策略。简单的事实性问题走单次检索,复杂的多跳问题走迭代检索,需要对比的问题走多路检索。Agent 还可以判断检索结果是否足够,如果不够就改写查询再检索一轮。

另一个方向是 GraphRAG,把知识库构建成图结构,实体和关系作为节点和边。检索时不仅找相似的文本块,还沿着图结构扩展相关实体,能回答需要多跳推理的问题。GraphRAG 的构建成本比基础 RAG 高很多,适合知识密度高、关系复杂的场景。

还有一个方向是自适应切分,根据文档内容动态决定切分粒度。技术文档切细一点,叙述文档切粗一点,代码块单独处理。这需要在切分前对文档做分类,实现复杂度较高,但效果提升明显。

这些进阶方向都建立在基础 RAG 管道之上。基础管道没跑通,直接上这些高级方案只会让问题更难排查。我的建议是先把本文讲的四个环节做扎实,有了稳定的 baseline 和可观测性之后,再逐步引入更复杂的策略。

我在实际项目里的体会是,RAG 管道的质量提升不是线性的,而是阶梯式的。每解决一个瓶颈,效果会明显提升一截,然后进入平台期,直到找到下一个瓶颈。切分、嵌入、检索、重排序,每个环节都可能是瓶颈,排查时要有耐心,用数据说话,不要凭感觉调参。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进