ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Codex CLI 模型切换、权限管控与 AGENTS.md 配置实践

Codex CLI 模型切换、权限管控与 AGENTS.md 配置实践

上个月接手一个半老不新的仓库,包管理器版本混乱、测试脚本三年没人动过。我原本打算花两天做一次彻底梳理,结果用 Codex CLI 配了一份还算讲究的 AGENTS.md,把模型切换和权限管控按场景分层调好,第一天下午就把依赖对齐和测试补齐这两件事推完了。这件事之后我才意识到,多数人对这类终端编码代理的抱怨——"不听话""乱改文件""跑一半卡住"——问题基本不在模型本身,而在于三件事没配对:Codex CLI跑的是哪个档位的模型、权限管控给到了什么粒度、AGENTS.md里写没写清楚这个仓库的规矩。这篇就按这三条线,把我踩过的坑和现在稳定用的配置完整拆一遍。适合已经装好工具但用得不顺的人,也适合准备把它接进团队流程、正在评估风险边界的人。所有参数和路径我都会给出可直接抄的写法,同时标注哪些是我实测有效的、哪些需要你按自己环境再确认。

1. 先把 Codex CLI 的定位搞清楚再动手

1.1 它到底解决哪一类问题

很多人第一次用 Codex CLI,会把它当成"命令行里的补全工具",这是定位偏差。补全工具处理的是光标周围几十行的局部上下文,而 Codex CLI 处理的是任务级上下文:你给它一句"把 src/legacy 下的回调风格统一成 async/await,改完跑一遍测试",它会自己规划步骤——先列文件、再读文件、再改、再执行验证命令、发现失败再回头改。这个"自己规划多步并执行"的能力,才是它和编辑器插件的本质区别。

由此可以推出它的能力边界。适合的场景:批量机械重构、给没有测试的老模块补测试、跨文件重命名与接口迁移、读陌生仓库并产出结构说明、修 CI 里那条一直红的流水线。这类活共性是"步骤多但判断少",人做起来枯燥且容易漏,正是代理擅长的。不适合的场景:需要人做架构取舍的设计决策、依赖视觉判断的界面微调、涉及生产数据的操作、以及任何你需要留完整审计痕迹的变更。最后一条尤其重要——代理改代码的速度远快于人审代码的速度,如果你所在的流程有强制评审要求,务必让它产出小颗粒度的提交,而不是一次性糊一个大 diff 给你。

还有一个常被忽略的点:它的价值不在"写得多",而在"验证闭环"。我现在的用法基本是让它改完必须自己跑验证命令,跑不过就自己修,修到过为止。这个闭环一旦建立,返工率会明显下降。反过来,如果你不让它跑验证,它就会"看起来很自信地"交一份编译不过的代码,你还得自己从头查。

1.2 安装与首次运行的最小路径

安装本身没什么坑,关键是 Node 版本。Codex CLI 依赖较新的运行时,Node 建议 22 以上,低于这个版本会在启动阶段报语法错误,而报错信息往往指向依赖包内部,很容易误判成安装失败。先用node -v确认,再动手装。

# 方式一:npm 全局安装 npm install -g @openai/codex # 方式二:macOS 用 Homebrew brew install codex # 验证 codex --version

登录环节有两条路:交互式账号登录和 API Key。前者适合个人日常使用,后者适合 CI 或容器环境。我一般建议本地开发用交互式、流水线用环境变量注入 Key,不要在仓库里放任何凭据文件。首次运行直接敲codex会进入交互式界面(TUI),此时它会提示你选择工作目录、确认信任范围。这里有个容易被忽略的细节:首次在某个目录启动时它问的"是否信任此目录",本质是在确定沙箱的可写边界,别顺手全点同意,尤其当你在家目录或者包含多个项目的父目录下启动时。

# 指定工作目录启动 codex --cd /path/to/your/repo # 非交互模式跑一次性任务(适合脚本/CI) codex exec "跑一遍 lint 并修掉所有可自动修复的问题"

