让 Claude / Cursor / Copilot 帮你写代码这事儿,听起来很美。真用起来你就知道——AI 写代码,跟刚毕业又心高气傲的新人差不多:能写、能跑、看着挺像模像样,但你不盯紧了,第二天你就在屎山里游泳。
不是说 AI 不行——是它不知道这个项目的规矩。它没经历过你踩过的坑,没看过那个失败现场,不知道为什么”全屏 OCR”在这个项目里是禁忌。
所以我们项目里有一份 AGENTS.md,145 行,专门写给 AI 看的。这篇说说每一条背后的真实账。
为什么要写这种文件
最早不写。让 Cursor 在项目里自由发挥,结果:
- 同样的工具方法,AI 重复造了三份,分散在三个文件
- AI 喜欢用
getattr(obj, 'xxx', None)——可读性灾难 - AI 写新功能时完全无视项目已有的命名规范、目录结构
- 测试里硬编码本机绝对路径
- 写到一半把已有的功能误删,理由是”看起来没用到”
每一条都得人肉去 review、回滚、改正。比自己写还累。
后来想通了——AI 不是不能写,是不知道边界。把边界写出来,明确告诉它”这种事不能做”“那种事必须做”,效果立马不一样。
AGENTS.md 就这么诞生了。
文件长什么样
挑几段贴出来。完整文件 145 行,分几个大块:
1 | |
看着像古板老板娘列的车间规矩——其实每一条背后都有一次具体的”事故”。
几条规则的真实账
挑几条最有代表性的展开说说。
“禁止使用强模板匹配作为核心方案”
模板匹配是新手最容易上手的方案——截一张按钮的图,cv2.matchTemplate 一调,搞定。
我们早期就这么干的。然后游戏更新了一次,按钮换了配色——所有模板全废。再然后用户用 1920×1080 之外的分辨率——所有模板全废。再再然后某个皮肤更换——所有模板部分失效。
短短两个月模板库重做了三轮。最后下狠心全部迁到 YOLO + OCR + CLIP 的多信号融合。这条规则就是那段血泪的产物。
不写在 AGENTS.md 里?AI 看你代码里有 cv2.matchTemplate 的痕迹,下次写新功能保准给你来一段——它觉得”这个项目已经在这么做了”。
“尽可能不使用全屏 OCR,效率过低”
OCR 跑全屏是个昂贵操作。一张 1920×1080 截图丢给 OCR,CPU 单线程上要花 200~500ms。每次决策都这么搞,UI 直接卡死。
正确做法是先用便宜的方式(HSV 蒙版、YOLO 框)定位到目标区域,再对小区域做 OCR。30×100 像素的 OCR 大概 10~20ms,差一个数量级。
AI 不知道这个性能差距。它写代码图省事,“管它呢,OCR 跑一遍最直接”。写在规则里,每次它要做识别都得想一下”是不是该先收窄区域”。
“点击 Yolo_Box/元素尽量使用 device.click_element(),非自行判断的坐标不允许使用 device.click()”
click_element 接受一个 YOLO 检测框,内部会算出框中心点再点击。click(x, y) 接受坐标。
为啥要分?因为坐标是相对于截图分辨率的。同一个像素坐标在不同分辨率下指向完全不同的 UI 元素。click_element 内部会做坐标系转换,click 不会。
AI 第一反应永远是 click(x, y)——它觉得直接。然后用户分辨率一换,所有点击全偏。
规则写明白,AI 至少会先尝试 click_element,找不到合适的 element 再考虑 click。
“能复用的工具方法尽量写到 src/utils 中”
这条针对的是 AI 最喜欢的毛病——重复造轮子。
让 AI 加个新功能,它需要个”模糊字符串匹配”。它不会去翻你 string_tools.py 看有没有,直接在新文件里写一个 def fuzzy_match(...)。下个月需要类似功能时,又写一个略有不同的 def similar_match(...)。半年后你的项目里散落着八个”模糊匹配”实现,谁都不知道该用哪个。
规则写明白,AI 会先去 src/utils 翻翻。即使它还是想新写一个,至少会留个”我没找到合适的现有方法”的说明,方便你 review 时纠正。
“不理解需求、资料不足、规则冲突时,必须停止并询问用户”
这条是反 AI 本能的——AI 天生爱”自圆其说”。你给它一个模糊需求,它会自己脑补一个合理的解释然后开始动手。代码写得很顺,但走的不是你要的方向。
写明白”不懂就问”,AI 至少在执行前会先确认。哪怕只是确认 30% 的细节,也比闷头干完后推倒重来强。
“不得伪造测试通过、删除失败样本、跳过失败用例或隐藏失败原因”
这条够直白,听起来还有点搞笑——但真的发生过。
AI 跑测试发现某个用例失败,第一反应是”分析失败原因然后修”。当它修不动的时候,它会非常自然地”修改测试本身让它通过”——把 assert 改宽松、把测试 skip 掉、甚至直接 mock 掉被测函数。
第一次发现这事儿的时候我盯着 diff 看了好几分钟才反应过来。AI 没”恶意”——它只是把”测试通过”当成 KPI 了,达成 KPI 的最短路径就是改测试。
写规则不能让你完全杜绝,但能极大降低发生率。每次 review 也得专门盯一下”测试本身有没有被改”。
反 AI 味的几条
除了”禁止做什么”,还有”必须怎么写”的约束。这部分针对的是 AI 特有的写作病。
1 | |
AI 写 README 的味儿很冲——
🌟 这是一个革命性的工具,重新定义了 XXX 的体验。本项目采用先进的 AI 技术……
谁看了不抠脚?写规则强制把这种 hype 内容删掉。
1 | |
AI 写错误提示也是一绝——
在执行 task_runner.execute_step() 方法时遇到 ConnectionResetError, 详情:Connection reset by peer (errno 54)。请检查 src/core/device/Android/adb_client.py 第 234 行。
这种提示甩给普通用户,等于让他自己看堆栈。规则强制 AI 把堆栈隐藏到日志里,UI 上只显示”连不上设备,请检查 USB 线”。
写 AGENTS.md 的几条心得
写了几版之后总结的:
1. 规则要带”为什么”,至少在团队内部知识里要有。
AGENTS.md 本身要简洁,但每条规则背后的原因得有记录——可以是 commit message、可以是单独的 ADR、可以是内部文档。AI 偶尔会”挑战”规则(“我觉得这条不适用于当前场景”),有原因记录在你能直接反驳。
2. 规则越具体越好,避免空话。
“代码要清晰”是废话。“字符串匹配必须使用 src/utils/string_tools.py”是规则。前者 AI 当耳边风,后者它真的会查。
3. 规则数量要克制。
145 行已经接近上限——再长 AI 自己都注意力涣散。每加一条规则都要问:这条值不值得占 AI 的注意力预算?
4. 规则要定期 review。
项目演进过程中,有些规则会过时(比如某个工具方法被废弃),有些新坑要补上规则。每个季度过一遍 AGENTS.md,删过时的、加新的。
5. 把规则和实际审查结合。
写规则不等于强制执行。AI 还是会偶尔越界,PR review 时人要盯一下。我们的做法是 review checklist 直接对照 AGENTS.md 的几个关键条款——“有没有写死坐标”“测试有没有被改弱”。
一个意外收获
AGENTS.md 写完之后,我们发现一件有意思的事——这份文件不仅对 AI 有用,对新加入的人类同事也很有用。
新人来了,让他先读一遍 AGENTS.md,半小时就能把项目的”边界规矩”理清楚。比口口相传”哦对了我们不许用模板匹配”靠谱得多。
某种意义上,写给 AI 的规范,最后变成了这个项目最浓缩的工程文化沉淀。
收个尾
让 AI 写代码这事儿,未来肯定越来越普遍。但 AI 永远不会自己知道”这个项目的规矩”——这些规矩是你踩坑踩出来的,是你的工程文化,是你团队的共识。
把这些规矩显式写出来,是给 AI 一份”入职手册”。它不会替你做决策,但至少能在你的边界内做事。
不写 AGENTS.md 让 AI 写代码?就跟新人入职第一天没人带、没文档、没规矩,让他自由发挥一样——能用的产出占比,懂的都懂。