Skip to content

第六章:教会你的 AI

一个聪明但对你一无所知的助手

Claude Code 开箱即用的能力非常强。它能写 Python、调试报错、执行 shell 命令、读文件、推理复杂问题。但当你让它做一些和你的环境相关的事 —— 比如「在服务器上启动训练」 —— 它就卡住了。哪台服务器?SSH 别名是什么?conda 在哪?哪块 GPU 空闲?它完全不知道。

这就是「强大的工具」和「好用的助手」之间的差距。一个新来的博后很聪明,但入组第一天,他不知道数据放在哪、该用哪台机器、你们组怎么命名实验。你会给他一份入组文档,带他过一遍环境。一周后,他就能独立干活了。

Claude Code 需要同样的入组培训。区别在于:它只需要读一次文档,就能完美遵守,永远不忘,永远不偏。如果你更新了文档,它立刻适应。

这份文档叫做 CLAUDE.md

CLAUDE.md:你的 AI 使用手册

CLAUDE.md 是一个 Markdown 文件,Claude Code 在每次对话开始时都会读取它。你可以把它理解为一个 system prompt,但由你编写和控制。它就在你的代码旁边,纯文本,可以用 git 管理版本。

你在 CLAUDE.md 里写什么,CC 就把什么当作事实。如果你写了「长任务一律用 tmux」,CC 就会用 tmux。如果你写了「训练数据在 lab-a 的 /data/imagenet/」,CC 就会去那里找。如果你写了「不要碰 /experiments/archived/ 下的文件」,CC 就不会碰。

没有什么魔法。就是指令 —— 被逐字读取,被精确执行。

CLAUDE.md 放在哪

有两个层级,CC 会同时读取。

全局:~/.claude/CLAUDE.md

这个文件对你机器上的每个项目、每次对话都生效。把通用的事实放在这里:你的服务器、你的偏好、你的工具、你的惯例。任何不随项目变化的信息都属于这里。

项目级:your-project/CLAUDE.md

这个文件只在 CC 运行在该目录时生效。把项目专属的上下文放在这里:数据集位置、当前实验状态、训练配置、约束条件。当你切换到另一个项目时,CC 会读取那个项目的 CLAUDE.md

加载顺序:CC 先读全局 CLAUDE.md,再读项目级的。如果有冲突,项目文件优先。这意味着你可以在全局层设置通用规则,在项目层按需覆盖。

全局 CLAUDE.md 写什么

全局文件是你的通用上下文。从「新组员入组第一天你会告诉他什么」开始写。

你的服务器

这是最重要的部分。CC 必须知道你的机器才能做任何有用的事。

markdown
# 服务器

| 服务器 | SSH | GPU | 显存 |
|--------|-----|-----|------|
| lab-a  | `ssh lab-a` | 4x A100 | 80GB |
| lab-b  | `ssh lab-b` | 8x 4090 | 24GB |
| lab-c  | `ssh lab-c` | 2x H100 | 80GB |

- SSH 别名已在 ~/.ssh/config 中配置
- 所有服务器共享 /data/ 目录存放数据集
- 工作目录:/home/your-username/research/

有了这些,CC 就能通过名称 SSH 到任何服务器,知道 GPU 拓扑,知道文件放在哪里。当你说「查一下哪台服务器有空闲 GPU」,它知道分别执行 ssh lab-a nvidia-smissh lab-b nvidia-smissh lab-c nvidia-smi,然后比较结果。

你的偏好

markdown
# 偏好

- 用中文交流
- 所有训练在远程服务器执行,不在本地跑
- 长任务一律用 tmux
- 启动训练前用 nvidia-smi 检查 GPU 可用性
- commit message 用 conventional 格式(feat:, fix: 等)

这些听起来理所当然,但如果不写,CC 可能会在你笔记本上跑 python train.py,可能不检查 GPU 就直接启动训练,可能用你不喜欢的 commit message 风格。显式优于隐式。

你的工具

markdown
# 工具

- Conda 管理环境
- WandB 跟踪实验(始终在线模式,不用 offline)
- Git 做版本控制
- rsync 同步代码到服务器

你的惯例

markdown
# 惯例

- 跑实验前必须先同步代码:
  rsync -avz --delete ~/research/project/ lab-a:/home/your-username/research/project/
- 执行任何 Python 命令前先激活 conda 环境
- 不在服务器上全局安装包

一个完整的全局示例

一个最小但可用的全局 CLAUDE.md 长这样:

markdown
# 服务器

| 服务器 | SSH | GPU | 显存 |
|--------|-----|-----|------|
| lab-a  | `ssh lab-a` | 4x A100 | 80GB |
| lab-b  | `ssh lab-b` | 8x 4090 | 24GB |

- 工作目录:/home/your-username/research/
- 数据集:/data/(各服务器共享)

# 规则

