跳到主要内容

907 篇博文 含有标签「insider」

查看所有标签

KV Cache 驱逐:供应商称其为“缓存压力”,而你的账单则称其为“双倍前缀费用”

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的应用程序开启了一个包含 4 万 token 系统提示词和完整工具库的长对话。第一轮对话按写入费率为前缀付费,且提供商的 KV 缓存(KV cache)开始预热。第二轮对话在 90 秒后到来。你假设这会命中缓存。有时确实如此。但有时,同样的 4 万 token 会再次以未缓存的价格出现在你的账单上,而你的代码在第一轮和第二轮之间没有任何改动。

改变的是别人的流量。KV 缓存是共享基础设施。你的租户被分配到一个推理节点上,而在你的两轮对话之间的 90 秒内,该节点接纳了足够多的其他租户,从而将你的前缀从内存中驱逐。提供商的控制台会将其描述为“缓存压力(cache pressure)”。你的财务团队会将其描述为一项翻倍的支出项。这两种描述都是准确的,但原因都不在你的代码里。

KV 缓存预热 Cron 任务只在蓝环境运行而从未进入绿环境,原因竟是主机绑定从未迁移

· 阅读需 12 分钟
Tian Pan
Software Engineer

事故复盘将十二天前的一次部署确定为支出增加 3.6 倍的原因,而当时在场的参与者中,没有一个人在变更发布时参与其中。部署过程非常常规:蓝绿切换,流量按计划转移到绿色环境,蓝色环境停用,流水线变绿,发布工程师关闭了工单。生产环境的 SLO 都没有触发。应用层的告警也没有响起。系统运行得完全符合设计。

原本的设计是一个每五分钟运行一次的 Cron 任务,它每五分钟针对稳定的系统提示词前缀 (system-prompt prefix) 预热提供商的 Prompt 缓存。这种预热为团队在冷启动时带来了 91% 的缓存命中率,并在每个会话的第一次请求中获得了大约 4 倍的成本优势。该 Cron 任务是一年前首次引入蓝绿模式时编写的,其主机选择器 (host selector) 被固定在蓝色池 (blue pool),以避免在重叠窗口期间运行两次预热。当绿色环境变成活跃环境而蓝色环境消失时,该 Cron 任务失去了它的主机,并从“每五分钟运行一次”悄无声息地转变为“永不运行”。随着提供商缓存的 TTL 使预热的前缀过期,缓存命中率在接下来的 36 小时内逐渐下降。成本仪表盘计算的是每日窗口内的平均单次请求成本,平滑了趋势,直到下一个计费周期让问题变得显而易见。

供应商移除的 Logprobs 字段如何静默地破坏了你的置信度路由

· 阅读需 13 分钟
Tian Pan
Software Engineer

在事故复盘报告中,最昂贵的代码行反而是没人写出的那一行:一个字段缺失的 200 OK。原本应该将难题上报(Escalate)给更强模型的路由,在整整六周的时间里上报的流量为零。成本看板在欢庆,质量看板却在下滑——但仅限于那组被现有评估集低估的难题切片。直到客户投诉系统以前能正确处理的特定问题时,一切看起来都还像是场胜利。

起因是协议栈上层的一个响应结构变化。供应商的中级方案取消了逐 Token 的 logprobs,这在发行说明中被称作“特定层级的特性对等调整”。客户端收到的仍是有效的 JSON,HTTP 状态码依然是 200,响应中的模型标识符与请求中的模型标识符也完全匹配。唯一的变化是,路由用来做上报决策的字段消失了,而一年前在一次事故中添加的防御性默认设置,悄然变成了每个请求的生产环境默认行为。

供应商上调 max_tokens 默认值,导致你的尾部响应长度翻倍

· 阅读需 13 分钟
Tian Pan
Software Engineer

你的事故时间线显示没有部署。你的代码没有变。你的流量组合没有变。你的提示词也没有变。然而,你的 p99 输出长度在一周内翻了一番,下游渲染层开始截断响应,而且在流量没有请求更长答案的情况下,你的输出 Token 账单增长了 38%。这种变化是真实的,回归是可以衡量的,但你的版本控制系统中没有记录——因为发生变动的值是你的代码从未发送过的。

供应商提高了一个隐式默认值。发布说明将其归类为“改进的长内容表现”。有问题的参数是 max_tokens,你的应用程序从第一天起就忽略了它,因为文档中记录的默认值很慷慨,而且你的输出很少接近这个值。默认值从 4096 移动到 8192,以适应供应商新模型中更长的推理过程。无论你是否想要,你的应用程序都获得了新的默认值,因为缺少参数本身就是一种配置选择——而供应商拥有更改其背后值的权利。

这种故障模式下,供应商侧的“无操作”(no-op)发布会作为行为变化、成本变化和用户体验(UX)变化同时在你的系统中传播,而你团队唯一的诊断信号是月底寄来的账单。

