RAG 并没有你想象的那么复杂

Hacker News Top 新闻

摘要

文章探讨了六种 RAG 架构,并建议根据数据新鲜度、查询模式和规模等因素选择合适的方法,以避免过度工程化。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/08/26 12:12

# 六种RAG架构——以及如何避免过度工程化 来源:https://www.lighthousenewsletter.com/p/rag-is-simpler-than-you-think ![图片描述](https://substackcdn.com/image/fetch/$s_!yF7E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03ad851c-75b8-4afe-ae16-fd98c8e61836_1920x1280.jpeg) 如今,大多数人似乎都在过度工程化他们的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?)语义分块还是固定大小分块?我如何评估我的分块策略是否良好? 使用全文搜索,你可以跳过所有这些。你的文档就是你的文档。搜索直接有效。 使用大型语言模型将杂乱的用户查询转换为干净的关键词搜索。 大多数“语义搜索”问题实际上是*查询表述*问题。 ![流程图](https://substackcdn.com/image/fetch/$s_!TXCo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F035b8f95-ee55-4356-a00e-d6e5f1e76f4e_1400x400.avif) 用户以对话方式提问。词汇不匹配(用户说“修复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毫秒的延迟。你的语料库相对稳定(不是每分钟都在变化)。 ![流程图](https://substackcdn.com/image/fetch/$s_!DbiV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2237f1d5-80c6-4894-8a29-bac5bb4d2e3d_1400x400.avif) 让我们按当前定价(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毫秒的延迟。对于面向用户的搜索,这是可察觉的。这才是真正的权衡所在——不是成本,而是速度。 当你引入嵌入向量时,你需要决定如何分块文档(固定大小?语义?按章节?)。你需要确定使用多大的分块大小和重叠。你需要处理跨越重要上下文的分块。 这增加了纯全文搜索可以避免的复杂性。 如果你的数据变化频繁,为什么还要花钱重新嵌入所有内容? ![流程图](https://substackcdn.com/image/fetch/$s_!Yl1E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8df52ca-f2e6-46be-b95d-9e3b6aa6621b_1400x400.png) **高文档变动率**(每日超过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%解决方案的人。**

相似文章

我认为RAG不再是企业的默认答案

Reddit r/AI_Agents

一位实践者认为RAG不再是企业AI的自动化解决方案,指出许多问题实际上是数据卫生或结构化查询问题,而带有工具使用的智能体往往更好。