半夜,pager 难得没响,我在翻 arXiv 的新提交。cs.SE 底下挂着一条,11 月 3 号提交的,标题长得能当腰带:Agentic Behavior Engineering: A Design-by-Contract Methodology for Specifying, Verifying, and Governing Enterprise AI Agents。三十页,六图五表,作者 Yang Song。
副标题里规约、验证、治理三个词并排放,显得哪块都覆盖了。这手法我见得多。
点开它的理由很简单:它挂在 cs.SE,不挂 cs.AI。写软件工程的人谈 agent,和做模型的人谈,不是一回事。后者聊能力边界,前者聊出了事怎么收拾。我值这么多年班,只关心后者。
还有一层。这是同一位作者在微软 Azure 架构中心那份实践指南的扩写,CC BY 4.0。先在文档站放一版,收一圈实战反馈,再加厚到三十页挂 arXiv。这条路径我不反感——它比反过来强。反过来是先发论文,再让一线去猜怎么落地。
论文开头那句判断,我看完把杯子放下了。
它说企业部署 agent 的维护问题,常规测试解决不了。模型不确定性它认,但真正大的风险是:行为变更的因素常常来自团队外面——退役的模型版本、改过的策略、上游 schema 变动,以及某人为了让一个 case 过去,改了半句 prompt。
这几条我挨个点头。
尤其是最后一条。为了让一个 case 过去改半句 prompt,这种 commit 你在 review 里根本看不出它动了什么,diff 就一行,没有测试挂,第二天线上多出一类错误输出,没人能把它和那一行联系起来。
这不是模型不确定,这是人的确定性的愚蠢。
补一刀:这些变更,一条都不归你管,出了事全归值班的背。
论文后面那一大套,我大致分两半——一半是我在 runbook 里用脏话写过的东西,一半是又一套框架。
先说好的。
它把可观测的 agent 行为当成受版本控制的工程制品。不是 prompt,不是模型,是行为。听着像废话,那你想想你们团队版本控制里现在管的是什么:prompt 在某个人的 Notion 里,模型版本写在一张忘了更新的 wiki 表格里,测试用例在一个没人跑的 repo 里。
行为呢?行为在客户投诉里。
然后是契约。Design by Contract 在软件工程里不算新东西,它改了一下搬过来:契约只写规格,规则带稳定 ID,分三类——必须做什么、禁止做什么、以及证据不足时必须弃权。
三类里第三类最值钱。
我接过太多这种电话:agent 在没有依据的时候硬给了一个答案,格式漂亮,语气笃定,错得很自信。把"什么情况下必须弃权"单列成一类规则,这不是锦上添花,这是把最常出事的那条路先堵上。
论文还特意把"证据缺失"和"验证为否"分开。这两个在日志里都长得像失败,处理方向却完全相反——一个该去补数据源,一个该去改逻辑。我们的监控把两者塞进同一个 error 里,然后开会研究为什么 error rate 上升了。
好话说到这儿。
五职责:Specify、Ground、Control、Verify、Observe。念一遍,S、G、C、V、O。顺不顺?不顺。行业规矩,凡是整出五个英文单词框架的,落地时四个变成 Confluence 里一张没人再打开的图,剩下那个变成季度汇报里的一页 PPT。
我知道这话不讲理。我就是这么判断的——一个框架能不能活,不看它分得对不对,看它能不能让凌晨三点被叫起来那个人多省十分钟。这五个词里,半夜真正有用的是 Control 和 Observe;Specify 是白天的活,Verify 是给 CI 的。
写到这儿我自己也犹豫。Ground 单列出来可能恰恰是对的——它说的是把规则锚到证据上,锚不到就只能弃权,跟上面那条是一根绳上的。行,五个里我认三个。
真正让我坐直的是两处实现细节。
第一处:发布门禁用每个场景的 pass^k 可靠性,不用总体准确率。
翻成人话——同一个场景跑 k 次,次次都过才算这个场景过;只要有一个场景零次通过,这版就上不了线。不是把所有场景的通过率加起来除以场景数。
因为你那个 92% 是谁的 92%?是平均在一个整体上的。整体里可能有那么一个场景,它 0 次通过——那就是每次上线都在赌它这回别出现。而它偏偏总在半夜出现。
我们现在的评测集有多少是这么算分的,我不敢去查。查出来大概要重做。
第二处:生产里每一次运行都按契约分类,每一个发现都路由到"该改的那个资产"。
这句是冲着事故报告去的。见过太多复盘写成"多种因素叠加",从头到尾挑不出一处人因、一个该点名没点名的环节。按这个做法,一次错误运行先归到某条规则 ID——规则写漏了,场景没覆盖,上游数据源变了,还是运行时策略放行了不该放的。归到哪一类,就由哪个资产的主人去改。不许含糊。
我一开始觉得这条太理想化。后来想起来,我们那套老告警分流干的就是这个——告警带一个 service 标签,路由到那台机器的主人。区别是我们的标签是手写的,经常写错,写错了就路由到我这。契约规则 ID 至少比手写标签强。
得泼盆冷水,不然前面夸得太客气。
这套东西有前提:你的 agent 得可观测,日志得串得起来,每次运行得能归到一条规则上。我见过的大部分团队,连一个 request id 都串不齐,agent 的输出混在应用日志里,中间还夹着三行 debug print。
所以这篇是写给平台团队的,不是写给半夜接电话那个人的。它没回答"我只有三个人、一半时间在救火,第一周该干什么"。
这个问题得我们自己填。别因为它没写就把论文撂下——第一周能做的事其实小得可怜:把你们现在所有 agent 输出里"本该弃权却硬答了"的例子挑二十个出来,写成规则。二十条,用不了一天。
本期教训:下次谁再报"这个 agent 准确率 95%",先别信,问一句——哪个场景是 0 次通过?