codex exec这个子命令值得单独说。它不走 TUI,直接把任务跑完输出结果,退出码能反映成败,非常适合塞进脚本。我把它用在两个地方:一是每日定时跑一次"检查依赖是否有已知问题并生成报告",二是提交前的自动化检查。注意非交互模式下没人给你点"同意",所以权限策略必须提前配好,否则它会卡在等待审批上直到超时。

1.3 配置文件长什么样、放在哪

Codex CLI 的主配置在用户目录下的~/.codex/config.toml,这是 TOML 格式,和 JSON 配置的工具相比可读性好不少,注释也能写。我现在的配置大致是这样,可以直接当模板改:

# ~/.codex/config.toml model = "gpt-5-codex" model_reasoning_effort = "medium" approval_policy = "on-request" sandbox_mode = "workspace-write" [sandbox_workspace_write] network_access = false # 常用档位预设,用 --profile 切换 [profiles.fast] model_reasoning_effort = "low" [profiles.deep] model_reasoning_effort = "high"

字段含义逐条说清楚:model是默认模型标识,model_reasoning_effort控制推理强度(后面单独讲),approval_policy决定"要不要停下来问人",sandbox_mode决定"能不能写文件、能不能联网",[sandbox_workspace_write]是workspace-write模式下的细化项。[profiles.xxx]是预设组,命令行用--profile fast就能整套切换,比每次敲一长串参数舒服得多。

提示:不同版本对字段名的支持有差异,改完配置后先用codex --help或跑到 TUI 里执行/status看一眼实际生效值,别假设写进去就一定生效了。我自己就遇到过把旧字段名写进配置、程序静默忽略、结果一直用默认模型跑了好几天的尴尬情况。

2. 模型切换:不是越强越好,是越匹配越好

2.1 模型档位之间的真实差异在哪

新手最容易犯的错,是无脑用最强档跑所有任务。实际用下来,不同档位的差异主要体现在三个维度:多步规划的稳定性、单步执行的细致程度、单位时间的产出。高推理档在长链路任务上明显更稳,比如"找出这五个模块之间的循环依赖并拆掉"这种需要反复推理的活;但如果你只是让它"把 utils 里这三个函数改成箭头函数风格",用高推理档纯属浪费,响应慢、token 消耗大,收益却几乎为零。

还有一个维度容易被忽略:上下文窗口。不同模型能吃进去的上下文长度不一样,长会话跑到后期,如果你中途切到一个窗口更小的模型,早期的对话内容会被截断,代理就对前面讨论过的约定"失忆"了。这个现象很隐蔽——它不会报错,只会开始做出和前面约定相悖的改动。我的应对办法是:一个任务一个会话,不要在一个会话里干三件不相干的事,也别指望跨会话记忆。

关于具体模型标识,我不在这里写死版本号,因为模型迭代速度很快,写了大概率过时。稳妥做法是进 TUI 后输入/model看当前可用列表,或者用codex --help查默认值,再根据列表里的命名规律(通常带轻量/标准/高推理的区分)自己选。

2.2 三种切换方式及各自适用场景

切换模型有三条路径,用对了场景很重要。

第一条:启动参数。codex -m <模型名>或codex --model <模型名>,配合-p <profile名>调用预设。适合"我这次就是干某类活"的一次性场景,比如临时跑一个大规模重构。

第二条:配置文件。改~/.codex/config.toml的model字段,影响之后所有会话。适合确定长期主力档位,一般设成标准档即可。

第三条:会话内切换。TUI 里输入/model,会列出可选模型让你点选,切完当前会话立即生效,上下文保留。适合任务进行到一半发现"这活比想象中复杂"的情况——我经常是开局用低档快速摸底,发现确实绕,中途切高档接着干。

# 临时指定模型 + 推理强度 codex -m gpt-5-codex -c model_reasoning_effort="high" # 用预设启动 codex --profile deep # 非交互模式指定模型跑任务 codex exec -m gpt-5-codex "分析 tests 目录下覆盖率最低的三个文件并列出原因"

