🐎 第2章 温故知新:记忆系统工程实践
📄 一句话概括

同一个项目写两份 CLAUDE.md:一份像项目简介,一份像操作手册。 行数差一行,token 却差 141——中文长句很吃 token,短命令几乎不吃。 这一节给一条可操作的判据:这条如果被违反了,我能当场指出来吗?指不出来的,删掉或者改写。

📝 本章和前面几章的关系

上一节讲层级,这一节讲项目记忆那一层里到底写什么。 这一层是最常被写坏的:它离开发者最近,很容易被写成一份 README。 但 README 是给人看的,CLAUDE.md 是给模型看并且要它照做的。

一、两种写法的差别不在文笔

演示里两份文件都是给同一个亮化工程管理平台写的,一份十二行,一份十三行。 简介式那份讲项目背景、为什么自研、架构大致什么样,语句通顺,人读着舒服。 手册式那份只有命令、约定、禁区,一句废话没有,人读着像说明书。

指标摆出来差得很明显:简介式模糊词 3 行、可执行行 4 行;手册式模糊词 0 行、可执行行 7 行。 关键不在谁写得好,在于两类句子在模型那儿的待遇完全不同。

二、模糊指令为什么等于没写

「代码结构参考了若干开源项目,尽量保持清晰」——这句话对人不算坏话,写文档时到处都是。 但模型读完不知道该干什么。「尽量保持清晰」到底允不允许一个文件八百行? 「命名上尽量使用英文」能不能用拼音? 每一条模糊指令都会变成一个自由裁量点。 而模型每次裁量的结果可能不一样——同一个任务跑两遍,出来的目录结构可能不同。

不是它不稳定,是这句话本来就允许两种做法。你把判断权交给了它,然后又抱怨它判断得不一样。 还有一个更隐蔽的坏处:模糊句子会占掉注意力。十三条里有两句云里雾里,剩下的十一条也会被稀释。

三、可判定原则

判据只有一条:这条规矩如果被违反了,我能不能当场指出来? 「金额一律用 Decimal,禁止用 float」——能。看一眼类型就知道了。 「新增接口必须同步写 tests 下对应用例」——能。看 tests 目录里有没有对应文件。

「保持适当的耦合度」——不能。什么叫适当?谁来判? 按这条筛一遍,通常会删掉三到四成。删完再读一遍,会发现剩下的每一条都在干活。 删掉的那些不是没用,它们属于 README、属于设计文档、属于新人培训材料。 只是不该占模型的常驻预算。

四、一份能照着写的骨架

第一段放命令。起服务、跑测试、跑迁移、跑 lint,一条一行,照抄能跑。 这段最值钱,因为它是模型最常需要的、也最容易猜错的东西。 第二段放约定。技术栈、命名、目录结构、错误处理方式。写「是什么」不写「为什么」。 第三段放禁区。不要改什么、不要用什么、哪些目录只读。禁区比约定更值钱,因为违反代价高。

第四段可以放验收方式。改完怎么自检,跑哪条命令算过。这一段直接决定它什么时候停。 不要再加第五段。背景、历史、架构图,都放别处。 长度上,一份能用的 CLAUDE.md 通常在一百行以内。 超过两百行,基本可以断定里面混进了本该放技能或者文档的东西。

五、一份能直接抄的骨架

下面这份是按四段结构写的,内容换成你自己的就行。 它不到三十行,覆盖了模型最常需要、也最容易猜错的东西。

# 项目名

## 命令
- 装依赖:uv sync
- 起服务:uv run uvicorn app.main:app --reload
- 跑测试:uv run pytest -q
- 迁移:uv run alembic upgrade head
- 格式化:uv run ruff format .

## 约定
- 金额一律用 Decimal,禁止用 float。
- 新增接口必须同步写 tests/ 下对应用例。
- 组件按业务域分目录,不要建 components/common。
- 提交信息一行写完,不超过五十字。

## 禁区
- 不要直接 pip install,一律走 uv add。
- 不要改 migrations/ 下已提交的脚本,要改就新加一条。
- 不要动 data/raw 下的原始数据,只读。

## 验收
- 改完跑 uv run pytest -q,全绿才算完成。
- 涉及接口的改动,同时贴出 curl 示例。

四段各管一件事:命令让它别猜、约定让它别问、禁区让它别撞、验收让它知道什么时候停。 最后一段最容易被漏掉。没有验收标准,它只能靠自己判断「做完了没有」,而这个判断经常偏乐观。 骨架只是骨架。往里填的每一条都要能过可判定那一关,否则填了也是白填。

六、写完怎么验

第一遍自己读:每一行能不能用「是/否」回答。不能的改写或者删。 第二遍数冲突:同一个主题是不是出现了两次(这跟上一节的叠加有关)。 第三遍实跑:让它按这份文件干一件小事,看它有没有照做。 没照做的那几条,要么写得不够硬,要么本来就不该放在这里。

第三遍最有用,也最少人做。写完不验,等于没写。

七、动手 Demo:两份 CLAUDE.md:一份像简介,一份像操作手册

同一项目、两份文件,行数差不多。 用四个指标量一遍:总行、正文行、模糊词行、可执行行、带路径或命令的行。 然后逐行看那几个模糊词长什么样,再算一遍 token——这里会出现一个反直觉的结果。

VAGUE = [u"尽量", u"适当", u"合理", u"根据需要", u"参考", u"保持", u"逐步"]
ACT = [u"用", u"跑", u"禁止", u"必须", u"不要", u"一律", u"同步"]

def stat(text, name):
    body = [x for x in text.split(u"\n") if x.strip() and not x.startswith(u"#")]
    vague = [x for x in body if any(v in x for v in VAGUE)]
    act = [x for x in body if any(a in x for a in ACT)]
    return name, len(body), len(vague), len(act)

