跳至正文
这篇笔记的目录
回到笔记存档
技术开发

不把 Agent 写死,从一套规则到一套判断方法

从 AGENTS.md,子代理,Computer Use,媒体预算到面向读者写正文,记录我怎样把 Agent 规则整理成一套可判断,可迁移的开发准则.

#Codex#AI Agent#AGENTS.md#Development#Guidelines

我维护了一份叫 codex-development-guidelines 的仓库, 用来整理和改进 Agent 的基础开发准则.

最初整理这个仓库时,我想做的其实很简单.给自己的 Agent 写一份更完整的 AGENTS.md,让它在开发,委派,浏览器操作,媒体处理,Git 恢复和验证方面少犯一些低级错误.

但规则越写越多之后,问题逐渐变得明显.一份看起来严谨的规则,很容易变成另一种形式的僵化.它可能要求每个线程都重新回答一遍偏好,可能把某台机器上的习惯当成所有人的默认配置,也可能为了满足某条流程而机械地创建子代理.

所以这个仓库后来真正关心的,不再是如何堆出一份更长的 Agent 规则,而是如何让 Agent 在不同用户,不同环境和不同任务之间做出合适的判断.这篇文章算是对《GPT5.6时期 Codex App 的一些使用心得》AGENTS.md 和开发笔记部分的补齐,同时也来单独介绍一下仓库的相关内容.

一份不断吸收使用教训的规范, 也可能不断积累过度限制.

我希望它逐渐成为通用的 Agent 开发准则, 而不是要求所有人复刻我的电脑, 模型配置和工作习惯. 可如果只是把具体要求全部删掉, 留下几句灵活处理和尊重用户, 原来那些真实问题又没有得到解决.

这次重写, 很大一部分时间就花在两者之间. 哪些经验值得保留, 哪些结论只适用于我, 哪些原本看起来很合理的规则, 换一个场景就会变成障碍.

其中最有意思的一段, 是我让 Agent 编写面向读者的写作规则, 结果它写出来的规则说明, 自己就犯了同样的问题.

先了解用户, 再给建议, 最后由用户选择#

如果要给这个仓库找一个最重要的原则, 我会选择这个.

先了解真实环境和用户的需求, 再提出有依据的建议, 最后仍以用户的选择为准.

这里的了解, 不等于一上来把所有事情都问一遍.

当前是什么 Shell, Git 是否可用, 仓库有没有未提交修改, 系统实际暴露了哪些工具, 这些能检测的事实, Agent 应该自己检查. 用户希望优先节省费用还是缩短等待, 是否允许安装依赖, 是否愿意把交互任务交给子代理, 这些才涉及选择.

例如, 检测到用户正在使用 PowerShell, 只能说明当前命令需要适配这个环境. 它不等于用户已经同意把 PowerShell 设成未来所有任务的默认选择.

同样, Agent 可以解释为什么建议使用 Git, 因为它有助于检查差异和保留恢复点. 但用户选择暂时不用 Git, 不应该导致普通工作直接被拒绝. 应该继续讨论现有条件下怎样备份和验证, 而不是反复劝说用户接受推荐.

我也不希望所谓的用户偏好, 最后变成每个新线程开头的一整套问卷.

初次建立工作方式时, 问清楚当然有价值. 但已经明确回答过的事情, 就应该复用. 本次只是修改一小段文本, 就没有必要顺便询问视频处理预算, 模型分层和发布权限. 真正出现新选择时再问, 而不是为了证明流程完整而问.

用户偏好也不意味着 Agent 不再提供判断. 如果某个选择会增加费用, 牺牲可靠性或者碰到权限限制, Agent 应当把后果讲清楚. 但讲清楚以后, 不能悄悄替用户换成它认为更好的方案.

我想保留的是有判断力的协作, 不是替用户决策, 也不是把所有判断重新推回用户.

浏览器操作, 到底该交给谁#

关于 Browser Use 和 Computer Use, 我纠结过很久.

我最开始限制主代理使用这类工具, 主要是因为自己的使用方式. 主代理通常选择价格更高, 推理投入更大的模型, 同时主线程又会长期保留项目上下文.

让这样的线程不断操作界面, 很容易同时碰到几个麻烦.

