RAG 并没有你想象的那么复杂
摘要
文章探讨了六种 RAG 架构,并建议根据数据新鲜度、查询模式和规模等因素选择合适的方法,以避免过度工程化。
暂无内容
查看缓存全文
缓存时间: 2026/08/26 12:12
# 六种RAG架构——以及如何避免过度工程化
来源:https://www.lighthousenewsletter.com/p/rag-is-simpler-than-you-think

如今,大多数人似乎都在过度工程化他们的RAG技术栈。他们直接跳向嵌入向量、向量数据库和重排序管道。与此同时,他们的用户其实只想找到那个写着*“如何重置我的密码”*的文档。
在工程领域,始终是“合适的工具解决合适的问题”。在AI检索系统中也是如此。
在深入具体方案之前,我们先来明确何时应该使用哪种方法。关键因素是:
**1. 数据时效性要求**——实时更新(新闻、社交媒体)适合易于重建索引的方法。每日或每周更新适合混合方法。稳定的语料库(每月或季度更新)则预嵌入是合理的。
**2. 语料库特征**——高变动率(每日变化超过10%)意味着应避免完全预嵌入。稳定文档适合预嵌入。长尾分布(90%从未被访问)则意味着按需计算更优。
**3. 查询模式**——关键词密集的查询应首先考虑全文搜索。语义或对话式查询受益于嵌入向量。混合模式则需要混合方法。
**4. 规模与性能**——每日查询量少于1000次,简单方法即可满足。每日1K到10K次查询需要选择性优化。超过10K次查询则值得进行全面优化。
**5. 团队能力**——没有机器学习专业知识,应坚持使用全文搜索加查询重写。有一些机器学习经验,混合搜索可以管理。拥有机器学习团队,更高级的方法才可行。
现在,让我们来看看方案手册。从顶部开始。只有当有数据证明需要时,才向下移动。
经典的BM25算法。Elasticsearch。Postgres全文搜索。这是*“嵌入向量”*成为动词之前就存在的东西。
你刚刚起步。用户使用关键词式查询*(“pandas 合并 dataframe”)*。精确匹配很重要*(“发票 #12345”)*。你希望没有机器学习的复杂性。你的语料库包含专有术语*(稍后详述)*。
零API成本。快速(低于10毫秒)。易于调试(你能精确看到文档为何匹配)。出奇地有效(处理许多用例)。**无需分块策略**——直接处理完整文档。**无评估复杂性**——易于测试和验证。无模型过时风险(BM25算法不会改变)。
会错过同义词(“car” vs “automobile”)。在语义查询(“我应该如何...?”)上失败。无法理解关键词之外的意图。
根据我的经验,这能处理相当大一部分用例。不要跳过这一步。你可能会惊讶于它能走多远。
当你直接跳向嵌入向量时,你立即面临这些问题:分块大小?(512个token?1024?)重叠多少?(50个token?100?)语义分块还是固定大小分块?我如何评估我的分块策略是否良好?
使用全文搜索,你可以跳过所有这些。你的文档就是你的文档。搜索直接有效。
使用大型语言模型将杂乱的用户查询转换为干净的关键词搜索。
大多数“语义搜索”问题实际上是*查询表述*问题。

用户以对话方式提问。词汇不匹配(用户说“修复bug”,文档说“调试”)。你有内部术语(你的框架称为“Atlas”)。你希望能够快速迭代查询策略。
每次查询成本*约$0.001*(使用GPT-4o-mini进行查询重写)
大型语言模型可以移除停用词(“我如何”变成无意义词)。它可以添加同义词(“car”变成“car automobile vehicle”)。它可以翻译领域术语(“加速代码”变成“优化性能”)。它可以分解复杂查询(“读取CSV并绘图”分解为[“读取CSV”, “绘图数据”])。它能从你的术语表学习(通过系统提示)。
使用嵌入向量时,如果结果不佳,你需要调整分块策略,重新嵌入整个语料库,在你的评估集上运行回归测试,并祈祷它有所改善。
使用查询重写时,如果结果不佳,你只需调整系统提示。仅此而已。可以立即测试。
更好的是,你可以创建一个循环:
代理可以迭代、学习和适应——所有这些都无需重新嵌入任何内容。
假设你的公司有一个名为“Atlas”的Python框架。如果你使用通用嵌入向量:
```
通用嵌入模型(在互联网上训练):
“Atlas” = [指向:希腊神话、地图、地理的向量]
你的实际Atlas文档 = [关于数据处理的向量]
相似度得分:0.15(非常差!)
```
模型完全不知道你的“*Atlas*”存在。它只能退回到训练时学到的知识。但使用查询重写:
对于专有术语,精确的关键词匹配胜过语义理解。
使用BM25获取候选结果(前50-100个),然后用嵌入向量进行重排序(取前10个)。
BM25速度快,擅长关键词匹配。嵌入向量擅长语义理解。两者结合,可以互相弥补不足。
用户提出语义问题(“*寻找X的替代方案*”)。单独的BM25加查询重写效果不佳(你有数据证明这一点)。你可以容忍100-500毫秒的延迟。你的语料库相对稳定(不是每分钟都在变化)。

让我们按当前定价(OpenAI text-embedding-3-small,每100万token $0.02)算笔账:
- 每次查询嵌入50个文档(平均每个500 token)意味着 50文档 × 500 token = 25,000 token
- 成本:25,000 × $0.00002 = 每次查询约$0.0005。按每天1,000次查询 × 30天计算 = 每月约$15。
实际上相当合理。但这里有个关键:**延迟**。
实时嵌入50个文档会为每次查询增加200-500毫秒的延迟。对于面向用户的搜索,这是可察觉的。这才是真正的权衡所在——不是成本,而是速度。
当你引入嵌入向量时,你需要决定如何分块文档(固定大小?语义?按章节?)。你需要确定使用多大的分块大小和重叠。你需要处理跨越重要上下文的分块。
这增加了纯全文搜索可以避免的复杂性。
如果你的数据变化频繁,为什么还要花钱重新嵌入所有内容?

**高文档变动率**(每日超过10%的文档更新)。**实时内容**(新闻、社交媒体、实时更新)。你正在**尝试不同的嵌入模型**(无需重新索引)。**数据时效性至关重要**(文档必须是最新的)。较小的K值用于重排序(20-50个文档)。
```
按需/在线(每天1000次查询,每次50个文档):
- 嵌入成本:约$15/月(持续支出)
- 存储:$0(仅存储文本)
- 延迟:每次查询200-500毫秒
- 时效性:完美(始终最新)
- 模型切换:简单(只需更改API调用)
```
有一点人们很少提及:**嵌入模型会被弃用**。
OpenAI弃用了text-embedding-ada-002,转而支持text-embedding-3。如果你用旧模型预嵌入了1000万个文档,现在你需要用新模型重新嵌入所有1000万个文档,更新你的向量数据库,在你的评估集上运行回归测试,验证质量没有下降,处理过渡期,并应对任何API变更。
你只需更改一行代码。搞定。
延迟。你每次查询都在嵌入文档。只有当你能接受200-500毫秒的延迟,K值较小(重排序20-50个文档,而不是500个),并且你的用例更看重时效性而非速度时,这种方法才可行。
预嵌入经常访问的文档(“热层”),按需嵌入很少访问的文档(“冷层”)。
访问模式遵循帕累托分布。20%的文档获得80%的流量。
明确的访问模式(某些文档被访问的频率远高于其他)。中到大型语料库(超过100K个文档)。稳定和变化内容的混合。常见查询需要良好的延迟。希望在模型更新时最小化重新嵌入量。
80%的查询速度快(命中预嵌入缓存)。很少访问的文档保持新鲜。仅在切换模型时重新嵌入热层(占语料库的20%)。适应变化的访问模式。最佳的延迟/成本/灵活性权衡。
当你的嵌入模型被弃用时:
```
完全预嵌入:重新嵌入100万文档 × $0.01 = $10,000 + 停机时间
热/冷层:重新嵌入20万文档 × $0.01 = $2,000 + 最小停机时间
按需嵌入:更改一行代码 = $0 + 零停机时间
```
预先嵌入所有内容。存储在向量数据库中。使用ANN(近似最近邻)搜索。
极高的查询量(每日超过10K次查询)。需要低于50毫秒的延迟。**非常稳定的语料库**(每月变动低于5%)。访问模式广泛(无长尾)。你有机器学习团队管理基础设施。
```
预嵌入(100万文档):
- 一次性嵌入:100万文档 × 500 token × $0.00002 = $10
- 存储:100万 × 1536维 × 4字节 = 6GB(约$10-30/月)
- 搜索延迟:低于50毫秒(极快!)
- 时效性:仅与上次重建索引一样新
```
文档变化频繁(每周超过10%)。你正在尝试不同的嵌入模型。低查询量(每日低于1K次查询)。你没有先尝试更简单的方法。
这就是完全预嵌入最痛苦的地方。当你需要切换模型时,你会面临**停机时间**(重新嵌入时搜索性能下降)、**计算成本**(重新嵌入数百万文档)、**测试负担**(对新嵌入运行全套回归测试)、**分块重新评估**(也许新模型在不同分块大小下表现更好?),以及**风险**(如果新模型对你的领域效果更差怎么办?)。
> *对于大多数系统来说,这是过度设计。我见过团队花数月优化他们的向量数据库设置,而查询重写本可以解决他们90%的问题。*
但如果你是Pinterest、Shopify,或者处理大规模稳定语料库,这就是你最终需要做的。
接下来是精彩部分。我们一直在讨论单一意图的查询:*“我如何合并dataframe?”*
但真正的用户会问这样的问题:**“我如何读取CSV文件、清理缺失数据并绘制结果?”**
这是三个独立的意图。将此作为单一查询来搜索,就像试图找到一家同时供应披萨、寿司和墨西哥卷饼的餐厅。祝你好运。
现代智能体RAG系统(Perplexity, ChatGPT搜索)优雅地处理这个问题:
1. 分解查询。
2. 最优路由每个子查询
3. 将结果组合成连贯的答案
每个子查询都聚焦且精确,从而带来更好的检索结果。并行执行意味着更低的延迟(最大值,而非总和)。自适应路由导致更低的成本(只有复杂查询才需要为LLM付费)。结构化输出提供更好的用户体验。
**不分解**
- LLM重写整个复杂查询:$0.005
- 嵌入50个文档:$0.025
- 总计:$0.03
**分解后**
- 分解:$0.001
- 子查询1(简单):$0
- 子查询2(简单):$0
- 子查询3(复杂):$0.001
- 总计:$0.002
便宜15倍,质量更好。
这正是智能体检索真正闪光的地方。代理可以智能地决定哪些子查询需要昂贵处理(嵌入),哪些可以用廉价方法处理(简单预处理 + BM25)。
好了,你读到这里了。你只是想知道:“我应该构建什么?”
**从这里开始:你是否有任何搜索功能?**如果没有,先构建BM25。说真的。停止阅读并去构建它。如果你已经有搜索功能,继续。
**衡量你的基线。**运行你当前的搜索2-4周,收集用户反馈。用户对结果满意吗?如果是,停止。你已经完成了。去发布功能吧。如果否,继续。
**主要的抱怨是什么?**
如果用户说“找不到明显存在的文档”,首先尝试查询重写。每次查询$0.001,无需重新索引,值得一试。运行2周的A/B测试。如果你看到明显改善,保留它,你就完成了。如果不够,继续。
如果用户说“结果还行但不算好”,对混合搜索(稀疏检索加嵌入重排序)进行A/B测试。增加的延迟值得吗?如果是,决定如何实现。如果你的数据变化频繁,使用按需嵌入。如果你有明显的热门文档,使用热/冷层。如果你有稳定的语料库和高规模,使用完全预嵌入。如果延迟不值得,那就进一步优化查询重写。
如果用户说“需要更好的语义理解”,使用混合搜索,并根据你的情况选择方法。高变动率(每日超过10%)意味着按需嵌入。中等规模且模式清晰意味着热/冷层。大规模且数据稳定意味着完全预嵌入。
**关键决策因素:**
全文搜索加查询重写提供完美的数据时效性、低设置复杂性和低于50毫秒的查询延迟。模型切换微不足道,无需分块,并且适用于大多数用例。
按需嵌入提供完美的数据时效性、低设置复杂性,但查询延迟较高(200-500毫秒)。模型切换微不足道,需要分块,最适合高变动率场景。
热/冷层提供混合的数据时效性、中等设置复杂性和50-100毫秒的查询延迟。模型切换容易,需要分块,为不同需求提供了平衡的性能。
完全预嵌入在重建索引前数据会过时,设置复杂性高,但查询延迟低于50毫秒。模型切换痛苦,需要分块,专为大规模操作设计。
**80/20法则:**60%的系统应止步于全文搜索加查询重写。25%需要按需嵌入或热/冷层的混合方案。10%需要完全预嵌入。5%需要定制解决方案。
**底线:不要成为那个为60%的问题构建5%解决方案的人。**
相似文章
@LearnWithBrij:别再像2022年那样构建RAG了。分块→嵌入→检索→生成 这条流水线能用……直到你尝试上线……
一个帖子解释了构建生产级RAG超越简单分块-嵌入-检索-生成所需的四个关键层次:智能查询路由、高级索引、多类型检索和持续评估。
大多数生产环境中的 RAG 应用都在自信地胡说八道,而这一现象却鲜有人讨论
文章指出了生产环境中 RAG 系统的一种关键故障模式:由于版本控制问题和缺乏不确定性机制,系统会生成自信但错误的回答。文章建议通过引入路由层、检索评分和幻觉检测等架构改进来缓解这些错误。
@_avichawla: 面向AI工程师的8种RAG架构:(用法说明)1)Naive RAG——纯粹基于向量相似度检索文档…
一个推文串,解释了8种不同的RAG架构(Naive、Multimodal、HyDE、Corrective、Graph、Hybrid、Adaptive、Agentic)及其使用场景,并暗示了一种改进的索引技术。
我认为RAG不再是企业的默认答案
一位实践者认为RAG不再是企业AI的自动化解决方案,指出许多问题实际上是数据卫生或结构化查询问题,而带有工具使用的智能体往往更好。
@akshay_pachaar: RAG vs. Graph RAG vs. Agentic RAG,清晰说明!标准RAG将文档嵌入向量并检索最相关…
清晰解释标准RAG、Graph RAG和Agentic RAG,涵盖它们的区别、用例以及如何处理单跳与多跳查询。