如何更放心地让 Agent 写代码
从反复提醒走向可执行的工程约束
让 Agent 写代码,最让人不放心的往往不是它完全不会做,而是它能完成大部分工作,却在某些地方反复犯错:绕过已有接口、重复实现一套逻辑、忘记边界条件,或者把上次刚纠正的问题又写回来。于是,人不断补充提示词、修改规则文件,再逐条检查它的改动。
poteto 的这篇帖子提出了另一种投入方式:把更多精力放在代码库和自动验证上,让 Agent 顺着项目里最自然的路径工作时,就更容易做对。这些投入可以减少后续依赖文字提醒和逐条审核的负担。
本文先完整整理原帖的四层方法和操作步骤,再用工具执行权限的例子解释如何落地。后文的具体工程示例与试验方案属于延伸说明,不代表作者已经在这些场景中做过验证。
一 为什么先改代码库
原帖的观察很直接:Agent 喜欢模仿已有代码,也倾向于采用最短的实现路径。因此,代码库里已经存在的模式,会影响它下一次怎么写。
如果项目里到处都有直接访问数据库、绕过权限检查、复制粘贴业务逻辑的例子,再加一句“请遵守统一规范”,作用就很有限。它看到的实际代码与文字要求相互冲突,还需要自己判断该信哪个。
反过来,如果常见功能已有清晰入口,模块之间通过稳定接口协作,类型能够表达有效状态,Agent 就不必在每个任务里重新猜测结构。这里的目标是让“最容易写出来的实现”尽量就是正确实现。
这并不要求为了 Agent 重造一套架构。很多工作本来就是良好的软件工程:减少重复、收紧边界、明确职责,把重要条件落实到代码。Agent 的加入只是让这些基础建设的价值更明显,因为同一种模式会被更快、更频繁地复制。
二 四层方法如何分配精力
作者把信任基础分为四层,并称之为倒金字塔。从上到下依次是:代码库改进、自动检查与验证、文字说明、人工审核。越靠上,越值得投入精力,让下游的重复判断和检查变少。
这个顺序表达的是长期投入的侧重,不是固定百分比,也不是说每个任务都必须按四道工序依次通过。高风险变更仍然需要认真审核;已有项目也可以先为一个老问题补测试,再逐步调整结构。
第一层 用代码结构减少出错的机会
原帖列出的重点包括更好的架构、更强的类型与不变量、清晰的边界。
架构决定哪些职责放在一起、哪些操作必须通过规定接口。例如,把工具调度和实际工具实现分开,由调度层统一处理执行前检查,工具实现只负责具体工作,可以减少每个调用点自行拼装流程的机会。
类型帮助程序区分不同事物。把“待审批的调用”和“已经批准的调用”表达为不同状态,比四处传递一个随时可能被误解的布尔值更清楚。但类型能约束到什么程度,取决于语言和检查配置;运行时输入仍可能需要校验。
不变量指程序在指定范围内始终应该满足的条件。例如,“一个已拒绝的工具调用不能进入执行状态”。它不只是文档里的愿望,还应体现在状态转换、参数检查和测试中。
边界则规定谁能做什么。底层执行器不应成为所有模块都随手调用的公共捷径;如果确实存在内部接口,也应明确哪些模块可以使用,并通过检查约束依赖方向。
作者强调的是按问题类别消除错误,而不是一次次修补相同症状。例如,统一处理某类输入校验后,新功能就不必重复实现那段检查。不过,代码也会被修改,所以还需要下一层机制守住这些约束。
第二层 用自动检查尽早发现错误
原帖把 lint、测试、CI 和 TLA+ 等验证手段放在 static analysis 一项下。严格来说,这个分类偏宽:测试通常会运行程序,CI 是执行检查的流程,而 TLA+ 用于描述和分析系统模型。把这一层理解为“自动检查与验证”,更容易把握作者的用意。
不同工具各有职责。lint 可以检查规定的代码模式和部分依赖限制;类型检查发现接口、参数和状态使用问题;测试验证具体输入与操作后的行为;CI 把这些检查放进提交和合并流程;在确有复杂状态或并发问题时,模型检查等方法还能分析指定模型是否违反性质。
它们的共同优势是:能明确判断的问题,不必每次都让模型读一遍规则、推理一遍,再让人重新检查。一个稳定的检查可以反复运行,失败时给出具体反馈,因此有机会减少重复推理与返工的 token(模型处理文本的计量单位)消耗。
但“检查通过”必须对应明确范围。一个测试能证明该测试场景下没有执行工具,不能证明所有入口、所有并发情况都安全;TLA+ 对模型的分析,也不能自动证明实际代码完全符合模型。应把最重要的规则变成可执行检查,并确认检查真的能抓住要防的错误。
第三层 把需要判断的内容留在文字里
原帖所说的 prose 包括注释、规则文件、AGENTS.md(给编程 Agent 的项目说明文件)和 skills(可复用的工作指引),也就是需要 Agent 阅读理解、无法完全由程序强制落实的说明。
“尽量少用”不是不写。业务背景、设计原因、兼容性取舍、暂时不能修改的范围,往往无法靠 lint 表达,需要解释给 Agent。只是能被稳定检查的要求,不宜长期只靠一句提醒。
例如,“不能绕过权限入口”可以写成规则,但还应检查代码依赖;“这个接口暂时保留是因为旧客户端仍在使用”则需要留下背景,避免 Agent 把它误当成无用代码。好的文字帮助它理解检查背后的原因,而不是复制另一份庞大的约束清单。
作者特别提到 /create-verification-skill。它的作用是为当前项目建立验证流程,让 Agent 知道如何启动真实应用、操作关键功能、收集证据和清理测试现场。skill 本身仍是需要遵循的说明;它能够调动实际测试和工具,但不会因为写成一个文件就自动成为强制门禁。
第四层 把人工审核用在重要的判断上
人工审核最难随着代码产量同步扩大。Agent 可以快速提交很多改动,人却很难按同样速度细致理解每个 PR(代码合并请求)。因此,作者建议把一部分审核精力前移,用来建设一个让 Agent 默认更容易做对的环境。
自动检查擅长回答已定义的问题,但需求是否合理、业务行为是否符合预期、代价是否值得、是否触碰安全和数据边界,仍然需要人的判断。高风险改动不能因为测试全绿就跳过必要审核。
更好的循环是:人发现问题后,不只在当前 PR 留一句意见,还问一句“这类问题能否通过结构或检查减少”。能落实的部分进入代码库,下一次人就能少看重复错误,把注意力留给新的风险与取舍。
三 确定性为什么有价值
原帖认为,代码库改进更确定,也更节省 token,让人更放心。这个判断可以理解为:一条已经落实到程序中的约束,不需要每次依赖模型重新理解和记住。
例如,如果只提醒编程 Agent“新增工具时必须接入统一权限入口”,它仍可能漏接。把底层执行器限制为内部接口,并增加依赖检查和行为测试,才能让绕过入口的改动更难引入、更容易被发现。这里的重点是约束编程 Agent 产出的代码,而不是要求运行时模型记住一条提示词。
改造、维护和运行检查本身也有成本。值得优先处理的,是反复出现、影响较大、能够通过简单机制解决的问题,而不是为了“更适合 Agent”不断增加抽象层。
四 从过去的纠正记录里找改造方向
原帖后半段给出一套具体工作流:安装 cursor/plugins,创建一个新 Project,再让 Agent 从历史反馈中找出最常见的问题,提出有数据支撑的改造方案。[1][2]
这里的 Project 可以理解为承载这次任务和相关上下文的项目空间;原帖没有展开具体界面操作,不能据此假定不同工具的入口与能力完全一致。
这套方法的起点不是凭空问“请优化整个项目”,而是你已经指出过的真实问题。聊天记录、代码审核意见和历史提交,包含了项目当前最容易出错的地方,也包含你怎样判断这些错误。
先澄清并确认任务
虽然原帖把这一步写在编号 4,但它明确要求在开始前执行:使用 /sharpen 和 /in-your-own-words,先把任务变得清楚,再用自己的话复述并与你确认。
确认的重点包括要分析哪个项目、哪些历史材料可以使用、只出方案还是允许改代码,以及哪些行为必须保持。作者给出的帖子是一份工作流建议;把它转发给 Agent,不应被默认为已经批准访问所有聊天、安装插件或修改仓库。
收集你曾经提出的反馈
原帖第一步让 Agent 查看 Slack 或聊天消息,以及你针对 PR、代码和架构留下的审核意见。
要找的不是一句孤立的“这里不好”,而是反复出现的原因。例如,多次新增功能都绕过同一入口,多次把可选状态当成必有状态,或者每次重构都会误删某条兼容分支。把反馈与当时的代码、需求和后续修复对应起来,才能区分稳定的工程问题与一次性的偏好。
恢复你如何引导 Agent 的上下文
第二步使用 /recall 回看过去的工作记录,理解你通常怎样纠正方向:哪些是澄清需求,哪些是收紧范围,哪些是在重复提醒同一条约束。
这样做不是为了把每次对话都堆进新的提示词,而是恢复原因。如果只看到“不要这样改”,却不知道当时为什么不能改,就容易把局部决定误写成永久规则。
查历史提交并提出有证据的方案
第三步组合 /poteto-mode、/correct 和 /architect,检查过去的提交,寻找 Agent 最常踩的坑,再提出让自己负责的代码更适合 Agent 工作的架构方案。
原帖还明确要求:开放的技术问题优先用原型回答,不要全部推回给人;方案要有真实数据支撑。例如,先在小范围验证某种接口能否减少重复代码、检查能否抓住旧错误、现有行为是否仍通过测试,再决定是否扩大改造。
这与开始前确认需求并不冲突。目标、边界和重要取舍需要人与 Agent 对齐;已经确定范围内的技术假设,则应尽量由 Agent 自己调查和验证。涉及新的权限、生产变更或范围扩大时,仍需重新确认。
五 七个命令各自负责什么
这些命令来自 cursor/plugins 仓库中的 pstack 插件,属于该插件定义的 skills,不是所有 Codex 或其他 Agent 产品都默认内置的命令。实际使用需要先确认所在工具支持相应插件及调用方式。命令名只是入口,重要的是它背后的工作方法。[2]
/create-verification-skill:创建项目专用的验证流程,覆盖真实应用的启动、操作、证据收集与清理。它帮助 Agent 从“代码看起来对”走到“关键行为实际验证过”。[3]
/recall:恢复近期工作的上下文,包括进度、反复遇到的问题和后续动作,避免只凭零散片段判断。[4]
/poteto-mode:组织调查、设计、实现和验证等工程步骤,并按需要调用其他 skills。[5]
/correct:把重复错误转化为可执行的防护,优先考虑架构,其次是类型、lint 和测试,最后才补充文字说明;还要证明这些检查确实能抓住过去的错误。[6]
/architect:先明确类型、函数签名和模块边界,再推进实现,减少一边堆代码一边临时决定结构。[7]
/sharpen:让任务要求更严谨、更具体,而不是擅自扩大任务范围。可以围绕四个问题补足任务:专业人士会多做什么?从什么一手材料开始?用什么具体方法?用什么独立证据证明结果正确?这四问分别检查专业标准、依据、方法和验证,而不是把一个小任务扩成大项目。[8]
/in-your-own-words:用自己的话重述目标及背后的问题,让用户检查 Agent 是否真正理解。[9]
六 用工具权限检查串起四层方法
下面是一个延伸示例。这里有两个角色:一个是帮助开发者修改项目的编程 Agent,另一个是项目运行时请求调用工具的模型。文章讨论的是怎样让前者更可靠地维护后者所在的软件,不应把两者混为一谈。
假设开发者反复发现:编程 Agent 新增工具时,直接调用了底层执行函数,漏掉权限检查。只在 AGENTS.md 加一句“所有工具必须检查权限”,仍然依赖它每次都记住。
第一层可以调整执行结构。模型提出工具调用后,统一交给调度入口。入口检查权限:拒绝就返回拒绝结果;需要审批就等待决定;允许后才进入执行。底层执行器保持为内部模块,并约束哪些代码可以依赖它。统一入口本身不自动阻止绕过,模块封装和依赖检查需要一起配合。
这不等于必须使用 Hook。统一入口是在组织调用路径;Hook 是在特定位置插入扩展逻辑的机制。日志可以挂在执行前后的 Hook 上,权限也可以通过 Hook 实现,但必须明确拒绝如何中止执行,以及必需检查失败时怎样处理。不能因为“有一个 Hook”就认为权限一定得到落实。
第二层增加测试。模拟权限拒绝,检查底层执行器调用次数为零;模拟需要审批但尚未批准,也应为零;再覆盖批准、拒绝和取消后的状态转换。可以加入一个故意绕过入口的错误版本,验证依赖规则或测试会失败,避免出现“测试一直绿,却根本没测到风险”的情况。
第三层留下简短说明:为什么执行器不能被直接调用,新增工具应接入哪里,哪些历史兼容要求必须保留。第四层由人审查权限策略是否合理、测试是否覆盖真实风险,以及这一改造是否引入不必要复杂度。
这个改造让某类重复错误有了清晰结构和可验证的防线。它比每次口头提醒更可靠,也更容易解释失败发生在哪里。
七 从一个反复出现的问题开始
对个人项目,最实用的起步方式不是全面重构,而是选一类已经有证据的重复问题。先记录它出现在哪些提交、导致什么后果、目前为什么容易写错,再判断应放在哪一层解决。
优先选择最小有效改动。能通过收紧一个接口解决,就不必新增整套框架;能通过测试明确验证,就不要先写几十条规则。改完后保留原有行为测试,并加入针对历史错误的失败用例,确认防护机制确实有效。
如果想比较 Agent 是否更容易做对,可以设计一组受控对照:从同一仓库基线出发,建立未改造版和只应用目标改造的版本,使用相同任务、模型和设置,比较完成质量、重复错误、人工纠正次数、工具调用、token、耗时及检查成本。Agent 的结果有波动,单次成功只能作为初步证据;重要结论应重复验证。
对照目标应是错误减少、行为保持和维护负担下降,不是规则文件越来越长,也不是删除行数越来越多。对于权限、事务、兼容性等高风险部分,先限制范围,再根据结果逐步扩大。
结语
这篇帖子的重点,是把与 Agent 协作中反复消耗的判断,尽可能沉淀到项目里。结构让正确路径更自然,检查让错误及时暴露,文字解释必要背景,人负责重要取舍,并持续判断哪些经验值得落实成机制。
当下一次你准备再次提醒 Agent 时,可以先问:这个问题真的只能靠它记住吗?如果能用一个清晰接口、一条类型约束或一个有效测试解决,就把经验留在代码库里。这样,过去花在纠正错误上的精力,才会帮助未来的每一次开发。
来源
[1] poteto 原帖
[2] cursor/plugins 的 pstack 插件
[4] recall
[5] poteto-mode
[6] correct
[7] architect
[8] sharpen
系列目录 · 与 AI 共事
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9