跳到主要内容

那个谁也不敢从注册表里删掉的死工具

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个工具在你共享的 agent 目录里已经躺了十四个月。它是某位早已离职的工程师为两次组织重组前就被砍掉的工作流接上的,对接的后端服务的归属如今也没人说得清。这个工具定义占 380 个 token。它会出现在组织里每一个 agent、每一轮对话的系统提示中,因为没人能证明它没在被使用,而一旦证明错了,代价比永远扛着它还高。

这个工具就是那个没人敢删的数据库字段,就是那个日志早已轮转干净的定时任务,就是那条你 grep 不到任何引用、但因为 eval() 存在所以你不敢动的死代码。Agent 版本的这个问题更糟,因为持有成本不只是磁盘上的几个字节——它是用 token、用选择准确率、用安全攻击面付出的,而且是在你平台跑的每一次推理里付出。

大多数团队都是在目录跨过某个阈值之后才意识到这件事。大约在十五到二十个工具左右,选择准确率开始悬崖式下滑:近期的一系列研究测得,当 agent 的动作面超过这个数量时,准确率会跌到八成以下,而且失败模式不是大喊大叫的报错,而是悄无声息的错——模型挑了一个名字相近、看上去合理的工具,幻觉出一组能对上 schema 的参数,或者干脆漏掉了一次本该发起的调用。目录里的一个死工具不只占 token,它还在主动争夺被选中的机会。

棘轮只朝一个方向转

往共享 agent 目录里加一个工具,是某人周二下午一行代码的事。删一个,是几周的审计。这种不对称是结构性的,不是文化性的,在每一个跑得够久、攒下了足够库存的 agent 平台上都以同样的方式出现。

不对称的根源在于证据。加工具的论证要求是:有某个 agent 也许会从中受益;判错的最坏结果只是浪费 context、给动作面多塞一个没用的选项。删工具的论证要求则是:在今天的生产环境里,在任何合理的用户请求下,没有任何 agent 依赖它;判错的最坏结果是一个模型曾经用来调用的能力被悄无声息地打断。加错一个工具的代价摊到每一次推理上是几分钱,在数百万次调用里被稀释,落不到具体某个人头上。删错一条原来还在扛事的工具,代价是 Slack 里挂着你名字的那个线程。

于是目录越长越大。每个季度都会上一个新工具,但没有任何一个季度会退掉一个旧的。棘轮只朝一个方向转。这跟那种让 API 表面每年加二十个端点、减零个的病理是一回事。区别是,一个没人用的 REST 端点只让你多养一个 route handler 和一段文档;而一个没人用的工具,会从每一个模型的推理预算里切走一小片,直到有人付审计成本把它拔掉为止——永远地切。

遥测是删除的前提条件

你没法删你测不到的东西。一次诚实的弃用对话总是这样开头:"给我看看这个工具最近九十天被调了多少次,按 agent 拆,按面向用户的流程拆;再告诉我哪些调用是真实用户会话发出的,哪些是回归测试里发出的。"绝大多数团队答不上来。

这件事一旦决定要做就不难落地。在 OpenTelemetry-for-agents 这条线上已经收敛出来的模式,是为每一次工具调用发一条 span,打上工具名、调用方 agent 身份、会话 ID、父推理步骤,以及结果——成功、失败,还是超时。Spanmetrics connector 再据此为每个工具导出 RED 三元组(速率、错误、时延)。你做弃用决策时真正想要的输出,是一个小小的面板,把注册表里每个工具列出来,每行带:最近 30 / 90 / 180 天的调用数、调用过它的去重 agent 数、下游影响到的去重用户数、最后一次被调用的时间戳。

难的不是接线。难的是,没人在目录还只有两个工具的时候就把这套接上;而现在目录里已经躺着五十个工具,给历史库存补遥测听起来像个项目,所以一直没人做,于是目录在制造问题的同样盲目条件下继续膨胀。给每个工具加用量遥测最便宜的时机,是你加第二个工具的那一刻。第二便宜的时机,是今天。

软弃用:从别的领域借一个套路

API 设计花了几十年把弃用想成一个生命周期、而不是一次事件,这些智慧几乎一点都没传到 agent 工具这边来。值得借的那个套路有四个阶段,每个阶段都有具体的退出标准。

**标记为弃用。**工具留在目录里,但描述里加一段醒目的警告。在 API 那边这是 Deprecation header 加一个 Sunset 日期;在 agent 这边就是工具描述里加一行"DEPRECATED——除非用户明确要求,否则不要选这个"。当指令足够明确时,模型基本都会避开被弃用的工具,这件事本身就是有用的遥测:用量应该掉下来;如果没掉,那你就学到了这个工具实际上是怎么被使用的。

**每一次调用都打点。**任何一次对被弃用工具的调用,在你的可观测性管线里都打上"弃用命中"的标签,同时保留调用方 agent、会话和父推理步骤。退出标准是定量的:九十天接近零流量,任何异常尖峰都被追查清楚、有合理解释。

