
1. 为什么你的 Claude Code 总在 API 层“自由发挥”团队里用 Claude Code 写后端接口最常听到的抱怨不是模型不会写代码而是它写得太“随性”。同一个仓库里A 同事的接口用 Zod 校验入参B 同事的接口直接把req.body丢给 service 层C 同事的失败返回是{ message: xxx }D 同事又变成{ error: { code, msg } }。前端调用层被迫写一堆 if-else 去兼容测试用例越写越厚联调时全靠吼。问题的根子不在模型能力而在规则没有在正确的时机出现。很多团队把所有约定一股脑塞进CLAUDE.md结果每次改个 UI 组件、写个单元测试Claude 都要背着一整套 API 规范去推理注意力被稀释真正碰到src/api/下的文件时反而记不住那三条最关键的约束。api-design.md这个自动触发器解决的正是这件事它是一份带paths范围限定的规则文件只有当 Claude Code 正在读写src/api/**/*.ts这类后端路由文件时规则才会被加载进上下文。平时它安静地躺在.claude/rules/目录里不占注意力一旦 Claude 打开 API 文件它就像门禁卡一样被激活把“输入必须校验、返回必须统一、公开接口必须限流”这三条底线推到模型面前。这篇内容面向的是已经在用 Claude Code 做团队协作、但接口规范总被忽略的后端同学。我会给出可直接复制的settings.json配置骨架、api-design.md的完整写法、触发验证动作以及实测中容易踩的坑。目标很明确让规则在编码时自动生效而不是等 code review 时再事后补救。2. 前置准备TaoToken 接入与 Claude Code 环境在配置规则文件之前得先保证 Claude Code 能正常跑起来。我这边是通过 TaoToken 接入的它的 API 地址是https://taotoken.net/api兼容 Anthropic 的接口协议Claude Code 直接改环境变量就能用。第一步是拿到 API Key。打开控制台页面https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite登录后在 API Keys 菜单里创建一个新 key复制出来备用。这个 key 只在创建时完整显示一次记得先存到密码管理器里。第二步是配置 Claude Code 的环境变量。在项目根目录或者你的 shell 配置文件里设置export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的key如果你用的是 Claude Code 的 CLI也可以直接在~/.claude/settings.json里配置环境变量这样不用每次开终端都 export。配置完成后跑一次claude --version确认能正常启动再随便问一句“你好”验证连通性。第三步是确认项目结构。Claude Code 的规则文件放在项目级.claude/rules/目录下所有 Markdown 文件会被递归发现。项目级.claude/适合提交到 git 做团队共享用户级~/.claude/更适合个人配置。我们要做的api-design.md就放在项目级目录里跟着仓库走团队每个人拉下来都能用同一套规则。这里有个容易混淆的点settings.json管的是行为、权限、环境变量这类配置而api-design.md属于 Claude 读入的指导性上下文影响的是模型生成代码时的判断倾向。两者职责不同不能互相替代。规则文件让 Claude 更倾向于写合规代码但它不是编译器也不是 CI 网关真正的强制兜底还得靠测试和 hooks。3. 可复制配置api-design.md 与 settings.json 骨架3.1 api-design.md 的完整写法在项目根目录创建.claude/rules/api-design.md内容如下--- paths: - src/api/**/*.ts --- # API Design Rules ## 输入校验 所有 endpoint 必须用 Zod schema 校验输入。 - 在 handler 入口处调用 schema.parse(req.body) 或 schema.safeParse - schema 命名统一用 CreateXxxSchema / UpdateXxxSchema - 校验失败返回 400错误信息只暴露安全字段不回传内部堆栈 ## 返回结构 所有接口返回统一为 { data: T } | { error: string }。 - 成功时返回 { data: ... } - 失败时返回 { error: ... }HTTP 状态码同步设置 - 禁止直接返回裸对象、裸数组或 HTML 错误页 ## 限流 所有公开 endpoint 必须加 rate limit。 - 使用共享 limiter 实例避免每个路由单独 new - 特殊限流策略需在代码注释里说明原因 - 内部管理接口走鉴权网关可豁免顶部的 YAML frontmatter 是关键。paths字段基于 glob 模式src/api/**/*.ts的含义是src/api/目录下递归匹配任意层级子目录的 TypeScript 文件。src/api/users/create.ts会命中src/api/orders/[id]/route.ts会命中而src/components/Button.tsx和scripts/generate-api.ts不会命中。规则只在 Claude 处理匹配文件时进入上下文。3.2 settings.json 配置骨架在.claude/settings.json里配置项目级设置让团队共享同一套行为{ permissions: { allow: [ Read, Edit, Bash(npm run lint:*), Bash(npm run test:*) ], deny: [ Bash(rm -rf:*), Bash(git push --force:*) ] }, env: { ANTHROPIC_BASE_URL: https://taotoken.net/api } }这个骨架做了三件事允许 Claude 读取和编辑文件、允许跑 lint 和 test 命令、禁止危险操作。env里把 base URL 固定下来团队成员不用各自配环境变量。API Key 不要写进这个文件用系统环境变量或者~/.claude/settings.json的 local scope 管理避免提交到仓库泄露。3.3 触发验证动作配置写完后怎么确认规则真的生效了最直接的办法是让 Claude Code 去改一个 API 文件观察它的行为。打开 Claude Code输入帮我在 src/api/cart/items.ts 里新增一个 POST handler接收 productId 和 quantity如果规则生效Claude 生成的代码里应该出现 Zod schema 校验、{ data } | { error }的返回结构、以及 rate limit middleware 的引用。如果它直接写了个裸 handler 把 body 丢给 service 层说明规则没被加载。另一个验证方式是看上下文。Claude Code 在处理文件时如果命中了paths规则规则内容会出现在它的工作上下文里。你可以直接问它“你现在加载了哪些项目规则”它应该能说出api-design.md里的三条约定。如果它说没有加载任何规则检查一下文件路径和 glob 写法是否正确。4. 验证请求从触发到生成合规代码4.1 一个完整的触发案例假设项目结构是这样的project/ ├── .claude/ │ ├── rules/ │ │ └── api-design.md │ └── settings.json ├── src/ │ ├── api/ │ │ ├── cart/ │ │ │ └── items.ts │ │ └── orders/ │ │ └── create.ts │ └── components/ │ └── Button.tsx当 Claude Code 被要求修改src/api/cart/items.ts时api-design.md的paths规则命中规则内容进入上下文。Claude 生成的代码大概长这样import { z } from zod; import { Router } from express; import { rateLimit } from express-rate-limit; const CreateCartItemSchema z.object({ productId: z.string().uuid(), quantity: z.number().int().positive().max(99), }); const limiter rateLimit({ windowMs: 60 * 1000, max: 30, }); const router Router(); router.post(/api/cart/items, limiter, async (req, res) { const parsed CreateCartItemSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: Invalid input }); } try { const item await cartService.addItem(parsed.data); return res.json({ data: item }); } catch (err) { return res.status(500).json({ error: Failed to add item }); } }); export default router;对比一下没有规则时的输出Claude 很可能直接写const { productId, quantity } req.body;然后调 service返回res.json(result)。代码更短但输入没校验、返回结构不统一、公开接口没限流。规则文件的价值就体现在这里——它不改变模型能力但改变了模型的默认姿势。4.2 验证规则是否真的按路径触发改完 API 文件后再让 Claude 去改一个前端组件帮我把 src/components/Button.tsx 的样式调整一下这时候api-design.md不应该被加载因为Button.tsx不匹配src/api/**/*.ts。你可以问 Claude“当前上下文里有 API 设计规则吗”它应该说没有。如果它说加载了说明 glob 写得太宽比如写成了**/*.ts那就会误触发。这个对比验证很重要。路径级规则的核心价值就是“只在需要时出现”如果它在前端文件里也触发就失去了减少噪音的意义。实测下来src/api/**/*.ts这个范围对大多数 Node.js 后端项目都够用monorepo 里如果有多个 API 区域可以继续拆成src/api/admin/**/*.ts、src/api/public/**/*.ts等更细的规则文件。4.3 用 hooks 做工程兜底规则文件管的是生成倾向它不能保证 Claude 永远不漏校验。成熟一点的做法是配一个 hook在 Claude 编辑完文件后自动跑 lint 或测试。在.claude/settings.json里加{ hooks: { PostToolUse: [ { matcher: Edit, command: npm run lint -- --fix } ] } }这样 Claude 每次编辑文件后lint 会自动跑一遍。如果它写的 API 代码违反了团队的 ESLint 规则比如没加 Zod 校验就用了req.bodylint 会报错Claude 看到错误后会自己修正。规则文件管“应该怎么写”hooks 管“写错了能不能过”两者配合比单独依赖任何一边都稳。5. 本篇常见错排查5.1 规则文件不生效最常见的原因是路径写错了。.claude/rules/目录必须在项目根目录下不能放在src/里面。文件名必须是.md结尾api-design.md可以api-design.txt不行。frontmatter 的paths字段必须是 YAML 数组格式缩进用两个空格不能用 tab。另一个原因是 glob 写得太窄。比如写成src/api/*.ts那只匹配src/api/下一级文件src/api/cart/items.ts就命中不了。要递归匹配子目录必须用**。如果写成src/api/**那所有文件类型都会命中包括.json、.md范围太宽。推荐src/api/**/*.ts这种精确到扩展名的写法。5.2 规则加载了但 Claude 不遵守规则内容太泛是主因。如果只写“写干净的 API 代码”Claude 理解大方向但落不到动作。api-design.md里的三条都带可执行判断有没有 Zod schema、返回是不是{ data } | { error }、公开 endpoint 有没有 rate limit。越接近验收标准的规则越容易变成稳定行为。规则太长也会降低遵循度。有的团队把命名、分层、分页、错误码、日志字段、OpenAPI 注释、鉴权、缓存、幂等键全塞进去几十条规则让 Claude 迷失重点。路径级规则最适合放少量高优先级、强约束、跨接口稳定成立的内容。更细的内容拆成专门文档或者放进 skill在需要做 API 设计评审时再调用。5.3 settings.json 和 rules 混淆settings.json管的是行为、权限、环境变量api-design.md管的是模型生成代码时的判断倾向。有人以为在settings.json里写了规则就能强制 Claude 遵守其实不是。settings.json的permissions控制的是 Claude 能做什么操作不是它该怎么写代码。规则文件是指导性的不是强制性的。真正的强制兜底要靠 hooks 和 CI。api-design.md让 Claude 倾向于写合规代码hooks 在编辑后跑 lint 和测试CI 在合并前跑完整检查。三层配合规则才不会变成一纸空文。5.4 限流配置在多实例下失效express-rate-limit默认用内存存储单进程跑没问题但部署到多实例或 Kubernetes 后每个实例各算各的限流效果会被实例数稀释。如果项目是这种部署形态需要在api-design.md里补一条公开接口的 limiter 必须用外部存储比如 Redis做共享状态。否则 Claude 在本地单进程示例里写得很好上线后限流形同虚设。5.5 API Key 泄露风险不要把 API Key 写进.claude/settings.json提交到仓库。项目级settings.json适合放团队共享的非敏感配置Key 用系统环境变量或者~/.claude/settings.json的 local scope 管理。如果团队需要统一管理 Key用 CI 的 secret 机制注入不要硬编码。6. 让规则在正确的时间出现api-design.md这个自动触发器本质上是在做检索式上下文注入。Claude Code 不需要在每次推理时携带全量项目规则而是在当前任务命中某类文件时把相关规则加入上下文。这很像传统软件里的局部作用域——全局变量过多会污染程序状态全局规则过多也会污染模型注意力。把 API 规则限定在src/api/**/*.ts就像把变量声明放进真正需要的函数体里减少副作用也减少误触发。平时它沉在.claude/rules/里不消耗注意力等 Claude 打开 API 文件时它才被激活提醒模型别写裸奔接口、别返回混乱结构、别让外部输入绕过 schema。如果你还在用CLAUDE.md塞所有规则可以试着把 API 规范拆出来放进.claude/rules/api-design.md配上paths范围。改完之后让 Claude 去改一个 API 文件观察它的输出有没有变化。如果它开始主动加 Zod 校验和统一返回结构说明触发器生效了。接入方面TaoToken 的 API 地址是https://taotoken.net/api控制台在https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keys 管理在https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite。如果你在配规则文件时遇到 Claude Code 不加载的问题可以先检查接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite里的环境变量配置确认 base URL 和 key 都对。想先验证模型对话是否正常可以用模型对话页面https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite发一条测试消息。长期做编码和 Agent 任务的团队可以看看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite按团队规模选合适的方案。规则文件不是越集中越好而是要和代码结构对齐。代码边界清楚Claude 的上下文边界也会清楚。api-design.md的paths规则就是这个思想的一个很小、但很典型的样本。