原文:Claude 官方博客 How Claude Code Works in Large Codebases: Best Practices and Where to Start 本文是阅读原文后的笔记 + 我自己在几个项目里的实践经验。反馈欢迎评论区拍砖。


TL;DR

一句话:决定 AI 编程表现的,模型只占一半,另一半是你围绕它搭的「马具(harness)」。

这句话是原文的核心。以前我们干「提示词工程」,现在要干「上下文工程」和「工具链工程」。本文会展开这个马具体系:

  • Claude Code 怎么「看」代码(什么不一样)

  • 五大扩展点、两大能力点

  • 常见错误对照表

  • 我自己踩过的几个坑

如果你在使用 Claude Code 或者有计划使用,这篇文章加上原文一起看,能省下你三个月踩坑的时间。


一、Claude Code 不一样的地方:它不做 RAG

现在大部分代码助手都走「全量向量化 + RAG 检索」路线:把代码库全部 embedding 存起来,查询时检索相似片段。Cursor、Cody 都是这个方向。

Claude Code 不是。它像人类工程师一样干活

  1. 遍历文件系统

  2. 读取文件

  3. 用 grep 精准搜索

  4. 跨文件追踪引用

你在终端里怎么看代码,它就怎么看代码。

为什么不做 RAG

原文里的句子我反复品了几遍:

embedding pipeline 跟不上活跃开发团队的速度。等你查询时,索引反映的可能是几天甚至几周前的代码。

这个问题任何用过全仓检索工具的人都掏过:查出来一个函数,点进去发现已经被删了。实时检索 + grep 永远反映的是现场代码状态,不会出现这种问题。

代价是:你得给它一份「初始上下文」。在亿行代码里 grep 是大海捞针 —— 你得告诉它 「该去哪个目录」「该用什么关键词」。这个「初始上下文」就是 CLAUDE.md 和 skills 干的事。

我自己的验证

我在一个 200k+ 行的 Go 项目里同时用了两个工具。Cursor 的 codebase index 经常跟不上我刚被重构过的文件,问「某个函数什么时候被调用」,给出的引用点一半以上已经不存在。Claude Code grep + ast-grep 走一遍,资料准到可以直接拿去改。

结论:如果你的代码库是「静态的」(开源项目、一次性研究、SDK 文档),RAG 路线够用;如果你的代码库是「活的」(多人开发、频繁重构、每天上百 PR),Claude Code 的实时检索路线在加上好的上下文以后实际能用得更顺。


二、五大扩展点(The Harness)

这是原文最有价值的部分。Claude Code 本质上只是个「听话干活的执行体」,真正让它能用于严肃项目的是这五个扩展点。

1️⃣ CLAUDE.md —— 项目通用上下文

你可以把它理解为「项目的 README + .cursorrules + onboarding 文档」的三合体。根目录一个全局的,子目录可以放局部的。每个会话自动加载,所以内容要足够「通用」。

什么叫足够通用?

✅ 该放:
  · 项目的业务背景 —— 这个服务是干什么的,上下游是谁
  · 技术栈 —— 语言、框架、部署方式
  · 代码规范 —— 命名、错误处理、日志格式
  · "什么是什么" —— 项目里的黑话、模块名字代表什么
​
❌ 不该放:
  · 「仅部分场景需要」的专业知识(安全、部署、财务)→ 这是 skill
  · 可重用的函数库说明 → 这是 docs/
  · 变动频繁的迭代信息 → 这是 changelog

最常见的错误:不加选择地把什么都填进 CLAUDE.md,结果每个会话都烧几千 token 去加载「今天用不到的知识」。Token 费才是老板的隐性成本。

2️⃣ Hooks —— 自动化与持续改进

Hooks 是 Claude Code 反复被低估的部分。三个最常用的:

Stop hook —— 会话结束后自动调用。你可以让 Claude 反思「本次学到了什么」,把结论写回 CLAUDE.md。实质上是让项目上下文「随使用进化」。

Start hook —— 会话开始时加载动态上下文。比如拉一下最近一周的 git log 重点、跨部门 announcements。静态的 CLAUDE.md 加动态的 Start hook → Claude 总是能获取最新状态。

lint/format hooks —— 这个是最重要的。以前我们让 AI 二次复述「记得运行 gofmt」「记得加错误处理」,问题是它记不住。现在:

# .claude/hooks/post-edit
#!/bin/sh
golangci-lint run --fix \"$CHANGED_FILES\"
goimports -w \"$CHANGED_FILES\"

Claude 改完代码会自动跑错误,不需要你提醒。能用脚本强制的东西不要用 prompt 去管。

