跳到主要内容

171 篇博文 含有标签「rag」

查看所有标签

知识时效路由:在生产 AI 中将查询匹配到正确的时间层

· 阅读需 10 分钟
Tian Pan
Software Engineer

这是一个在生产环境中比任何人愿意承认的更频繁出现的场景。用户询问 AI 助手当前的利率政策。你的 RAG 系统获取了一份高度相关的美联储文件——语义相似度评分高达 0.91——模型自信地返回了答案。但这个答案已经过时六个月了。RAG 索引上次刷新是在十月份。参数化知识则更为陈旧。一次实时 API 调用本可在 400 毫秒内返回正确的当前数据,但没有人在路由逻辑中加入这样的判断:这个问题的答案允许有多旧?

这种失败不是检索失败,而是时序路由失败。系统在其技术栈的某处确实能够获取正确信息,只是将查询发送到了错误的层级。

权限感知检索:企业 RAG 的访问控制必须在向量层

· 阅读需 10 分钟
Tian Pan
Software Engineer

有一种故障模式几乎出现在每一个企业 RAG 部署中:一名员工向内部 AI 助手询问薪酬政策相关问题。系统返回了正确、具体的信息——却是从一份该员工本无权查看的 HR 文档中提取的。由于没有人监控检索层,这件事不会立刻让任何人丢掉工作。但那份机密文档已被索引,用户的查询在语义上命中了它,模型忠实地报告了它所找到的内容。

这个错误并不罕见,它是将公共网络 RAG 模式原封不动地应用于私有组织知识却不做架构适配的默认结果。公共网络 RAG 没有访问控制层,因为公共网络内容本身就没有访问限制。而企业数据有——这一约束从根本上改变了整个系统的设计。

摘要有效性问题:如何识破 AI 压缩掉的关键信息

· 阅读需 12 分钟
Tian Pan
Software Engineer

摘要失败往往是隐性的。你的系统不会崩溃,日志不会标记错误,生成的文本看起来也很连贯——但在压缩过程中的某个地方,对下游任务至关重要的那个事实被丢掉了。RAG 流水线返回了一个自信的答案。多跳推理器得出了一个结论。客服代理给出了建议。所有这些都基于一个不再包含原始约束、例外或答案所依赖的数据点的摘要。

这就是摘要有效性问题:即“与原文保持一致”的摘要与“保留下游任务所需信息”的摘要之间的差距。大多数团队并没有针对此进行度量。他们上线的流水线只验证了摘要的存在,而不是摘要的完整性。

扼杀 AI 流水线吞吐量的预处理瓶颈

· 阅读需 12 分钟
Tian Pan
Software Engineer

某团队构建了一个 RAG 功能,测量端到端延迟后发现慢得无法接受,随即开始优化模型调用。他们尝试了更小的模型、批量请求,并调整了 temperature 和 token 上限。经过两个迭代周期,延迟下降了 15%,但功能依然太慢。他们从未测量过的是:在 LLM 收到任何提示词之前,文本分块和嵌入生成就已经耗费了 600ms。

这种模式在分布式系统中普遍到有了专有名词:优化了错误的组件。在 AI 流水线中,LLM 调用显而易见且易于测量,而其之前的所有环节都是隐形的——除非你主动做埋点,否则根本发现不了——而吞吐量恰恰死在那里。

“什么发生了变化”查询是你的索引无法回答的 RAG 问题

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个用户问你的助手,“这季度我们的退款政策有什么变化?”系统返回了一个当前退款政策的、格式良好的自信总结。用户点点头,关闭聊天,并根据一个与他们提出的问题完全无关的信息采取行动。你的评测套件(eval suite)没有捕捉到这一点。你的忠实度指标(faithfulness metric)没有标记它。检索看起来很完美——它返回了高度相关的分块(chunks)。合成看起来也很完美——它引用了它使用的每个分块。唯一的问题是,问题是关于 变化 的,而你的索引没有变化的概念。

这是向量相似度检索无法通过调优修复的失败模式。同一文档的两个版本具有几乎相同的嵌入(embeddings)——这就是好的嵌入所 的,它们将语义等效的文本折叠到同一个邻域中。因此,当你问“什么改了”时,检索器返回其中一个版本,LLM 总结该版本,而答案在沉默中成为了“什么都没变”的幻觉。用户无法察觉。你的评测集可能也无法察觉,因为你的评测集是围绕“什么是 X”的问题构建的,而不是“现在 X 有什么不同”。