每次观察和操作都有工具返回, 多轮下来上下文越来越大. 响应延迟, 输出速度和页面等待又会累积到整个任务里. 如果工具还不断返回截图, 或者把图像数据带进持久化会话, 压力就不只体现在模型账单上, 还可能落到传输和本地存储上.

于是一个很直观的想法出现了. 把点击交给更便宜更快的模型, 主代理只负责判断.

但这个想法并没有真正解决问题.

界面操作不是把鼠标挪到一个坐标那么简单. 模型要理解当前画面, 把意图转换成正确的工具参数, 判断操作有没有生效, 还要在状态变化后继续行动. 如果它反复认错控件, 主代理就得逐张截图检查, 一步一步纠正.

最后看起来是便宜模型在执行, 实际上昂贵模型仍然全程陪同, 还多了一层沟通成本.

更让我犹豫的是, 在一些使用体验里, 高级模型的界面理解和操作能力确实明显更好. 为了节省单次调用费用, 坚持让不适合的模型先失败几轮, 未必是在节省.

假设一个快模型每轮花 3 秒, 需要 30 轮才能完成任务, 这些轮次合计就是 90 秒. 另一个模型每轮花 8 秒, 但只需要 8 轮, 合计是 64 秒. 这组假设只想说明, 单轮更快和任务更快是两件事. 如果轮数相同, 结果又会不同.

我后来开始把几件原本绑在一起的事拆开考虑.

  • 谁承担最终判断和验收责任.
  • 哪个模型有能力完成眼前的操作.
  • 操作应该发生在主线程还是独立执行上下文.
  • 这次任务允许消耗多少时间, 费用和媒体资源.

主代理是一种职责, 不应该成为最强模型的唯一使用位置. 子代理也不是低价模型的同义词.

如果环境支持, 困难的交互任务完全可以交给使用高级模型的独立执行代理. 它负责一个完整但有边界的阶段, 比如筛选数据, 导出报告并核对结果, 而不是每点一次按钮就回头请示.

主代理拿到必要证据后检查结果, 不需要把全部操作重新看一遍.

当然, 这也不是万能答案. 独立代理可能没有同样的工具权限, 看不到原来的登录会话, 或者无法获得相同的视觉输入. 模型名字一样, 不代表实际执行条件一样.

如果操作只有很短的几步, 交接反而更麻烦, 在已有授权允许的情况下直接完成也可以. 如果用户明确禁止主代理使用浏览器, 则不能因为子代理不可用就自动解除限制.

我最后留下的方向, 不是永远用便宜模型快点点, 也不是永远用高级模型慢慢点. 而是看完整任务的结果和代价, 同时尊重当前环境真正提供的能力.

一张十几 MB 的截图, 改变了我对工具成本的理解#

有一次我让 Agent 检索 4K 视频里的画面, 单张截图就有十几 MB.

单独看, 它只是一张截图. 但多张一起原样上传, 就可能带来明显的网络压力, 甚至碰到上游的 payload too large.

这件事让我意识到, 不能只用 token 来理解 Agent 的资源消耗.

模型输入和上下文是一笔成本, 请求实际传输了多少字节是另一笔, 会话历史在本地保存了多少内容又是第三笔. 把工具操作交给子代理, 并不意味着这三笔成本一起消失. 关闭子代理, 也不能据此断言之前的截图已经被删除.

因此我更愿意要求 Agent 在上传之前先检查尺寸, 单文件体积和批量总量. 原视频和完整截图留在本地, 审阅时只传递足以支持判断的代表性画面.

但压缩也不能成为另一个机械规则.

如果任务是在找细小文字, 压缩到看不清就失去了意义. 如果任务需要核对像素, 有损压缩可能改变待检查的内容. 如果截图用于后续界面操作, 裁剪和缩放还会影响坐标对应关系.

所以需要保留原件和审查副本的对应关系, 需要时使用无损局部裁剪, 并让执行者知道当前看到的是哪一个时间点, 哪一块区域.

这里真正需要控制的是不必要的传输, 不是盲目追求最小文件.

这也是我重写规则时反复遇到的结构. 原则可以比较稳定, 但具体尺寸, 数量和处理方式必须跟着任务走.

不要把主代理变成免费的长期辅导老师#

委派之后, 还有一个容易被低估的问题.

子代理给出的结论, 主代理不能直接照单全收. 但主代理也不能无限等待, 或者对一个已经明显偏离方向的代理进行多轮一对一辅导.

