跳到主要内容

61 篇博文 含有标签「retrieval」

查看所有标签

检索流水线的数据驻留:那些跨境而去的 Embedding,以及并未跨境的 LLM 调用

· 阅读需 11 分钟
Tian Pan
Software Engineer

交付 “面向欧盟客户的 AI” 的团队通常只交付一种驻留控制:锁定在欧盟地区的推理端点。采购团队拿到 DPA,架构图在 “模型托管在法兰克福” 旁边打上绿色对勾,接着发布。架构图中没显示的是:客户的原始查询在前往模型的途中被美国托管的嵌入 API 向量化;查询与之匹配的向量存储的运维平面位于 us-east-1;重排序模型是部署在供应商自选地区的第三方 SaaS;提示词缓存在命中的情况下是按地区键入的,而在未命中的情况下则是全局的;记录检索块的追踪存储有一个 30 天的保留期存储桶,并为了冗余进行跨区域复制。

推理层遵守了驻留规定。而检索流水线甚至不知道自己也是参与者。

这就是大多数 “符合 GDPR” 的 RAG 部署在面临团队甚至没意识到会到来的审计时失败的缺口。修复方案不是针对模型调用增加另一个控制 —— 而是意识到数据驻留是客户字节所接触的每个组件的属性,并且拥有 “LLM” 的团队最多只拥有涉及到的六个表面中的一个。

你的检索管道从未衡量的中间上下文盲区

· 阅读需 10 分钟
Tian Pan
Software Engineer

检索日志很干净。针对你手动标注的查询集,Recall@10 在几个月内都没有出现退化。答案质量仪表盘显示忠实度(faithfulness)保持在 90% 以上。然后,一位客户向你的支持代理粘贴了一个问题,金标准文本(gold passage)就在组合提示词的 12 个位置中的第 7 位,而模型的回答却好像从未检索到它一样。

检索团队会告诉你该分块(chunk)确实在那里。提示词团队会告诉你提示词是正确的。两者在技术上都是对的。模型关注了前一千个标记(tokens),关注了最后一千个标记,却略过了答案所在的中间地带。你的流水线正面临着一种位置注意力偏置(positional attention bias),没有哪个团队对此负责,没有哪个仪表盘在追踪它,也没有哪个基准测试能捕捉到它。

你增加的 Reranker:对召回率的拖累超过了对精准度的提升

· 阅读需 12 分钟
Tian Pan
Software Engineer

离线评估的结果非常明确。在向量搜索的前 50 个结果之上叠加一个交叉编码器(cross-encoder)后,nDCG@5 提升了 4 个点。团队在周二上线了该功能。到了周四,p99 检索延迟已超过 SLO(服务水平目标)700 毫秒,客户成功团队也开始转发空结果页面的截图,而这些页面在旧的流水线下本应是有内容的。真正关键的指标——用户感知的回答质量——下降了。重排序器(reranker)实际上是一个被团队冠以“改进”之名的性能退化,而评估标准则是将这种退化隐藏在众目睽睽之下的幕后黑手。

这是生产环境检索中最常见的失效模式之一,且很少被准确描述为:一个评估缺陷(evaluation bug)。重排序器完成了它的宣传任务:以更细的粒度对前 50 个结果进行了重新排序。问题在于,用于证明其合理性的指标——在无限预算下针对完整重排序列表计算的离线 nDCG——描述的是一个生产系统并不存在的理想世界。在生产环境中,最终输出的答案并非评分最高的重排序列表,而是系统在请求截止时间前所能返回的任何内容。一旦你以此方式重新定义指标,重排序器的贡献就不再是 4 个点的提升,而是一条曲线。

你的嵌入模型在训练中从未见过的专业术语检索库

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个检索团队针对其产品目录发布了一个开箱即用的嵌入模型 (embedding model)。评估集——从上个月搜索日志中抓取的几百个查询——回传的 recall@10 达到了 0.91。他们将其推向生产环境。三周后,支持部门开始转发工单:一位用户搜索了某个零件的具体 SKU,结果得到了五个看起来很有道理但错误的零件。另一位用户搜索了一个功能的内部代号,结果得到了一个无关功能的营销名称。评估集从未捕捉到这一点,因为评估集是从系统已经处理过的查询中提取的——即关于常用术语的查询。作为业务核心的长尾术语 (jargon) 从未被采样。

