跳到主要内容

178 篇博文 含有标签「rag」

查看所有标签

评估了错误的 RAG 管道环节

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 RAG 评估仪表盘显示为绿色。忠实度(Faithfulness)为 0.91,回答相关度(Answer Relevance)为 0.88,你花了两个迭代周期构建的 LLM-as-judge 评估框架显示系统运行良好。与此同时,一位用户刚刚问了一个问题,而答案就在你的检索器(retriever)从未提取出的文档中,你的模型写下了一个自信、结构清晰但完全没用的回答,内容与问题相关但风马牛不相及。评判员给了它高分。它读起来很顺畅。它基于模型 确实 获取到的片段。它只是用与用户需求无关的内容回答了一个错误的问题。

这是大多数团队评估检索增强生成(RAG)时存在的隐性结构缺陷:他们给文章打分,却从未检查学生是否拿到了正确的书。RAG 系统是两个连接在一起的机器——一个是决定 模型能看到什么 的检索器,另一个是决定 如何处理这些内容 的生成器。几乎生产环境中的每一个评估框架都只衡量第二个机器。第一个机器,也就是真正决定答案质量上限的那个,却在未经监控的情况下运行。

淘汰嵌入模型:在不中断搜索的情况下重新索引数百万个向量

· 阅读需 11 分钟
Tian Pan
Software Engineer

有一种特定类型的故障永远不会表现为宕机。服务状态保持绿色,延迟平稳,错误率为零,而搜索结果却悄然开始返回垃圾信息。这就是当你将一个新的嵌入模型(embedding model)指向由旧模型构建的索引时会发生的情况。没有任何程序崩溃。只是搜索结果不再有意义了。

原因在于几何学。嵌入模型不会为某个概念分配固定的坐标——它定义了一个 空间,而同一句话落在哪里完全取决于绘制地图的模型。去年模型产生的向量与今年模型嵌入的查询之间不存在“近”或“远”的关系。它们是根据不同的尺子衡量的。它们之间的余弦相似度(Cosine similarity)只是一个数字,而且这个数字毫无意义。

因此,当有人提交一个标题为“升级到新嵌入模型”的工单时,他们提交的并不是一个配置更改。他们提交的是一个披着单行代码差异(diff)外衣的完整数据迁移。如果你把它当作普通的库版本升级来处理,你就是在发布一个无声的故障。

间接提示注入:你以为处于惰性的数据平面

· 阅读需 11 分钟
Tian Pan
Software Engineer

大多数团队在针对错误的层面进行威胁建模。他们加固了聊天框——速率限制、输入校验、监视用户输入内容的越狱分类器——却将模型读取的所有内容视为惰性的。Wiki 页面、支持工单、抓取的网页、日历邀请、某人上传的 PDF:在他们眼中这些只是数据,而不是指令。它们是供模型总结的背景材料,而不是让模型执行的命令。

这种假设本身就是漏洞。一旦你的 Agent 获取了内容并将其放入上下文窗口(Context Window),该内容的执行权限就与你的系统提示词(System Prompt)完全一致。在“这是你的指令”和“这是供参考的文档”之间没有权限边界。它们都只是 Token,而模型经过训练,会遵循出现在任何地方的指令。

你的智能体读了页面。没人看到广告。

· 阅读需 11 分钟
Tian Pan
Software Engineer

互联网经济建立在一个极其古老以至于无人明说的假设之上:加载页面的那个东西长着眼睛。当人类到来,广告曝光触发,联盟营销 Cookie 植入,分析事件记录访问——这一连串微小的变现事件支撑着内容的产出。现在,这条链条的每一个环节都在同时断裂,因为你网站的读者中,机器人的比例正日益增长。它们是 Agent,而 Agent 是看不见广告的。它提取答案,将其交给别处的用户,除了日志行之外什么也没留下。

这并非一个你可以作为工程师在旁观望的遥远出版商问题。如果你正在构建任何基于检索(Retrieval)的东西——无论是 RAG 管道、浏览网页的 Agent,还是总结网络内容的产品——你正处于一个市场的需求侧,而该市场的供给侧刚刚发现自己一直在免费赠送库存。修正正在进行中,它背后有基础设施和标准支撑,并且它将作为一项新的成本支出和新的失败模式降临在你的架构上:上个季度还免费开放的上游资源,这个季度就变得需要付费、授权或直接关闭了。

你的上下文是有质量的:数据重力与“计算向数据移动”的回归

· 阅读需 11 分钟
Tian Pan
Software Engineer