-c这个参数值得记住,它可以在命令行覆盖任意配置项,语法是-c key=value,嵌套字段用点号。这个能力在写脚本时特别好用——不用为了一次特殊需求去改全局配置。

2.3 按任务分层的选型对照表

下面这张表是我这几个月沉淀下来的经验值,你可以直接拿去当默认策略,再按自己项目特点微调。

任务类型建议推理强度大致耗时量级说明
格式化、重命名、注释补全low数十秒机械变换,高推理无收益
单文件内逻辑修改low 到 medium1 到 3 分钟边界清晰,上下文需求小
补单元测试medium3 到 8 分钟需要读懂被测代码的意图
跨文件接口迁移medium 到 high5 到 15 分钟依赖关系复杂,规划易出错
排查间歇性失败high10 分钟以上需要多轮假设验证
陌生仓库摸底与产出结构文档medium5 到 10 分钟主要是读,不需要高强度推理
大范围重构方案设计high15 分钟以上建议先让它出方案再执行

用这张表的正确姿势是:先按任务类型选一档,跑一次看结果质量,如果发现它反复在同一个地方打转或者漏掉明显依赖,就往上提一档重跑;如果发现它很快就完成且质量足够,就往下压一档省时间。别一上来就默认最高档,那是把工具当锤子用。

2.4 切换模型时的三个真实坑

坑一:切档后行为风格突变。不同模型对同一份 AGENTS.md 的遵从度不一样。我遇到过在标准档下严格按约定跑测试的配置,切到轻量档后它开始跳过验证直接说"已完成"。解决办法是在 AGENTS.md 里把"必须执行验证命令"这条写成硬性要求并放在最靠前的位置,同时权限配置上不让它轻易跳过。

坑二:长会话中途降档导致上下文压缩。一个跑了四十多轮的会话,中途切到小窗口模型,它开始重复问已经回答过的问题。这种时候正确的做法不是硬撑,而是把当前进展总结成一段话写进 AGENTS.md 或者单独存一个任务笔记文件,然后开新会话。

坑三:非交互模式下模型标识写错不报错。codex exec里如果写了不存在的模型名,某些版本的表现是静默回退到默认模型,你从输出里完全看不出来。所以我在脚本里一定会先跑一次codex --version和一个极简任务做冒烟测试,确认模型确实生效。这个习惯来自一次 CI 里跑了两周才发现用的根本不是指定模型。

3. 权限管控:让代理能干活但不能乱来

3.1 两个正交维度,别混为一谈

Codex CLI 的权限体系由两个维度组成,很多人把它们混着理解,结果配置出来自己都说不清会发生什么。

第一个维度是审批策略(approval policy),回答"它要不要在动手前问你"。可选值大致是untrusted(只允许安全的读操作,其他一律问)、on-request(模型自己判断什么时候需要请求批准)、on-failure(先跑,失败了再问)、never(从不问,直接干)。第二个维度是沙箱模式(sandbox mode),回答"它物理上能不能写、能不能联网"。可选值大致是read-only、workspace-write、danger-full-access。

这两个维度是相乘关系,不是替代关系。举个容易误解的组合:approval_policy = "never"配上sandbox_mode = "read-only",效果是"它不问你就直接尝试,但所有写操作都会被沙箱拦下来失败"。听起来安全,实际上很浪费——它会反复尝试写入、反复失败、反复重试,最后给你一份"任务无法完成"的报告。正确的思路是先想清楚"这个任务需要写到哪",再决定沙箱,最后才决定审批。

审批策略沙箱模式实际行为推荐场景
on-requestworkspace-write写工作区不问,越界才问本地日常开发,默认首选
on-failureworkspace-write先执行,失败才请求任务明确、想减少打断
untrustedread-only几乎每步都问首次接触陌生仓库、审计
neverread-only只读分析,不打断CI 里做代码审查报告
neverdanger-full-access完全放开一次性容器内,用完即弃