那些你的团队遗忘在后台且正使用生产环境凭据运行的 MCP 服务器

· 阅读需 12 分钟
Tian Pan
Software Engineer

周一,一位新工程师加入了团队。到周三时,她已经搭建好了本地 Agent 环境:一个桥接到公司部署 API 的 MCP 服务,指向 Staging 环境,并与她的编辑器相连。入职文档引导她完成了 OAuth 流程。她粘贴到服务器环境文件中的令牌是同事发给她的——这与 CI 流水线用于发布到 Staging 环境的是同一个令牌。到周五,她已在共享办公空间与团队一起进行协作开发。

MCP 服务仍在运行。绑定在 127.0.0.1。无需身份验证。令牌已加载到进程中。她没多想,因为她并没在使用它。但那天访问任何网站的任何标签页,都可以通过她自己的浏览器与她的本地服务通信。共享办公空间 Wi-Fi 上的任何其他笔记本电脑也同样可以,因为她没注意到该服务实际上绑定到了 0.0.0.0。你的 CI 流水线用来推送到 Staging 的 OAuth 令牌,现在任何能诱导浏览器向本地 IP 发起请求的人都能触及——在 2026 年,这只需要一个弹窗。

本文讨论的就是这类故障:“我在笔记本上开发”与“我的笔记本是对手可以触及的服务器”之间的鸿沟。MCP 服务在设计上恰好处于这个鸿沟之中。大多数团队尚未察觉。

模型指标卡的基准测试:当你的合同引用该数字时,其方法论已发生偏移

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的采购团队在上个季度续约了推理合同,并带着一丝自得地注意到,引用“HumanEval pass@1 达到 84%”的质量条款已被供应商最新的模型卡(model card)轻松超越,现在报告的数值是 87%。提高了三个百分点。条款已达成。合作关系很稳健。与此同时,你推理团队自己的回归测试集——那个真正运行你产品所依赖的任务的测试集——显示自模型更新发布以来,在留出法评估案例上出现了 2% 的下降。这两个数字都是真实的,但合同里只写了其中一个。

这就是当营销产物在法律文件中承重时的情况。模型卡上的基准测试数字只是测量结果的标题;而产生该数字的方法论则是附录中的一个注脚,合同审查链上的任何人都不会去读它。当供应商更改方法论时——从贪婪解码(greedy decode)切换到三选一采样(best-of-three sampling),添加结构化输出系统消息,或者更换提示词模板以匹配模型新的聊天微调——数字的变动与你的实际流量毫无关系,而与数字的计算方式息息相关。你的合同条款引用了该数字,而对方则掌控着产生该数字的协议。你签署了一个对方可以在不违约的情况下修改其含义的条款。

供应商将你的模型标识符重定向到特定租户的微调模型,而其他人使用的却是基础模型

· 阅读需 12 分钟
Tian Pan
Software Engineer

客户支持团队升级了一个问题:“你的助手以前能正确处理退款资格问题。但上周开始出错了。”值班工程师调取了对话记录,在开发账号中使用相同的模型标识符回放了完全相同的提示词(prompt),得到了正确的回答,于是以“无法复现”为由关闭了工单。两周后,另一名客户提出了同样的投诉。工程师再次在同一个开发账号中进行回放,结果依然正确。团队开始归咎于没人做过的提示词更改。

请求中的模型标识符从未改变。响应字段中的字符串与请求字段中的字符串匹配。评估套件在六周内一直保持绿色。生产流量使用的模型权重与评估套件使用的模型权重是两套不同的集合,而且在该账号的整个生命周期中一直如此——直到过去这六周,它们变成了同一套权重,而团队注意到这一点仅仅是因为客户先发现了。

那个按会话分桶并导致 A/B 测试分群漂移的模型发布标志

· 阅读需 12 分钟
Tian Pan
Software Engineer

事后分析会以一句房间里所有人都希望是真的话开头:新模型在满意度上赢得了 4 %,p 小于 0.01,发布吧。一个月后,一项更冷静的分析发现,这种提升其实是一个混杂因素,模型表现实际上持平或略差,而团队在中间几周一直在争论哪个 prompt 更改“导致”了这一胜利。模型本身并没有导致任何结果。实验衡量错了对象,因为标志服务(flag service)和分析流水线在静默状态下对“分群(cohort)”的定义产生了分歧。

这是 A/B 测试中最昂贵的故障模式之一,因为系统中没有任何东西是损坏的。标志服务工作正常。实验追踪器工作正常。仪表板能正常渲染。统计数据是根据接收到的数据正确计算的。故障存在于三个组件之间的缝隙中,每个组件对身份都有不同的假设,而且除非你主动寻找,否则这个缝隙是不可见的。