我希望主代理检查的是决定结论是否成立的证据. 比如声称修复了某个问题, 就核对相关改动和验证结果. 声称找到某个画面, 就提供对应时间点和可访问的证据. 一份写得很自信的总结, 不等于这些证据已经存在.

如果第一次交付有一个具体而可纠正的问题, 可以给一次定向反馈. 如果仍然没有改善, 或者已经看不出继续指导的价值, 就应当结束这次委派, 重新判断下一步.

重新判断不一定是换更强模型.

反复认错按钮, 可能与模型能力有关. 截图根本没有显示目标区域, 可能是观察不足. 页面一直无法加载, 可能是环境问题. 没有操作权限, 则不是多推理几轮就能解决的.

同样, 换一个代理不能把已经花掉的预算和失败次数重新归零. 有些动作还可能已经产生副作用, 不能因为上一个代理没说清楚, 新代理就再执行一遍.

反过来, 如果只是一个主代理轻松就能完成的简单任务, 根本没必要先创建子代理.

我不希望规则最后变成一种表演. 为了符合委派规范而委派, 然后再为这次不必要的委派补上计划, 交接和验收.

面对环境阻力, 什么时候应该停下来#

我对失败重试的要求, 也经历了类似变化.

我不是希望 Agent 一遇到问题就把任务退回来. 能在现有权限内换一个等价命令, 修正参数或者使用已经具备的工具, 就应该继续做.

但如果 Shell, 依赖, 网络或者工具本身已经形成明显阻力, 再重复相同动作没有什么意义.

例如, 一个工具无法处理当前文件格式, 而另一个可安装的工具确实更适合. Agent 应该解释目前卡在哪里, 新工具能解决什么, 来自哪里, 会改动什么, 有哪些风险和替代方式, 然后征求用户意见.

这比静默安装一堆依赖更尊重用户, 也比坚持原方法重试十几次更有帮助.

如果用户明确要求不能安装新工具, 那就回到这个限制下寻找方案, 或如实说明无法完成的部分. 不能把坚持任务目标理解成自动获得修改环境的授权.

我越来越在意规则有没有说明停止以后该做什么. 只有一句不要重试, 容易让 Agent 过早放弃. 只有一句尽力完成, 又容易让它不计代价地继续.

我让模型写一条写作规则, 然后被它的示例逗笑了#

这次整理里, 最让我意外的发现来自文档本身.

最初我注意到的是一种编写视角混入正文的现象. 我遇到过模型在写 README, PR 正文或者发布说明时, 把它与请求者之间的对话带进去.

用一个假设情境来说明. 某个报表工具增加了 CSV 导出功能, 需要面向使用者发布版本说明. 如果正文写成下面这样, 说话对象就发生了错位.

按你的要求, 我已经加好了导出功能.

这句话拿来回复委托它的人很自然, 但发布说明的读者并不知道这里的你是谁. 对读者真正有用的内容其实很简单.

新增 CSV 导出功能.

于是我要求把这类问题写进规则, 让模型区分对话里的工作汇报和交付物正文.

结果它在 README 里制作了一组写作示例. 有一项把下面这句当成不合适的表达.

按你的要求, 我把规则拆成了六个模块.

然后把这一句列为适合交付物的内容.

六个模块将运行时行为与采用配置分开.

我看到的时候真的没绷住.

示例附近没有交代这些模块是什么, 为什么是六个, 又为什么能得出后面那层关系. 一个本来要教人摆脱对话背景的例子, 自己先依赖了一段没有说明的背景.

模型去掉了按你的要求和我, 却没有解决读者凭什么能理解这句话的问题.

即使 README 更前面曾经介绍过一组模块, 也不能认定读者滑到这段例子时, 就会自动把它们对应起来. 示例没有明确告诉读者, 它是在引用本文结构, 还是随手假设了某个别的项目.

而且这里还有事实层面的错误. 当时仓库中的模块是在解释上下文与记忆, 委派与工具, 媒体传输, 环境阻力, 文件恢复, 验证与资源等主题. 工作期间的行为由运行时规则约束, 初次配置由另一套流程负责, 并不是这六个主题模块完成了两种职责的分离. 把含糊指代补全, 仍不等于把关系说对.