3.2 沙箱的实际边界在哪

workspace-write的"工作区"通常指你启动时所在的目录及其子目录,加上一些临时目录。这个边界比很多人想象的窄:如果你想让它写的东西在仓库外面(比如某个共享缓存目录、或者生成产物输出到../dist),默认会被拦。解决办法不是升到danger-full-access,而是用白名单把那个路径加进去:

[sandbox_workspace_write] network_access = false writable_roots = ["/path/to/shared/cache"]

network_access这个开关特别值得单独拎出来说。默认关闭是有道理的——代理如果能随便联网,它可以下载任意脚本执行,风险面立刻放大一个数量级。但现实里有一类任务确实需要网络:装依赖、拉取某个包的元信息、访问内部服务做接口联调。我的处理原则是按需临时开,不在全局配置里常开:

# 只在这次会话里开网络 codex -c sandbox_workspace_write.network_access=true --cd ./repo

这里有个副作用要提前知道:开了网络之后,包管理器写缓存、写 lock 文件的行为可能落在工作区之外,进而触发额外的审批弹窗。我一般的做法是先用一次性的、在网络开启状态下把依赖装好并提交 lock 文件,之后日常开发就把网络关掉,避免代理在不该联网的时候偷偷去查什么东西。

3.3 配置的层级与优先级

配置有三个来源:全局用户配置、项目级配置(较新版本支持在仓库内放置配置文件)、命令行参数。优先级从低到高,命令行最高。这个层级设计的实际意义在于:团队可以把项目级配置提交到仓库里,保证所有人跑同一个代理时行为一致,个人再在全局配置里覆盖自己的偏好。

我在项目里放的项目级配置通常只写三件事:默认模型档位、沙箱边界(哪些目录可写)、以及必跑的验证命令相关的环境变量。审批策略我不放在项目级,因为它和个人工作习惯强相关——有人喜欢全程不打断,有人喜欢每步确认,这个不该由仓库强制。

注意:把danger-full-access或者approval_policy = "never"写进项目级配置是相当危险的做法,等于要求所有拉这个仓库的人都在无防护状态下跑代理。哪怕是在内部仓库,也建议至少保留workspace-write的沙箱。

3.4 我在权限配置上的几条硬规矩

规矩一:全局配置永远不写danger-full-access。这个模式我只在一次性容器里用,用完即弃。原因很简单:全局配置意味着"以后每次启动都是这个状态",而人是有惰性的,一旦习惯了不被打断,就不会再去检查它干了什么。

规矩二:never只和read-only搭配。我把它用在 CI 的代码审查环节——让代理读整个仓库、分析潜在问题、输出一份报告,全程不需要写权限,自然也不需要审批。这个组合非常安全,因为最坏情况它也只能读。

规矩三:on-failure要用在任务描述足够明确的时候。这个模式的逻辑是"先干,出错再问",收益是减少打断,风险是如果任务描述模糊,它可能朝着完全错误的方向执行一大堆命令才发现不对劲。我的判断标准是:如果一句话能把验收标准说清楚(比如"让npm test全绿"),就用on-failure;如果说不太清楚(比如"优化一下这个模块"),就用on-request。

规矩四:看到反复弹窗先想是不是沙箱边界设窄了。有些人嫌弹窗烦就直接开到最松,这是典型的用错解法。弹窗频繁通常说明任务需要的写入范围超出了当前沙箱,正确做法是把那个具体路径加进writable_roots,而不是把整个沙箱拆了。

4. AGENTS.md:把团队约定写进上下文

4.1 它的加载机制决定了怎么写

AGENTS.md 是一份纯文本约定文件,代理启动时会自动读取并作为上下文的一部分。关键在于它的加载顺序:用户级别的全局文件在~/.codex/AGENTS.md,然后是仓库根目录的AGENTS.md,再往下是当前工作目录沿途各级子目录里的AGENTS.md。层级越深、距离工作目录越近的,优先级越高。