模型并没有失败。模型完全按照其训练要求执行了任务,只是针对的是一个不包含团队提供语料库的词汇分布。团队将嵌入视为一种领域中性的原语 (domain-neutral primitive)——一个从文本到向量的函数——而实际上,它是一份关于它可以解析哪些词汇的契约,是与别人的训练语料库签署的。

按摄入日期分片的向量索引

· 阅读需 11 分钟
Tian Pan
Software Engineer

在按时间分区的向量索引中,隐藏着一种特定类型的召回率谎言,而构建离线评估的人通常是最后才发现它的人。仪表盘显示 recall@10 为 0.94。检索器在 94% 的情况下都能提供正确的片段。产品团队正基于这个数字发布更多以检索为基础的功能。接着,客服工单接踵而至:“助手引用的指南与答案不符”、“助手链接到了上周版本的政策”、“助手找不到我两个月前上传的文档”。这些工单都不与 0.94 这个数字冲突。它们证明了 0.94 衡量的是错误的东西。

这种机制很简单,也很容易被忽视。向量索引按摄入日期进行分片,因为这是保持高写入吞吐量、停用旧数据以及将热工作集保留在快速内存中的最简单方法。离线测试集每晚从生产日志中生成,这意味着查询是从最新分片恰好持有的同一个近期窗口中提取的。召回率是根据存在于一两个分片深处的基准真相(ground truth)来衡量的。检索器在这些查询上表现出色,因为在生产环境中,路由层会将这些查询保留在同一个分片内。

源文档更新从未同步到向量索引的那些 Embedding

· 阅读需 12 分钟
Tian Pan
Software Engineer

一名支持工程师在值班频道发了消息。一位客户粘贴了助手上周检索到的一个句子,合规团队回复说:我们已经不再这么说了。他们已经停用这句话四个月了。CMS 中的文档显示是正确的。但向量索引中的嵌入分块(chunk)仍然是旧的内容,且拥有极高的相似度得分,并在每次相关查询时被提供给模型。没人改过检索代码。没人改过模型。真相源(source-of-truth)变了,而索引却对此一无所知。

这是摄取流水线(ingestion pipeline)的一种失败模式:它最初是为“创建”而设计的,后来演变成了一个也要处理“更新”的系统,却没有人专门为“更新”进行设计。“创建时嵌入”的任务在每份文档首次写入的那天运行。一个季度后,CMS 团队发布了一个编辑端点,由另一个团队负责,他们将其接入了搜索、面向公众的渲染器和变更日志 feed —— 接入了每一个消费者,除了那个隐藏在不同名称下的派生数据集。数月过去,语料库发生了漂移。检索系统开始回答那些公司早已正式抛弃的问题,而唯一的信号来自于一位困惑的客户。

被切分边界拦腰截断的关键句,以及随之消失的答案

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 RAG 流水线将文档切分为 512 个 token 的片段,并带有 50 个 token 的重叠。这是一个标准的行业默认设置。在你的语料库中,有这样一句话——“除非订单来自欧盟地区(在这种情况下监管窗口为 14 天),否则退款将在 5 个工作日内处理”——它恰好跨越了分块边界。分块 N 包含前半部分。分块 N+1 包含后半部分。

用户提问“欧盟退款需要多长时间”。检索系统给分块 N 打分最高,因为查询嵌入与第一段碎片中的“欧盟地区”对齐。而包含唯一实际答案的分块 N+1 排名太低,无法同时被检索到。智能体回答“5 个工作日”,并自信地引用了分块 N。客户人在法兰克福。答案是错误的。流水线完全按照设计运行。

这种故障模式不会出现在你的分块质量评估中。分块是格式良好的。语料库是格式良好的。嵌入模型是格式良好的。分块之间的边界——你在自己文档中划下的那些线——才是答案所在。

当你的 RAG 流读取时发生的 Wiki 中途编辑问题

· 阅读需 13 分钟
Tian Pan
Software Engineer

你平台团队的一名技术文档工程师正在移动一个段落。这并非比喻——她正真实地从入职指引页剪切一个章节,粘贴到运维手册中,删除第三页上的一个草稿占位符,并修改第四页上的一个弃用警告。整个编辑过程大约花费了她 11 分钟。而你的 RAG 摄取任务每 15 分钟运行一次。恰好在第 6 分钟时,任务启动了。

