跳到主要内容

861 篇博文 含有标签「insider」

查看所有标签

那个在你的代码冻结期间送达的模型弃用通知

· 阅读需 9 分钟
Tian Pan
Software Engineer

邮件是在周二发出的。你那两个最重要的功能所依赖的 Checkpoint 进入了 90 天的下线期。你的工程团队正处于为了另一个发布而进行的协同代码冻结(Freeze)的第二周。等到冻结解除时,你将只有不到三十天的时间来针对新模型重新验证两个生产环境的功能——这里的“重新验证”意味着重建评估集、运行影子流量、获得产品负责人签字,并在一个没人关注的 Feature Flag 之后发布,因为发布团队还在忙着处理代码冻结原本针对的那个项目。

这种冲突并不少见。主要供应商发布废弃周期的频率是以月为单位的,每个在托管模型上运行的团队现在都经历过至少一个周期。团队尚未吸收的教训是,供应商的废弃并不是像库升级那样的工程事件——它是一个运行在你无法控制的时钟上的排程事件,任何没有预留预算的路线图都会将这笔成本视为一场意外。

你的智能体在链式工具调用中获得的 OAuth 权限范围

· 阅读需 11 分钟
Tian Pan
Software Engineer

用户在你的智能体授权页面上点击一次“授权”。当会话结束时,该智能体已经链式调用了 11 个工具,协商了 3 次提权授权,现在拥有了它所触及的每个工具的权限并集。用户只记得授权了一件事。你的审计日志却显示它拥有半个账户的读写权限。OAuth 标准说一切都在按设计运行,而这恰恰就是问题所在。

经典的 OAuth 授权模型是为“一个应用与一个 API 通信”的世界构建的。智能体在两年前打破了这一假设,而标准在实践中尚未跟上,即使规范已经更新。其结果是一类无人刻意发布的静默权限提升——它随着每一次工具注册而累积,而你的安全审查却一直在盯着前门。

你的智能体平台忘了配置的值班轮换

· 阅读需 12 分钟
Tian Pan
Software Engineer

AI 平台团队有四名工程师。他们七个月前发布的内部 Agent 现在每天为 200 名员工回答问题。在第一个月,创始工程师亲自处理了每一个 Slack 消息——周二晚上 11 点,周日上午,甚至公司团建的晚上。随后,她因推动采用率方面的贡献而晋升为资深工程师(Staff Engineer),三周后,她在下午 6 点后就不再查看频道了,因为那是资深工程师该做的。原本打算取代她的值班轮换(on-call rotation)从未正式化,因为运营模式总是打算在“试点之后”再解决。

当 Agent 针对四分之一的用户静默降级的那天——一个悄然落后的检索索引,或者改变了拒绝行为的模型版本切换,或者是架构轮换后现在返回空数组的工具——投诉并不会降临到平台团队的传呼机(pager)上。它们落在帮助台队列中,由那些无法访问 Agent 追踪(traces)、不知道什么是系统提示词(system prompt)、并且被 IT 部门告知该 Agent “由 AI 团队负责”的人员处理。从第一个用户投诉到第一位工程师查看 trace,中间过去了 16 个小时。平台团队没有人玩忽职守;只是根本就没有人在执勤。

自身训练语料库成为泄露途径的 PII 脱敏器

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个团队在他们的日志流水线前端部署了一个经过微调的脱敏模型。它在数据进入长期存储之前剥离姓名、电子邮件、账号和 IP 地址。该模型体积小、速度快,且易于与接入层(ingestion workers)并行部署。隐私审查通过了该方案。六个月后,一位客服工程师将一行看起来很奇怪的日志粘贴到调试工具中,脱敏器产生的输出包含了一个真实客户的电子邮件地址——而这个地址在输入中根本没有出现。

流水线完全按照其构建初衷运行。而脱敏器本身就是泄露源。

你的编程智能体生成的那些人类已经不再阅读的 PR 描述

· 阅读需 12 分钟
Tian Pan
Software Engineer

一年前,你的团队采用了 PR 描述模板。它包含 ## Summary## Changes## Test plan 和一排复选框。审查者非常喜欢它:每个 PR 都有上下文,每个 PR 都有测试计划,每个 PR 都有结构。六个月后,编程助手学会了填写它。现在,每个 PR 依然有 ## Summary## Changes## Test plan 和一排复选框 —— 但审查者不再阅读标题以外的内容了。曾经聚焦注意力的格式,现在反而成了“此处不值得关注”的信号。结构比它所承载的信号寿命更长。

这不是代码质量问题。这些 PR 中的代码通常是没问题的。问题在于,撰写描述的行为已经从思考变更的行为中被剥离,而描述正是审查者用来分级处理(triage)其有限注意力的工具。当该工具变得格式统一、措辞合理,且与其他所有 PR 毫无区别时,审查者的注意力分级机制就失效了。曾经用于挖掘异常情况的系统,现在将所有内容摊平成了同样的形状。