实跑输出:

--------------------------------------------------------------------
两份 CLAUDE.md:一份像简介,一份像操作手册
--------------------------------------------------------------------

  两份都是给同一个项目写的,行数差不多。差别在哪,先把指标摆出来。
| 写法 | 总行 | 正文行 | 模糊词行 | 可执行行 | 带路径或命令 |
|---|---:|---:|---:|---:|---:|
| 简介式 | 12 | 8 | 3 | 4 | 0 |
| 手册式 | 13 | 9 | 0 | 7 | 3 |


  ① 差在哪一行
  --------------------------------------------------------------------
  简介式那份,模糊词命中 3 行,可执行行只有 4 行。
  手册式那份,模糊词 0 行,可执行行 7 行。
  两组数字说的是同一件事:前者在描述这个项目是什么,后者在告诉模型怎么做。

  ② 逐行看那几个模糊词
  --------------------------------------------------------------------
  · 2024 年决定自研一套系统,逐步替代原有流程。
  · 代码结构参考了若干开源项目,尽量保持清晰。命名上尽量使用英文,避免拼音。
  · 如果需要新增模块,请根据需要合理规划目录结构,保持适当的耦合度。
  ! 这些句子对人不算坏话,写给人看的文档里到处都是。
  但模型读完不知道该干什么:「尽量使用英文」到底允不允许拼音?「合理规划」是按功能分还是按层分?
  每一条模糊指令都会变成一个自由裁量点,而模型每次裁量的结果可能不一样。
  同一个任务跑两遍,出来的目录结构可能不同——不是它不稳定,是这句话本来就允许两种做法。

  ③ 手册式怎么写的
  --------------------------------------------------------------------
  - 起服务:uv run uvicorn app.main:app --reload
  - 跑测试:uv run pytest -q
  - 迁移:uv run alembic upgrade head
  - 金额一律用 Decimal,禁止用 float。
  - 新增接口必须同步写 tests/ 下对应用例。
  - 组件按业务域分目录,不要建 components/common。
  - 提交信息用中文,一行写完,不超过五十字。
  - 不要直接 pip install,一律走 uv add。
  - 不要改 migrations/ 下已提交的脚本,要改就新加一条。
  ! 每一条都能当场判定做没做到:用了 uv 没有、测试写了没有、提交信息是不是中文。
  能判定,才谈得上遵守。

  ④ 长度也是指标,但行数不等于 token
  --------------------------------------------------------------------
  简介式 12 行,手册式 13 行——手册式还多一行。
  可 token 是 349 对 208,手册式反而少了 141。
  ! 中文长句很吃 token,短命令和路径几乎不吃。
  简介式那几段漂亮的长句,换算过来比九条命令还贵——而它们对「该怎么做」一点帮助都没有。
  所以判断一条该不该留,不看长短看用处。
  写给人看的背景说明放 README,给模型的常驻预算只留能判定的句子。
  ! 判断标准一句话:这条如果被违反了,我能当场指出来吗?指不出来的,删掉或改写。

①第一张表五行数字。简介式模糊词 3 行、可执行 4 行;手册式模糊词 0、可执行 7。 这两组数不是文风差异,是「这段文字能不能被判定」的差异。 ②把模糊词那三行原样打出来。 读一遍就明白问题在哪:每一句都留着裁量空间,而裁量空间就是不一致的来源。 「尽量使用英文,避免拼音」——那变量名叫 user_id 还是 yonghu_id?「避免」到什么程度算避免? 这两句话放在一起,能解释出三种做法。 ③手册式那九条,每一条都能当场判定。这就是可判定原则落地之后的样子。 ④最反直觉的一格在这里:手册式多一行,token 反而少 141。 原因是中文长句吃 token,短命令和路径几乎不吃。简介式那几段漂亮的长句,换算过来比九条命令还贵。 所以「删短一点」这个直觉有时会失效——真正该做的是把长句换成短句,不是把内容砍掉。

30 秒实验

  1. 把手册式里那条「金额一律用 Decimal,禁止用 float」改写成「金额处理要严谨」,重跑第 ① 步。 哪几个指标会变?
  2. 给简介式加一段「验收方式」:改完跑 uv run pytest -q 全绿才算完成。可执行行变成几行?
  3. 找一份你自己项目的 README,按可判定原则过一遍,数一数有几行能留下。

常见误区

  1. 把 README 改名成 CLAUDE.md。前者讲这个项目是什么,后者讲该怎么动手,两者的读者和用途都不同。
  2. 以为写得越多越好。常驻内容是每轮都要付的,多一句无关的话就多挤掉一分注意力。
  3. 用「尽量」「适当」「合理」。这类词在给模型看的文件里等于没写,因为它不知道边界在哪。
  4. 只写「要做什么」不写「不许做什么」。禁区往往比约定更值钱,因为违反代价高。
  5. 写完不验。让它按文件干一件小事,是最快发现「这条写得不够硬」的办法。
自测三问(点开对答案) 1. 判断一条规矩该不该留在 CLAUDE.md 里,最快的问法是什么? —— 问「这条如果被违反了,我能不能当场指出来」。 指不出来的说明它是模糊指令,要么改写得更具体,要么挪去 README。 2. 为什么行数多一行、token 反而更少是可能的? —— 因为 token 由字符与词决定,不由行数决定。 中文长句每字几乎都算一个 token,而短命令、路径、参数里有很多可以合并的片段。 3. 一份 CLAUDE.md 通常该写多长?超过多少说明写歪了? —— 能用的一般在一百行以内。 超过两百行,基本可以断定里面混进了本该放技能或文档的内容——那些不需要每轮都在。

根目录的写完了,下一节讲怎么让一部分规矩只在碰到某些文件时才生效。

相关笔记