同一组对照里, 还有一个所谓的正面示例.

完成后的正文, 不加入描述回答修改轮次的标签.

这甚至还不是正文. 它是在告诉写作者该怎么写, 只是被放到了适合交付物的内容那一栏.

所以问题根本不只是删掉几个带有助手口吻的词.

一段话可以没有第一人称, 没有进度旁白, 没有提到用户要求, 但仍然没有提供实际内容, 或者仍然依赖不存在的背景.

人脑不是 Transformer, 显示器也不会一次显示全文#

顺着那个失败示例, 我开始把问题拆成三个层次.

  • 作者掌握了哪些背景.
  • 文档实际写入了哪些信息.
  • 读者到当前段落, 已经能理解哪些事情.

这三者显然不能直接画等号.

作者知道一个选项会覆盖原文件, 不代表文档已经告诉读者. 文档在后面解释了这个选项, 也不代表前面让读者点击保存时, 读者已经知道后果.

假设某工具有 R1 和 R2 两种保存模式, 一段操作说明写成这样.

  1. 选择 R2.
  2. 点击保存.
  3. R2 会覆盖原文件, R1 会另存为副本. 需要保留原文件时请选择 R1.

站在看完整段文字的位置, 信息似乎齐了. 但对按顺序操作的人来说, 第三步来得太晚.

还有一种更日常的情况. 假设一个文件工具在手册中介绍了保存方式, 但用户打开的保存窗口并不展示那份列表. 窗口里出现下面这句提示.

选择前面介绍的第一种方式保存.

用户只想保存文件, 现在却必须回到手册寻找一个没有名字的第一种方式.

如果工具确实有一个名为保留原件的选项, 并且它的效果是另存副本, 提示就可以直接写出来.

保存时选择保留原件, 将修改另存为副本.

这些例子让我产生了一个有点好笑的联想. 模型写文章时, 有时像是把读者也当成了另一个子代理, 默认对方拿到了同样完整的上下文, 随时可以把远处的信息关联过来.

但人脑不是 Transformer, 显示器也不会在打开页面的一瞬间, 把全文都显示出来并建立好联系.

人会按顺序读, 会略读, 会中途打断, 也会通过链接直接进入某一节. 阅读过程本身就有顺序和局部范围.

这里的 Transformer 和子代理只是我描述阅读感受的比喻. 我没有通过这些例子证明模型内部真的把人类读者当成了子代理, 也没有证明模型能可靠利用全文里的每一个细节.

不过, 这个比喻帮助我把原本笼统的 AI 味, 变成了几个可以逐项检查的问题.

这句话的对象在哪里被介绍过. 当前动作需要的前提有没有提前给出. 读者直接进入这个例子时是否仍然知道它在说什么. 文字里写出的关系, 有没有得到情境中的事实支持.

检查这些, 比单纯要求写得自然一点更具体.

不能为了去掉 AI 味, 再造一套僵硬的写作禁令#

我也不想从这件事走向另一个极端.

第一人称并不是问题本身. 个人博客当然可以写我, 邮件也可以表达作者自己的安排. 问题是这句话的说话者和背景, 是否属于当前文章.

向后引用也不是一律不行. 当前操作已经解释清楚以后, 再告诉读者去哪个章节了解备份恢复, 完全合理. 没必要把整份恢复手册复制到每个保存按钮旁边.

假设读者已经具备相关专业知识, 也不是什么错误. 面向熟悉 CSV 的读者介绍导出功能, 不必每次重新解释 CSV 是什么.

真正需要防止的是, 作者把自己知道的事情偷偷算进读者已经知道的事情里.

后来我更倾向于使用带有完整情境的实际样本, 而不是给模型一堆抽象的应该和不应该.

例如, 假设一个 PR 修复了空报表导出崩溃, 三项相关回归测试通过, 但完整测试套件没有运行. 那么摘要可以写成这样.

修复空报表导出时的崩溃. 三项相关回归测试通过, 完整测试套件尚未运行.

不能把它写成所有测试通过, 也不能只留下在这里说明修复内容和测试结果.

前者扩大了证据, 后者没有交付正文. 两种错误都不是靠调整语气就能修复的.

覆盖广, 不等于每次都执行全部条例#

重新回看其他规则, 我发现类似问题并不限于写作.

