☰
Codex突然变蠢?过期Skill与AGENTS.md配置才是真凶
2026/10/10 10:21:27 网站建设 项目流程

如果你的 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

接着用同一个最小任务跑 Codex:

codex 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 个真正有效的 Skill,AGENTS.md 从 800 行瘦到了 100 行出头,整体行为稳定性反而上了一个台阶。最后一个私人小技巧:把 AGENTS.md 当成需要维护的代码来对待,发现疑似过时的规则别等,当场加一行注释“TODO:这条规则疑因目录重命名失效,下次任务前核实”。Codex 读到注释时反而能主动去确认,这个小习惯帮我省掉了好几次翻车。如果看完这篇你只准备做一件事,我建议就从备份和盘点开始:把 AGENTS.md 和 skills 目录各自打一个包,跑一次你最近觉得翻车的那条任务指令,再逐项关掉配置跑一次。先让配置的选择变成显式的,问题往往就已经解决一半。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询