有一件事我直到用了 Claude Code 三个月才搞清楚------
它的上下文窗口是 200K tokens,但这个数字在大型代码库里根本撑不了多久。
粗略换算:一个普通 Java 服务文件大约 200-500 行,按每行 10 个 token 计算,200K tokens 大约能容纳 400-1000 个完整文件。听起来不少,但一次深度调试或功能开发,Claude 会连带读依赖、读测试、读配置------不知不觉上下文就满了,然后开始"失忆",重复犯之前说好不会犯的错。
我们当时接手了一个运行了 4 年的 Spring Cloud 单体拆微服务的项目,代码量 8 万多行,依赖关系错综复杂。最开始用 Claude Code 就是当一个聪明的补全工具------让它改几个文件、写几个测试,能跑就行。但慢慢发现,同样的问题同事用 Claude Code 能 20 分钟搞定,我自己要来回折腾两个小时。
差距不在模型,在使用方式。
把摸索出来的 10 个技巧整理成这篇,每个都是踩过坑之后才真正理解的。
技巧一:CLAUDE.md 不是越详细越好,超过 200 行就是在害自己
大多数人的误用
刚开始用的时候,我把 CLAUDE.md 当成一个什么都往里塞的"说明书"------项目架构、API 文档、代码规范、常用命令、禁止事项......洋洋洒洒写了 500 行,觉得交代得越详细 Claude 表现越好。
结果恰恰相反。Claude 开始忽略文件里后半段的内容,说好不要改的文件照样改,说好用的框架换成了另一个。
为什么会这样
CLAUDE.md 的内容会在每次会话开始时直接注入上下文窗口,按照官方文档的数据,一份典型的项目 CLAUDE.md 大约消耗 1800 tokens。但如果你的文件是 500 行,消耗就到了 5000-8000 tokens。
更关键的问题是:CLAUDE.md 是以"上下文"的方式加载的,不是"配置规则"。Claude 读完它之后,并不会像代码里的 if/else 那样严格执行,而是"知道了这个信息,根据情况判断"。文件越长,重要规则被稀释的概率越高,反而让 Claude 觉得每条规则的权重差不多。
正确做法
官方建议是:CLAUDE.md 保持在 200 行以内,只写 Claude 靠自己读不到的信息。
具体来说,哪些值得写:
markdown
# 项目构建
- 运行:mvn clean test -pl user-service(单服务测试)
- 全量构建:./scripts/build-all.sh(大约 3 分钟)
# 不要动的文件
- src/legacy/DataMigration.java(迁移脚本,已废弃但生产依赖)
- .env.production(生产环境变量,只读不改)
# 代码规范差异
- 这个项目用 MyBatis 不用 JPA,不要引入 Hibernate
- 服务间通讯走 OpenFeign,不要用 RestTemplate
# 架构决策
- 每个服务独立数据库,禁止跨服务直接访问 DB
哪些不用写:Java 基本语法、标准 REST 规范、Claude 读代码就能推断出来的东西。
如果确实有很多规则,用 .claude/rules/ 目录做路径隔离------比如只在修改 src/api/**/*.java 时才加载 API 规范文件。这样规则按需加载,不会每次都占满上下文。
json
// .claude/rules/api-conventions.md 的 frontmatter
---
paths:
- "src/api/**/*.java"
---
# API 规范(只在修改 API 层文件时加载)
- 所有接口返回 Result<T> 包装类
- 参数校验用 javax.validation 注解,不要手写 if
判断标准很简单:如果去掉某条规则,Claude 是否会做出不同的决定? 答案是"不会"就删掉。
图:200K tokens 上下文的实际分配------启动自动注入约 7400 tokens,一次典型调试 Session 消耗约 30,400 tokens(15%),探索陌生大模块不用 Subagent 可能耗掉 80%+
技巧二:一个 Session 做太多事是效率杀手
大多数人的误用
打开 Claude Code,开始让它修 Bug,修完顺手让它加个功能,加完让它写测试,写完觉得文档也顺手更新一下......几个小时过去,这个 Session 的上下文里全是各种文件读取记录、失败尝试、修改历史,乱成一锅粥。
然后发现 Claude 开始犯奇怪的错误------明明说好的变量名,它换成了另一个;明明已经修好的问题,重新冒出来了。
为什么会这样
Claude 的 Session 是有状态的,所有的"对话"都累积在上下文里。读了 10 个文件、尝试了 3 种方案、来回改了 2 次------这些全都在消耗上下文空间。当上下文快满的时候,Claude 会触发自动压缩(compaction),把之前的对话总结成摘要。
但压缩是有损的。你在对话里说的临时决定、中途修改的方向、某个特定的约束,在压缩后可能就消失了。 而 CLAUDE.md 里的内容在压缩后会重新注入,所以写进文件里的规则比口头说的更可靠。
正确做法
养成按任务切换 Session 的习惯。用 /clear 在无关任务之间重置上下文。
一个实用的工作流:
bash
# 任务 A:修复登录 Bug
claude
# 完成后
/clear
# 任务 B:新增支付功能
claude
如果当前任务涉及大量文件阅读(比如理解一个陌生模块),用 Subagent 来做------让子 Agent 去读文件、做调查,只把结论带回来,不让探索过程污染主 Session 的上下文。
用 subagent 去读一下 payment-service 模块,
弄清楚现有的支付流程,然后告诉我需要在哪里加新的支付渠道
子 Agent 在自己独立的上下文里跑,读了 100 个文件也不影响你的主 Session。
图:遇到新任务时的 Session 管理决策树------何时 /clear、何时 /compact、何时用 Subagent、何时开 Worktree
技巧三:Plan 模式是你在大型代码库里最重要的工具
大多数人的误用
让 Claude 直接改代码------特别是在大型代码库里,不知道它会改哪些文件,结果改完一看,动了 15 个文件,其中有几个地方改法明显不对,还不知道该从哪里开始 revert。
为什么会这样
大型代码库里的修改往往有连锁反应。改一个接口,可能涉及 Controller、Service、Mapper、DTO、测试、文档......Claude 知道要改这些,但执行顺序和改法不一定符合你的预期。在代码直接落地之前,你没有机会说"等一下,这个地方不对"。
正确做法
启动 Plan 模式(Shift+Tab 切换,或 --permission-mode plan)。在这个模式下,Claude 读文件、分析代码,给出完整的变更计划,但不执行任何修改。
实测下来,这是大型代码库里提升效率最明显的单一操作。典型的工作流:
[Plan 模式下]
我要在 user-service 里添加手机号登录功能。
先读一下现有的登录实现,告诉我需要修改哪些文件,
以及每个文件具体的改动方向。
Claude 会给出一份类似这样的计划:
计划修改以下文件:
1. UserController.java - 添加 /login/phone 接口
2. UserService.java - 添加 phoneLogin() 方法
3. SmsService.java - 添加验证码校验逻辑
4. UserMapper.java - 添加按手机号查询用户的 SQL
5. LoginDTO.java - 添加 PhoneLoginRequest 内部类
不需要修改:认证中间件(复用现有 token 逻辑)
你看完计划,觉得没问题了,再切回正常模式让它执行。这样改的是你知情的、你同意的,不会有意外。
进阶用法 :看完计划,按 Ctrl+G 在文本编辑器里直接编辑这份计划,改掉你觉得不对的地方,再让 Claude 按修改后的计划执行。
技巧四:上下文不够用时,多开几个 Session 并行跑
大多数人的误用
一直在同一个 Session 里工作,遇到上下文快满的提示就用 /compact 压缩一次,继续跑。但压缩完 Claude 表现变差了,又不知道是什么原因。
为什么会这样
/compact 会把历史对话压缩成摘要,节省 tokens,但压缩后 Claude 失去了很多具体的上下文细节。之前读过的文件内容、之前探索过的路径------摘要里可能只剩几行概述。
对于大型代码库的复杂任务,一个 Session 根本不够用。
正确做法
用 Worktrees 开多个并行 Session,每个 Session 处理独立的子任务。
bash
# 创建一个新的 worktree,专门处理认证模块重构
claude --worktree auth-refactor
# 另一个终端,另一个 worktree,处理支付模块
claude --worktree payment-feature
每个 Worktree 是独立的 git 分支和独立的文件系统快照,两个 Session 的修改不会相互干扰。用完合并就行。
对于特别大的单体仓库(monorepo),还可以配置 sparsePaths 做稀疏检出,只让 Claude 看它需要的那部分:
json
// .claude/settings.json
{
"worktree": {
"baseRef": "fresh",
"symlinkDirectories": ["node_modules", ".cache"],
"sparsePaths": ["packages/user-service", "shared/common-utils"]
}
}
这样一个 monorepo 里,Claude 只会看 user-service 和共用工具,不会被其他 50 个服务的代码干扰。
技巧五:给 Claude 能验证自己的工具,效果会好很多
大多数人的误用
让 Claude 改完代码,自己去跑测试看结果,再回来告诉 Claude "有个测试失败了"。
这个来回就是效率损耗。
为什么会这样
Claude 的核心能力是"探索-修改-验证"的循环。如果它每次改完都要等你来告诉它结果,这个循环断了,很多次可以自动修复的小问题变成了需要你手动介入的问题。
而且更重要的是:当 Claude 能自己运行测试、看到输出,它的修复精准度会明显提升。 因为它能看到真实的错误信息,而不是你描述的错误信息。
正确做法
在 prompt 里明确告诉 Claude 验证方法:
修改 UserService 的 findByPhone 方法,
让它在手机号格式不对时抛出 InvalidPhoneException。
改完之后运行 mvn test -pl user-service -Dtest=UserServiceTest,
确保测试通过。如果测试失败,看错误信息继续修。
或者用 Hooks 自动化这个过程------每次文件修改后自动跑 lint:
json
// .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "mvn checkstyle:check -pl user-service",
"timeout": 30
}
]
}
]
}
}
这样每次 Claude 改完代码,自动跑一次 checkstyle,违规直接反馈给 Claude,它自己修,不需要你盯着。
技巧六:@ 引用文件比让 Claude 自己"找"更高效
大多数人的误用
"帮我修一下登录的 Bug" → Claude 开始 grep 整个项目,读了十几个文件,花了大量上下文 tokens,才找到问题所在。
为什么会这样
如果你不告诉 Claude 去哪里找,它会自己做 codebase 搜索------这很消耗上下文。每一次 grep、每一次 Read 都在占用 token 配额。在 200K 的上下文里,读 5 个 2000 行的文件就花掉了大约 5% 的额度。
正确做法
用 @ 直接引用你知道相关的文件或目录:
@src/api/UserController.java @src/service/UserService.java
登录接口在高并发下出现了 token 不一致的问题,帮我看一下是哪里有并发问题
这样 Claude 直接拿到了你指定的上下文,不用到处搜索。减少了不必要的文件读取,也让 Claude 更聚焦在你认为相关的代码上。
还有一个进阶技巧:对于大型项目,配置自定义的文件建议命令。这样用 @ 触发的自动补全是项目专属的,不是通用的文件系统搜索:
json
// ~/.claude/settings.json 或 .claude/settings.json
{
"fileSuggestion": {
"type": "command",
"command": "~/.claude/scripts/project-file-index.sh"
}
}
这个脚本可以结合你的项目结构(比如 Maven 的 module 划分)返回更精确的文件建议,而不是把整个文件树都列出来。
技巧七:Auto Memory 在悄悄学习,你需要知道它记了什么
大多数人的误用
不知道有 Auto Memory 这个东西。或者知道了,但觉得这是黑盒,不去管它。
为什么会这样
Claude Code 有个功能叫 Auto Memory(自动记忆)。当你纠正 Claude 的行为、告诉它某个项目的特殊规则,它会把这些学到的东西存入 ~/.claude/projects/<项目>/memory/MEMORY.md,下次 Session 自动加载。
这是个很有用的功能,但也有两个坑:
第一,你可能不知道它"记住"了什么错误的东西。比如你曾经在某个测试场景里让它用了一个临时方案,结果它把这个临时方案记下来了,之后每次都用,让你莫名其妙。
第二,MEMORY.md 的前 200 行会自动加载进每个 Session,如果记了很多乱七八糟的内容,无形中消耗上下文。
正确做法
定期审查 Auto Memory:
bash
# 打开当前项目的自动记忆文件
~/.claude/projects/<项目hash>/memory/MEMORY.md
或者在 Session 里直接运行 /memory,查看当前加载的所有记忆文件,该删的删,该修正的修正。
对于一些明确不想让 Claude 自动记忆的内容,可以在 CLAUDE.md 里显式说明------CLAUDE.md 里的规则优先级更高,而且是你主动维护的,比 Auto Memory 更可控。
技巧八:Subagent 不只是"让它自己想",而是上下文隔离的关键手段
大多数人的误用
只知道 Subagent 可以并行处理任务,觉得这是一个"速度"工具。
为什么会这样
Subagent 最重要的作用不是速度,而是上下文隔离。当你让 Claude 探索一个陌生模块时,它会读很多文件,这些读取全都进入你的主 Session 上下文。如果改用 Subagent,这些文件读取发生在子 Agent 的独立上下文里,主 Session 只收到最终结论。
正确做法
凡是"先搞清楚某件事,再告诉我结果"的任务,都适合用 Subagent:
用 subagent 去调查一下 order-service 里的库存扣减逻辑,
包括:现在的并发处理方式、已有的测试覆盖范围、有没有已知的并发问题。
调查完告诉我结论,不用给我读文件的过程。
还有一个更高级的用法:Writer/Reviewer 模式。一个 Session 写代码,写完之后用另一个 Session(或 Subagent)来 Review。因为 Reviewer 没有参与写代码的过程,不会带入"我觉得这样写是对的"的偏见,Review 质量更高。
用 subagent review 一下 @src/payment/PaymentProcessor.java
这段代码,重点看:事务边界是否正确、异常处理有没有漏洞、
有没有可能出现重复扣款的场景。
技巧九:Hooks 做到"每次自动做",CLAUDE.md 只能做到"大概会做"
大多数人的误用
把很多应该用 Hooks 实现的自动化规则写进了 CLAUDE.md。比如"每次改完代码要运行一遍 lint"。
为什么这样不可靠
CLAUDE.md 里的规则是给 Claude 的"建议",Claude 会尽量遵守,但不能 100% 保证。特别是在上下文接近满的时候,这些规则可能被"遗忘"。
而 Hooks 是程序级别的触发------在特定事件发生时,无论 Claude 愿不愿意,脚本都会执行,结果都会反馈给 Claude。
正确做法
把"每次必须做"的事情写成 Hooks,"应该怎么做"的风格规范写进 CLAUDE.md。
几个真正有用的 Hook 场景:
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/check-dangerous-commands.sh",
"timeout": 5
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "mvn checkstyle:check -q 2>&1 | head -20",
"timeout": 30
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/session-summary.sh"
}
]
}
]
}
}
第一个 Hook 在每次执行 Bash 命令前先检查有没有危险操作(比如 rm -rf、DROP TABLE);第二个每次文件修改后自动跑代码风格检查;第三个在 Session 结束时自动记录这次做了什么,方便下次继续。
这些都是"每次必须做"的事情,用 Hook 实现比写进 CLAUDE.md 可靠得多。
图:CLAUDE.md 是"告知型"软性约束,Hooks 是"程序化"确定性执行------两者定位不同,不要混用
技巧十:大型代码库里的权限配置不是障碍,是保障
大多数人的误用
嫌权限确认烦,直接开 --dangerously-skip-permissions 或者在 settings 里把所有权限都 allow。
为什么这是个坑
在小项目里,Claude 改错了无所谓,撤销就行。在 8 万行代码的生产服务里,如果 Claude 在没有任何权限控制的情况下随意执行命令------比如不小心跑了数据库 migration、删了临时文件但那个文件正在被其他进程用------代价可能相当大。
我们曾经遇到过 Claude 误删了一个本地缓存目录,虽然能恢复,但恢复过程花了一个小时,而那个任务本身只要 20 分钟。
正确做法
配置精细化权限,不是全开也不是全关,而是只放行你真正信任的操作:
json
// .claude/settings.json
{
"permissions": {
"allow": [
"Bash(mvn test *)",
"Bash(mvn clean compile)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git add *)",
"Bash(git commit *)",
"Read(**)",
"Edit(src/**)",
"Write(src/**)"
],
"deny": [
"Bash(rm *)",
"Bash(DROP *)",
"Read(.env*)",
"Read(**/secrets/**)",
"Write(**/migrations/**)"
]
}
}
允许读所有文件、改 src 目录下的代码、跑 Maven 命令和 Git 操作;禁止删文件、禁止读取密钥文件、禁止直接写 migration 脚本。
这样配置完之后,大部分正常开发操作 Claude 能直接执行,不会反复问你,但真正危险的操作被拦住了。权限配置的目标不是让你省掉所有确认,而是把需要确认的操作缩减到真正值得你看一眼的那些。
常见问题
Q: Claude Code 的上下文满了之后,用 /compact 好还是 /clear 好?
A: 取决于当前任务的状态。如果还在同一个任务里,正在进行中的修改有价值保留,用 /compact------它会总结关键信息,保留重要的上下文。如果你已经完成了这个任务,准备开始下一个无关的任务,直接 /clear------彻底清理比有损压缩好。一个判断标准:如果你能用一段话清楚地描述当前任务的状态,那就 /clear 重开,把那段描述作为新 Session 的开场白效果更好。
Q: CLAUDE.md 里的规则 Claude 不遵守怎么办?
A: 先检查文件是否太长(/memory 可以查看当前 Session 加载了哪些文件)。CLAUDE.md 超过 200 行的话,精简是第一步。其次,确认规则表达是否够具体------"写好的代码"不如"使用 2 空格缩进,类名用 PascalCase"。如果某条规则是"必须执行"的(比如每次提交前要跑测试),换成 Hook 来保证,不要靠 Claude 自觉。
Q: 在大型代码库里,怎么让 Claude 快速找到相关代码?
A: 两个方法:一是用 @ 直接引用你知道相关的文件,省去 Claude 搜索的过程;二是让 Claude 用 git log --all -S "关键词" 这种 git 命令搜索,比 grep 全文要精准,而且能看到变更历史。如果你的代码库有特殊的模块划分或目录结构,在 CLAUDE.md 里说明,"认证相关代码在 auth-service/src/main",这样 Claude 搜索时有范围。
Q: 多个 Worktree 并行工作时,怎么合并结果?
A: 每个 Worktree 是独立的 git 分支。并行工作完成后,正常走 git merge 或 git rebase 流程。区别是可以在合并前用另一个 Session(新的上下文)来 Review 所有变更,Review 质量会更好,因为 Reviewer 没有参与编写过程。
Q: Auto Memory 记录的内容会影响哪些 Session?
A: Auto Memory 是 per-repository 的,所有该仓库的 Worktrees 共享同一份 memory。也就是说,在 main 分支上让 Claude 学到的东西,在 feature 分支的 Session 里也会生效。这通常是好事,但偶尔会出现"在一个场景下学到的临时习惯影响到另一个场景"的问题------定期用 /memory 检查和清理是好习惯。
参考资料
说实话,Claude Code 在大型代码库里真正发挥出来需要一段适应期。不是工具本身难,而是思维方式要转变------你不再是在"写代码",而是在"指挥一个有能力但需要明确边界的工程师"。
上下文管理、权限配置、CLAUDE.md 设计,这些看起来像是繁琐的前置工作,但它们决定了你是把 Claude Code 当成一个省心的协作者还是一个每次都要从头解释的新手。我现在在同一个 8 万行代码库里,效率比半年前高了不止 3 倍,差距完全在这些配置和使用习惯上。
下一篇打算写 Claude Code Subagent 和 Agent Teams 的组合玩法------多个 AI 并行工作、自动协调任务、合并结果,这个玩起来更有意思。感兴趣的关注一下,不然算法不一定推得到你。如果你身边有人也在用 Claude Code 做大型项目,这篇可以直接转给他,省他自己踩一遍坑。