你的 Embedding 模型选择决定了 RAG 的上限,而 LLM 无法突破它

· 阅读需 13 分钟
Tian Pan
Software Engineer

我建议的一个团队花了两个月时间在其 RAG 流水中不断更换 LLM。从 Claude 到 GPT,再到 Gemini,最后又换了回来。每一次更换都能让幻觉率降低几个百分点,但从未在关键指标上有所进展:他们的支持代理找到正确知识库文章的概率仍然不到 60%。他们调优的层级错了。检索器返回的是无关的文本块,而无论 LLM 多聪明,都无法根据检索器从未呈现过的文档来回答问题。

嵌入模型是 RAG 系统中决定 LLM 甚至“被允许”看到什么的部分。它描绘了语料库的几何结构——即在向量空间中,哪些文档会落在哪些查询附近。一旦这种几何结构出错,LLM 就只是一个对错误上下文侃侃而谈的自信叙述者。换一个更聪明的 LLM 通常只会让回答更显“文采”,而不会让回答更准确。

分层内存压缩:你的智能体内存缺失的四个层级

· 阅读需 12 分钟
Tian Pan
Software Engineer

大多数智能体内存系统将一个四层的问题压缩成两层,然后在出现破绽时表现得大吃一惊。一个是当溢出上下文窗口时会被截断的会话缓冲区(conversation buffer),另一个是旧内容堆放其中的“长期记忆”向量数据库。那不是内存架构。那只是一个队列和一个杂物抽屉。

如果一个智能体连续三个周一向老用户询问同一个新手引导问题,这并不是因为模型不好,而是因为系统中没有一个地方能保存“该用户跨会话告知我的事情”,并且其生命周期不同于“所有用户告知我的关于产品如何运作的事情”。这是不同的记忆。它们有不同的访问模式、不同的隐私契约以及不同的遗忘规则。将它们混为一谈是架构上的错误——而且这是可以修复的。

无人测试的隐私边界:为什么“无状态”工具是 AI 时代的 IDOR

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个被标记为“无状态”的工具是运行时无法兑现的承诺。在函数签名的背后,坐落着 Redis 缓存、向量索引、嵌入存储、限流表、记忆层、热路径上的 LRU——其中任何一个都是共享的基底层,一个用户的数据可能会落在另一个用户的响应中。函数是无状态的。系统则不然。在 2026 年,这是我在 Agent 系统中看到的最常见的隐私漏洞,因为几乎没有人对此进行测试。

对于任何开发过经典 Web 应用的人来说,这种漏洞的形式都熟悉得令人沮丧。不安全的直接对象引用(IDOR)曾是 Bug 赏金猎人们十年来的家常便饭:一个请求处理程序接收记录 ID 并返回记录,却不检查调用者是否有权查看。AI 时代的版本是同样的漏洞,但影响范围更广:一个工具调用接收查询并返回数据,却不检查调用者的租户是否拥有该数据。查询是用自然语言表达的。缓存键是一个哈希值。检索是近似的。这些都不能免除你的授权责任,但其中的每一项都让漏洞在代码审查中更难被发现。

单向量版本标签:每个 Embedding 迁移背后的缺失列

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个新的嵌入模型发布了。基准测试数据提升了 4 %。一位 Staff 工程师提交了一个工单:“将 embedding 升级到 v3。”两周后,索引已完成重新嵌入,别名已切换,团队通过特性标志(feature flag)发布了变更。六周后,支持工单堆积如山。搜索结果“感觉不对劲”。复盘会召开了。没人能解释为什么出现了退化,因为没有系统崩溃,每个仪表盘显示的都是绿色。

问题不在于模型的更换。问题在于向量存储根本不知道哪些向量来自哪个模型。数据库里没有这一列。没有用于追踪哪些记录已回填的迁移表。没有 alembic_version 行,没有 schema_migrations 表,也没有先前状态的 pg_dump。团队将 embedding 升级视为一次简单的配置切换,而向量存储在模式(schema)层面缺乏能阻止他们犯错的概念。

