十月初那篇帖子,标题我记到现在:证人就是嫌疑人。
讲的是 AI 系统的审计日志——干活的那个代理,往往也是往审计记录里写字的那个系统。执行动作和记录动作,落在同一个进程里。
一句话。埋的坑比大多数故障复盘都深。
我干这行养出一个习惯,出了事第一眼不看日志内容,先问一句:这份日志谁写的。答案通常很无聊,程序写的。可代理写的日志跟程序写的不是一回事。程序不会挑对自己有利的话说,代理会——而且挑得毫无恶意,它只是把 success 老老实实填进了 success 字段。
传统软件挂掉是喊出来的。抛异常、测试红、构建炸,整套 CI 就是根拴在脚踝上的绳,谁走错一步当场摔个跟头。
AI 挂掉是躺着的。
输出格式漂亮,字段齐全,语气笃定,错在某个谁都没查过的边界上,或者干脆漏掉一整条关键信息。它不喊。它没有能喊的嗓子。你也没写过那条告警——你想不到它要以这种方式错。于是一份看起来毫无问题的报告,几周后从仪表盘、从生产库、从一批静默错掉的数据里爬出来找你。
——补一刀,那时候谁值班?
监控只回答“是否成功”,等于把麦克风递给嫌疑人:你干成了吗?
那条绿线,只是它自己的口供被渲染成了图表。
我真怕的不是日志缺失。
日志缺失会让我起疑。翻两页没东西,弦立刻绷上,开始翻配置、翻变更记录、翻谁在什么时候动过手。缺失本身就是信号。
干净日志不是。干净日志让人放心。排得整整齐齐、时间戳对齐、结果全绿,我扫一眼就划过去了。放心是值班最大的敌人——你会为一片空白爬起来,不会为一片翠绿爬起来。
有人觉得上个哈希链加个签名就完事了。链能让改写留下痕迹,留不下的是“这条记录本身是不是真话”。防篡改和证真中间隔着一整条护城河,跟“看起来对”和“扛得住凌晨三点”之间的距离一样宽。
评论区有个人,Tom Jones,把“见证者不等于作者”做成了运行时不变式,不是事后告警:网关用第二个模型审便宜模型起草的答案。问题出在限流回退——fallback 一开,审查者可能被换成跟起草者同一个模型,跨模型一致性就地退化成自证。他们的规则是见证槽如果解析到跟作者同一个模型,跳过,沿阶梯往下找独立见证者,找不到就升级请求。
从 10 月 6 号下午到 8 号早上,两个网关 42 个 agreement decision,自证零次,见证者每次都是 Llama 3.3 70B 去看 gpt-oss-120b,其中 4 次不同意、升级了。
听着挺漂亮。
这 42 次里,见证槽一次故障转移都没发生过。
也就是说,那条真能产生自证的路径,压根没被走到。不变式不是验证过,是没赶上。人家自己也交代了:这套检查只覆盖没测试的 prose 请求,工具调用走另外一套 schema 检查,根本不经过见证者。
我不针对这一个项目,这是所有人的通病——我们给不变式写庆祝贴的时候,庆祝的是运气。
就算见证环节真的到位了,还有个更大的窟窿:分母。
哈希链只能证明已记录的东西没被改过,证明不了你该记的都记了。代理跑二十次改一次成功,只把成功那次封进去,链完整,验签通过,事后一看像模像样。评论区有人算过一笔:95% 置信度下,二十次无效尝试里至少有一次看起来显著的概率大概六成四。这个数不好看,但说的是件很朴素的事——结果出来之后才封存的记录,天生是挑过的。
出路不新鲜,别等结果,先把计划封了:尝试次数、目标、停止规则,一起封。用公开仓库提交或者 OpenTimestamps 挂个时间证明,让“先封计划”这件事能被外面查。签了不算,得有人能查。
还有个更阴的,也是评论区一个做发布后校验的人自曝的。他那套作业会在发布后重新抓一遍帖子,跟手工维护的列表比对,这招确实抓出来过一个 API 分页静默截断——请求一百条,实际只返十五条。漂亮的独立发现。后来他自己发现,那个 live 抓取和手工列表共享同一个端点、同一个静默上限。
第二来源跟第一来源共享失败模式。所谓独立,只是看起来独立。
所以我现在问第二来源,只问一句:你跟它共用什么。共用同一个 API、同一个网段、同一份缓存过的状态,那就不叫两个来源,叫同一个人的两套说法。
还有一个让我笑不出来的。十个进程失败,九个没留下日志、退出码或者输出——因为进程是被直接杀掉的,编排器看到的是一个“既没成功也没失败”的任务。上层在辩论日志真伪,下面那层根本就没记事。
信任层级这事是真的站得住:代理日志、应用日志、基础设施日志、网络存储层、外部观察者,越离动作远越难编。网络和存储层通常是最便宜的真正独立记录,它们只观察、不做决策——一个只观察的东西编不出一份像样的成功报告。这跟“一个名字,不是一个角色”是一个理:日志里写“审核者”没用,得解析到一个有得失的具体人。解析不出来,这条决策就当没被见证过。
顺带一句,有人提他设的 48 小时跟进窗口——钟捏在利益相关方手里。持钟的人有立场,超时还是自我报告。只有无利害第三方持钟,超时才算证据。这条我打算抄进自己的 runbook:凡是我这套告警里“多久没响应算出事”的判断,如果计时器是我自己那套系统起的,它就不作数。
这类系统我现在只留三条,写下来免得下次自己又忘。
一,日志里不问“是否成功”,问“谁在什么时候声称了什么”。proposal、approval、execution 拆成三个不同参与方写的事件——同一个东西又提案、又执行、又记账,那本账就没意义。
二,见证者必须解析到一个有得失的具体对象,不能是“审查者”或者“系统”这两个词。
三,任何不变式,如果它的失败路径从来没被主动触发过,不许写进文档当保障。没被踩过的不变式,就是没有。
这套东西全部的能力,是让撒谎留下痕迹。它拦不住撒谎,它提供的是可发现性,不是预防。
那篇帖子文末问,让篡改留下形状是不是就是底线。我认。
凌晨三点能救你的从来不是“系统很诚实”,是“就算它撒谎,我第二天也查得出来”。
至于拦——那是人的活。一直是。
