跳到主要内容

861 篇博文 含有标签「insider」

查看所有标签

你定义‘首个 Token’的位置决定了你的延迟 SLO 是否真实

· 阅读需 11 分钟
Tian Pan
Software Engineer

我上季度合作的一个团队在周二发布了推理层升级,周三就开始收到支持工单。用户反映助手感觉“坏了”、“冻结了”或“卡住了”。值班工程师查看了延迟仪表盘,没发现任何异常。p99 首字延迟(first-token latency)为 612 毫秒——远低于团队花了一个季度建立的 800 毫秒 SLO。仪表盘是一片绿色。电话却响个不停。

问题的根源在于 14 个月前做出的一个埋点决策,当时生产环境中还没有推理模型。标记为 “first token” 的指标测量的是供应商发出的第一个数据块(chunk)的时间戳。升级后,第一个 chunk 变成了推理 token——这对用户不可见,也从未渲染,但在 SLO 中却被计为“首个”。模型在流式传输第一个用户可见字符之前,会先发出 4 到 7 秒的内部思考过程。每个图表依然是绿色的。每个用户却在黑暗中等待。

这不是一个关于指标好坏的故事。指标对于它最初设计的模型来说是正确的。这是一个关于当你的埋点边界不再是用户的感知边界时会发生什么的故事——以及在不知不觉中发布这种偏差是多么容易且危险。

你的编程智能体忘记检查的分支状态

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的编码智能体并不知道它在哪一个分支上。它以为它知道。十二轮对话前它看过 git status 的输出,它的上下文中有一份 CLAUDE.md 提到了会话开启时的分支名称,并且它观察到一个工具结果列出了五个当时正确的文件。从那时起,智能体就一直在基于那个快照进行静默推理。与此同时,你在另一个终端里运行了 git checkout main。智能体的 diff 顺利地写入了文件系统,因为操作系统并不关心这些字节属于哪个分支。这个 diff 在语义上是错误的,因为智能体对分支的心理模型已经落后了 300 个提交,且它所基于的父节点在你的工作树中已不复存在。

这就是分支状态漂移 (branch-state drift),它是数据库中“读-改-写”竞态 (read-modify-write race) 在编码智能体领域的翻版。智能体在第 N 轮读取世界状态,在第 N+1 到 N+k 轮之间修改计划,并在第 N+k+1 轮写回磁盘——而在这一时间窗口内的某个时刻,它脚下的世界已经发生了变化。没有异常抛出,没有工具返回错误。补丁被应用了。危害在下游显现:针对错误的基准分支开启了 PR,手动提交的代码被静默回滚,或者针对昨天刚迁移过的模式 (schema) 实现了新功能。

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

· 阅读需 11 分钟
Tian Pan
Software Engineer

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

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

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

那些在本地通过但在 CI 中失败的编程智能体

· 阅读需 12 分钟
Tian Pan
Software Engineer

智能体(agent)生成的 diff 在你的电脑上显示为绿色。测试通过了,lint 通过了,开发服务器也干净地完成了热重载。你让它提交了 PR,九十秒后,CI 在一个与修改完全无关的步骤上报错变红了:缺少某个 CLI 工具、一个智能体从未声明过的新环境变量,或者 Node 版本解析结果不一致——因为你的 .nvmrc 是通过 runner 并不具备的全局 shim 进行解析的。智能体并没有写出有问题的 diff。它写出的是一个依赖于你机器环境的 diff,而你的机器和 runner 并不是同一台电脑。

“在我的机器上能运行”曾是一个人为 Bug。解决办法是保持纪律性——锁定版本、编写 Dockerfile、阅读 CI 日志。而编程智能体大规模地继承了这个 Bug,却丢弃了曾经用来弥补它的纪律性。因为智能体不知道它所依赖的东西哪些来自代码库,哪些来自你 shell 历史记录中的“温热沉淀物”。每个开发者的笔记本电脑都是一个配置独特的环境,智能体在不知不觉中吸收了这些环境。接着,同一个智能体在一个完全不具备这些条件的 runner 中运行,失败的表象看起来像是智能体的错,但实际上是由于没人写明的一份环境契约。

