Claude Code在大型项目中的最佳实践指南

Written by

in

文章目录
  • 很多团队引入 Claude Code 后,效果参差不齐。有的团队在百万行 monorepo 里用得飞起,有的团队在几千行的小项目里反而觉得"不如直接写"。 差距不在模型,在配置。 Anthropic 的 Applied AI 团队观察了大量企业级部署后,总结出一套可复用的模式。这篇文章把这套模式拆开讲清楚,每一层都附上可以直接抄走的配置片段,让你少走弯路。
  • 先搞清楚一个基础问题:Claude Code 是怎么在代码库里找东西的? 它不用 RAG。 大多数 AI 编码工具的路子是:把整个代码库向量化,查询时检索相关片段。这套方案在小项目上没问题,但在活跃的大型团队里会出问题——embedding 管道跟不上提交速度。你查的时候,索引可能还停留在两周前的状态,返回的是已经被重命名的函数、已经删掉的模块,而且没有任何提示说这些信息已经过期。 Claude Code 的做法更接近一个真实的工程师:遍历文件系统、读文件、用 grep 精确定位、跨文件追踪引用。它直接在开发者本地机器上运行,操作的是实时代码库,没有需要维护的中央索引。 你可以在一次会话里看到它真实的"思考路径"——大致是这样: > 帮我找一下订单超时退款的逻辑在哪 ● 我先看一下项目结构 └─ Bash(ls -la services/) ● 看起来订单相关在 services/order/,先 grep 一下关键词 └─ Grep(“refund|timeout”, path: “services/order”, output_mode: “files_with_matches”) ● 命中 3 个文件,重点看 refund_handler.go └─ Read(“services/order/internal/refund/refund_handler.go”, offset: 1, limit: 80) ● 这里调用了 TimeoutPolicy.shouldRefund,跳过去看定义 └─ Grep(“func.*shouldRefund”, path: “services/order”) 这个方案的代价是:它需要足够的起始上下文才能知道去哪里找。如果你让它在十亿行代码库里搜索一个模糊的模式,还没开始干活就会撞上上下文窗口限制。 所以,代码库的可导航性直接决定了 Claude Code 的上限。
  • 这是很多团队忽视的点:Claude Code 的实际表现,由围绕模型构建的"配套系统"决定,而不只是模型本身。 这套配套系统由五个扩展点组成,加上两个额外能力: 组件 是什么 何时加载 最适合做什么 CLAUDE.md Claude 自动读取的上下文文件 每次会话 项目约定、代码库知识 Hooks 在关键时刻触发的脚本 事件触发 自动化一致性行为、捕获会话学习 Skills 特定任务类型的打包指令 按需加载 跨会话和项目的可复用专业知识 Plugins 打包好的 skills + hooks + MCP 配置 安装后始终可用 在组织内分发一套完整配置 LSP 集成 通过语言服务器提供实时代码智能 配置后始终可用 符号级导航、自动错误检测 MCP 服务器 连接外部工具和数据源 配置后始终可用 让 Claude 访问内部工具 Subagents 独立的 Claude 实例 按需调用 探索与编辑分离、并行工作 这五个扩展点有构建顺序,每一层都建立在前一层之上。下面逐层拆。
  • CLAUDE.md 是 Claude 在每次会话开始时自动读取的上下文文件。根目录放全局信息,子目录放局部约定。 关键原则:精简、分层。 根目录的 CLAUDE.md 只放指针和关键注意事项,其他的放到子目录里。内容越多,噪音越大,性能越差。
  • 大多数团队把 Hooks 理解成"防止 Claude 做错事的脚本"。这只用到了 Hooks 一半的价值。 Hooks 更大的价值在于持续改进。
  • 大型代码库有几十种任务类型。如果把所有专业知识都塞进每次会话,上下文会被撑爆,性能会下降。 Skills 解决这个问题的方式叫渐进式披露:把专业工作流和领域知识打包成独立的 Skill,只在任务需要时加载。
  • 一个团队摸索出了好用的 Skills + Hooks + MCP 配置组合,怎么让整个组织都用上? 答案是 Plugins:把这些东西打包成一个可安装的包。新工程师入职第一天安装这个 Plugin,立刻拥有和老员工一样的上下文和能力。
  • 没有 LSP 的情况下,Claude 用文本匹配来找代码。在大型代码库里,grep 一个常见函数名比如 process 可能返回几千个匹配,Claude 要烧掉大量上下文逐个打开文件判断哪个才是目标。 有了 LSP,Claude 获得了和 IDE 一样的导航能力:追踪函数调用到定义、跨文件追踪引用、区分不同语言中同名函数。过滤在 Claude 读任何文件之前就完成了。
  • MCP 服务器是 Claude 连接内部工具、数据源和 API 的方式。
  • Subagents 是独立的 Claude 实例,有自己的上下文窗口,接受任务、完成工作、只把最终结果返回给父实例。 在大型代码库里,一个常见的高效模式是:探索和编辑分离。
  • 如果你的团队刚开始在大型代码库里用 Claude Code,按这个顺序来: 先写 CLAUDE.md:根目录放全局信息(用上面的模板抄一份),关键子目录放局部约定。精简,只放真正有用的。 配置 .ignore 和权限规则:排除生成文件和构建产物,提交到版本控制。模板见上面 .claude/settings.json。 设置 LSP 集成:特别是 C/C++/Java 这类强类型语言,这是最高投入产出比的基础设施。 构建第一批 Hooks:从 lint/format 自动化开始,再加一个 stop 反思 hook,最后做命令拦截。 把可复用的专业知识打包成 Skills:不要全塞进 CLAUDE.md。先做 3-5 个高频任务的 Skill。 打包成内部 Plugin 分发:让新人 claude plugin install 一行命令就能上车。 指定一个 DRI:没有负责人,配置会腐烂。 三到六个月做一次配置审查:随模型演进调整,删掉已经不需要的规则。 Claude Code 在百万行 monorepo、几十年历史的遗留系统、跨几十个仓库的分布式架构里都有成功案例。这些环境的共同点不是代码库有多整洁,而是团队在配置上做了投入。 模型只是一半,配置才是另一半。 把这另一半做到位,差距就出来了。 以上就是Claude Code在大型项目中的最佳实践指南的详细内容,更多关于Claude Code在大型项目中的实践的资料请关注风君子博客其它相关文章!
  • 目录
    • 先说结论
    • Claude Code 怎么理解大型代码库
    • 核心认知:模型只是一半,配置才是另一半
    • 第一层:CLAUDE.md——让 Claude 理解你的项目
      • 一个真实的根目录 CLAUDE.md
      • 子目录的 CLAUDE.md 只补充该目录特有的信息
      • 一个容易犯的错误
    • 第二层:Hooks——让配置自我进化
      • 基础用法:写完文件自动格式化
      • 进阶用法:阻止危险操作
      • 最被低估的用法:会话学习 Hook
    • 第三层:Skills——按需加载专业知识
      • 一个 Skill 的真实结构
      • Skills 的路径作用域
      • 实际的 Skill 库示例
    • 第四层:Plugins——把好的配置分发出去
      • 一个内部 Plugin 的目录结构
      • Anthropic 观察到的真实案例
    • 第五层:LSP 集成——从文本匹配升级到符号导航
      • 配置 LSP 集成
      • 没 LSP 和有 LSP 的对比
    • 第六层:MCP 服务器——连接内部工具
      • 一份典型的 MCP 配置
      • 注意构建顺序
    • 三个让大型代码库可用的配置模式
      • 模式一:让代码库对 Claude 可导航
        • 保持 CLAUDE.md 精简分层
        • 从子目录初始化,不要从仓库根目录
        • 按子目录作用域设置测试和 lint 命令
        • 用 .ignore 文件和权限规则排除噪音
        • 为目录结构不规范的代码库构建代码地图
      • 模式二:随模型演进主动维护 CLAUDE.md
        • 模式三:给 Claude Code 管理分配明确的负责人
        • 一个容易忽视的细节:Subagents
          • 实战示例
            • 用 Subagent 做并行验证
            • 总结:从哪里开始

              很多团队引入 Claude Code 后,效果参差不齐。有的团队在百万行 monorepo 里用得飞起,有的团队在几千行的小项目里反而觉得"不如直接写"。

              差距不在模型,在配置

              Anthropic 的 Applied AI 团队观察了大量企业级部署后,总结出一套可复用的模式。这篇文章把这套模式拆开讲清楚,每一层都附上可以直接抄走的配置片段,让你少走弯路。

              先搞清楚一个基础问题:Claude Code 是怎么在代码库里找东西的?

              它不用 RAG。

              大多数 AI 编码工具的路子是:把整个代码库向量化,查询时检索相关片段。这套方案在小项目上没问题,但在活跃的大型团队里会出问题——embedding 管道跟不上提交速度。你查的时候,索引可能还停留在两周前的状态,返回的是已经被重命名的函数、已经删掉的模块,而且没有任何提示说这些信息已经过期。

              Claude Code 的做法更接近一个真实的工程师:遍历文件系统、读文件、用 grep 精确定位、跨文件追踪引用。它直接在开发者本地机器上运行,操作的是实时代码库,没有需要维护的中央索引。

              你可以在一次会话里看到它真实的"思考路径"——大致是这样:

              > 帮我找一下订单超时退款的逻辑在哪
              
              ● 我先看一下项目结构
                └─ Bash(ls -la services/)
              
              ● 看起来订单相关在 services/order/,先 grep 一下关键词
                └─ Grep("refund|timeout", path: "services/order", output_mode: "files_with_matches")
              
              ● 命中 3 个文件,重点看 refund_handler.go
                └─ Read("services/order/internal/refund/refund_handler.go", offset: 1, limit: 80)
              
              ● 这里调用了 TimeoutPolicy.shouldRefund,跳过去看定义
                └─ Grep("func.*shouldRefund", path: "services/order")
              

              这个方案的代价是:它需要足够的起始上下文才能知道去哪里找。如果你让它在十亿行代码库里搜索一个模糊的模式,还没开始干活就会撞上上下文窗口限制。

              所以,代码库的可导航性直接决定了 Claude Code 的上限。

              这是很多团队忽视的点:Claude Code 的实际表现,由围绕模型构建的"配套系统"决定,而不只是模型本身。

              这套配套系统由五个扩展点组成,加上两个额外能力:

              组件 是什么 何时加载 最适合做什么
              CLAUDE.md Claude 自动读取的上下文文件 每次会话 项目约定、代码库知识
              Hooks 在关键时刻触发的脚本 事件触发 自动化一致性行为、捕获会话学习
              Skills 特定任务类型的打包指令 按需加载 跨会话和项目的可复用专业知识
              Plugins 打包好的 skills + hooks + MCP 配置 安装后始终可用 在组织内分发一套完整配置
              LSP 集成 通过语言服务器提供实时代码智能 配置后始终可用 符号级导航、自动错误检测
              MCP 服务器 连接外部工具和数据源 配置后始终可用 让 Claude 访问内部工具
              Subagents 独立的 Claude 实例 按需调用 探索与编辑分离、并行工作

              这五个扩展点有构建顺序,每一层都建立在前一层之上。下面逐层拆。

              CLAUDE.md 是 Claude 在每次会话开始时自动读取的上下文文件。根目录放全局信息,子目录放局部约定。

              关键原则:精简、分层。

              根目录的 CLAUDE.md 只放指针和关键注意事项,其他的放到子目录里。内容越多,噪音越大,性能越差。

              # 项目概览
              
              这是一个电商平台的 monorepo,约 80 万行代码,模块如下:
              
              - /services/payment   - 支付服务(Java 17 + Spring Boot 3.x)
              - /services/inventory - 库存服务(Go 1.22)
              - /services/order     - 订单服务(Go 1.22)
              - /frontend           - React 18 + Vite + TypeScript
              - /infra              - Terraform + Helm
              - /docs               - 架构与 API 文档
              
              详细模块约定见各目录下的 CLAUDE.md。
              
              # 全局硬性约定
              
              - 所有对外 API 的变更必须同步更新 `/docs/api-changelog.md`,未更新视为不完整
              - 数据库迁移文件放在 `/migrations`,命名格式:`YYYYMMDD_HHmm_描述.sql`
              - 禁止直接修改 `/generated` 目录下的文件(由 buf/protoc 生成)
              - 提交前必须本地通过 `make precommit`
              - 任何新增依赖需要在 PR 描述里写明引入理由
              
              # 常用命令
              
              | 场景 | 命令 | 说明 |
              |------|------|------|
              | 日常单元测试 | `make test-unit` | 约 1 分钟 |
              | 完整测试 | `make test` | 约 20 分钟,CI 才跑 |
              | 启动本地环境 | `make dev` | 依赖 Docker Desktop |
              | 类型 + lint 检查 | `make check` | 提交前必跑 |
              
              # 不要做的事
              
              - 不要在 `/services/payment` 里写新功能时跑全量测试,单跑该模块即可
              - 不要在 PR 里同时混入格式化变更与逻辑变更
              - 不要把环境变量写进代码,统一在 `infra/env/` 配置
              

              # /services/payment
              
              ## 技术栈
              - Java 17,Spring Boot 3.2.x,Gradle 8
              - 数据库:PostgreSQL 15(主)+ Redis 7(限流/幂等)
              
              ## 测试与构建
              - 本模块测试:`./gradlew :payment:test`
              - 集成测试需要 docker-compose:`make payment-it`
              - 构建产物:`./gradlew :payment:bootJar`
              
              ## 关键文件
              - `PaymentProcessor.java` —— 入口,**线程安全要求**,修改前必读类头注释
              - `gateway/` —— 各支付渠道适配,新增渠道走 `GatewayAdapter` 接口
              - `idempotency/` —— 幂等键存储,禁止绕过
              
              ## 常见任务索引
              - 新增支付渠道:参考 `docs/add-gateway.md`
              - 修改对账逻辑:必须同时更新 `tests/reconciliation/`
              

              把可复用的专业知识塞进 CLAUDE.md。比如把"如何做安全审查的 30 条清单"全塞进根目录——这些内容应该放进 Skills,按需加载,而不是每次会话都占用上下文。

              判断标准很简单:这条信息每次会话都需要吗? 是 → CLAUDE.md;否 → Skill。

              大多数团队把 Hooks 理解成"防止 Claude 做错事的脚本"。这只用到了 Hooks 一半的价值。

              Hooks 更大的价值在于持续改进。

              // .claude/settings.json
              {
                "hooks": {
                  "PostToolUse": [
                    {
                      "matcher": "Write|Edit",
                      "hooks": [
                        {
                          "type": "command",
                          "command": "if [[ "$CLAUDE_FILE_PATH" =~ \.(ts|tsx|js|jsx)$ ]]; then npx prettier --write "$CLAUDE_FILE_PATH" && npx eslint --fix "$CLAUDE_FILE_PATH"; fi"
                        },
                        {
                          "type": "command",
                          "command": "if [[ "$CLAUDE_FILE_PATH" =~ \.go$ ]]; then gofmt -w "$CLAUDE_FILE_PATH" && goimports -w "$CLAUDE_FILE_PATH"; fi"
                        }
                      ]
                    }
                  ]
                }
              }

              {
                "hooks": {
                  "PreToolUse": [
                    {
                      "matcher": "Bash",
                      "hooks": [
                        {
                          "type": "command",
                          "command": ".claude/hooks/guard-bash.sh"
                        }
                      ]
                    }
                  ]
                }
              }
              

              .claude/hooks/guard-bash.sh

              #!/usr/bin/env bash
              # 拦截高危命令:rm -rf /、生产数据库连接、force push 到 main
              INPUT=$(cat)
              CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
              
              if echo "$CMD" | grep -qE '(rms+-rfs+/|drops+database|--force.*origin/main)'; then
                echo '{"decision":"block","reason":"危险命令已拦截,请人工确认后再执行"}'
                exit 0
              fi
              
              if echo "$CMD" | grep -qE 'psql.*prod|kubectl.*-ns+production'; then
                echo '{"decision":"ask","reason":"该命令会接触生产环境,请确认意图"}'
                exit 0
              fi
              

              {
                "hooks": {
                  "Stop": [
                    {
                      "hooks": [
                        {
                          "type": "command",
                          "command": ".claude/hooks/session-reflect.sh"
                        }
                      ]
                    }
                  ]
                }
              }

              .claude/hooks/session-reflect.sh

              #!/usr/bin/env bash
              # 会话结束时,让 Claude 自己反思有没有值得沉淀到 CLAUDE.md 的东西
              SESSION_DIR="${CLAUDE_PROJECT_DIR}/.claude/sessions"
              mkdir -p "$SESSION_DIR"
              
              cat <<'PROMPT' > "$SESSION_DIR/reflect-prompt.md"
              回顾这次会话:
              1. 我有没有走过弯路?是因为缺少哪条上下文?
              2. 哪些用户的纠正应该写进 CLAUDE.md 让以后不再犯?
              3. 是否发现了应该写成 Skill 的可复用模式?
              
              请生成 patch 建议,不要直接修改文件。
              PROMPT
              
              # 触发一次独立 Claude 进程做反思,写到 inbox 等人 review
              claude -p "$(cat $SESSION_DIR/reflect-prompt.md)" 
                --output-format json 
                > "$SESSION_DIR/$(date +%Y%m%d-%H%M%S).reflection.json"
              

              第二天上班的时候,DRI 把 sessions/ 里的反思扫一遍,把真正有价值的沉淀到根 CLAUDE.md。这是配置随时间自我进化的核心机制。

              大型代码库有几十种任务类型。如果把所有专业知识都塞进每次会话,上下文会被撑爆,性能会下降。

              Skills 解决这个问题的方式叫渐进式披露:把专业工作流和领域知识打包成独立的 Skill,只在任务需要时加载。

              .claude/skills/payment-gateway-onboarding/
              ├── SKILL.md              # 入口文件,含 frontmatter
              ├── checklist.md          # 接入新支付渠道的 30 项检查清单
              ├── templates/
              │   ├── adapter.java.tmpl # 适配器模板
              │   └── test.java.tmpl    # 测试模板
              └── references/
                  └── compliance.md     # PCI-DSS 合规要点(按需读取)
              

              SKILL.md

              ---
              name: payment-gateway-onboarding
              description: 接入新的第三方支付渠道(Stripe / Adyen / 支付宝 / 微信支付等)。当用户提到"接入支付"、"新增 gateway"、"对接 XX 支付"时使用。
              allowed-paths:
                - services/payment/**
              ---
              
              # 接入新支付渠道
              
              ## 第一步:确认信息齐全
              在动手前,确认拿到了以下材料(缺一不可):
              - [ ] 渠道方的 API 文档与沙箱环境凭证
              - [ ] 商户号 / appid(生产 + 沙箱)
              - [ ] 回调签名算法与公私钥
              - [ ] 合规备案文档(见 `references/compliance.md`)
              
              ## 第二步:生成骨架
              基于 `templates/adapter.java.tmpl` 创建新文件:
              `services/payment/src/main/java/.../gateway/<channel>/<Channel>Adapter.java`
              
              ## 第三步:实现 GatewayAdapter 接口
              必须实现:`charge`, `refund`, `query`, `verifyCallback`。
              幂等键统一走 `IdempotencyService`,不要自己造轮子。
              
              ## 第四步:测试矩阵
              按 `checklist.md` 跑完 30 项检查,缺一项不允许合并。
              

              注意上面 frontmatter 里的 allowed-paths——这个 Skill 只在 services/payment/** 下工作时激活。前端工程师改 React 组件时,不会被这个 Skill 打扰。这对 monorepo 特别重要。

              成熟团队的 .claude/skills/ 目录大概长这样:

              .claude/skills/
              ├── security-review/             # 安全审查清单
              ├── payment-gateway-onboarding/  # 新增支付渠道
              ├── db-migration/                # 数据库迁移规范
              ├── api-changelog/               # API 变更自动更新 changelog
              ├── incident-postmortem/         # 事故复盘模板
              └── frontend-component-new/      # 新增前端组件
              

              每个 Skill 只在被相关任务激活时加载,平时不占上下文。

              一个团队摸索出了好用的 Skills + Hooks + MCP 配置组合,怎么让整个组织都用上?

              答案是 Plugins:把这些东西打包成一个可安装的包。新工程师入职第一天安装这个 Plugin,立刻拥有和老员工一样的上下文和能力。

              acme-platform-plugin/
              ├── plugin.json                  # 清单
              ├── skills/
              │   ├── deploy-to-staging/
              │   └── internal-rpc-client/
              ├── hooks/
              │   ├── settings.json
              │   └── scripts/
              │       └── jira-link.sh
              └── mcp/
                  └── servers.json             # 内部 analytics / Jira / Confluence MCP
              

              plugin.json

              {
                "name": "acme-platform",
                "version": "1.4.2",
                "description": "Acme 内部 Claude Code 配置:部署、Jira、内部 RPC 工具集",
                "skills": ["./skills/deploy-to-staging", "./skills/internal-rpc-client"],
                "hooks": "./hooks/settings.json",
                "mcp": "./mcp/servers.json",
                "minimum-claude-code": "1.0.0"
              }

              工程师只需要:

              claude plugin install git@github.acme.com:devplatform/claude-code-plugin.git
              

              一家大型零售商在全面推广 Claude Code 之前,先构建了一个 Skill,把 Claude 连接到他们的内部分析平台,让业务分析师不用离开工作流就能拉取性能数据。这个 Skill 被打包成 Plugin,在大规模推广前就分发到位了——先做基础设施,再做推广,这是顺序问题。

              没有 LSP 的情况下,Claude 用文本匹配来找代码。在大型代码库里,grep 一个常见函数名比如 process 可能返回几千个匹配,Claude 要烧掉大量上下文逐个打开文件判断哪个才是目标。

              有了 LSP,Claude 获得了和 IDE 一样的导航能力:追踪函数调用到定义、跨文件追踪引用、区分不同语言中同名函数。过滤在 Claude 读任何文件之前就完成了。

              // .claude/settings.json
              {
                "lsp": {
                  "servers": {
                    "typescript": {
                      "command": "typescript-language-server",
                      "args": ["--stdio"],
                      "rootMarkers": ["package.json", "tsconfig.json"]
                    },
                    "go": {
                      "command": "gopls",
                      "args": ["serve"],
                      "rootMarkers": ["go.mod"]
                    },
                    "java": {
                      "command": "jdtls",
                      "rootMarkers": ["pom.xml", "build.gradle"]
                    },
                    "cpp": {
                      "command": "clangd",
                      "args": ["--background-index", "--clang-tidy"],
                      "rootMarkers": ["compile_commands.json"]
                    }
                  }
                }
              }

              # 没 LSP:grep 找 ProcessOrder 的定义
              $ grep -rn "ProcessOrder" .
              找到 437 处匹配
              → Claude 需要打开 N 个文件来确定真正的定义
              
              # 有 LSP:goToDefinition
              → 一次调用直接返回 services/order/internal/processor.go:42
              → 上下文消耗:1 个文件
              

              一家企业软件公司在推广 Claude Code 之前,专门在全组织部署了 LSP 集成,目的是让 C 和 C++ 的导航在大规模场景下可靠运行。对于多语言代码库,这是投入产出比最高的基础设施投资之一。

              MCP 服务器是 Claude 连接内部工具、数据源和 API 的方式。

              // .claude/mcp.json
              {
                "mcpServers": {
                  "jira": {
                    "command": "npx",
                    "args": ["-y", "@acme/mcp-jira"],
                    "env": {
                      "JIRA_BASE_URL": "https://acme.atlassian.net",
                      "JIRA_TOKEN": "${JIRA_TOKEN}"
                    }
                  },
                  "internal-docs": {
                    "command": "node",
                    "args": ["./tools/mcp/confluence-server.js"],
                    "env": {
                      "CONFLUENCE_SPACE": "ENG"
                    }
                  },
                  "code-search": {
                    "command": "./tools/mcp/sourcegraph-server",
                    "env": {
                      "SG_ENDPOINT": "https://sg.internal.acme.com"
                    }
                  }
                }
              }
              

              配上之后,Claude 可以直接调用 mcp__jira__create_issuemcp__internal-docs__search 这类工具,不需要 copy-paste。

              MCP 服务器应该在基础配置(CLAUDE.md、Hooks、Skills)都到位之后再构建。常见的反模式是:

              "我们先接一个 GitHub MCP 上去看看效果。"

              ——结果是 Claude 在还没搞清楚项目结构的情况下乱调外部 API,搞出一堆噪音。基础不打好,外部工具只会放大混乱。

              根目录只放指针和关键注意事项。Claude 在遍历代码库时会逐层加载 CLAUDE.md,根目录的上下文永远不会丢失,所以不需要在根目录塞所有信息。

              在 monorepo 里,这可能反直觉——工具通常假设从根目录运行。但 Claude 会自动向上遍历目录树加载所有 CLAUDE.md,所以从子目录开始工作,既能获得局部精确上下文,也不会丢失根目录的全局信息。

              # 反例:在仓库根目录,让它修支付服务的 bug
              cd ~/work/acme-monorepo
              claude
              # → 加载根 CLAUDE.md,但本地上下文还是仓库根,开搜会扫到很多无关目录
              
              # 正解:直接进子目录
              cd ~/work/acme-monorepo/services/payment
              claude
              # → 既加载了根 CLAUDE.md,又加载了 services/payment/CLAUDE.md
              # → 命令、测试范围都自动收敛到本服务
              

              当 Claude 只改了一个服务,却要跑整个测试套件,会超时,还会用无关输出浪费上下文。子目录的 CLAUDE.md 应该指定该目录适用的命令:

              # /services/inventory/CLAUDE.md
              
              ## 命令
              
              - 单元测试:`go test ./...`(只跑本服务,约 30 秒)
              - 集成测试:`make inventory-it`(依赖 docker-compose,约 3 分钟)
              - 构建:`go build ./cmd/server`
              - Lint:`golangci-lint run ./...`
              
              ⚠️ 不要在本目录下跑 `make test`(那是全量测试,20 分钟,会超时)。
              

              注意:这个方案对服务化架构效果好。对于有深层跨目录依赖的编译型语言 monorepo(比如大型 C++ 项目),按子目录作用域更难实现,可能需要项目特定的构建配置。

              // .claude/settings.json
              {
                "permissions": {
                  "deny": [
                    "Read(/generated/**)",
                    "Read(/node_modules/**)",
                    "Read(/build/**)",
                    "Read(/.next/**)",
                    "Read(/dist/**)",
                    "Read(/vendor/**)",
                    "Read(/**/*.min.js)",
                    "Read(/**/*.lock)"
                  ],
                  "ask": [
                    "Bash(git push:*)",
                    "Bash(rm -rf:*)",
                    "Bash(kubectl:*)"
                  ]
                }
              }

              把这个文件提交到版本控制,整个团队都能获得同样的降噪效果,不需要每个人单独配置。

              如果代码没有按常规目录结构组织,在仓库根目录放一个 CODEMAP.md,给 Claude 一个可以扫描的目录:

              # 代码库结构地图
              
              ## 一级目录
              - `/core`           核心业务逻辑(Java,约 30 万行)
              - `/adapters`       外部系统适配器(按渠道分子目录)
              - `/legacy-billing` 旧版计费系统(PHP,**只读**,2026Q4 下线)
              - `/tools`          内部开发工具,CI 也依赖
              - `/docs`           技术文档(ADR + API 规范)
              
              ## 重要入口
              - HTTP 入口:`core/src/main/java/.../HttpServer.java`
              - 定时任务:`core/src/main/java/.../jobs/JobScheduler.java`
              - 配置加载:`core/config/` + 环境变量见 `infra/env/`
              
              ## 历史包袱
              - `core/util/Helpers.java` —— 4000 行的"什么都往里塞"工具类,要拆但还没拆
              - `adapters/legacy-mq/` —— 已停用但还没删,触发别影响
              

              然后在根 CLAUDE.md 加一句:不熟悉本仓库的话先读 CODEMAP.md

              CLAUDE.md 里的指令是为当时的模型写的。模型升级后,这些指令可能变成负担。

              一个告诉 Claude 把每次重构拆成单文件变更的规则,可能是为了帮助旧模型保持专注——但新模型完全能处理协调的跨文件编辑,这条规则反而会阻止它做正确的事。

              建议每三到六个月做一次配置审查,在重大模型发布后也值得做一次。问自己每条规则:

              问题 处理
              这条规则是在补偿模型的某个局限吗? 是 → 测试新模型是否还需要
              这条规则是在表达真实的项目约定吗? 是 → 保留
              半年内有人违反过这条规则吗? 没有 → 可能已是常识,可以删
              这条规则的反例容易在 PR 里抓到吗? 是 → 移到 hook/CI,不要靠 prompt

              一份很务实的审查清单可以做成 Skill:

              # .claude/skills/config-audit/SKILL.md
              ---
              name: config-audit
              description: 季度性审查 CLAUDE.md,识别可以删除或迁移到 hook 的规则
              ---
              按以下步骤逐条审查:
              1. 读取所有 CLAUDE.md(根 + 各子目录)
              2. 对每条规则打三个标签:[必要 | 可移除 | 可移到 hook]
              3. 生成 diff 提案到 `.claude/audit-YYYY-MM.md`,不直接改文件
              4. 邮件 / Slack 通知 DRI review

              技术配置到位了,但没有人负责维护,配置会腐烂,好的实践会停留在少数人手里。

              Anthropic 观察到推广最顺利的公司,都在大规模推广之前做了专项基础设施投入。有的是两个工程师提前构建了一套 Plugins 和 MCP,让第一批用户一上手就有生产力。有的是整个团队专门负责 AI 编码工具的基础设施,在推广前就把一切准备好。

              最低可行版本:一个 DRI(直接负责人)。这个人负责:

              • Claude Code 配置的所有权
              • Settings、权限策略、Plugin 市场、CLAUDE.md 约定的决策权
              • 保持这些内容的时效性
              • 每月发一份"配置变更 + 数据指标"周报

              没有这个角色,自下而上的采用会产生热情,但也会产生碎片化——每个团队各自 摸索,好的实践停留在部落知识里,无法扩散。

              对于大型组织,尤其是受监管行业,治理问题会早早浮现:谁控制哪些 Skills 和 Plugins 可用?如何防止几千个工程师各自重复构建同样的东西?AI 生成的代码如何走和人工代码一样的审查流程?

              建议从一开始就建立跨职能工作组,把工程、信息安全、合规代表拉在一起定义要求,共同制定推广路线图。

              Subagents 是独立的 Claude 实例,有自己的上下文窗口,接受任务、完成工作、只把最终结果返回给父实例。

              在大型代码库里,一个常见的高效模式是:探索和编辑分离

              假设你要在一个 50 万行的服务里重构日志模块。直接做的问题是:父 Agent 一边搜一边读,光是搞清楚"现在的日志怎么用的"就吃掉了 60% 的上下文,等到要编辑时已经没空间了。

              正确的做法:

              > 我要把项目里的 log4j 全部替换为 slog,先帮我摸清现状
              
              ● 我先派一个只读 subagent 去做完整调研,结果写到文件,然后我基于结果做改动。
              
              ● Task(subagent_type: "explore", description: "调研 log4j 使用")
                Prompt:
                  遍历整个仓库,找出所有 log4j 的使用方式。生成报告到 .claude/scratch/log4j-usage.md,
                  包含:
                  1. 所有 import log4j 的文件路径
                  2. 按使用模式分类(直接 logger.info / 包装类 / 自定义 Appender)
                  3. 特殊用法清单(异步 logger、MDC、自定义格式)
                  不要做任何修改。
              
              ● [subagent 干完,返回报告路径]
              
              ● 现在我读这份报告,制定迁移计划
                └─ Read(".claude/scratch/log4j-usage.md")
              

              父 Agent 的上下文窗口几乎没被探索消耗,全留给真正的重构编辑。一次任务跑下来,能多撑 3-5 倍的工作量。

              > 改完后帮我跑三组验证
              
              ● 并行启动三个 subagent:
                Task(subagent_type: "test-engineer", "跑所有 log 相关单元测试")
                Task(subagent_type: "security-reviewer", "确认 slog 配置没泄漏 PII")
                Task(subagent_type: "verifier", "对照迁移清单逐项核对")
              

              主 Agent 等三个结果汇总,再决定是否合并。这个模式在大型 PR 收尾阶段特别好用。

              如果你的团队刚开始在大型代码库里用 Claude Code,按这个顺序来:

              1. 先写 CLAUDE.md:根目录放全局信息(用上面的模板抄一份),关键子目录放局部约定。精简,只放真正有用的。
              2. 配置 .ignore 和权限规则:排除生成文件和构建产物,提交到版本控制。模板见上面 .claude/settings.json
              3. 设置 LSP 集成:特别是 C/C++/Java 这类强类型语言,这是最高投入产出比的基础设施。
              4. 构建第一批 Hooks:从 lint/format 自动化开始,再加一个 stop 反思 hook,最后做命令拦截。
              5. 把可复用的专业知识打包成 Skills:不要全塞进 CLAUDE.md。先做 3-5 个高频任务的 Skill。
              6. 打包成内部 Plugin 分发:让新人 claude plugin install 一行命令就能上车。
              7. 指定一个 DRI:没有负责人,配置会腐烂。
              8. 三到六个月做一次配置审查:随模型演进调整,删掉已经不需要的规则。

              Claude Code 在百万行 monorepo、几十年历史的遗留系统、跨几十个仓库的分布式架构里都有成功案例。这些环境的共同点不是代码库有多整洁,而是团队在配置上做了投入。

              模型只是一半,配置才是另一半。 把这另一半做到位,差距就出来了。

              以上就是Claude Code在大型项目中的最佳实践指南的详细内容,更多关于Claude Code在大型项目中的实践的资料请关注风君子博客其它相关文章!

              站内搜索