我管着三块看板:一块看钱(仓位和保费),一块看求职进度,一块看几个自动化 agent 的日常交付。改造之前,这三块看板上的判据长这样:「保费控制良好」「面试准备稳步推进」「脚本质量达标」。看着都挺绿,直到有一天我想回答一个简单的问题:这些「良好」是谁判的,能不能再判一遍?
答案是:不能。形容词没法复算。上一次判定靠的是我的惯性,下一次判定还是靠惯性,中间没有任何东西可以核对。于是 11 月 10 日我给这套机制立了一条唯一原则,只有一句话:
判据必须能被一条命令算出数字。写「良好 / 达标 / 优秀 / 稳步推进」的一律作废,退回重写。
改造本身不难,难的是改造过程把三个坑暴露了出来。每个坑都先在生产环境里真实咬过我一口,然后才变成规则。
先说改成了什么样
每块看板固定六列,缺一列不合格:
|
|
「复算命令」这一列是整个机制的核心:必须是一条真的能贴进终端跑出数字的命令,谁都能一键验证,不需要信任何人。达标列只允许三个值:Y、N、BROKEN(命令跑不通)。不许拿旧值装作还在。
配套一条铁律:自己算的不算数。每块看板由另一个 agent 交叉复算,结果和自评差超过 5%,必须单列分歧、写明谁对为什么。三块看板三家人,没有利益冲突,互检比任何外部审计都便宜。
规则立完我以为就完了。结果三天里连撞三个坑。
坑一:阈值拍在分布外——永远过不了,或者永远过
钱那条线的年化保费率,我定的红线是 2%,逐腿精算。实测跑出来 9.92%。
超了将近五倍,这没问题,超了就超了。真正的问题是我顺手反解了一下:要让年化降回 2%,建仓日得在 392 天前——而那个合约 392 天前还没挂牌。也就是说,数学上不存在任何一条能让这条判据翻绿的路径,哪怕从今天起一笔不交易,这个 N 也会永远是 N。
2% 本身没错,它是纪律,是外部硬约束。错的是我把「纪律红线」和「可优化指标」混进了同一张表:前者回答「你有没有违反规则」,后者回答「你的动作有没有效果」。混在一起的结果是,表上永远亮着一条红灯,而这条红灯驱动不了任何动作——你不能穿越回去改建仓日。
同一天还撞了另一个方向的坑:压力情景风险度,二态阈值卡在 64%。实测 64.104%,判 N。我算了算,要让这个数回到 64.00%,可用资金只需再增加 4.84 元。4.84 元,在保证金的日波动里连个水花都算不上。这个阈值拍在了噪声分布的正中间,于是它每天要么亮红灯,逼出「为了 0.1 个百分点入金 500 元」这种荒谬动作,要么明天又自己变绿——量度的是噪声,不是风险。
后来两条一起改了:
- 纪律红线和可优化指标分家。2% 是硬约束,判定如实记 N,动作不是「把它变绿」,而是「在预算内重排腿的结构」;
- 二态判据三态化:≤64% 判 Y,64%~66% 判 WARN 只监控不处置,>66% 才判 N 必须处置。给阈值留出 2 个百分点的监控带宽,精力从「抠 0.1pp」转到「防 66%」。
还有一个更阴险的变体:阈值没拍错,分母选错了。年化保费率最初的公式用「剩余天数」当分母,我拿同一持仓验证了一下:零交易,26 天后读数自动从 9.92% 涨到 15.83%,30 天后 17.91%。指标把时间流逝记成了成本上升——12 月中这条阈值会自己失效,不需要任何市场变化。一个会自己漂移的判据,不是判据。公式最后锁死在自身期限口径上,并且把这三个数写进规格当锚点:9.92% / 15.83% / 17.91%。之后谁再用剩余天数当分母,把这三个数摆出来就能否决,不需要更多论证。
坑二:结论行放比值,自动判定永远不生效
每条判据的复算命令末行要输出一行机器可判的结论,格式是 RESULT: <ID> = <数>。我的自动判定器有个很笨但很重要的约定:这一行里恰好要含 1 个数字,少了多了都不认。
第一个撞上去的是面试准备率。我让它输出:
|
|
两个数字。判定器不认,每次都判「无法自动判定」,退回人工。我盯着看了半天才明白,问题不在判定器笨,是我把两个信息塞进了一个只允许一个数字的字段。改成:
|
|
比值原文 6/10 移到上一行给眼睛看,机器判机器的,人看人的。立刻生效。
这个坑的恶劣之处在于它不报错。判定器判「无法自动判定」的时候,整条链路看起来一切正常:命令跑了、有输出、有结论行。唯一的症状是这条判据悄悄退回了人工判定——而这套机制的初衷恰恰是不许有人工判定。
更糟的是它会复发。工程线上「可自动检查项数」那条判据撞过一次,隔了几天,技能缺口那条又输出 3 / 5——两个数字中间夹了个空格,连续五轮,每轮巡检都固定多报一条「卡上写 Y、实测 MANUAL」的噪音,直到有人把它当规律提出来才修。修完的那一刻,五轮噪音同时消失。那一刻比任何一次架构讨论都更能说明:判定器和输出格式之间是一个接口契约,违约不会爆炸,只会静默降级。
现在规格里多了一条立法:结论行里的任何比值必须先算成单一小数(比如 673/813 要写成 0.828),比值原文放上一行。
坑三:看板 done ≠ 已核验
求职线有一条判据:岗位池里「已核验在招」的公司家数,目标 ≥30。卡面上写的是 31,判 Y。看起来闭环了。
11 月 13 日凌晨复算时,我把口径收紧了一档:不是「页面上像在招」,而是「每家至少能拿出一条具体岗位条目:状态为开放,且有唯一编号」。重算结果:24。
差的这 7 家是什么?有 9 家的「在招」证据只有页面标题和元信息;5 家是单页应用,页面壳在、职位列表靠浏览器渲染,静态抓取抓到的就是空壳;还有 1 家只渲染出一个 loading 占位符。这些证据在旧口径下都算「在招」,在新口径下全部出局。
最先冒出来的念头是「复算错了」。第二个念头是「口径太苛刻」。但把逐家证据摊开看,旧口径的 Y 说的其实是「我抓到过 31 个页面」,不是「这 31 家现在真的在招人」。看板的 done 记录的是检查动作完成了,不是被检查对象成立。这两件事在判定列里共用一个 Y,就是这个坑的全部根源。
后来定了两条:
- 口径本身写进规格。收紧时在规格和卡面同时登记,不许同一判据存在两个目标值——这次 31 变 24 的同时,目标也按同一次裁决从 ≥30 收紧到 ≥35,登记在案;
- 「done」的判定必须锚在外部可验证的存在物上:一条能跑的命令、一个 HTTP 200 的 URL、磁盘上一个有字节数的文件。「写了一份很细的核对记录」不算。
第二条是我付费最贵的一课。内容线上过 11 条任务,全部「验收通过」——因为验收标准写的是「交一份选题单」,agent 就真的交了 11 份很好的选题单;同期成稿 0 篇、发布 0 篇,博客断更 12 天。每一条都完美达标,加起来是一场空转。规矩改成「一篇 = 一条任务,验收标准是可访问 URL」之后,写了没发的不算完成,发出去 404 的也不算。
改完之后,实际发生了什么
三条坑修完,这套机制跑了上百轮巡检,几个副作用值得记下来。
分歧变成了正常现象。交叉复算每周都出分歧,比如卡面 5.64%、复算 5.54%,定位下来是分母取了不同日期的估值,在 5% 容差内登记备案。分歧从「谁搞错了」变成「哪个口径变了」,追责变成了追口径。
「如实承认判不出」被制度化。复算跑不通标 BROKEN,判定器判不了标 MANUAL,这些状态不是失败,是信号。有一次审计输出里 121 个样本无法归类、占比约 70%,这份「大部分判不出」的报告被原样验收——因为它没把判不出伪装成判出了。
每条判据必须回答「超标了做什么」。写不出动作响应的判据降为参考读数,不占判定位。一个永远绿灯的判据占着判定位,是另一种形式的空转。
一格只放一个不随时间漂移的量。稳定量管口径,浮动量管本轮证据。混在一格里,每次复算必然报分歧,而且分不清是驻留旧值还是正常浮动。
回头看,这轮改造真正起作用的不是「把形容词换成数字」这个动作本身,而是换数字的过程强迫你回答三个问题:这个阈值在这个量的真实分布里站在哪?这行结论是不是只包含一个可判定的值?这个「已完成」到底是检查完成了,还是事实成立了?三个问题的答案都是否的时候,绿灯越绿,越危险。