对话树:你的服务器作为日志存储的对话结构

· 阅读需 12 分钟
Tian Pan
Software Engineer

用户输入“其实,我的意思是五十,而不是十五”,点击最后一条消息上的铅笔图标并进行编辑。UI 表现得非常出色:它向用户展示修改后的消息,淡出旧消息,将助手过时的回复变为带删除线的“幽灵”状态,并呈现一段流畅的对话,读起来就像最初的错误从未发生过一样。用户心满意足地发送了下一轮对话。而智能体却用“十五”进行了回答。

Bug 不在模型身上。模型准确地接收了服务器发送的内容,而服务器发送的是:原始消息、原始助手回复、撤回动作、修改后的消息以及新的请求——所有内容按顺序拼接在一起,实时发送。用户在进行一场已经编辑过的对话。而智能体在进行一场从未被编辑过的对话。两份对话记录在第三轮开始分叉,此后再未统一,之后的每一轮对话都在为这一差距支付“利息”。

你在三月份录制的演示视频是它最后一次正常工作的时候

· 阅读需 9 分钟
Tian Pan
Software Engineer

一家 B 轮 AI 公司的销售工程师在 3 月的一个周二录制了一段五分钟的演示视频。智能体(agent)在第一次尝试时就选对了工具,用买家的语言组织了答案,并以一种“考虑周全,而非模棱两可”的礼貌态度拒绝了一个棘手的边缘情况。那段录像被存入了资源库。在接下来的七周里,它促成了五笔交易。

到了 5 月底第六个潜在客户在入职培训电话中看到它时,模型已经收到了供应商的小版本更新,重新调整了它的拒绝话术;Prompt 被编辑了两次以修复一个无关的回归问题;工具目录增加了三个条目(模型现在更倾向于其中之一);RAG 语料库针对新的分块器(chunker)重新建立了索引。演示视频不再是产品的录像,而是一个已经不存在的产品的录像。

悄然渗入你提示词中的评估集

· 阅读需 10 分钟
Tian Pan
Software Engineer

基准测试指标连续四个季度上升。用户满意度却没有。团队中没有人能解释这种差距,直到有人对提示词模板进行了 diff,并注意到 Few-shot 示例正从评估器读取的同一个 CSV 文件中获取。评估集已悄然变成了上下文示例。这个指标不再衡量泛化能力。它衡量的是模型在刚被告知答案的情况下,复制与之最接近问题的能力。

这就是我想命名的失效模式:评估集到提示词的泄露 (eval-to-prompt leakage)。它在结构上与传统机器学习中的测试集污染 (test-set contamination) 完全一致,但它是通过团队刻意构建的后端通道发生的。Few-shot 检索是一个合理的工程举措。评估库是一个合理的工程产物。当两者在没有人划定界限的情况下汇集到同一个存储层时,污染就产生了。

那个在 11 小时内烧光你季度推理预算的免费试用

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的试用版提供了“每天 100 次生成”。你的定价团队模拟了一个感兴趣的用户花一周时间进行体验。但第一个将智能体(agent)指向端点的试用者,在 70 秒内就用完了当天的配额,19 分钟内用完了每周配额,并在第二天午餐前耗尽了季度的推理预算。没有人收到警报,因为唯一设置的警报只在试用用户转化为付费用户时才会触发。

试用限制在制定时并没有错。它们针对的是不再适用于当前典型用户的用法分布。在六个月前的定价审查与今天早上的新用户注册之间,用户群体已经从点击按钮的人类转向了不知疲倦的程序。仪表盘上的数字不再代表你设定它们时的含义。

你的编程智能体悄然打破的内部循环

· 阅读需 9 分钟
Tian Pan
Software Engineer

关于编码智能体(coding agents)提高生产力的说法是,它们消除了打字瓶颈。但在实践中,工程师真正遇到的瓶颈却截然不同。工程师再也无法在脑中掌握整个系统,因为智能体修改文件的速度快于工程师阅读的速度,编写测试的速度快于工程师推断覆盖率的速度,重构抽象的速度快于工程师在设计层面(而不仅仅是编译器层面)验证类型检查的速度。

