代理墙钟预算:一场与工具超时机制的赛跑
有一种 Agent 漏洞,当你孤立地观察任何单个组件时,它都不会出现。模型没问题,工具没问题,重试策略也没问题。纸面上的超时值甚至可以说很慷慨。然而,一个通常在 8 秒内完成的工具,却总是在一个已经在 7.9 秒时将其宣告为失败的 Agent 面前折戟。Agent 围绕一个从未发生过的“错误”重新规划,并启动了第二次调用,而第一次调用的结果即将与其发生碰撞。
漏洞不在任何一个框框里。它存在于两个没人同意应该同步的时钟之间的缝隙中。
有一种 Agent 漏洞,当你孤立地观察任何单个组件时,它都不会出现。模型没问题,工具没问题,重试策略也没问题。纸面上的超时值甚至可以说很慷慨。然而,一个通常在 8 秒内完成的工具,却总是在一个已经在 7.9 秒时将其宣告为失败的 Agent 面前折戟。Agent 围绕一个从未发生过的“错误”重新规划,并启动了第二次调用,而第一次调用的结果即将与其发生碰撞。
漏洞不在任何一个框框里。它存在于两个没人同意应该同步的时钟之间的缝隙中。
一个只被写入却从未被读取的缓存算不上缓存。它只是一个增加了额外延迟、按 KB 计费的日志系统。而这种失效模式最残酷的版本是,从每个角度看缓存都是健康的:set 调用成功,get 调用返回迅速,键(key)格式正确,值(value)有效,TTL 设置合理。唯一的问题是,没有任何一次 get 调用能找到之前 set 调用写入的键,因为键中的一个字段在每次计算时都会发生变化。
这是一个关于调试过程的故事:为了“能分辨出我正在看的是哪条缓存记录”,一位工程师在缓存键中添加了一个时间戳。结果,在没人察觉的两个星期里,系统悄悄地为每场对话多支付了 14 次额外的 LLM 调用费用。
一个检索增强生成(RAG)管道可能会连续数周出现性能退化,而没有任何指标能察觉到。相关性评分看起来正常,检索延迟没有变化。触及受损主题的评估切片(eval slice)向错误方向移动了 0.25 个点,而你的每周审查将其归因于噪声。直到有人阅读了模型为某个客户工单实际接收到的上下文窗口,发现同一个段落出现了三次——一次是标题格式,一次是小写格式,一次是去除了标点的格式——你才意识到,一个月以来,你的前五名(top-five)在暗地里其实只是前二名。
这类故障的特点是:系统完全在按照指令行事。检索器正在返回与查询最相似的向量。这些向量中的每一个都确实与正确的主题相关。索引根本不知道其中三个向量来自同一个段落(只是以三种方式索引了三次),因为原本应该捕获这种情况的入库阶段去重环节正在静默跳过它。
你的仪表盘显示缓存命中率为 71%。你的财务伙伴很满意。你的 p50 延迟也表现正常。然而,一个来自长时间运行的智能体(agent)会话的客户支持工单传了过来:第 14 轮对话花了 11 秒才产生首个 token,第 15 轮花了 8 秒,第 16 轮花了 9 秒。你调出链路数据(trace)。每一轮对话报告的 cache_read_input_tokens 值都是 0。系统提示词有 1.6 万个 token。用户认为智能体坏了,你认为你的供应商坏了。你们两个都不对。总体的命中率是一个幸存者统计数据 —— 它平均了那些容易命中缓存的短对话,并悄悄吸收了那些在会话中期崩溃为“首轮冷启动”的长对话。
这是任何供应商的复盘报告都不会向你描述的故障模式,因为从他们的遥测数据来看,系统正在按设计运行。负载均衡器正在做出它被要求做出的路由决策。缓存正按照它被要求遵循的时间表进行填充和置换。你传递的提示 —— prompt_cache_key、会话 ID、用户 ID,或者你序列化到该字段中的任何字符串 —— 始终都只是建议性的,而“建议性”意味着“在方便时会被忽略”。在负载压力下、发生扩缩容事件时、上游节点(pod)正在排空时,或者亲和性感知层饱和时,你的提示会悄无声息地降级为均匀的路由决策。请求落在一个冷启动的节点上。原本可以以亚毫秒级成本提供服务的前缀 KV 张量就在 16 英尺外的兄弟机架上,却无法访问。你的对话再次支付了全额前缀成本,而你仪表盘上的标题数字纹丝不动,因为另外 2000 个只有一轮的对话都正常命中了缓存。
合规审计总是从同一个问题开始,而你的团队也总是以同样的方式回答:“客户数据在哪里处理?”在欧盟(EU)地区。幻灯片是这么说的,SDK 配置截图证实了这一点,DPA(数据处理协议)也做出了承诺。接着,审计员提取了上个季度的请求日志样本,将其与服务商的每请求区域头信息(per-request region header)进行比对,房间里顿时安静了下来。在大约 40 分钟的容量事件期间,大约 4% 的欧盟企业 Prompt 由美国区域的推理节点提供服务,而团队对此一无所知。保存可重用前缀(prefixes)的缓存位于全球池中。支持团队查询的追踪存储(trace store)位于 us-east。DPA 成了幻灯片。合同成了一个路由提示(routing hint)。
这种事件不会出现在事后分析(postmortem)中,因为没有任何服务降级。模型返回了答案,用户得到了响应,延迟图表保持平稳。出故障的是仪表盘从未监测到的东西:请求穿过服务商基础设施的地理路径。那些绝不会将 us-east-1 的 URL 与“请求实际上在 us-east-1 执行”混为一谈的工程师,在 LLM API 层级却经常犯同样的错误,因为服务商的区域参数看起来像 AWS 的参数,在正常路径(happy path)下表现也像 AWS,但一旦首选区域的 GPU 耗尽,它就会静默降级为“尽力而为(best effort)”模式。
你的重试逻辑在遇到 429 时会退避。当延迟上升时,你的队列深度告警会触发。在这两个信号之间,存在一个供应商负载区间,此时正确的做法是“减速 20%”——而供应商唯一会告诉你的是那个姗姗来迟的二进制限流信号。对于智能体集群协作来说,最有用的信号恰恰是没有任何推理 API 真正公开的那个。
429 是墓碑,而不是警告。当你收到它时,供应商已经认定你的流量过载,你已经浪费了一次请求的 Token 计数,而且——如果你与其他消费者共享租户——他们可能也收到了。有趣的故障模式不是 429 本身;而是它发生前的几秒钟,那时全世界的客户端都在“一切正常”和“你被切断”之间盲目飞行。