你让 OpenAI Codex / Codex CLI “加个用户设置页面”,它生成的代码看起来能跑,但文件放在 src/UserSettings.tsx 而不是项目里其他页面所在的 src/pages/settings/index.tsx;命名是 UserSettings 而不是项目里一致的 SettingsPage;用了 useState 而你的项目全是 Zustand。Codex(包括 Codex CLI、Codex agent、ChatGPT Code Interpreter 风格的子任务)默认按”通用最佳实践”生成,不会自动模仿你项目里既有约定。这篇讲怎么用 AGENTS.md + 显式引用 + plan-first 把它框回项目风格。
常见原因
按命中率从高到低排序。
1. 项目没有 AGENTS.md / CLAUDE.md / .cursorrules
Codex 在每次启动时只读取一两个固定文件(OpenAI Codex 是 AGENTS.md,Claude Code 是 CLAUDE.md,Cursor 是 .cursorrules)。没有的话它只能扫几个最近编辑的文件靠猜。
你:加个用户设置页面
Codex:(没 AGENTS.md,看了 README,里面没说目录约定)
→ 创建 src/UserSettings.tsx
你的项目:所有页面在 src/pages/*/index.tsx
如何判断:仓库根目录有没有 AGENTS.md、CLAUDE.md、.cursorrules 任一文件?没有就是这个原因。
2. Codex 没读过任何同类型文件
即使有指南,如果 prompt 没指向具体的”参考样本”,Codex 还是按训练里的”标准 React 项目”写,与你的本地约定脱节。
如何判断:让 Codex 列出它在生成前读过哪些文件。codex --verbose 或 agent 模式里看 tool call 日志,如果只有它新写的文件、没有 read_file 同类型旧文件,就是这种情况。
3. Prompt 没说”按现有风格”
默认 prompt “实现 X 功能”等于放任 Codex 自由发挥。它会用最通用的 React + axios + useState 写法,无视你项目的 Zustand / SWR / TanStack Query / shadcn-ui 选型。
如何判断:对比生成代码用的库和 package.json dependencies——如果引入了项目里没装的库(或忽视了已经装的状态管理库),prompt 太宽松。
4. 项目结构本身就不一致(AI 学错了)
如果项目里一半文件用 kebab-case、一半 PascalCase,一半在 pages/、一半在 routes/,Codex 随机模仿其中一种,结果看起来就像”风格不对”。
如何判断:跑 find src -name '*.tsx' | sort 看命名是否统一;如果一半 PascalCase 一半 kebab-case,是项目自身先有问题。
5. monorepo / 多 workspace 下 Codex 选错了根
monorepo 里 Codex 看到 root package.json 就以为是入口,往 root 写文件,但实际逻辑应该在 apps/web 或 packages/ui 里。
如何判断:生成的文件出现在 root 或错误的 workspace,而不是与同类型代码同 workspace。
最短修复路径
按收益排序。Step 1+2 通常能让 Codex 一次生成就贴近项目。
Step 1:写一份 AGENTS.md,把路径、命名、技术栈全列清楚
放在仓库根目录。Codex CLI 启动会自动读:
# AGENTS.md
## 项目结构
- 所有页面:src/pages/<feature>/index.tsx
- 共享组件:src/components/<PascalName>.tsx
- API 调用:src/lib/api/<resource>.ts
- 类型定义:src/types/<resource>.ts
- monorepo 主代码在 apps/web,不要写到 root
## 命名约定
- 组件文件:PascalCase(SettingsPage.tsx)
- hook 文件:useXxx.ts
- 路由 segment:kebab-case(user-settings)
## 技术栈(不要引入替代品)
- 状态管理:Zustand(禁止 Redux / Recoil / 裸 useState 做全局)
- 数据请求:TanStack Query(禁止 axios 裸用)
- 表单:react-hook-form + zod
- 样式:Tailwind + shadcn-ui
## 工作流
- 改完跑 `pnpm typecheck && pnpm lint && pnpm test`
- 不要新建依赖前先问
Step 2:每次 prompt 都引用一个具体的”参考样本”
让 Codex 在写之前先读一个同类型已存在的文件:
帮我加一个 "Notifications Settings" 页面。
请先用 read_file 看这两个文件,复制它们的结构和风格:
- src/pages/account-settings/index.tsx(同类型页面)
- src/components/SettingsCard.tsx(卡片组件用法)
然后按 AGENTS.md 的命名和目录约定生成新页面。
不要引入新依赖,沿用 Zustand + TanStack Query。
显式 read_file 调用比”参考现有风格”模糊指令有效得多。
Step 3:要求 plan-first,写代码前先确认结构
让 Codex 先输出计划,你确认后再让它写:
开始写代码前请输出一个 plan,包含:
1. 要创建/修改的文件路径列表
2. 每个文件的简短目的
3. 引入的新依赖(如果有)
4. 涉及哪些既有模块
等我说 "go" 再开始 edit。
如果路径错了,plan 阶段就能拦住,省得回滚。
Step 4:用 tree + naming pattern 让 Codex 自查
在 AGENTS.md 末尾加一段自查指令,触发 Codex 自我验证:
# 在 AGENTS.md 里写:生成新文件后必须执行
tree src/pages -L 2
# 确认新页面路径符合 src/pages/<feature>/index.tsx
或者直接给个验证脚本:
node scripts/verify-structure.mjs
# 输出 OK 或列出违规文件
Step 5:monorepo 用 --working-dir / cd 锁定 workspace
避免 Codex 把文件写到 root:
# Codex CLI
codex --working-dir apps/web "加一个用户设置页面"
# 或在 prompt 开头明确
"工作目录是 apps/web。所有新文件必须在 apps/web/src 下,
不要碰 root 或其他 workspace。"
agent 模式开始就 cd apps/web,再做后续操作。
预防建议
- 仓库根目录维护 AGENTS.md(Codex)/ CLAUDE.md(Claude Code)/
.cursorrules(Cursor),三者可以软链或定时同步 - 新增任何文件类型时先更新 AGENTS.md,再写第一个样本,再让 AI 模仿
- 在 prompt 模板里强制”先 read_file 一个同类型样本,再开始写”
- 写一个
scripts/verify-structure.mjs,CI 阶段跑,把命名 / 目录违规的 PR 拦下 - monorepo 项目固定让 Codex 在子目录启动,别在 root
- 季度 review AGENTS.md,把 AI 反复犯的同一种错(比如总选 useState)写进去