
如果你的 Codex 最近突然开始频繁自作主张改错文件对明确指令视而不见先别急着骂模型变笨了——转过身去看看仓库里的 Skill 目录和 AGENTS.md。我前两周就撞上过这么一回一个平时很稳的 Codex 实例跑一个“给接口加个 total 字段”的小任务竟然顺手把三个模块重构成了另一套架构还把我精心写的分页逻辑给删了。排查到最后才发现问题根本不在模型而在两年前埋下的一份旧 Skill 和一份早已和仓库脱节的 AGENTS.md。这问题特别普遍你以为配置是帮 Codex 提升上限其实过期的配置正在一点一点拽它的下限。这篇文章就是我从症状、根因到清理迁移的完整记录适合所有正在用 Codex 处理真实项目、又明显感觉“它最近变蠢了”的人。1. Skill 不是“装完就完”旧技能包的几种腐化方式1.1 先搞清楚 Skill 是怎么“进入” Codex 的很多人的误解是把 Skill 当成一个静态说明文档存进去就再也不管。实际上在 Codex 这类终端编码代理的工作流里Skill 是一个会被主动扫描、匹配和注入的活文档。工具的加载器会遍历指定目录比如项目里的 .agent/skills 或者用户级配置目录读取每个文件夹下的 SKILL.md文件头部的 frontmatter 里 name 和 description 会被拿去建立索引任务来的时候工具根据语义匹配决定要不要把对应的正文塞进上下文里。这个过程跟人类带新人很像你给新同事的不是一本随时可以查的百科而是每次工作前都往他桌上扔几本“你可能用得上的手册”。手册多了、旧了他就会照着错误的手册做事。所以“曾经的 Skill”问题本质上是一个时效性问题。它们在你刚配置的那一刻可能很好用但随着项目迁移、框架升级、脚本删改技能包里的每一条指令都在慢慢过期。可怕的是你不会主动感知到这件事因为你根本看不到 Codex 的内部决策只能看到它越来越不听话。1.2 我整理出来的四种腐化模式我把自己这些年见过的 Skill 翻车现场归成四类每一类都有很典型的可辨识症状整理成一张表方便对照腐化类型典型症状常见例子格式腐化Skill 无法被正确识别或者被频繁误激活旧版 SKILL.md 缺 description 字段导致所有涉及数据层的任务都误匹配到这个技能内容腐化正文步骤含混模型自由发挥空间大某 Skill 里写“按需优化查询”模型每次都能截断操作、乱加索引依赖腐化引用的脚本、模板、路径已失效Codex 反复尝试补全迁移助手 Skill 引用了 scripts/migrate.sh但文件早已删除模型总在尝试“重建”它规则腐化旧的权限规则、目录约定与当前项目结构冲突规则写着“不要动 legacy/”但这个目录已经重命名模型为了避开它绕了一大圈格式腐化最阴险因为它会让 Skill 变成一个“万金油”不管什么任务都被激活白白消耗上下文还容易把模型往错误方向带。内容腐化是日常大头很多人写 SKILL.md 只图自己看得懂不图机器可执行语义含混的步骤就是给模型自由发挥留的口子。依赖腐化最惊悚因为它会让 Codex 觉得自己在做“分内之事”——模型不会告诉你脚本不存在它会很努力地把脚本“脑补”出来而脑补的产物往往就在你的代码库里留下一堆莫名其妙的文件。规则腐化则是老仓库迁移后的高发问题目录一改名旧规则立刻变成劝退指令。1.3 为什么“多”不等于“强”Skill 库最容易犯的错就是囤积。我见过有人攒了二十多个 Skill 还觉得 Agent 更强了结果每次会话的上下文窗口是有限的每多激活一个 Skill就是在压缩模型真正处理代码的空间更重要的是匹配算法面对一堆描述模糊的技能时误激活的概率会直线上升。这跟带新人是一个道理给新手员工一摞厚重的手册不如给三张关键流程卡。配置 Skill 也是这样少而准永远好过多而杂。如果你发现 Codex 干什么事都拖泥带水先数数它到底激活了几个技能。另外一个很容易被忽略的坑是很多 Skill 正文里会写“先读取某某配置文件”“再执行某某脚本”如果这些路径已经不存在模型就像拿着过期的地图找路。它不会停下来说“地图错了”只会顺着错误路线继续走直到走出一条诡异的路。2. AGENTS.md 里那些“规矩”正在悄悄绑架模型2.1 先说清楚 AGENTS.md 的初衷AGENTS.md 的作用是给 AI 代理一份项目级的操作说明书工具在打开项目时会自动读取根目录的这个文件把它当作行为约束。如果一个 Skill 相当于“具体任务的专项手册”那 AGENTS.md 就是整栋楼的物业公约哪些地方能去哪些事能做用什么命令验证。初衷很美好但问题在于公约一旦跟不上项目演进它就会变成对模型最隐蔽的绑架。因为 Skill 至少还有“激活”的过程而 AGENTS.md 是默认生效的——你甚至未必意识到它在对你的 Codex 发号施令。我见过不少人把 AGENTS.md 当成写满“愿望清单”的地方什么锦上添花的建议都往里塞比如“尽量复用现有工具”“保持代码整洁”这种废话。这类规则不仅没有约束力还会让真正重要的硬性约定淹没在一堆噪声里。模型是概率系统它对上下文里每一行字的注意力权重是不一样的当整份文件 80% 都在说正确的废话时那 20% 的关键约束反而容易被忽略。2.2 五种典型的“绑架”症状第一种是过时命令。AGENTS.md 里写着“构建用 make build测试用 make test”仓库却早已切换到 npm 或 pnpm于是 Codex 每次任务都会先尝试 make发现根本没有 Makefile然后自己脑补一个构建流程出来浪费时间还容易出错。第二种是过度禁止。禁止清单写了一大堆模型怕踩雷干脆绕着走把简单改动硬是憋成一次伤筋动骨的大重构。第三种是示例代码已经失效。约束里附带了一段旧接口的调用示例模型在新代码里照抄这段旧 API连编译都过不了。第四种是层级冲突。根目录要求“所有业务代码放 core/ 下”子目录又规定“放 mods/ 下”模型会在两个规则之间摇摆行为随机漂移。第五种是上下文膨胀几千行的 AGENTS.md 纯注入就吃掉大量上下文关键约束反而被稀释。这五种症状往往不是孤立的。一份老旧的 AGENTS.md 常常同时犯下好几个毛病命令过时、示例失效、目录对不上号。而它的影响力又比单个 Skill 大得多因为 Skill 只在匹配时注入AGENTS.md 每次会话都在场它不像是“干扰项”更像是“指挥棒”。2.3 为什么说它比 Skill 更隐蔽Skill 的问题通常能被你看见因为你会看到日志里它被激活看到它把奇怪的指令加进上下文。但 AGENTS.md 的干扰是策略级的——它不说话却改变了 Codex 对每个任务的判断方式。表现就是模型行为很不稳定同一个问题今天这样做明天那样做。你以为是抽卡运气其实是因为它在两份矛盾规则之间反复横跳。排查难度也因此高一个量级它不会报错不会警告只会让你觉得“模型今天是不是状态不好”。3. 一次真实翻车排查从“乱改代码”到锁定元凶3.1 事故现场上个月我在整理模拟项目X的重构计划仓库结构比较老根目录有一份 800 行的 AGENTS.md.agent/skills 下躺着 4 个 Skill其中三个是上一个技术栈时代留下的。交给 Codex 的任务很明确在 users 列表接口返回体里增加 total 字段不要改动路径和分页逻辑。结果它一顿神操作把分页逻辑删了把三个文件里的实现整套替换成新方案还引入了异步队列git 提交信息写的是“重构用户模块以便支持后续扩展”。我当时的表情可以用扭曲来形容。冷静下来之后我做了一组对照实验整个过程比定位普通 bug 更像在玩推理游戏。3.2 第一步分别关掉 AGENTS.md 和 Skill做最小化 A/B我先备份不直接删除mv AGENTS.md AGENTS.md.bak mv .agent/skills /tmp/skills.bak接着用同一个最小任务跑 Codexcodex run 给 users 列表接口返回体增加 total 字段不改接口路径和分页逻辑结果非常干净模型一步到位。这说明问题肯定出在配置层不在模型本身。接下来要定位是哪一个配置在捣鬼做法是先只关 AGENTS.md、Skill 保持原样跑一次再只关 Skill、AGENTS.md 保持原样跑一次。结果很有意思只保留 AGENTS.md 时行为异常只保留 Skill 时也有问题。也就是说两边都有问题而且影响方向还不一样。这彻底推翻了我最初“只要让配置更完整就更好”的想法。3.3 第二步二分法定位 AGENTS.md 里的具体“绑匪”把 AGENTS.md 从 800 行拆开测试我采用了最笨也最可靠的二分法先注释掉后半部分保留前半部分跑任务正常再注释掉前半部分保留后半部分跑任务异常立刻复现。于是迅速锁定问题在后半部分的一个小节里。那行规则写着“禁止修改 shared/ 目录下的任何文件”。问题来了这个项目的 shared/ 目录早在两个月前被重命名为 core/。模型拿到的规则是禁止一个不存在的目录为了遵守这条幽灵规则它只能绕开 core/去动那些本不该碰的模块。这条规则在当下技术栈里完全就是负资产但它作为“最高约束”被 Codex 严格执行了。这个发现让我出了一身冷汗Codex 并不是故意捣乱它只是忠实地执行了一条已经失效的禁令。这个案例特别能说明 AGENTS.md 的风险——你以为是在约束 AI 不乱来实际上是在教它往错误方向跑。3.4 第三步打开 verbose 日志看 Skill 的注入现场接下来处理 Skill。我用 verbose 模式跑了一次简单任务codex run --verbose 打印 users 接口相关文件列表日志里能清楚看到匹配结果一个名叫 database-migration-helper 的 Skill 被以高优先级激活了。这个 Skill 是两年前数据库从旧框架迁移到新框架时留下的SKILL.md 正文里引用了 scripts/migrate.sh而这个脚本早已不存在。它的描述又写得很宽泛导致 Codex 每次接到任何与数据层相关的任务都会先尝试把整套迁移流程塞进去。模型很听话一直想把不存在的脚本补出来最终就形成了各种匪夷所思的“额外操作”。证据链整理成这样配置项问题明细影响表现根目录 AGENTS.md幽灵目录规则shared/ 已改名 core/模型绕开正确目录改动无关模块Skill: database-migration-helper引用不存在的 scripts/migrate.sh描述过于宽泛每次数据层任务都被激活反复尝试重建迁移脚本到这我算彻底明白了Codex 不是变笨而是背上了一书包过期的“行为准则”。这两份配置在它们诞生的年代或许很有价值但在今天的项目里每一行都是拉着模型往下走的负资产。4. 给“老年配置”做手术清理与迁移的实操清单4.1 全量盘点先搞清楚家底不管你现在有没有症状我都建议先做一次盘点。用一段命令把所有配置文件捞出来find . -iname SKILL.md -o -iname AGENTS.md | sort同时看一眼最后修改时间。凡是半年以上没动过的进入待审名单。这一步的目的不是立刻删除而是建立一份“配置资产清单”搞清楚存量里哪些还活在当前技术栈中哪些已经是博物馆展品。很多人对自己的配置毫无概念只记得“我曾经配过很多”但真要你说出每个 Skill 干什么、哪条 AGENTS.md 规则还有效往往答不上来。没有这份清单后面所有清理都无从谈起。4.2 冻结归档给每个配置打状态标签结构安全的做法是归档而不是删除。我习惯在仓库里建一个 .config-archive/ 目录把暂时不用的配置 mv 进去在文件头注释里标记状态和原因。状态我统一用三种active当前生效、deprecated已废弃待删、pending-review待复审。全部归档后Codex 的扫描器不会再读它们但 git 历史里随时能找回避免误删后悔。这一步的心理价值也很大当你明确知道“删掉它也随时能恢复”时你才敢真正做减法而不是为了保险把所有旧配置继续留在扫描路径里。4.3 Skill 重构格式、描述、依赖三件事一起做真正要回购的 Skill 必须过三关。第一关是 frontmatter 三件套——name、description、version 必须齐全。description 越窄越好写成“仅在用户请求与 XX 有关时使用”避免万金油描述导致误激活。第二关是正文只保留稳定步骤凡是会随项目变化的细节写成占位符或者让模型去读目标文件确认不要在 Skill 里硬编码。第三关是依赖自检。Skill 引用的脚本开头必须做存在性校验如果文件不存在就直接报错并停止执行绝不能让模型脑补出新的实现。一个简化的校验示例if [ ! -f scripts/migrate.sh ]; then echo scripts/migrate.sh not found; skill is out of date, stop. exit 1 fi这一关非常关键能挡掉我上面踩过的那类大坑。脚本一旦能证明自己过期模型就会乖乖停下来问人而不是自己造一个不存在的工具出来。4.4 AGENTS.md 瘦身只留“不可变约定”重构 AGENTS.md 的原则是只写那些换了任何一代模型都不会改变的项目硬约定比如构建命令、目录职责、安全边界。所有会随时间变化的细节要么删掉要么写成“以当前仓库为准先读 package.json 或配置文件确认”。我自己把单文件上限压到 120 行以内超过就拆到子目录级文件并且要求子目录文件第一行声明继承关系。下面这个模板我反复用了很多次# 项目约定 ## 构建与测试 - 构建使用 package.json 中 scripts 对应命令 - 测试使用包管理器对应的 test 命令 ## 目录职责 - src/ 存放业务源码 - tests/ 存放测试用例 ## 硬性禁止 - 不要改动 vendor/ 下自动生成的代码 - 不要在业务代码中直接硬编码密钥 ## 注意事项 - 涉及接口变更时先阅读现有接口文档再动手这个模板刻意省略了所有具体命令名因为它只保留“怎么确认”的路径而不是直接给模型一个可能过期的结论。AGENTS.md 最忌讳的就是把自己写成一份教程——它应该是项目的“不变骨架”而不是一次性的操作手册。4.5 变更后的验证固定“金丝雀任务”配置改完不能直接上正式任务我会用一个固定的小任务清单做回归。我把这些任务写在一个 canary.md 文件里内容基本是这种稳定且轻量的请求# 金丝雀任务 1. 列出 users 接口的定义文件路径。 2. 简述该接口当前的返回结构。 3. 在不修改任何代码的前提下给出增加 total 字段的最小改动点。每次改完配置先跑金丝雀任务对比输出。如果输出漂移了说明这次改动引入了新问题如果输出稳定再跑真实任务。把模型行为当成测试用例来管理是这套体系里最值钱的一步。它不一定能覆盖所有场景但至少给了你一个低成本的安全网让每次配置变更都可观测、可回滚。5. 如何让配置不再随版本腐烂长期治理心得5.1 给所有配置加上“有效期”配置和代码一样都有保质期。我现在的习惯是SKILL.md 和 AGENTS.md 的头部都写 version 和 last_reviewed 字段。每次升级框架、迁移目录结构、替换构建工具之后顺手全局搜一遍配置文件里跟旧技术栈有关的关键词比如旧目录名、旧命令名。半年没有变动的 Skill直接标 deprecated。这是最便宜、最有效的防腐剂。很多项目出问题不是某一次大重构导致的而是无数个“先这样用着回头再改”的小妥协累积出来的。5.2 配置也走“小步提交 diff review”Skill 库和 AGENTS.md 我会放到独立的 Git 仓库里管理。任何变更都不是一个人在文件里改一下就行而是先提交再 diff review。看 diff 时重点不是看格式而是看这条规则是在约束模型还是在约束代码示例是否和当前仓库一致有没有引入会频繁变化的干扰项我把它当成跟 review 普通代码一样严肃的事。配置一旦脱离了版本管理它就会变成所有人都不敢动、没人敢删的灰色地带最终变成模型行为里最不可控的变量。5.3 少即是多给 Codex 做减法经历了这次事故之后我最大的转变是Codex 的能力从来不是靠无限堆配置堆出来的。配置的作用是帮它理解项目的不变骨架而不是替它决定每一步怎么做。我现在在模拟项目X里只保留了 5 个真正有效的 SkillAGENTS.md 从 800 行瘦到了 100 行出头整体行为稳定性反而上了一个台阶。最后一个私人小技巧把 AGENTS.md 当成需要维护的代码来对待发现疑似过时的规则别等当场加一行注释“TODO这条规则疑因目录重命名失效下次任务前核实”。Codex 读到注释时反而能主动去确认这个小习惯帮我省掉了好几次翻车。如果看完这篇你只准备做一件事我建议就从备份和盘点开始把 AGENTS.md 和 skills 目录各自打一个包跑一次你最近觉得翻车的那条任务指令再逐项关掉配置跑一次。先让配置的选择变成显式的问题往往就已经解决一半。