深度体验 Claude Code 半年:架构剖析与工程实践避坑指南

1. 它的底层到底是怎么跑的?
很多人误解了,Claude Code 的核心根本不是"回答问题",而是一个死循环的代理控制过程:
收集上下文 → 采取行动 → 验证结果 → [完成 或 重新收集]
用了这么久我才意识到,卡住进度的时候,往往不是模型怎么变笨了,多数情况下是我们塞了错误的上下文,或者是它虽然写出了代码,但根本没办法判断改对没改对,也没法自己撤回刚才的操作。
对这套系统,盯紧这五个核心就行:结果忽好忽坏?去查上下文的加载顺序。自动化失控了?赶紧去看看约束层有没有防线,别瞎抱怨 AI 太飘。长会话质量狂掉?那就是中间产物把上下文给污染了,直接换个新会话,比你按着头反复调 Prompt 有用得多。
2. 概念边界:MCP、Plugin、Tools、Skills、Hooks 都是干嘛的?
简单记:
- 给 Claude 新动作能力,用 Tool / MCP。
- 给它一套固定的工作方法,用 Skill。
- 需要隔离危险测试环境,用 Subagent。
- 要强制设槛查账卡脖子,用 Hook。
- 跨项目到处乱发,用 Plugin。
3. 上下文工程:最重要的系统约束
很多人把上下文当成"容量问题",但卡住的地方通常不是不够长,而是太吵了。有用的信息全被无关痛痒的东西淹了。
Claude Code 标榜的 200K 上下文绝对不是全部能用。其中光是固定开销(系统指令、Skill 描述、MCP Server 工具定义)往往就占了 15K 到 20K。那些最大隐形杀手就是 MCP 的工具定义。比如一个典型 MCP Server(如 GitHub)包含二三十个工具,光这部分固定开销就有好几千 tokens。如果你接了 5 个 Server,开销直接逼近 2.5W tokens(12.5%)。在那些需要读大量代码的场景里,这 12.5% 能要命。
推荐的上下文分层做法:
- 始终常驻 →
CLAUDE.md:项目契约、构建命令、绝对禁止的事项。 - 按路径加载 →
rules:特定语言、目录或文件类型的专属规则。 - 按需加载 →
Skills:特定工作流、领域知识。 - 隔离加载 →
Subagents:大量探索阶段、并行研究。 - 不进上下文 →
Hooks:确定性脚本、审计、强制阻断。
说白了,偶尔用的东西,平时千万别加载进来。
怎么处理 Tool Output 噪声?
除了 MCP 工具定义之外,动态输出的噪声也是隐藏大坑。你跑一次 cargo test 少说几千行,在稍微大点的仓库里跑这命令,满屏全是废话。机器不需要看全部日志,它只要知道"过了,还是挂了",但只要它出现在上下文里,就会实打实地吃掉你宝贵的对话历史和文件内容空间。
这个思路后来被做成了像 RTK(Rust Token Killer)这样的工具。简单说:它在命令输出给被 Claude 看到之前直接把它砍掉。你跑几千行的测试,它只会重写成 ✓ cargo test: 262 passed。机器真正需要知道的核心也就是这句。
压缩机制的陷阱
默认压缩算法是按"可重新读取"判断的,这意味着早期的 Tool Output 和文件内容会被优先删掉,悲剧的是,它很容易顺带把你定好的架构决策和约束理由也一起扔了。过了俩小时你再让它改代码,它可能根本忘了刚开始定的规矩,莫名其妙的 Bug 就是这么来的。
怎么解决?在 CLAUDE.md 里强行写明压缩优先级(Compact Instructions),规定好它在压缩时必须保留你的架构决策、修改过的核心文件和没完成的遗留 TODO。
还有一种更暴力的方案:开新会话前,逼它自己写一份 HANDOFF.md。把当前进度、试过的错、跑通的路写个明明白白,下个机器拿着新鲜上下文只看这一个文件就能接着干。不要把希望寄托在破算法的摘要质量上。
4. Skills 设计:用的时候才加载的工作流
关于 Skill,很多人把它当成了"保存的 Prompt",但差别挺大的。一个好队伍里的 Skill,描述里一定要明明白白告诉它"什么时候用我",而不是长篇大论"我是谁"。
几个避坑点:
- 别写有头没尾的流程。要有完整的步骤要求、输入和停止条件。
- 核心正文只放导航点和硬约束,长篇大论的资料赶紧拆到附带文件里去。
- 如果这技能会产生副作用,赶紧加上
disable-model-invocation: true。不然 Claude 会觉得自个儿是天选之子,随便乱跑。
Claude Code 团队在内部也特别强调“渐进式披露”。不要一次全甩给机器,先给大纲框架定范围,再按它执行进度去找细节资料,配合脚本收集本地确定性内容。
比如你搞个配置迁移(高风险动作),一定要在里头内置“cp 备份”、“干跑确认”和“出错回退”。不要瞎指望它凭直觉把每步兜底都做好。描述符尽可能的缩短,只要写明用途就行了,废话会耗尽你们的常驻上下文空间。
5. 工具设计:让 Claude 少选错
给人用的接口要功能齐全,但给 AI 用的工具,重点其实是容易用对。
工具设计要分清主次:
- 加上明确的前缀按系统归类资源。
- 当能合并成高层任务工具时,不要拆出一群烂基层碎片,避免让机器看着几百个命令抓瞎。
我看过 Claude Code 内部工具的演进。刚开始他们给已有工具加了个提问参数,指望 AI 碰到不能决定的事就问;AI 直接当没看见跳过去。后来强制它输出特定格式停下来;它经常忘了格式,这提问机制形同虚设。最后他们直接写了个名叫 AskUserQuestion 的死命令,机器想发话就必须显式调用这个。这一招,稳了。
你就是想它停下来问个事,直接砸一个带卡点的新工具下去,比用什么标记参数都痛快。还有搜索工具一开始用了 RAG 库,快是快但特别脆,机器也不爱用。后来索性改回最直接的 Grep 命令让它自己爬文字,马上顺从了许多。
6. Hooks:强制插入管理层逻辑
Hooks 经常被误解成"帮你全自动收尾的脚本"。但这东西其实本质是把不放心交给机器乱挥霍的事,收拢回绝对死板的确切流程。
像改了敏感防护文件要不要拦截,做完任务后给不给你推送。这些小事,你甭指望机器次次都能记清楚位置并执行。
写上一个在它刚改完特定扩展名文件时就强制验证或打 Log 的 Hook,能在你 100 次的连续操作中省去几十个检查来回,省下的几十分钟都够喝个下午茶了。最好配上直接截断输出 head -30,别把输出又反向污染给上下文。
我现在的感受是,只写 CLAUDE.md,Claude 经常装瞎;只配 Hooks,细节判断又很受限。三个连起来:CLAUDE.md 发命令定死标准,Skill 教它遇到失败怎么捞,Hook 最后直接在底层放冷枪拦截,这样才能彻底锁死你的安全范围。
7. Subagents:找个专人来背锅
Subagent 实质就是从主对话派出去的独立大活人,上下文单独挂账,权限也收紧卡死了。我用下来的感觉是,这哥们的最大价值不在"并行",而在隔离。
你让主进程去扒拉巨大的代码库跑测试,立马就吃绝户了,以前聊啥统统被冲洗掉。直接塞个 Subagent 专门跑外卖腿脚的工作,主进程就只在最终节点拿个摘要数据,干净多了。最关键的是把子代理的访问权限控制得小点,该跑后台的赶紧锁在死环境里。
8. 怎么才算个真正有用的 CLAUDE.md?
这东西实际上是你和机器间的私下契约,不是团队知识库,也不是百科全书。它只用来放"以后无论老死不相往来也绝对不能违反"的事情。
应该放什么:
- 编译、跑图、跑测试这些死命令。
- 架构死穴、不能越界的模块分布。
- 只有你们能踩到的诡异环境暗坑。
- 绝对禁止的操作(直接罗列在
NEVER标签下)。 - 压缩截断时必须保命的护城河指引。
千万不要放:
- 大段虚假的背景说明、API 参考。
- 写诸如"请写出牛逼高效的高质量代码"这种虚得没边的口号。
- 那些它本身看仓库结构立马明白的东西。
实战终极绝招:如果它今天又犯了相同的傻事,直接吼一句:“Update your CLAUDE.md so you don’t make that mistake again。"(去更新你的 CLAUDE.md 免得这事再出岔子。)
你让它自己把补丁规则写进去,它基本不会再忘。久而久之你甚至会发现,它已经替你维护出了一套完整的团队死线,这可比反复对它絮絮叨叨强得多。
WenHaoFree