Hadoop 时代的一代人彻底学会了一个教训,以至于它成了一种本能:移动数据是昂贵的,所以要把计算移动到数据所在的地方。每一个 MapReduce 调度器、每一个 HDFS 块放置决策、每一个“数据本地化”(data locality)仪表盘的存在都是为了服务于这一原则。然后,在托管模型 API 的兴起和智能体(agent)热潮之间的某个时刻,我们悄然颠倒了这一原则——而且没有人重新评估这一决策的成本。

看看现代智能体循环(agent loop)实际上在做什么。它从向量数据库中检索一堆文档,从对象存储中提取代码库快照,从六个内部服务中收集工具执行结果,将所有这些内容拼接进一个上下文窗口,然后将整个负载发送到通常位于不同 VPC、不同区域、甚至不同云平台的模型端点。然后在下一轮对话中重复这一过程。周而复始。你的上下文具有质量,而你正在为每一次跳转支付运费。

你的上下文流水线需要一份新鲜度 SLA

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的智能体(agent)用上个季度的价格回答了客户的计费问题,复盘报告会将此归咎于模型。但不应该如此。Prompt 组装正确,检索评分很高,模型对所给的所有信息进行了合理的推理——而所给的一切在三天前都是真实的。在 CRM 导出、文档同步和向量索引重建之间的某个环节,“世界的当前状态”悄然变成了“截至周二的世界状态”,而你的技术栈中没有任何环节在衡量这种差异。

数据工程师在几年前就解决了这类问题。一个消费十张上游表的下游仪表板拥有血缘关系(lineage)、新鲜度检查以及一个在夜间任务出错时进行呼叫的轮值机制。你的智能体所消费的上下文窗口也是同样的东西——一个由文档、工单、代码、CRM 和记忆连接而成的物化视图(materialized view)——只不过没有人负责这个连接(join),没有任何东西衡量它的陈旧度,当它提供昨天的真相时,失败却被归类为“模型幻觉”。

你的 Embedding 是个人身份信息 (PII):反向攻击与向量数据库中的被遗忘权

· 阅读需 11 分钟
Tian Pan
Software Engineer

在你公司的内部数据分类政策中,总会有这么一个表格。原始客户文本——支持票据、医疗笔记、聊天记录——被归入“敏感”行,受到加密要求、访问控制和删除服务等级协议(SLA)的保护。然而,还有一个存储着 这些文本对应的 嵌入向量(embeddings)的向量库,它被归类为……什么也不是。衍生数据。匿名数学。只是一堆浮点数。

这种分类是错误的,而且这种错误现在已经得到了实验证明。逆向攻击(Inversion attacks)可以从嵌入向量中重建原始文本——在研究最充分的场景下,92% 的案例可以 准确 恢复 32 个 token 的输入,包括临床笔记中的全名。如果攻击者拿到你的向量后能读出你客户的话,那么你的向量就继承了这些话语的敏感性。监管机构已经开始公开声明这一点,而大多数检索架构尚未对随之而来的后果做好准备:删除请求必须触及每个索引、每个快照和每个衍生工件——而不仅仅是行存储(row store)。

PII 脱敏哨兵如何悄然瓦解你的向量索引

· 阅读需 11 分钟
Tian Pan
Software Engineer

一位支持工程师调出了你的 RAG 控制台来调试一个投诉。客户问的是“我的账户现在看起来是什么样的”,得到的回答逻辑清晰且自信,但内容却完全是关于另一个人的账户。检索到的前三个数据块(chunks)全部属于其他客户。工程师针对最新的语料库快照运行了同样的查询,以排除索引延迟的可能性,结果相同。随后,她针对六个月前、即隐私脱敏器上线前的快照运行了查询。结果,正确客户的数据块排在了第一名。

脱敏器的工作逻辑符合预期。每一个姓名都被替换为 [NAME],每一封邮件都被替换为 [EMAIL],每一个账号都被替换为 [ACCOUNT]。法务团队拥有清晰的审计追踪,安全团队也关闭了合规工单。但这两个团队都没考虑到的是,这些被安插在数百万份文档中相同句法插槽里的“哨兵”标记,被嵌入模型(embedding model)视为普通 Token —— 且这些 Token 之间的共现关系比任何真实内容都更可靠。脱敏器不仅删除了信息,它还添加了一个全新的、极其强烈的信号,即所有脱敏文档都共有这一特征,而其他文档则没有。

引用索引失效:当你的分块器开始添加行号前缀时,偏移了一位