这个机制带来一个很实用的用法:根目录放全局约定,子目录放模块专属约定。比如一个前后端同仓的项目,根目录的 AGENTS.md 写通用的构建命令和代码风格,frontend/AGENTS.md写组件命名规范和状态管理约定,backend/AGENTS.md写数据库迁移流程和接口版本规则。代理在前端目录里干活时,能同时看到通用约定和前端专属约定,而不会把后端的规矩套到前端代码上。

需要注意的一个细节:如果你在根目录启动、但让它改的是深层子目录的文件,子目录的 AGENTS.md 是否被读取,取决于实现细节。稳妥做法是在任务描述里显式指明"参考frontend/AGENTS.md",或者干脆--cd到那个子目录再启动。

4.2 一份可以直接抄的模板结构

我现在的 AGENTS.md 基本固定成六段,顺序很重要,因为代理对靠前内容的遵从度通常更高。

# 项目约定 ## 必须先读 - 这是一个 Node + TypeScript 项目,包管理器固定用 pnpm,不要用 npm 或 yarn。 - 所有命令都在仓库根目录执行,不要在子目录里单独 install。 ## 常用命令 - 安装依赖:pnpm install - 开发:pnpm dev - 单测:pnpm test - 单文件测试:pnpm test <文件路径> - 类型检查:pnpm typecheck - 格式化:pnpm format ## 目录地图 - src/core:核心逻辑,改动需谨慎,接口变更必须同步更新 src/core/index.ts 的导出 - src/adapters:外部集成,每个适配器一个目录 - tests:集成测试,单测与被测文件同目录 - scripts:一次性脚本,不进构建产物 ## 代码风格 - 不用 default export,统一具名导出 - 异步统一 async/await,不用回调 - 错误处理统一走 src/core/errors.ts 里定义的错误类型 - 新增依赖前必须先问我 ## 禁区 - 不要修改 migrations 目录下已经存在的文件,只能新增 - 不要动 .github/workflows 下的任何配置 - 不要提交任何带真实凭据的文件,配置一律走环境变量 - 不要删除 tests 目录下已有用例,只能新增 ## 完成标准 - 改完代码必须执行 pnpm typecheck 和 pnpm test,两者都通过才算完成 - 如果测试失败,先判断是你的改动导致的还是本来就失败,不要盲目改测试来让它变绿 - 最终回复里必须列出你改了哪些文件、跑了哪些命令、结果如何

这份模板里最值钱的是最后两段。"禁区"段落解决的是"代理热情过度"的问题——它天然倾向于"帮你把问题彻底解决",而彻底解决有时候意味着删掉一个"看起来没用"的测试、或者"顺手优化"一下已经上线的迁移脚本。把这些写清楚,能省掉大量事后回滚。"完成标准"段落解决的是"自说自话"的问题,明确要求它跑验证并把结果列出来,你就有了一个可核查的交付凭证,而不是一句"已完成"。

4.3 什么该写、什么不该写

写 AGENTS.md 最容易犯的错是写成一份项目 README 的复制品。判断标准很简单:能从代码或配置里直接读出来的信息,不要写。比如"这个项目用 TypeScript"——它看一眼tsconfig.json就知道了,写进去纯占上下文。真正值得写的是那些"读代码读不出来"的东西。

我总结的该写清单:非默认的工具选择(为什么用 pnpm 不用 npm)、有隐含顺序的操作流程(先跑迁移再跑测试)、代码里看不出的业务约束(某个字段不能为空是因为下游依赖)、团队的口头约定(提交信息格式、分支命名)、明确的禁区、以及验收标准。

不该写清单:能从配置文件推断的、具体的依赖版本号(会过期)、大段业务背景介绍(占上下文且和改代码无关)、历史遗留问题的心路历程、以及任何你希望"它自己判断"的模糊表述。最后一条尤其反直觉——很多人喜欢写"请遵循最佳实践",这句话对代理来说等于没写,因为"最佳实践"在不同语境下完全不同,它只能瞎猜。

