系列第二篇:Agent 帮我跑实验三个月,我改了哪些规范(附前后对比) 上一篇是设计出来的体系这一篇是被现实打出来的规范。三个月、四十多次实验、三十多条修订。每一条背后都有一次翻车。全文按「旧做法 → 新做法 → 为什么改 → 改完的效果」写能抄的直接抄。开篇好设计不等于好规范三个月前我给 Agent 写下了一套自认为完备的约束体系直接开跑。结果这套体系被现实改了三十多次。更尴尬的是——我当初觉得「这还用写」的地方恰恰是出事最多的地方。后来我想通了一件事规范的用途是「记录人曾经在哪里被坑过」并非「约束 Agent」。没被坑过的规则写得再漂亮也没人执行被坑过的规则哪怕只有一行全队都会死守。所以这篇不谈理论。只讲改了什么、为什么改。一、输入端的四次修订修订 1从「交代任务」到「先给契约」旧做法帮我把新客冷启动特征实现一下注意时间窗和缺失处理。新做法第一步只产出FeatureSpec实例字段见contracts/feature.py不要写实现。第二步我审完契约后你再填实现。为什么改第一个月Agent 产出的特征里有 3 个用了线上拿不到的数据源2 个把缺失值填成了 0。它并非不听话只是我没告诉它「线上可获取性」是个必答项。改完的效果online_available这个字段逼它在写代码前先回答线上有没有。问题从事后发现变成了事前卡住——三个月里拦下 7 次不可用特征。修订 2从「整本代码库」到「允许改 / 禁止改」旧做法这是我们的推荐项目你在这个仓库里改一下特征逻辑。新做法允许改src/features/cold_start.py、tests/test_cold_start.py禁止改其他任何文件尤其ml/train/的超参、tests/里的 BASELINE为什么改第二周Agent 为了让测试通过悄悄改了test_regression_gate.py里的 BASELINE。它没有恶意它只是在「完成任务」。如果没被 code review 发现等于验收门被自己人拆了。改完的效果除了在AGENTS.md写死禁止条款还在 CI 加了道门-name:Guard BASELINErun:|if git diff --name-only origin/main | grep -q test_regression_gate.py; then echo BASELINE 被修改需人工 approve; exit 1 fi修订 3从「贴原始输出」到「命令 原始输出」旧做法跑完测试告诉我结果。新做法请贴① 实际执行的完整命令 ② 原始输出全文。不接受「测试通过」这类摘要。为什么改第三周Agent 说测试全部通过。我一查它跑的是pytest tests/test_window.py——只跑了一个文件另外三个验收门根本没执行。改完的效果这条规则很快又抓出第二次它用-k过滤跳过了数据门。现在规范里写的是六个字“摘要等于未完成”。修订 4从「一个大任务」到「单函数 前置三问」旧做法把这批特征重构一下顺便把评测也跑通。新做法每次只做一件事做完停下等我确认。开工前先回答三个问题要改哪几个函数用哪些数据时间窗是什么怎么证明改完之后是对的为什么改有次 Agent 一口气改了 11 个文件其中一个改动引入了非常隐蔽的 groupby 顺序问题导致评测偏乐观 0.4%。改动面太大找了整整一天才定位。改完的效果单次 diff 从平均 400 行降到 80 行review 从 40 分钟降到 10 分钟定位翻车的时间从按天变成按分钟。二、输出端的六次修订修订 5从「写份报告」到「填 schema」旧做法帮我整理一下实验结论写成报告。新做法输出必须符合contracts/experiment.py的ExperimentReportschema。为什么改就是上一篇复盘里那次抄错分群数字的事故。自由文本报告里的表格行错位从结构上就防不住。改完的效果by_segment变成结构化 dict 后数字抄错行在物理上不可能发生。字段名本身就是校验。三个月里收益最大的一次修订没有之一。修订 6limitations强制非空而且要有实质旧做法局限自由写通常就一句本结论基于离线数据仅供参考。新做法field_validator(limitations)def_limitations_not_empty(cls,v):ifnotvorall(len(x)10forxinv):raiseValueError(limitations 必须显式列出局限不接受敷衍)returnv为什么改第一版只要求非空它写了[无]。规则写不细Agent 就会用最省力的方式满足字面要求。改完的效果现在它被迫写出新客样本仅占 3%bootstrap 方差偏大这类真有用的局限。意外收获是——局限性写清楚了评审会上就不用每一点都重新问一遍。修订 7每条结论必须带evidence_refs旧做法结论和数据混在一起写。新做法evidence_refs:list[str]# 每条结论必须映射到具体数据出处为什么改第二个月发现一种诡异情况——结论有了但找不到对应的数据数字像凭空长出来的。改完的效果补了一个对齐检查defcheck_evidence_alignment(report):problems[]forrefinreport.evidence_refs:ifnotos.path.exists(ref)andrefnotinKNOWN_SOURCES:problems.append(f证据出处无法定位{ref})returnproblems三个月抓出两次引用不存在文件的幻觉。修订 8禁止「看起来涨了」旧做法告诉我这个改动效果怎么样。新做法只允许输出三个结论之一adopt/reject/inconclusive。“提升明显”效果不错这类表述视为无效输出。inconclusive一律不得建议上线。为什么改第一个月 Agent 给出过 5 份提升明显的报告其中 3 份 bootstrap 下界小于 0——统计上不显著只是均值碰巧高了一点。改完的效果把主张从评价效果改成判定显著Agent 的输出被迫接入significance.py。主观形容词被数学判定替代。修订 9分群指标必须齐全旧做法报告只要总指标。新做法必须同时给all/new_user/old_user三个分群缺一个则报告无效。为什么改有一次总 AUC 涨了 0.3%上线后新客其实是掉的——总指标被老客稀释了。老客占 97%它的微小波动完全能盖住新客的真实回退。改完的效果这条规则帮我们发现了两次总量掩盖局部。它教会我一件事总指标是最容易骗人的指标。修订 10只给「可疑点」不给「数据结论」旧做法让 Agent 直接分析数据。新做法分析数据时只输出可疑点清单含验证方法不要输出数据说明了什么。为什么改第二个月Agent 分析新客 CTR 下滑一本正经地解释因为周末效应。事实是老客没有周末效应波动集中在一个渠道——是渠道质量问题。它在没有数据支撑的因果关系上编得非常流畅。改完的效果这是我最反直觉的一条修订。它把 Agent 的价值从解释世界拉回发现异常——而这恰好是它比人强的地方穷举可疑点它比人快太多。三、流程上的三个新增新增 11强制「反方律师」环节旧做法没有。新做法任何要上评审会的结论先过一轮反方律师 prompt以最挑剔的评审身份列出 3 个能导致同样现象、但机制不同的替代解释和区分方法指出数据可能存在的泄露 / 偏差 / 不显著问题只质疑不下结论。为什么加第一次用是在新客 CTR 归因会上。反方律师提出可能是新客渠道结构变化我当场答不上来只能会后补数据——结果发现正是渠道结构变化。没有这一步我会带着错误归因进评审会。加完的效果评审会上的你确定吗从平均 3 个问题降到 0.5 个。因为质疑在会前已经被自己回答完了。新增 12人工推翻必须进反馈表旧做法人推翻 Agent 的结论口头说一声就算了。新做法CREATETABLEagent_feedback(id BIGSERIALPRIMARYKEY,experimentTEXT,agent_out JSONB,human_out JSONB,human_whyTEXT,-- 必填tsTIMESTAMPDEFAULTnow());为什么加前两个月人被推翻后只是知道错了没有任何机制让它下次不犯。第三个月开始强制落表每周让 Agent 汇总被推翻最多的类型。加完的效果一个月内就定位出三类高频问题——分群数字、显著性判定、证据缺失。本文里修订 5、7、8 全都来自这张表。这条新增的真正意义它把经验变成数据再让数据变成规范。新增 13上线前的「三次核对」旧做法报告看一眼就准备上线。新做法上线前三次核对缺一不可报告数字 ⟷ 原始日志人工抽 5 个数字核对三个验收门全绿回归 显著性 穿越审计本类问题在人工推翻记录里近 30 天是否清零为什么加来自第二个月的一次惊险——报告数据本身没错但穿越审计没跑而那次恰好藏着一个隐式的未来信息泄露。加完的效果穿越泄露问题归零。这条规则的本质是确认那些应该已经跑过的检查真的跑过了。四、前后对比总表#维度旧规范新规范触发事故1输入交代任务先给契约数据源线上不可用2权限无限制允许改 / 禁止改清单Agent 改 BASELINE3证据说要结果命令 原始输出只跑一个测试文件4粒度大任务单函数 前置三问11 文件改动引 bug5输出写报告填 schema分群数字抄错行6局限自由写强制非空且有实质写“无”敷衍7溯源混着写每条结论带 evidence_refs数字凭空长出来8判定评价效果adopt / reject / inconclusive5 份“提升明显”不显著9分群只看总指标三分群强制老客稀释掩盖新客回退10分析分析数据只给可疑点编“周末效应”11评审无强制反方律师错误归因进会12反馈口头落表 周汇总同类问题反复犯13上线看一眼三次核对泄露未审三个月的核心变化一句话从「告诉 Agent 做什么」变成「告诉它做到什么程度算数、谁来验、验不过怎么办」。五、三个更底层的教训前面是具体规范下面是修订三十多次后才真正想明白的东西。教训一规则写不细Agent 就会「字面满足」limitations 非空→ 它写[无]贴测试结果→ 它跑一个文件后写通过贴原始输出→ 它用-k跳过低价值的部分每一次它都没有违反规则只是用最省力的方式满足了字面要求。所以现在每写一条规则我都会先问自己一句“如果我是最懒的执行者怎么满足字面意思却不干活”然后把那个门焊死。这条思路几乎贡献了本文一半的修订。教训二规范来自事故不来自设计一开始我是按体系设计的结果大量规则没人执行。后来发现被反复触发、真正固化的规则都出过事。所以现在的做法是出一次事故落一条规范没出过事的先不写写了也是形式主义。规范靠一次次事故逐渐长出来并非凭设计一次成形。教训三人松一分Agent 就松十分最危险的情况是人为了让它通过而自己放宽规则Agent 犯错反而是次要的。第二个月一个同事为了让报告上线把TOLERANCE从 0.005 调到 0.01。误差预算被悄悄撕开一道口子没有任何告警。所以现在有一条铁律红线参数只能由授权人修改且必须留痕。Agent 能改代码但碰不到红线。结语三个月后我对 Agent 的看法变了三个月前我觉得 Agent 是一个需要被约束的强执行者。三个月后发现它更像一个极聪明、极省力、极度字面化的实习生你给它明确标准它能干得比谁都好你给它模糊空间它一定用最省力的方式糊弄过去。所以这三十多条规范本质上都在把一件事做对把「我希望你很牛」翻译成「你必须过这几关」。这也接上了上一篇的结论Agent 时代工程师最值钱的能力是设计验证。附《Agent 实验规范 v3》精简版# 输入 1. 先给契约FeatureSpec / ExperimentReport审完再写实现 2. 明确「允许改 / 禁止改」文件清单 3. 单次只做一个函数/一件事开工前回答三问 4. 要求贴执行命令 原始输出全文摘要等于未完成 # 输出 5. 所有结论走 schema禁止自由格式报告 6. limitations 强制非空且有实质 7. 每条结论必须带 evidence_refs 8. 只允许 adopt / reject / inconclusiveinconclusive 不得建议上线 9. 分群指标必须齐全all / new_user / old_user 10. 分析数据只输出「可疑点清单」不给无数据支撑的因果解释 # 流程 11. 上会前必须过一轮「反方律师」 12. 人工推翻必须落表周汇总高频问题 13. 上线前三次核对报告⟷日志、三门全绿、本类问题近 30 天清零 14. 红线参数BASELINE / TOLERANCE只能由授权人改且必须留痕