供应商配额在你的全球流量从未选中的时区重置

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的每月 Token 配额在 00:00 UTC 重置。你最大的客户在东京,他们在 21:00 UTC(即当地时间第二天早上 6:00)达到峰值负载。当重置时刻到来时,东京的工作日已经在配额耗尽的降级方案中消耗了该周期的最后六个小时。429 错误看起来只是“偶发”,因为你仪表板上的 UTC 日历轴将每日重置边界隐藏在了普通的时间戳之中。

这不是速率限制(rate limit)的 Bug。这是一个日历 Bug。供应商为了结算方便选择了一个重置时钟,而你流量的地理分布决定了哪些客户会分配到周期末尾的空窗期。那些将配额定价为统一资源的团队,正基于一个用户从未见过的日历来进行配额分配。

你的产品视图从未呈现的推理 Token

· 阅读需 11 分钟
Tian Pan
Software Engineer

一位客户给支持团队发了邮件。AI 助手告诉他们在错误的司法管辖区申报纳税,他们非常生气,想知道助手是如何得出那个答案的。你的支持人员打开问题队列,看到了最终回复:自信、听起来很有道理,但却是错误的。他们看不到模型在给出回复前生成的 5000 个推理标记 (reasoning tokens),尽管这些标记确实存在,而且你的工程团队可以在 30 秒内从另一个屏幕上把它们调出来。证据就在公司里,只是拿在错误的人手中。

这就是团队在生产环境的智能体上启用扩展思考 (extended thinking) 时产生的差距。推理成为了每一次调用的核心产物,而你的组织尚未决定谁在什么时候、以何种精度、以及在多长时间内可以看到它。默认决策是由负责各个界面的团队分别做出的,他们的默认设置各不相同,而这些缝隙恰恰是客户投诉产生的地方。

你那两个独立的评估指标正不断破坏拒绝校准

· 阅读需 14 分钟
Tian Pan
Software Engineer

调出过去四次模型升级的仪表盘,查看安全指数(safety number)旁边对应的帮助指数(helpfulness number)。在每次发布中,总有一个指数在变动,而且几乎从不是同一个。负责安全评估的团队发布了一个“将拒绝加固提升了 6 个点”的修复程序,三周后,负责帮助性评估的团队发布了一个“在合法查询完成度上恢复了 5 个点”的修复程序。然后,循环再次开始。

这并不是两个团队在各自取得独立进展。而是一个模型在沿着同一个轴摆动,而组织却在用两把相反的尺子测量它,每把尺子上所谓的胜利都是另一把尺子上无声的损失。刚刚庆祝了安全性能提升的团队,在不经意间发布了一个拒绝更多合法医疗问题、法律问题和“如何做”问题的模型——而这些问题的词干恰好看起来像训练数据中的不安全内容。由于这种帮助性的倒退属于不同的冲刺周期、不同的负责人和不同的仪表盘,因此它被忽视了。

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

· 阅读需 12 分钟
Tian Pan
Software Engineer

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

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

擦除模型仍在读取的上下文:数据保留策略带来的隐患

· 阅读需 13 分钟
Tian Pan
Software Engineer

一个每晚运行的数据留存 worker(retention worker)会删除任何超过 30 天的用户消息。一个从 3 月初开始的长周期企业支持会话,到 5 月底仍然处于活跃状态。在第 41 轮对话请求进来时,你的 Prompt 组装器(prompt assembler)从同一个消息表中读取数据,而那个留存 worker 一直在悄悄地清理这个表。第 1 到 28 轮已经消失了。模型接收到的对话是从第 29 轮开始的,没有任何信号表明之前的对话曾经存在过。用户问道:“我们之前商定的 SLA 是什么?”模型自信地编造了一个数字,因为真正的答案在第 4 轮——而留存 worker 在前一天晚上把它删除了。

这不是模型故障。模型完全按照其应有的方式运行:从交给它的上下文中生成一个看似合理的答案。故障发生在更上游,处于两个团队之间的鸿沟中——每个团队都认为自己拥有消息表。

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

· 阅读需 10 分钟
Tian Pan
Software Engineer

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

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

智能体学会针对重试预算进行规划

· 阅读需 11 分钟
Tian Pan
Software Engineer

在生产环境中运行智能体(agent)得出的最令人不安的教训不是它们会失败——而是它们会学习。并不是指任何深度意义上的学习;权重并没有改变。但在一个会话(session)中,在一个轨迹(trajectory)中,模型所隐含的策略会根据其运行的底层环境(substrate)进行调整。如果你的底层环境代表智能体悄悄吸收了失败,智能体最终会察觉到这一点,并开始将其视为免费的算力进行规划。

最明显的例子就是重试层(retry layer)。你添加它是为了可靠性——在报错之前,SDK 会对失败的工具调用进行三次重试;你的中间件为每一步包装了指数退避(exponential backoff);你的循环捕获了格式错误的 JSON 并重新提示模型进行修复。这些都没错。但每一个机制都是智能体可以观察、概括并利用的副作用。一旦它这样做了,你的可靠性层就不再是安全网,而成了规划原语(planning primitive)。