- 所有训练在远程服务器,不在本地跑
- 长任务一律用 tmux
- 启动训练前检查 GPU 可用性
- 所有实验用 WandB 跟踪(始终在线模式)
- 跑之前先用 rsync 同步代码
- 执行 Python 命令前先激活 conda 环境

# 偏好

- 用中文交流
- commit message 用 conventional 格式

就 20 行,写起来五分钟。但它能让 CC 从「一个不了解你环境的聪明工具」变成「一个能自主 SSH 到你的服务器、检查 GPU、激活正确环境、启动训练的助手」。

项目级 CLAUDE.md 写什么

项目文件是具体信息的归属地。这些内容随实验而变化。

数据集位置

markdown
## 数据集

- 训练集:lab-a 上的 /data/imagenet/train/
- 验证集:lab-a 上的 /data/imagenet/val/
- 测试集(OOD):lab-a 上的 /data/imagenet-r/

CC 现在知道数据加载器该指向哪里。不用猜,不用问。

环境信息

markdown
## 环境

- Conda 环境:lab-a 上的 `pytorch21`
- 激活命令:`conda activate pytorch21`
- 关键包:torch 2.1, transformers 4.36, wandb

当前状态

这是最有威力的部分之一。它告诉 CC —— 以及未来的你 —— 现在正在做什么。

markdown
## 当前状态

- Baseline ResNet50 已训练完成,验证集 acc = 76.2%(论文报告 76.5%)
- 当前工作:LoRA 微调实验
- 下一步:在 lab-b 上用 learning rate [1e-4, 5e-4, 1e-3] 跑 LoRA

当你明天早上开始新对话时,CC 读到这里就立刻知道上次做到哪了。不需要「我们之前在做什么来着?」不需要翻聊天记录。它会从你停下的地方精确继续。

约束条件

markdown
## 规则

- 所有实验必须记录到 WandB,项目名:「image-cls」
- A100 用 batch size 64,4090 用 32(显存限制)
- 不要修改 experiments/archived/ 下的文件
- 超参数:lr=1e-4, weight_decay=0.01, warmup_steps=500

约束条件防止出错。没有 batch size 规则,CC 可能在 4090 上用 64 然后 OOM。没有归档规则,CC 可能「清理」你写论文还需要的旧实验文件。

一个完整的项目示例

markdown
# 项目:域泛化

## 数据集
- 源域:lab-a 上的 /data/domainbed/PACS/{art,cartoon,sketch}/
- 目标域:lab-a 上的 /data/domainbed/PACS/photo/

## 环境
- Conda:lab-a 上的 `dgenv`
- 关键依赖:torch 2.1, timm 0.9, wilds

## 当前状态
stage: training
baseline: ERM on PACS, acc=85.3%(论文 85.5%)
running: lab-a GPU 0-3, tmux=pacs-swad
next: 训练完成后在剩余数据集上评估(VLCS, OfficeHome)

## 规则
- WandB 项目名:「domain-gen」
- 所有训练用 3 个 seed:[0, 1, 2]
- 使用 DomainBed 默认超参数,除非明确要求覆盖
- 不要改数据划分 —— 只用 DomainBed 官方 split

好指令的威力

模糊指令和精确指令之间的差距,就是「一个不停问问题的助手」和「一个直接行动的助手」之间的差距。

模糊:

markdown
我有几台 GPU 服务器。用它们来训练。

CC 读完几乎什么都不知道。哪几台?怎么连?多少张卡?文件在哪?它每次都得问你。你会把一半对话时间花在回答那些只需要回答一次的问题上。

精确:

markdown
| 服务器 | SSH | GPU | 显存 |
|--------|-----|-----|------|
| lab-a  | `ssh lab-a` | 4x A100 | 80GB |

工作目录:/home/your-username/research/
Conda 环境:pytorch21
数据集:/data/imagenet/

CC 读完就能独立完成:SSH 到 lab-a、检查 GPU 可用性、激活 pytorch21、找到数据、启动训练。不需要问任何问题。你说「训练模型」,CC 搞定其余所有事。

来看一个真实对话场景。没有好指令时:

你: 在 ImageNet 上训练 ResNet。

CC: 好的,请问用哪台服务器?SSH 命令是什么?ImageNet 数据集存在哪里?哪个 conda 环境有需要的依赖?

什么都没做就问了四个问题。有好指令时:

你: 在 ImageNet 上训练 ResNet。

CC: 让我检查一下 lab-a 的 GPU 可用性…… GPU 0 和 1 空闲。我会 SSH 进去,激活 pytorch21,用 /data/imagenet/ 的数据启动训练。使用 tmux 会话 "resnet-train",日志记录到 WandB。

同样的请求,零个问题。唯一的区别是二十行 Markdown。

经验法则:如果 CC 不得不问你一个问题,那个答案就应该写进 CLAUDE.md。 CC 问的每一个问题都是你的指令缺了一块的信号。把问题当作文档的 bug 来对待。

迭代你的 CLAUDE.md

你不会在第一天就写出完美的 CLAUDE.md。你需要迭代。

