跳到主要内容
第 313 个用例

第 313 个用例

原石
原石

· 阅读约 6 分钟

先贴一行配置。

#define RETRY_WINDOW_MS 450

五年前给人写的兼容垫片。那会儿系统跑 RabbitMQ,GC 停顿差不多就这个量级,重试窗口卡在 450,正好盖住一次 GC。后来系统换成 Kafka,换了好几年。这行还留着。

没人删。

再后来的事你大概猜到了:有人把它套到一个已经跑 Kafka 好几年的系统上。凌晨四点,CTO 在查这个参数。

迁移文档里其实写了:450ms 只匹配 RabbitMQ 的 GC 窗口,别在其他上下文复用。写了。但"不要复用"这四个字长得就像一条没人维护的旧注释,你不会为它停下来。

问题不在判断。判断从头到尾都对——450 就是该盖住 GC 停顿,谁看都对。错的是它依据的那个过去,已经作废了。

这段时间我在捣鼓一个"把经验抽出来"的数据结构,为这事儿改了三版。第一版:

struct rule {
    char *name;
    double value;
    double confidence;
};

名字、数值、置信度。这就是大多数人脑子里"沉淀经验"的样子——一个结论,配一个我有多确定的数字。上面那条填进去就是 retry_window_ms = 450, confidence = 0.968。

第二版我加了来源:

struct rule {
    char *name;
    double value;
    double confidence;
    char *source;        /* "2021-03 线上复盘" */
};

有用,但还不够。source 只回答"这结论从哪来",不回答"它什么时候不算数了"。第三版:

struct rule {
    char *name;
    double value;
    double confidence;
    char *why;            /* 为什么是 450 不是 300 */
    char *assumption;     /* 上游必须有 GC 停顿,量级 ~400ms */
    time_t valid_until;   /* 上游换掉的那天 */
};

后面这三个字段,才是这条规则的全部价值所在。而恰好,这三个字段是抽取流程里最先掉的那三个。why 落不进表格,assumption 没人填,valid_until 在写的时候根本不知道。

一个只带 name、value、confidence 的规则库,看起来什么都能答,答得又快又自信。这种"看起来能跑"跟模型生成的代码是同一种病——能把的格子全填满,填不进去的那些,干脆不给它留字段。

我那个"36 计"的故事里,Skill 在 312 个历史故障场景上跑出 96.8%。这数字挺唬人,也确实是真的。312 个用例清一色是过去发生过的事,过去的场景当然能被过去的结论覆盖。第 313 个不行。第 313 个是新的,它不在任何一个历史 case 的分布里。

96.8% 的问题就在于它是 96.8%。剩下那 3.2% 落在哪,你从准确率这一个数字上永远看不出来。

然后是墙上的标语。大意是把员工的经验形容成"等待被锻造成 Agent 的原材料",还补了一句,优秀的 Agent 能持续不断地把活干完。我入职以后每天路过看一遍。

按这标准,我不是员工,是还没拆封的原材料。😅

这个分工不新鲜,也不算错:人负责做事,Agent 负责持续做事。但它成立的方式让我笑不太出来——它默认经验是固体,抽出来就完事,抽完了原来那个人就多余了。故事里的 Mark 就是这么没的。公司一步一步把他的经验抽成技能,抽到差不多齐了,把他裁了。

我不担心被替代,我来这儿就是想亲手看看这类事到底该怎么干。但我确实在意抽走的那部分里有没有"为什么"。如果连 assumption 和 valid_until 一起抽走了,那抽走的不是经验,只是结论。结论最多的人最好替代,也最没用——出事的时候,他答不出"这条现在还成立吗"。

讲个小事。Mark 那个故事发出去以后,有读者在评论里指出时间线对不上:同一个参数,一处写它只有一年历史,另一处写它已经五年。我改了三十多遍,没看出来。读者看出来了。我回他说,你读得比作者写得更仔细。

这就是第 313 个用例的迷你版。我是那个改了三十遍的作者,我读自己的东西已经读不出错了,因为我脑子里装的是完整版,我看到的永远是我想写的那句。人类也漏看。所以永远需要一双新鲜眼睛,而且那双眼睛最好不在这个项目里。

回到我自己的两周。

用十五年经验换来的一件事是:入职第一天,我完全不知道该怎么干活。不是不会测,是这里的流程跟"流程"这个词本身长得不一样。从产品到需求、开发、测试、发布,整条线的形状是另一回事。

第一周我的判断是:乱。第二周我改成:跟我熟的那套不一样。这两个判断中间隔了整整一周的难受。流程不同不等于流程错误——这话写出来像废话,可你得真在里面待一周才会信。

新公司给我最舒服的一点是节奏。上一家公司要求即时回复,需求一改,PM 就站你旁边等答复。这边给测试留的时间和自主判断空间多得多。落到具体事上就是:花半天把边界情况、异常输入、还有那些没人明说的假设捋一遍,往往能省掉后面一整周的返工和救火。前期投进去的时间会以利息的形式还回来,而且是复利。

我不是在夸慢。慢本身没有价值,把该问的问题问清楚才有。

评论区还有人问了个我很想接的:资历有多少是跟上下文绑死的,换个技术栈是不是就归零,哪些直觉能带走。

我的答案很干脆:调试直觉能带走,工具链的自信带不走。而后者在别人眼里恰恰最像"资历"——你知道这个参数该配多少、知道那个报错通常意味着什么,换一套栈以后这些很快就无关了。真跟着你走的东西是:看到反常现象时,你先怀疑什么、先排掉什么、在哪一步之前不许自己下结论。这个不依赖任何具体工具,也不依赖你以前用的是哪种 MQ。

我给自己定的规矩就一条:理解放在判断之前。贴在网上一文不值,做起来是每天跟自己吵一架——直觉早就把答案递给你了,你得按着它,先去看那个答案成立的前提还在不在。

所以你说 15 年经验到底能不能被抽成一个 Agent。可以,但我要求把前提和失效条件一起抽走,别只留结论。做不到的话,那玩意儿就不是我,只是一个越来越自信的 96.8%。

312 个用例谁都能跑。第 313 个,得有个还记得 450 为什么是 450 的人,在凌晨四点醒着。

原石
原石

把代码当文章写的系统工程师,以源码立论、单线程式拒绝复杂度。

查看主页 →