03-编码约束的艺术:CLAUDE.md / AGENTS.md 设计指南
编码约束的艺术:CLAUDE.md / AGENTS.md 设计指南
同样的 Claude Code,有人让它写出的代码像资深工程师的作品,有人让它写出的代码像实习生交的作业。差距的 80% 不在工具本身,而在于你有没有写好那个约束文件。这篇文章告诉你如何用不到 200 行文字,让 AI 的输出质量提升一个量级。
一个实验:有约束 vs 没约束
先看一个真实对比。同样的需求——“帮我写一个用户注册接口”——同一个模型,两种输出:
没有任何约束文件时:
# AI 生成的代码
def register(username, password):
db.execute(f"INSERT INTO users VALUES ('{username}', '{password}')")
return {"status": "ok"}
有 CLAUDE.md 约束时:
# AI 生成的代码
def register_user(username: str, password: str) -> dict:
"""注册新用户。密码使用 bcrypt 哈希存储。"""
if len(password) < 8:
raise ValueError("密码至少 8 位")
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
with get_db() as db:
existing = db.fetch_one("users", where={"username": username})
if existing:
raise ConflictError("用户名已存在")
user = db.insert("users", {
"id": uuid4(),
"username": username,
"password_hash": password_hash,
"created_at": datetime.utcnow()
})
return {"user_id": str(user["id"]), "username": username}
差在哪?
| 维度 | 无约束 | 有约束 |
|---|---|---|
| SQL 注入 | 直接拼接字符串 ❌ | 参数化查询 ✅ |
| 密码存储 | 明文 ❌ | bcrypt 哈希 ✅ |
| 输入校验 | 无 ❌ | 密码长度检查 ✅ |
| 错误处理 | 无 ❌ | 用户名重复检测 ✅ |
| 类型标注 | 无 ❌ | 完整类型标注 ✅ |
| 数据库操作 | 裸 SQL ❌ | ORM 封装 ✅ |
这 6 个差异,全部来自一个不到 100 行的 CLAUDE.md 文件。 AI 没有变,变的是你给它的约束。
两个文件的定位:CLAUDE.md vs AGENTS.md
很多人的第一个疑问是:这两个文件有什么区别?我需要都写吗?
CLAUDE.md AGENTS.md
───────── ─────────
平台:Claude Code 专属 平台:跨工具通用
作用域:Claude Code 行为规则 作用域:所有 AI Coding Agent 共用
格式:Markdown,自由结构 格式:Markdown,自由结构
位置:项目根目录 位置:项目根目录
触发:Claude Code 启动时自动读取 触发:Codex/Cursor/Copilot 等各自读取
谁读哪个文件
┌─────────────┐
│ 你的项目 │
├─────────────┤
│ CLAUDE.md │ ← Claude Code 读
│ AGENTS.md │ ← Codex CLI 读
│ │ ← Cursor 读(部分)
│ │ ← Copilot 读(部分)
└─────────────┘
什么时候只要一个,什么时候要两个
| 场景 | 写哪个 | 策略 |
|---|---|---|
| 只用 Claude Code | CLAUDE.md | 只写这一个,全量规则放里面 |
| 用 Claude Code + Codex | 两个都写 | AGENTS.md 放通用规则,CLAUDE.md 引用并补充 Claude Code 特有规则 |
| 只用 Cursor/Copilot | AGENTS.md | 部分 IDE 会读 AGENTS.md |
| 团队混用多个工具 | 两个都写 | AGENTS.md 是公约,CLAUDE.md 是特化 |
协同策略
┌──────────────────────────────────────┐
│ AGENTS.md │
│ "所有 AI 工具共同遵守的规则" │
│ │
│ - 项目技术栈 │
│ - 代码风格 │
│ - 安全红线 │
│ - 架构约定 │
└────────────┬─────────────────────────┘
│ 引用
▼
┌──────────────────────────────────────┐
│ CLAUDE.md │
│ "Claude Code 特有的规则" │
│ │
│ - @include AGENTS.md(或直接引用) │
│ - Hooks 配置说明 │
│ - Memory 类型约定 │
│ - Permissions 策略 │
│ - 本项目的 Skills 使用说明 │
└──────────────────────────────────────┘
五条设计原则
写好约束文件的秘密不在于"写得多",而在于"写得对"。这五条原则来自几十个项目的实践经验。
原则一:具体(Specific)
❌ "写干净的代码"
→ 什么叫干净?AI 不知道。它的标准和你的标准不一样。
✅ "函数不超过 30 行;类不超过 200 行;一个文件不超过 500 行"
→ AI 会用这个数字做判断依据。
技巧:把抽象的形容词(“好”、“干净”、“优雅”)全部替换成可量化的标准。
| 抽象要求 | 具体写法 |
|---|---|
| “好的错误处理” | “所有 IO 操作必须有 try/except,异常信息用中文” |
| “清晰的命名” | “布尔值用 is_/has_ 前缀,函数用动词开头” |
| “完善的测试” | “每个公开函数至少有 happy path + 异常 case + 边界值 3 个测试” |
| “高性能” | “数据库查询单次不超过 1000 行,循环内禁止 SQL 查询” |
原则二:约束(Constraints)
❌ "你是一个 Python 专家"
→ 这只是身份标签,不等于行为约束。
✅ "默认使用标准库。需要第三方库时必须先确认。数据校验用 Pydantic。
异步用 asyncio 而非 threading。"
→ 这是行为边界,AI 知道什么能做、什么不能做。
约束的核心是画框。框越小,AI 的输出越可控:
无约束 有约束
──────── ────────
AI 可以 你只允许
用任何库 用 FastAPI + SQLAlchemy
写任何风格 用 Black + 类型标注
选任何方案 先读现有代码,再复用模式
原则三:禁忌(Forbidden)
比告诉 AI "做什么"更重要的,是告诉 AI “绝对不能做什么”。
# CLAUDE.md 中的禁忌区
## 绝对不能做的事
- 不要把密钥/Token 硬编码到源码中(用环境变量)
- 不要跳过 pre-commit hooks
- 不要在没有 review 的情况下修改数据库迁移文件
- 不要删除注释——除非注释明确标注了"TODO: remove"
- 不要使用 eval() 或 exec()
- 不要拼接 SQL 字符串(必须用参数化查询)
禁忌区的价值在于防住最坏的情况。宁可多写一条禁忌,也别等出了问题再后悔。
原则四:短小(Concise)
约束文件不是文档,是命令。AI 每一行都会读,但注意力是有限的。
200 行以内 → AI 会认真读每一行
200-500 行 → AI 会浏览,但可能漏掉细节
500 行以上 → AI 只会抓关键词,大量规则被忽略
策略:如果规则超过 200 行,拆成多个文件。
CLAUDE.md ← 入口文件(<100 行),放最重要的规则 + 索引
│
├─ .claude/rules/testing.md ← 测试相关规则(按需引用)
├─ .claude/rules/security.md ← 安全相关规则
└─ .claude/rules/api-design.md ← API 设计约定
原则五:更新(Updated)
过期的约束比没有约束更危险。 因为 AI 会严格执行你写的规则,即使它已经不符合现状。
真实的灾难案例:
CLAUDE.md 写着:"所有 API 用 REST 风格"
但项目实际已经在迁移到 GraphQL。
结果:AI 生成了 300 行 REST 代码,全部白写。
习惯:每次技术决策变更后,检查约束文件是否需要同步更新。
分模块 vs 单文件:什么时候怎么拆
项目规模 策略 文件结构
──────── ──── ────────
个人小项目 单文件 CLAUDE.md 根目录一个文件
(<10 个文件) 所有规则写一起
中型项目 单文件 + 引用 CLAUDE.md(入口)
(10-50 个文件) 核心规则在入口 ↓ 引用
细节在独立目录 .claude/rules/*.md
大型项目 分层约束 AGENTS.md(通用公约)
(>50 个文件) 通用 + 工具特化 CLAUDE.md(Claude Code 特化)
.claude/rules/(分模块规则)
.cursor/rules/(Cursor 规则)
一个实用的中型项目 CLAUDE.md 模板
# 项目名称
## 技术栈
- Python 3.12+,FastAPI,SQLAlchemy 2.0,PostgreSQL
- 前端 React 18 + TypeScript + Tailwind CSS
- 部署 Docker + GitHub Actions
## 代码规范
- 所有 Python 代码用 Black 格式化(line-length=100)
- TypeScript 用 Prettier + ESLint
- 函数不超过 40 行,文件不超过 400 行
- 公开 API 必须有 docstring(Google 风格)
## 安全红线
- 禁止硬编码密钥、Token、密码
- 所有用户输入必须校验和转义
- SQL 查询必须参数化
- 文件上传限制大小和类型
## 架构约定
- 数据库迁移用 Alembic,不要直接改表
- API 返回统一格式:{ "code": 0, "data": ..., "message": "" }
- 异步操作用 asyncio,不要混用同步阻塞调用
- 日志用 structlog,不要用 print
## 规则索引
- 测试规则:`.claude/rules/testing.md`
- API 设计规范:`.claude/rules/api-design.md`
AGENTS.md 多平台通用写法
如果你同时在用 Claude Code 和 Codex CLI,需要确保两个工具的行为一致。AGENTS.md 就负责这件事。
关键:写"工具无关"的规则
❌ Claude Code 专属写法:
"使用 /skill 命令来运行测试"
→ Codex 没有 /skill 概念,这条规则对 Codex 无效
✅ 工具无关写法:
"修改代码后必须运行测试套件,确保所有已有测试通过后再提交"
→ 所有工具都能理解和执行
推荐的 AGENTS.md 内容分区
# AGENTS.md
## 项目身份
本项目是 XXX,主要服务 XXX 场景。
(帮 AI 理解它在什么项目里工作)
## 技术决策
- 为什么选了 A 方案而不是 B 方案
(帮 AI 理解技术背景,避免生成不合架构的代码)
## 通用规范
- 代码风格
- 命名约定
- 注释语言
(所有工具都能执行)
## 安全要求
- 通用安全红线
(SQL 注入、XSS、密钥管理等)
## 测试要求
- 什么情况下需要测试
- 测试框架和风格
常见误区与反模式
误区一:写教程而不是写规则
❌ "FastAPI 是一个现代 Python Web 框架,它的特点是..."
→ AI 不需要你教它 FastAPI。它比你还熟。
✅ "本项目用 FastAPI 2.0+,所有路由放在 api/ 目录下,用依赖注入管理数据库连接。"
→ 告诉 AI 这个项目怎么用 FastAPI,不是教它 FastAPI 是什么。
核心判断:如果你写的内容是在"解释概念",删掉。只保留"决策和约定"。
误区二:复制粘贴别人的 CLAUDE.md
GitHub 上有很多"最佳实践 CLAUDE.md 模板"。问题是:每个项目的约束都不同。
一个金融系统的安全要求 vs 一个个人博客的安全要求,能一样吗?模板可以参考结构,但内容必须自己写。
误区三:写一次就不再更新
约束文件是活文档。一个维护良好的 CLAUDE.md 应该随着项目演变而更新。建议在 PR Review 中增加一项检查:“这次改动是否需要更新约束文件?”
误区四:规则太松散,没有优先级
当你写了 50 条规则,AI 不可能每条都 100% 遵守。你要告诉它哪些是"死命令",哪些是"最好遵守":
## 🔴 硬性规则(违反必须拒绝代码)
- SQL 参数化
- 密钥不入库
## 🟡 推荐规则(尽量遵守,违反需说明理由)
- 函数不超过 40 行
- 测试覆盖率 > 80%
## 🟢 建议(参考即可)
- 优先用标准库
- 变量名尽量见名知意
5 分钟自检清单
写完约束文件后,用这个清单验证:
□ 我不在的时候,一个新同事能靠这个文件理解我的代码标准吗?
□ 有没有任何抽象的形容词("好"、"干净"、"优雅")?有的话替换成具体标准。
□ AI 读了之后知道绝对不能做什么吗?
□ 这个文件超过 200 行了吗?超过了就拆分。
□ 最近的技术决策反映在这个文件里了吗?
□ 我用别的 AI 工具(Codex / Cursor)时,这些规则还能生效吗?
更多推荐



所有评论(0)