Embedding 迁移需要数据库迁移二十年来一直依赖的相同产物:写入每个向量、在每次查询时检索、并作为切换和回滚准入准则的单条记录版本标签。这是大多数团队最容易忘记添加的一列,而后期补救的成本远高于前期添加。

Reranker 是你 RAG 评估中从未衡量的“静默”第二个模型

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个典型的 RAG 流水线包含两个模型,而不是一个。检索器从向量数据库中提取 50 到 100 个候选文档,而重排序器(reranker)——无论是交叉编码器(cross-encoder)、LLM-as-judge 提示词还是混合方案——都会对这些候选文档进行重新评分,并将前 5 个结果交给回答模型。你的评估套件测量端到端的回答质量,测量检索器的 recall@k,但它并不测量重排序器。因此,当重排序器发生隐性偏移(drift)时,仪表盘上显示的“回答质量下降了 4 个点”却没有任何因果线索,团队会花费三天时间去调试一个根本不是问题的提示词。

重排序器是那个隐性的第二个模型。它介于检索器和生成器之间,拥有自己的评分分布、自己的提示词(如果是基于 LLM)或自己的权重(如果是交叉编码器),并且它可以独立于其他任何组件发生性能退化(regress)。大多数团队从未单独对它进行评分。他们编写的评估套件将流水线视为一个具有长上下文窗口的单一模型,而实际上它是两个串联的模型,且其中间接口并不属于任何一个团队。

检索膨胀:当“加个 RAG 就行”变成架构上的干扰

· 阅读需 12 分钟
Tian Pan
Software Engineer

这种模式太熟悉了,以至于被视而不见。模型幻觉出了一个事实,于是团队增加了一个检索步骤。三周后,模型从不断增加的工具库中选错了工具,于是他们在工具目录上增加了一个检索步骤。模型的回答感觉太笼统,于是他们在过去的高质量回答上增加了一个检索步骤。一个季度过去了,系统现在变成了一堆检索器拼接在一起的提示词,而本质上,最初的问题依然存在。

改变的不是失败率 —— 而是失败模式的名称。“模型出错了”变成了“检索未命中”,这听起来更易处理,但事实并非如此。评估套件的分数更高了,因为从构造上讲,检索到的上下文对于测试集来说是分布内(in-distribution)的。生产环境的情况则截然不同,但到那时,架构已经有了三个检索层,每一层都有自己的嵌入模型、索引刷新频率和值班轮换,而且没有人想成为那个提议拆除它们的工程师。

这就是检索膨胀(retrieval sprawl)。这是一种架构上的分心:一种将难题(提示词设计、模型能力、模糊的规范)转移到更舒适的问题(信息检索工程)上,而实际上没有解决任何问题的方式。

你的向量数据库也有热点 Key:为什么 ANN 索引在生产成本上“撒了谎”

· 阅读需 12 分钟
Tian Pan
Software Engineer

你团队选择的向量索引是在一个生产环境中根本不存在的工作负载上进行基准测试的。每一个公开的 ANN(近似最近邻)基准测试 —— VIBE、ann-benchmarks、数据库厂商落地页上的对比表 —— 都是从语料库中均匀采样查询的,因此每个邻居查找的成本大致相同,每个分片承受的负载也大致相等。真实的检索流量并非如此。它呈现出齐普夫分布(Zipfian):极小部分的查询(今日新闻、趋势产品、循环的支持意图、客服团队整天收到的那几百个问题)命中的一小部分嵌入,其频率比中位数高出百倍。基准测试显示 HNSW 在 50ms p99 下的召回率为 0.97。而生产环境则显示一个分片正在熔化,其余的却闲得发慌。

这种不匹配并不是调优问题。而是向量检索继承了所有其他数据库工作负载的访问倾斜特性,而该领域标准化的索引在设计时并未考虑到这种特性。你的 KV 存储免费获得的缓存层 —— 预热你最常读取的行的操作系统页面缓存(OS page cache),针对热点 Key 的 LRU —— 在 ANN 中并不存在,因为图是按图结构顺序遍历的,而不是按访问顺序。热门嵌入在内存中依然是“冷的”,因为搜索算法的遍历模式在页面缓存看来是随机的,而你的“热门”集群位于单个分片上,其 CPU 运行火热,而集群的其他部分却在闲置。