在接下来的 15 分钟里,你的检索索引包含了一个在她的脑海中从未在任何单一时刻存在过的 Wiki 状态。入职指引页仍然保留着那个章节。运维手册里却还没有。那个草稿占位符在被删除到一半时被捕获了,里面包含了一句她从未打算发布的占位语句。旧的弃用警告仍然被索引着。当一名工程师询问智能体“我们如何在这个服务中处理凭证轮换”时,模型从同一个来源检索到了矛盾的分块,并自信地合成出评分较高的那一个。答案呈现出一种任何人都没写过的错误形态。

这是大多数团队在发布时都没有注意到的失效模式:单一事实来源是事务性的,摄取是轮询的,而两者之间的鸿沟就是“脏读”存在的地方。

被你的 RAG 当成工程规范引用的那张营销页

· 阅读需 10 分钟
Tian Pan
Software Engineer

一位支持工程师把客户工单粘进你内部的 AI 助手。问题很尖锐:"我们的 API 在免费层支持多区域写入吗?"助手秒回,引用了一个余弦相似度 0.91 的片段。答案是肯定的。这个片段来自 2023 年市场部为打赢竞品对比写的落地页。十八个月前,工程团队就把免费层的多区域写入功能下掉了,并发了一份没人在客户页面上链接过的、措辞简短的内部 RFC。这份 RFC 也在向量库里,只拿到了 0.74。

助手并没有幻觉。它检索到了得分最高的文档,然后忠实地把答案锚定在那段文本上。检索器尽到了职责。只是,那份职责本身就是错的。

那个把上周 Slack 消息当成昨天消息来读的智能体

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的运营 Agent 通过引用一条内容为 “我们明天发版” 的 Slack 消息,回答了一个关于即将到来的发布会的问题。Agent 将其视为当前的计划,并开始撰写沟通稿。然而,这条消息是六周前发布的。发版早就完成了。检索流水线(retrieval pipeline)根据你衡量的每一项指标——与 “发布日期” 的语义相似度、高于阈值的 top-1 置信度、与项目匹配的来源频道——抓取到了正确的文本块(chunk),而 Agent 基于一句仅在编写时的会议语境下才有意义的话制定了计划。

这里的 Bug 不在模型本身。Bug 在于,“明天” 并不是一个日期。它是一个指向时钟的指针,而该消息编写时的时钟并不是 Agent 阅读时的时钟。你的检索流水线索引了消息的正文,却丢弃了其框架(frame)。

语义过时的 Embedding:当向量不再理解当下

· 阅读需 10 分钟
Tian Pan
Software Engineer

你曾在十八个月前嵌入了知识库。模型没变。分块(chunks)没变。索引很健康,延迟也正常,召回率仪表盘是一条 0.86 的水平线。然而,客服团队正悄无声息地在工单回复中粘贴错误的文章链接,销售机器人在潜在客户询问新产品时不断翻出已弃用的 SKU,而一名内部用户刚告诉你助手“感觉变笨了”,却说不出具体原因。

一切都没坏。是你的嵌入(embeddings)老了。在你的领域中,“post”一词以前指的是博客文章;现在,语料库中有一半的地方用它指代 Slack 帖子、论坛帖子和职位发布(job posting),而你那十八个月前的向量仍将其视为同一个概念。编码这些向量的模型从未见过这些新含义,从未见过新的产品名称,从未见过品牌重塑,也从未见过引入了三个新术语的监管规定——而你的客户现在正不假思索地使用这些术语。检索系统回答了它知道如何回答的问题,但这已不再是你的用户正在提出的问题。

针对幻影库存的 RAG:当你的语料库描述产品已删除的功能时

· 阅读需 12 分钟
Tian Pan
Software Engineer

一位客户询问你的支持代理如何执行某项操作。代理检索到了三个相关性评分很高的文档分块,合成了一个自信的答案,并引导客户完成一个五步操作流程。然而,这个流程的最后一步是一个在四个月前就已经不存在的按钮。客户提交了工单。值班工程师调出评估套件,发现结果是绿色的;调出检索追踪,发现结果也是绿色的——模型没有产生幻觉,它忠实地引用了描述产品团队在上个季度发布中重命名的功能的文档。

这就是我想命名的失败模式:不是幻觉,也不是检索未命中,而是幻影库存 (phantom inventory) 问题。你的检索语料库是已不存在的产品界面的快照。向量存储不知道产品发生了变化。评估套件也不知道。唯一能持续捕捉到这一点的系统是支持工单队列,而当工单提交时,客户已经被告知去点击一个并不存在的按钮了。