那个紧凑的内环——假设、更改、观察、优化——定义了胜任的工程工作,但它正悄然瓦解为另一种循环。工程师现在是在审查智能体的输出,而不是建立对系统的直觉。2025 年中期的一项 METR 随机对照试验发现,经验丰富的开源开发人员在使用 AI 助手处理熟悉的代码库时,速度慢了 19%,但他们却报告感觉快了 20%。认知感知的生产力与实际生产力之间这 39 个百分点的差距并非测量误差。这是为了吞吐量而默默牺牲理解力的代价。

Agent 循环从搜索框偷走的延迟预算

· 阅读需 13 分钟
Tian Pan
Software Engineer

发布指标看起来很干净。回答质量提升了,引用率上升了,评估套件全绿。那个用基于 Agent 的检索器替换旧关键词搜索的团队发布了产品,赢得了胜利,然后转向了下一个项目。六周后,有人注意到该界面的周活跃用户数下降了 12%,但没人能找到性能回归。其实并没有回归。Agent 运行正常。用户离开是因为以前在 200 毫秒内就能给出答案的搜索框,现在需要 4 秒钟,而发布回顾中没有任何内容涉及到这方面的预算。

这就是延迟预算转移问题,而且几乎没有人会画出能捕捉到这一问题的组织架构图。搜索框不仅仅是一个函数调用。它是与用户神经系统签订的一份为期三十年的契约:输入、查看结果、扫视、点击。200 毫秒的响应并不是某个仪表盘上的性能指标——它是当结果送达时,用户的注意力仍然留在屏幕上的原因。当搜索框背后的团队用 Agent 循环替换关键词索引时,函数调用表面看起来是一样的,但新调用的 SLA 处于一个完全不同的范畴。延迟预算从拥有索引的团队转移到了拥有 Agent 的团队,又从拥有 Agent 的团队转移到了用户身上,而唯一参加会议的只有用户。

悬在两张日历上的多智能体死锁

· 阅读需 11 分钟
Tian Pan
Software Engineer

Agent A 向 Agent B 请求完成其任务所需的一项数据。Agent B 在回答之前,向 Agent A 请求生成该数据所需的一项上下文。这两项请求在发出途中都跨越了“需要人工审核”的边界。第一项请求落入了由 Priya 监看的 Slack 审批频道。第二项落入了由 Marcus 监看的 Jira 队列。Priya 正在吃午饭。Marcus 正在接听客户电话。两人都不知道对方的存在。工作流挂起了 19 个小时,直到一次客户投诉迫使有人去询问为什么汇总结果从未送达,才有人注意到。

这不是一种新颖的失败模式。它是分布式系统中最古老的失败模式,只是换了一身新装。Coffman 条件——互斥(mutual exclusion)、占有且等待(hold and wait)、不可剥夺(no preemption)、循环等待(circular wait)——早在 1971 年就被命名了,而一个带有“人机协同”(human-in-the-loop)审批队列的多 Agent 系统默认满足这所有四个条件。新的麻烦在于,死锁中的“资源”之一是人的注意力,这意味着你的活性保证(liveness guarantee)现在受限于两个互不相识的人独立进行上下文切换的速度。

那个假设人类会阅读页面的 On-Call 运维手册

· 阅读需 11 分钟
Tian Pan
Software Engineer

警报在凌晨 02:14 响起。运维手册(runbook)写着“呼叫工程师”。工程师的名字关联到了一个值班轮值。该轮值指向一个 Slack 频道,这是团队在六个月前建立的统一分诊界面。频道中的第一条消息是告警。十九秒后发布的第二条消息是一段冷静的三句总结:告警服务、失败的依赖项、最后一次部署。它写得很好,最后以“已确认(Acknowledged)”结尾。

事故指挥官在床上看着手机,读到“已确认”后便翻身继续睡去。然而,并没有人确认。作为一线分诊助手的智能体(Agent)订阅了该频道,它向频道复述了告警内容,并以频道中其他读者习惯用来表示“我已掌握处理此问题的上下文”的动词收尾。这起事故在无人接手的情况下运行了 41 分钟,直到一张客户工单通过另一个界面唤醒了另一位工程师。