要求保留开发笔记, 是为了恢复重要背景, 避免 Agent 忘记已经尝试过的方法和用户明确拒绝的方案. 如果它只管写新笔记, 开始工作前却不读旧笔记, 记录再完整也没有发挥作用.

要求备份, 是为了让修改可恢复. 如果补丁没有包含未跟踪的图片, 或者备份漏掉了关键素材, 只说已经保存 Git diff 仍然不够.

要求验证, 是为了让完成声明有依据. 构建通过, 不代表页面已经经过真人验收. 服务成功启动, 也不代表功能已经按真实使用路径测过.

要求限制重型任务, 是因为用户还要继续使用这台电脑. 但一个获得允许的开发服务器需要继续运行, 就不能为了把进程全部清空而结束它, 更不能随手终止用户自己的进程.

这些场景需要覆盖, 但没有理由在每次修改标点时都完整执行一遍.

我现在会从几件事去检查一条规则. 它想保护什么, 什么情况下触发, 需要什么证据, 哪些参数可以由用户调整, 当前条件不支持时又该怎么办.

例如, 媒体上传前检查体积是一条可以稳定保留的要求. 审查图片到底缩到多大, 则需要看文字细节和任务目的. 子代理需要停止条件, 但停止条件的时间和费用边界可以根据用户选择变化.

广泛覆盖的价值, 应该体现在遇到不同问题时都有可用的判断依据, 而不是让每个简单任务都承担最复杂场景的流程成本.

我还没有解决的部分#

这轮改进没有让我得到一份可以保证 Agent 永远正确的规则.

最直接的提醒就是那段 README. 当时仓库的结构检查已经通过, Agent 也做过场景审阅, 最后仍然把没有背景的句子和写作占位说明当作好例子交给了我.

结构检查能发现缺文件, 坏链接, 规则编号不一致, 但这和读者能不能顺畅理解不是一回事. 同一个 Agent 看过完整上下文后再审稿, 还可能在阅读时把缺少的信息自行补上.

后续整理进仓库的阅读案例, 开始刻意区分顺序阅读和直接进入某一节的场景, 同时保留一些本来就没有问题的例子. 否则审阅很容易变成看到第一人称就删, 看到引用就补一大段解释.

我还想进一步试试, 把同一段文字放在不同阅读条件下会怎样. 一组看到全文, 一组只看到独立章节, 再让读者指出无法确定的对象和前提. 对操作说明, 则检查在执行某一步之前, 是否已经获得决定这一步是否合适的信息.

这些是接下来值得验证的方向, 目前的使用记录和案例还不能替代这样的研究.

模型分层同样没有永久答案. 我更希望 Agent 从用户当前真正能用的模型出发, 核对身份, 发布时间, 费用, 相关能力和速度依据, 再按角色推荐. 大吞吐工作可以在能力够用以后优先考虑近期, 快速, 低成本的候选, 但不能只凭发布时间就宣布旧模型没有价值.

即使推荐很充分, 最终使用哪个模型, 是否接受额外费用, 要不要切换环境, 仍然应该由用户选择. 这类比较适合在建立配置或用户主动要求重新评估时做, 不适合变成每次开工前的市场调研.

还有一些问题, 光靠文字规则解决不了. 工具是否允许控制截图输出, 宿主如何保存历史, 子代理能否共享必要会话, 都会影响实际方案. 写一句应该隔离, 并不会凭空产生这些能力.

写到最后, 我更在意规则有没有留下判断空间#

最开始, 我想让 Agent 少犯一些重复的错误.

后来我发现, 给每个错误补上一条禁止项, 仍然不够. 规则需要保留错误发生的原因, 也需要承认换一个用户, 模型或者任务以后, 原来的处理方式可能不再合适.

我希望这个仓库积累的是这样的经验. 看见体积异常的截图, 知道先检查传输. 看见连续失败的操作, 知道区分能力和环境问题. 写一段正文, 知道读者没有参与之前的对话. 推荐一个工具或模型, 知道自己的判断还需要交给用户选择.

简单的事情可以直接做好. 复杂的事情需要边界和证据. 不确定的事情要说明不确定在哪里.

这些要求并不漂亮, 也很难靠一句提示词全部实现. 但比起让 Agent 更熟练地执行我的整套个人习惯, 我更希望它能理解, 眼前这个人为什么需要它这么做.