4.4 用"纠错沉淀"的方式渐进完善

不要指望一次写出完美的 AGENTS.md。我的做法是每次被它气到,就往里加一条。它跳过测试?加"改完必须跑测试"。它用了 npm 装了包导致 lock 文件冲突?加"固定用 pnpm"。它在修改数据库迁移文件?加进禁区。三个月下来,这份文件会变成一份非常贴合你项目的"血泪清单",价值远超任何通用模板。

有个小技巧:给它加规矩的时候,连同"为什么"一起写。比如不要只写"不要改 migrations",而是写"不要改 migrations 下的已有文件,因为生产环境已经执行过这些迁移,改动会导致新老环境结构不一致"。带上原因之后,代理在遇到类似但不完全一样的情况时,能做出更合理的判断,而不是死板地只认字面。

另一个技巧:AGENTS.md 别写太长。上下文是有限资源,一份两千行的约定文件会挤压它读代码的空间。我一般控制在 150 行以内,超了就说明有些内容该拆到子目录的 AGENTS.md 里去。

5. 三者串起来:一套能跑通的工作流

5.1 新仓库接手时的完整流程

拿到一个陌生仓库,我现在固定走这套流程,大概二十分钟能建立起可用的协作状态。

第一步,只读摸底。用最保守的组合跑一次分析任务,让它读目录结构、依赖清单、CI 配置、测试脚本,输出一份"这个项目怎么构建、怎么测试、有哪些明显技术债"的报告。这一步不给写权限,所以随便它跑都不会出事。

codex exec -s read-only -a never "分析当前仓库:说明构建方式、测试命令、目录职责划分,列出三个最明显的维护风险点"

第二步,根据报告写 AGENTS.md。把第一步的输出当素材,人工筛选后落成 AGENTS.md。这一步必须人工介入,因为代理总结出来的东西会包含大量"正确的废话",需要你删掉,同时补上它读不出来的团队约定和禁区。

第三步,做一次小改动验证。找一个真正需要改的小问题(比如某个函数缺参数校验),用on-request+workspace-write跑一次,观察它的行为:有没有按约定跑测试、有没有遵守禁区、最终报告是否完整。这一步是校准,如果发现它行为不对,说明 AGENTS.md 写得不够明确,回去补。

第四步,固化配置。把验证通过的模型档位和沙箱边界写进项目级配置,把 AGENTS.md 提交进仓库。之后再有人接手这个仓库,体验就是一致的。

5.2 日常迭代的节奏控制

日常使用时,我基本按"任务颗粒度"来决定配置,而不是按心情。

小改动(改个函数、补个校验、加一行日志)用低推理档配on-failure,追求的是快,几十秒出结果。中等改动(改一个模块的行为、补一组测试)用标准档配on-request,让它关键步骤问一下。大改动(跨模块重构、接口迁移)先单独跑一次"出方案"的任务,用高推理档配read-only,让它把改动计划和影响面列出来,人工审一遍确认没问题,再换成可写模式执行。

这个"先出方案再执行"的两段式用法,是我踩了不少坑之后固定下来的。直接让它在可写模式下做大改动,最常见的失败模式是"改到一半发现方向错了,但已经改了一大片",回滚成本很高。先让它用只读模式把计划写出来,成本几乎为零,收益却很大。

5.3 团队分发时要注意的事

把配置和 AGENTS.md 提交进仓库时,有几件事要提前想清楚。第一,不要把个人偏好写进项目级配置,比如审批策略、默认模型档位这类因人而异的东西,让每个人在全局配置里自己定。第二,项目级配置里不要出现任何路径硬编码,writable_roots这种字段在不同人机器上路径不同,写死了别人一跑就报错,这类配置应该通过环境变量或者干脆让人自己加。第三,AGENTS.md 要有版本感,改动较大的时候在提交信息里说明改了什么规矩、为什么改,方便其他人理解行为变化。