· 阅读需 12 分钟
Tian Pan
Software Engineer

分块器开始在每个块前添加 [line N]。Eval 变绿了(通过了)。从那天起,模型生成的每一条引用都指向了实际证据前的一个段落,这种情况出现在该产品所服务的受监管行业的每一份文档中。团队并不是通过评估发现这个问题的,而是通过一位审计人员发现的。审计人员查看了引用的句子,阅读后指出,该句子与其本应支持的断言完全矛盾。

这种回归错误(regression)能躲过代码审查、对三个示例文档的手动 QA 测试以及功能开关(feature-flag)的逐步推送。孤立地看,这些检查都没有错。它们都在问同一个问题——在预期的地方是否出现了引用——但没有一个检查在问审计人员问的问题,即:引用是否指向了断言来源的那个句子。这两个问题之间的差距,正是那个“差一错误”(off-by-one)长期潜伏的地方。

这种失效模式之所以值得专门写篇文章,不在于 Bug 本身。差一错误是陈年旧事了。有趣的地方在于,这个失效是由两个系统共同产生的:它们在整数的结构上保持一致,却在整数的含义上产生了无声的分歧。

引用链接依然有效,但内容已不再是模型引用的原文

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个 RAG 智能体用一段简洁的文字和一条引用回答了客户的监管问题。验证层获取了该 URL,看到返回码为 200 OK,勾选通过并发布。六个月后,合规性审计调取了对话记录,点击同一个链接,却发现页面现在的内容与智能体引用的完全相反。URL 没问题,对话记录中的引用也没问题,但两者不再匹配。客户的合规官询问智能体是否捏造了引用,而团队无法证明它没有捏造,因为证明该 URL 过去内容的唯一证据就是智能体自己声称它说过什么。

这不是通常意义上的幻觉。模型检索到了真实内容,忠实地提取了真实的句子,并给出了一个至今仍可解析的真实 URL。世界上任何链接检查工具都会认为这个引用是有效的。然而,审计依然失败了,因为验证层衡量的是错误的属性。可访问性(Reachability)并不等同于忠实度(Fidelity)。URL 只是指向受他人编辑控制的可变文档的指针,一旦文档发生变化,每一份引用它的对话记录都会变成一个随时可能爆发的“幻觉报告”。

你的财务团队构建的那个排除了 Embedding 重新索引成本的成本仪表盘

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的财务团队构建了一个精美的 AI 成本仪表盘。Token 支出,按功能划分。Embedding 支出,按供应商划分。每个季度,按功能的面板都会在领导会议上接受审查,有人会问为什么支持聊天(support-chat)的工作流增长了 12%,而产品经理会给出一个合理的解释。每个季度,按供应商的面板都会在基础设施会议上接受审查,有人会问为什么 OpenAI 的支出增长了 8%,而平台工程师会给出一个合理的解释。然而,每个季度,真正让你 AI 账单翻倍的那一行——语料库重索引(corpus re-index)——却落入了一个名为“基础设施”的第三个篮子里,没有人审查它,因为没有人负责。

那个篮子是 40% 的 AI 支出在没有归属的情况下白白流失的地方。本可以优化它的团队从未见过它。而能看到它的团队却无法告诉你它是为哪个功能服务的。仪表盘对它能解释的所有成本都保持诚实,而对它无法解释的成本保持沉默,而这恰恰是至关重要的成本。

那场无需部署就让你检索召回率减半的 Embedding 弃用事件

· 阅读需 12 分钟
Tian Pan
Software Engineer

在一个 RAG 系统中,可能上线的代价最高昂的嵌入 (embedding) Bug,是那种你的代码库没有任何变化、检索代码没变、索引没变、查询路径也没变的 Bug。然后在第六周的某个周二,有人注意到答案的质量不如从前了。

服务商为你十二个月前构建索引时所使用的嵌入系列发布了停用公告。平台团队将其归档在了一个拥有一年缓冲期的停用仪表盘中,然后就继续处理其他事情了。停用路径并不是一个生硬的截止——而是一个悄无声息的质量退化:被停用的端点开始路由到一个“兼容性”继任者,它返回相同维度的向量,但语义几何空间却有微妙的不同。查询嵌入开始与你一年前嵌入的语料库发生漂移。在六周的时间里,你的常规评估中的 Recall@10 下降了 47%。团队直到一个无关的质量仪表盘达到阈值时才追溯到原因,迫使一名高级工程师进行根因分析,最终发现问题指向了一个在这一年里没人动过的嵌入端点。