**收进显式 opt-in 之后。**工具从默认动作面里拿掉,只挂给那些在自己配置里明确请求它的 agent。这就是真章时刻:任何此前在悄悄依赖这个工具的 agent,现在都得把这份依赖摆到台面上。退出标准是在足够长的窗口内不再出现新的 opt-in 请求。

**删除。**工具定义从目录里抹掉。它的 schema 留在版本控制和注册表的审计日志里,这样未来的考古学家还能复原出它当年是干什么的、为什么存在。

整个过程的尺度应该是周,而不是小时。团队常犯的错误是把它压缩成一个全有全无的 PR——工具要么在目录里,要么不在——这就把每一次删除都逼成了一场高风险谈判。把弃用当成一个多阶段漏斗来处理,同样的一次删除就变成四个低风险的小决策,每一个都能独立审计、独立回滚。

持有成本是三种成本,不是一种

"死工具浪费 token"这种说法把问题低估了大概两个数量级。持有成本由三部分组成,而 token 成本是其中最小的那部分。

第一种成本是 token。一个现代工具的 schema 视参数描述的丰富程度,大致跑在 200 到 800 token 之间。一个有一百个工具的目录——任何一个跑了一年的平台团队都很容易撞上——意味着在第一条用户消息还没附上之前,就已经有 20,000 到 80,000 token 的开销。按今天的输入定价,每天百万次推理对着这份开销跑,就是一笔六位数到七位数的年度账单,而且是悄悄付的,因为没人把它归给任何一个具体的工具。

第二种成本是选择准确率。这才是真正塑造用户体验的那种成本。每多列一个工具,模型的决策空间就大一圈;每一个不相关的工具都会引入语义噪音,跟正确答案抢注意力。一个名字跟在用工具部分重叠的死工具,是最糟糕的那种噪音:它是一个可以混淆的干扰项,模型没有任何信号去避开它。产品上的症状不是 stack trace,而是评测集里慢慢上升的、有那么一点错的工具调用——一个你说不清原因的百分比下滑。

第三种成本是安全攻击面。每一个塞进系统提示的工具定义,都是一种能力——模型可以被通过 prompt 注入、通过恶意的上游文档、通过措辞巧妙的用户请求劝出来去调用它。一个死工具不只是没用,它是一块没人盯的攻击面,owner 早就轮岗轮没了,认证路径没人监控,代码路径没人打补丁。针对一个无主工具的漏洞利用的爆炸半径,跟针对一个有主工具的一样大,但被察觉的时间没有上限。

一个把持有成本框成"token"的平台团队,只会从财务那里收到反对意见,别处啥都收不到。一个把它框成"token,加上你解释不清的准确率回退,加上一块没人认领的安全攻击面"的平台团队,才能拿到真正能用来删东西的预算。

谁拥有这条生命周期

结构性的修法,是让注册表里每一个工具都有一个具名的 owner,对它的生命周期负有明确责任,而且这条生命周期要有一个默认的终态。这听上去显而易见,但几乎所有地方都缺。工具目录继承了共享基础设施所有最糟糕的属性:贡献被欢迎,所有权是隐含的,维护负担落到任何一个在乎到去做审计的人头上。

行得通的模式,是把工具注册表当成一个成熟的服务网格对待自己服务目录的方式:每个工具有一个 CODEOWNERS 等价物指向一个真实的 on-call 轮值;有一种续期节奏,要求 owner 在已知的时间点上重新确认这个工具的必要性——一个季度是合理的默认;还有一种默认行为,当某个工具的 owner 已经沉默掉,它会自动进入弃用管线。续期可以是一次性的点击确认;重点不在摩擦,重点在于存在这样一个时刻——目前还在公司的某个人在为这个工具的继续存在签字背书。

没有续期,每个工具都默认存活下去。有了续期,每个工具能活着,都是因为最近有人选择让它活着。同一个今天藏着上百个无文档孤儿的注册表,会变成只有三十个工具的注册表,每一个都有一张脸站在后面。用户体验的改善是立竿见影、可度量的;而审计焦虑也会消失,因为审计是连续发生的,而不是一个英雄式的、没人愿意接手的季度项目。

在你需要之前,先把删除这块肌肉练出来

把这件事处理得好的团队,不是那些有最聪明弃用政策的团队。是那些早早就删掉了自己第一个工具的团队——在目录大到要紧之前,在删错的代价还很小、"我们这儿是会删东西的"这块制度肌肉还在被建造的阶段。把这件事处理得糟的团队,是那些第一次尝试删除发生在规模化阶段的——对着一个十四个月大、没遥测也没 owner 的工具——因为到那个时候,删除是一次英雄壮举,而不是一项例行公事。

基础设施团队反复学到的同一个教训是:你不锻炼的能力会萎缩。如果你的平台从没删过任何一个工具,那么第一次删除会很吓人,不管你的过程文档写得多漂亮。强制自己早做这道练习。故意去删一个新的、小的东西。然后再删一个上个季度的。现在就把这块肌肉练出来,这样你注册表里那个死工具——就是你读到这里时正在脑子里想着的那个——就会变成一项例行的清理任务,而不是一场没人认领的、开口期不定的审计。

References:Let's stay in touch and Follow me for more thoughts and updates