还有一条经验:团队里第一个把 AGENTS.md 写起来的人,往往会被其他人抱怨"规矩太多"。这时候别硬推,先自己用两三周,把"因为它写了这条规矩,所以避免了一次事故"的具体例子攒出来,再拿出来讲。有具体案例支撑的约定,接受度会高很多。

6. 常见问题速查与排查思路

6.1 高频故障与对应处理

下面这些是我实际遇到过、并且有明确处理路径的问题,整理成表方便对照。表里"可能原因"一栏按发生概率从高到低排列。

现象可能原因处理方式
启动即报语法错误Node 版本过低升级到 22 以上,node -v确认
反复弹出写入审批目标路径超出沙箱边界加入writable_roots,而非放宽沙箱
装依赖一直失败沙箱禁网单次会话临时开network_access
非交互模式卡住不动审批策略需要人工确认但无人确认改成never配合read-only,或on-failure
不遵守 AGENTS.md 约定约定位置太靠后或表述模糊移到文件前部,补充"为什么"
跳过验证直接报完成完成标准没写死,或用了低推理档补"必须执行 X 且通过",考虑升档
中途开始重复问已答问题长会话切换了上下文窗口更小的模型总结进展后开新会话
改了不该改的文件禁区未声明把文件或目录写进 AGENTS.md 禁区段
输出内容与仓库实际情况不符工作目录不对或没读到子目录约定用--cd指定正确目录
codex exec退出码非零但看不出原因任务描述模糊导致代理主动放弃把验收标准写具体,先手动跑一遍目标命令

6.2 几个表里放不下的细节

关于"反复弹窗"的正确解法。新手最容易在这里走偏:嫌烦就直接把沙箱开到最大。但弹窗本身是个信号,它在告诉你任务的实际写入范围。正确做法是看弹窗内容,判断这个路径是不是真的该写。该写的加白名单,不该写的说明你的任务描述有问题——你在让它干一件超出预期范围的事。我遇到过一次它想写~/.npm缓存目录,追下去发现是包管理器版本不匹配导致的,加白名单只是掩盖问题。

关于"代理自我发挥"。有个现象是它会"顺手"做一些你没要求的事,比如修复一个无关的 lint 警告、重排一下 import 顺序。这在多数情况下无害,但如果你的仓库对 diff 的干净程度有要求,就需要在 AGENTS.md 里明确"只改动与任务直接相关的文件"。我现在的写法是"除直接相关文件外不产生任何变更,如发现其他问题请在最终报告中列出但不要修改",实测有效。

关于长任务的止损。一个任务跑了很久还在打转,别指望它能自己走出来。我的止损线是:同一个错误它尝试修复超过三次,就中断它,手动分析问题根源。常见根源有两个——任务描述本身有歧义(它每次理解都不一样),或者环境有问题(依赖没装好、测试本来就红)。把这两类问题解决掉再重跑,比让它在死循环里烧半小时划算得多。

关于成本控制。高推理档跑长任务的消耗会明显高于低档,如果在意成本,最有效的办法不是降档,而是把任务拆小。一个大任务拆成五个小任务,每个用低档跑,总成本往往低于用高档跑一个大的,而且中间你能检查,出错时回滚范围也小。这个结论和我最初的直觉相反,试过几次之后才确信。

关于验证命令的选择。让它跑的验证命令要满足两个条件:够快、够准。跑一遍完整集成测试花二十分钟,代理会倾向于跳过或者只跑一部分;只跑类型检查又太宽松,逻辑错误查不出来。我的做法是在 AGENTS.md 里明确"快速验证用 X,涉及核心逻辑改动时再跑 Y",给它一个分层的验证策略,而不是一个笼统的"跑测试"。

最后分享一个我一直在用的小习惯:每完成一个中等以上的任务,如果它表现不错,我会顺手检查一下 AGENTS.md 里有没有哪条规矩其实是多余的——有些约定在模型能力提升之后已经不需要了,留着只会占上下文。这份文件应该是一份持续瘦身的活文档,而不是一次写完就供起来的东西。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进