3️⃣ Skills —— 按需加载的专业知识 ⭐

这是本文最重要的一节。Skill 本质是你给 Claude 准备的「小型外部说明书」,只在需要时加载。

举例:一个有五个服务的后端仓库可能的 skills:

skills/
├─ security-review/     — 代码安全审查 SOP
├─ db-migration/        — 数据库迁移规范与回滚步骤
├─ incident-response/   — 线上故障时的调查 checklist
├─ doc-update/          — 修改完代码后怎么补文档
└─ cross-team-review/   — 跨团队代码调取时的沟通范本

所有 skill 都是纯文本。谁加载、什么时候加载、加载多少 —— 都是 Claude 自己判断的。关键是 description 要写准,让 Claude 一看就知道「这个 skill 是干什么的」。

原文里提到的「路径绑定」是个狠招:支付团队的部署 skill 只在 /services/payment/** 下起作用,别的同事在别的目录下干活不会错误加载。这是准企业级的设计。

4️⃣ Plugins —— 打包分发

Plugins 把 skills + hooks + MCP 配置打成一个包。新同事一加入项目,安装一个 Plugin 就获得全部配置。

这东西似乎不起眼但实际企业环境里是刚需。我见过公司在「怎么让新同事一入职就能用上 Claude Code」这件事上牺牲三个月 —— 每个人得手工拷 .vscode、拷 .claude、拷并改 hooks,几乎没人能第一天就进状态。Plugin 这件事存在就是为了杀掉这个损耗。

5️⃣ MCP Servers —— 连接内部工具

MCP 是 Anthropic 推的协议,让 Claude 能访问外部服务。原文举的例子:

  • 内部文档系统 —— 让 Claude 能查公司 Wiki

  • 工单系统 —— 让 Claude 能看到 Jira/Linear 上的 issue

  • 分析平台 —— 让 Claude 能查询生产环境的指标

这些东西以前都是要人手动粘贴到聊天里的。MCP 之后,Claude 自己去取。对于成熟的团队这个收益巨大,比如 incident response 场景里,Claude 可以同时查日志、查工单、查 deploy 记录,快速拼出故障线。

估计未来 12 个月 MCP 会从「赋能 Agent」变成「必选项」。


三、两大额外能力

LSP 集成 —— 性价比最高的投资

这是原文里最被低估的一点。原文讲了一个例子:某企业软件公司在推广 Claude Code 之前,先全公司部署了 LSP 集成,专门解决 C/C++ 代码的导航准确性问题。

LSP 能干什么?

IDE 里你右键一个函数选「跳转到定义」「查找所有引用」这些能力,本质是 LSP 提供的。现在 LSP 能提供给 Claude,让它不靠 grep 的文本匹配,而是靠符号级别的导航

代码上的区别:

场景:查「getUserName」在哪些地方被调用
​
grep 方式:
  匹配到所有 \"getUserName\" 出现的地方
  包括:定义、调用、注释、字符串、类似名字的变量
  伍老全部出现
​
LSP 方式:
  返回 \"getUserName 这个函数」被调用的实际位置
  不包含同名但是另一个类里的同名函数
  也不包括注释/字符串
  准确、可靠

多语言项目里这个区别是决定性的。 Python 项目里同名函数不多,但 Java/C# 项目里「getById」能出现上百次,全返回给 LLM 只会刷屏。

怎么配置(原文没写,我补上):

Claude Code 本身不是 IDE,你需要一个第三方的 MCP 服务器来提供 LSP 能力。社区里有几个可用的:

  • lsp-mcp (TypeScript) —— 轻量、支持多语言

  • mcp-language-server (Go) —— 性能好

  • claude-lsp (Rust) —— 实验性

装好之后,在 .claude/mcp.json 里配置,Claude Code 启动时会自动拉起 LSP 服务器。第一次启动会有几十秒到几分钟的 indexing 时间,后续进出都很快。

我自己在一个 Go + TypeScript 的 mono-repo 里跑了这套配置,Claude 提供重构建议的准确率明显上升 —— 以前它会混淆同名不同义的函数,现在叠加了 LSP 之后几乎没出过错。

一点实战提示:跑 LSP-MCP 的时候 streaming 一定要稳,因为代码补全场景对延迟敏感,断流体验非常差。

Subagents —— 上下文的读写分离

Subagent = 隔离的 Claude 实例。有自己的上下文窗口,干完活只返回结果。原文举的例子:派一个只读子代理去「摸清某模块结构」,主代理拿完整信息去编辑。

抽象来看:Subagent 是 LLM 体系里的「读写分离」。

你不想主代理的上下文被「摸查过程中看到的一堆字面」填满,你只想它拿到「结论」。所以你派一个隔离的子代理去读、去总结,只报告结论。主代理拿这个结论去做决策。

什么时候用 subagent?三个场景最常见:

  1. 侦察:让子代理去查某个代码区域、复现某个 bug、总结某文件的职责

  2. 并行:三个独立的任务同时派三个子代理去干,赢时间

  3. 危险操作:让子代理去试一个可能犯错的重构,犯错了不会污染主代理

代价:多一倍的 token 消耗。所以别滥用 subagent。


四、常见错误对照表

这个表原文里写得很凄凉,我透过自己踩坑的经验重新表达一下:

组件 本意 被误用成 后果
CLAUDE.md 项目通用上下文 什么都填,包括 skill 该干的事 每个会话烧 token,付费高峰月能翻倍
Hooks 自动化让代码质量稳 只用在 logging 错过了 80% 的价值
Skills 按需加载的专业知识 填进 CLAUDE.md 里 全场并发加载一加载一辈子
MCP 连接外部工具 不加配,让 Claude 猜 Claude 猜错了甚至都不知道自己猜错了
LSP 符号级导航 多语言项目不用 Claude 调错函数,改了同名但不同的 callsite
Subagent 隔离上下文 什么都派 token 消耗翻倍

五、我自己的三个坑

原文谈的是「应该怎么做」,我补三个「不应该怎么做」:

坑 1:把 CLAUDE.md 写成了二次总结版 README

最初我以为 CLAUDE.md 是给 Claude 看的 README。结果写了 5000 字的架构说明、环境变量、深入原理…… 开发一天费用翻三倍。后来才明白:CLAUDE.md 不是 README,是「Claude 每次会话都需要知道的底型信息」。「架构说明」不是每次都要知道的——那应该是 docs/ 里的阅读材料。

修正后:CLAUDE.md 800 字以内,只写项目身份、技术栈、几个项目里独有的黑话。改完后 token 费降下 40%。

坑 2:不用 hooks,仅靠 prompt 去要求 Claude「记得开 lint」

这个踩坑三个月。我提醒 Claude「改完后记得跑 golangci-lint」「记得跑测试」,它间歇性地记得、间歇性地忘记。后来看了这篇原文才意识到 —— 能用 hook 强制的东西不要用 prompt。

# .claude/hooks/post-edit :代码被 Claude 修改后自动运行
#!/bin/sh
golangci-lint run --fix $CHANGED_FILES
go test ./... -run TestChanged

这 6 行代码换来了三个月的清净世界。

坑 3:让 Claude「一下子读完所有文件」

刚开始用 Claude Code 时,我难免:「先读下这五个文件」「再读下那三个」 —— 上下文窗口几万 token 一会儿就填满了,但真正需要的信息可能只是几百 token。

现在我的做法是:让 Claude 自己去用 grep 和 read,只告诉它任务是什么。它 grep 一环就能看出哪些文件才是重点。遇到复杂任务就派 subagent。

这是「从提示词工程」转变为「上下文工程」的本质 —— 不要告诉它「拿什么」,告诉它「产什么」


六、与其他 Agent 系统的对比

Claude 官方上述架构 与 Hermes Agent 的设计高度重合。可以这样对照看:

Hermes 里的实践 Claude 官方的实践
Hermes Skills Skills —— 按需加载,不浪费上下文
delegate_task Subagents —— 隔离子任务
native-mcp skill MCP —— 连接外部工具
会话结束写笔记 Stop hook —— 从 session 中学习并沉淀
curator(技能管理) Hooks —— 自动记录和改进
AGENTS.md / .cursorrules CLAUDE.md —— 项目上下文

这不是巧合。两边都走到这个架构,说明「上下文窗口有限 + 按需加载 + 调度子任务」是当前 LLM 能力下唯一可扩展的工程架构。未来一二年其他主流工具(Cursor、Cody)估计也会收敛到这里。


七、从哪里开始

如果你还没用 Claude Code,或者刚开始用,推荐这个优先级:

  1. 先写 CLAUDE.md,控制在 500-800 字。只记项目身份、技术栈、业务黑话

  2. 装上 lint/format hook。最快 10 分钟,收益最大

  3. 试三个 skill。选你今年重复调度 5 次以上的包(比如「怎么写一个新接口」「怎么准备上线」)开始写

  4. 多语言项目加 LSP。单一语言可以暂不加

  5. MCP 最后考虑。需要团队配合、设计服务调用、维护的成本不低

最差的开头是什么都不加,裸奔 Claude Code。那不是「使用 Claude Code」,那是「使用一个被障碍了的 Claude Code」。


参考资料

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