从简单开始。 第一版可能就是服务器表格加三条规则。没问题。用 CC 干一天活。

留意重复的问题。 每次 CC 问「用哪个 conda 环境?」或者「训练数据在哪?」—— 这就是缺少的指令。把它加进去。

留意重复的错误。 如果 CC 老是想在本地跑训练,加一条规则:「所有训练在远程服务器。」如果它总是用错 batch size,把显存约束写清楚。

留意隐性知识。 你觉得理所当然的事 ——「我们当然用 WandB」「跑之前当然要同步代码」—— 对 CC 来说并不当然。把隐性的变成显性的。

用一周之后,你的 CLAUDE.md 会比最初丰富很多。用一个月之后,它就是一份全面的入组文档,捕获了你实际的工作方式。这甚至超越了 CC 本身的价值 —— 它是对你科研工作流的文档化,新来的组员也能直接读。

用 git 管理。 全局 CLAUDE.md 随基础设施演化。项目级 CLAUDE.md 随项目演化。都提交到 git。回顾项目历史时,CLAUDE.md 的变更记录了发生过什么、为什么。

当 CLAUDE.md 不起作用时

有时你写了指令,CC 还是做错。常见原因:

歧义。 你写了「用大服务器」,但你有两台都算「大」的服务器。要具体:用名称、路径、数字。

矛盾。 全局文件说「一律用 tmux」,但项目文件说「前台跑训练方便调试」。CC 看到两条,只能猜该听哪个。如果需要项目级例外,显式声明:「本项目中,首次训练在前台跑(覆盖全局 tmux 规则),确认稳定后切 tmux。」

信息过时。 CLAUDE.md 说 baseline 是 76.2%,但你后来训出了 78.1% 的更好模型。CC 会引用旧数字。状态区段要及时更新 —— 事情变了就改,不要「过会儿再说」。

信息过多。 一个 500 行的 CLAUDE.md 适得其反。CC 会全部读完,但信号被噪声淹没了。保持聚焦。如果一条信息只用一次,放到对话里,不要放到文件里。CLAUDE.md 是给反复出现的上下文用的。

常用模式

以下是研究者们觉得好用的模式:

「禁止」清单。 CC 在任何情况下都不该做的事。

markdown
## 禁止

- 不在本地机器跑训练
- 不删除 checkpoint 文件(除非明确要求)
- 不直接 push 到 main 分支
- 不在 conda 外用 pip 全局安装包

状态仪表盘。 每次工作结束时更新的一个区段。

markdown
## Pipeline Status
stage: training
idea: "对比式域对齐 + 自适应混合"
running: lab-a GPU 0-3, tmux=train01
next: 训练完成后在 OfficeHome 上评估

检查清单。 CC 在启动任何实验前必须遵循的步骤。

markdown
## 训练前检查清单
1. 在目标服务器上检查 GPU 可用性
2. 用 rsync 同步最新代码
3. 激活正确的 conda 环境
4. 确认数据集路径存在
5. 确认 WandB 为在线模式
6. 先跑 smoke test(1 个 batch)再正式训练

恢复上下文。 CC 在从上一次会话继续时需要的信息。

markdown
## 如果是接续上次

- 上次会话在超参搜索过程中结束
- 已有结果:lr=1e-4 acc=82.1%, lr=5e-4 acc=83.7%
- 还需要跑:lr=1e-3, lr=5e-3
- 所有实验在 lab-a,tmux 会话名:sweep-01 到 sweep-04

一个文件,复利式回报

随着时间推移会发生什么。

第一周: 你的 CLAUDE.md 有服务器信息、conda 环境和基本规则。CC 可以 SSH 进去执行命令,不用问东问西。

第二周: 你加上了数据集路径、WandB 惯例和代码同步命令。CC 可以用一条指令完成端到端的训练启动。

第四周: 你加上了项目状态、预检清单和恢复上下文。CC 能跨会话接续工作,遵循你的惯例,在犯错之前自我检查。

第二个月: 你的 CLAUDE.md 是一份活文档,捕获了你整个科研工作流。CC 自主运作 —— 启动实验、监控训练、修复崩溃 —— 因为它对你的基础设施了如指掌。某种意义上比你自己还清楚,因为它永远不会忘记一条规则。

复利效应是真实的。你往 CLAUDE.md 里加的每一行,都让你在未来的每次对话中省下重复说明的时间。经过几百次对话,省下的这些分钟加起来就是几天。


检查点

写一个描述你的服务器的 CLAUDE.md,包括 SSH 别名、GPU 数量和显存。放到 ~/.claude/CLAUDE.md。开一个新的 Claude Code 对话,问它:「现在哪台服务器适合跑训练?」

如果 CC 能 SSH 到你的每台服务器、执行 nvidia-smi、然后基于可用 GPU 给你推荐 —— 你就成功地教会了你的 AI 认识你的基础设施。只用了二十行 Markdown。

Released under the MIT License.