配额窗口机制重写后,这批夜间脚本是如何拖垮你的交互流量的

· 阅读需 13 分钟
Tian Pan
Software Engineer

一个稳定运行了十个月的 cron 任务是你系统中最危险的任务,因为其中的代码没变,你的代码也没变,唯一改变的是别人发布的、你们团队没人读的发行说明(release notes)中的一句话。那个每晚在 00:05 UTC 启动、在十分钟内清空工作队列并重新进入休眠状态的每晚 embedding 刷新任务,曾是教科书般的范例。它通过在用户醒来前占用几分钟刚重置的每分钟配额,并在当天的剩余时间内保持在每日配额之内,从而与白天的交互式流量和谐共存。接着,服务商重写了每日窗口的核算方式,保持了每分钟窗口不变,并保留了你客户端测试的所有签名。批处理任务依然稳定运行。但每晚 00:13 UTC,交互界面开始返回 429 错误。团队一直在追查一个根本不存在的、本应在一周后才开始的上游维护窗口。

Bug 从不在你的代码里。Bug 在于“每日限制”不再是前一天的意思,而你的调度程序固定在了一个与旧定义对齐的时钟边界上。这篇文章讨论的是:速率限制核算(rate-limit accounting)作为一种服务商可以在不破坏任何签名的情况下修改的契约;两个独立正确的调度是如何组合成拒绝服务模式的;以及如何通过架构手段让 cron 任务不再是一个连接到别人时钟上的定时炸弹。

当 On-Behalf-Of 悄然变成 Act-As:你的智能体继承的 OAuth 作用域陷阱

· 阅读需 10 分钟
Tian Pan
Software Engineer

安全审查称智能体(Agent)“代表”(on behalf of)用户操作。OAuth 令牌却有不同的说法,而审计日志也支持令牌的说法。

语言上的一点微小差别,在架构层面起到了意想不到的作用。“代表”(On behalf of)是安全审查在试图描述一种委派安排时使用的语言,即智能体是一个可识别的委派对象,并受此身份约束。“作为”(Act as)则是运行时的行为,此时智能体持有的令牌与用户本人的令牌完全一致,因此在任何下游系统看来,智能体就是用户。这两个短语描述了完全不同的威胁模型。典型的企业级 OAuth 集成交付的是后者,但宣传的却是前者。

那些被静音的 LLM 报警:当每一次值班看起来都和上一个一模一样

· 阅读需 11 分钟
Tian Pan
Software Engineer

一次真实的回归在生产环境中持续了两天。告警(Page)已经触发了。它触发得完全正确,阈值准确,严重程度也恰当。三周前,值班轮值(On-call rotation)为该告警族添加了一条静默规则,因为该系列中的每一条告警到目前为止都以同样的注释结案:“无须操作,调查中”。复盘(Post-mortem)无法诚实地将这种静默行为称为错误。这是对一系列值班人员没有 Playbook(运行手册)可循的告警流所做出的理性适应。那个重要的回归就在一个被静默的频道中发布了,因为团队的监控栈产生的信号无法指导具体行动,而团队唯一的应对方式就是:停止倾听。

这并不是一个告警 Bug。这是当团队沿用旧有的 Playbook 对 AI 功能进行埋点时,产生的一种结构性特征。延迟、错误率、拒绝率、输出 Schema 符合度、Judge-eval 漂移——每一个都是合理的指标。每一个触发时都带有同样模糊的“模型行为改变”措辞。但它们都没有告诉值班工程师该做什么,因为没有人写过将每个信号映射到具体动作的 Runbook,因为大多数情况下,信号并不能对应到具体的动作。值班轮值吸收着噪音,直到噪音盖过了信号,然后值班人员就会绕过产生这些信号的频道。

系统提示词提供的人格,模型每次都会以同样的方式选择

· 阅读需 11 分钟
Tian Pan
Software Engineer

我最近接触的一个产品团队针对回复人格设定(简洁、详尽、对话式)进行了一项为期三周的 A/B 测试,覆盖了所有用户群组。系统提示词描述了这三种设定,并要求模型选择最匹配用户的那一种。当他们打开数据集编写分析报告时,一个数字让他们愣住了:“详尽”组占据了 91% 的流量。另外两组的比例小到几乎可以忽略不计。

他们的实验平台没有标记任何异常。没有触发任何警报。流水线完全按照他们的指令运行。三周所谓的“多人格测试”产生了一个只能告诉他们关于“详尽”信息的数据集。另外两组样本太少,根本无法进行任何统计推断。

房间里的第一直觉是提示词需要改进——更好的指令、更清晰的人格区分、为对话式场景提供更刻意的示例。如果是在十年前基于规则的路由器中,这个诊断是正确的。但对于模型来说,它是错误的。提示词不是变量,路由器才是。