第 30 章:第一次修改

个人公众号

源码验证日期:2026-05-15,基于 commit 0d81bb6

上一章你搭好了工坊,源码可以跑起来了。这一章,你要亲手改点什么——哪怕只是改一行文字。

别小看”改一行文字”。这意味着你理解了代码结构,找到了目标位置,做了修改,构建成功,并且看到了效果。这是 Contributor 的第一步。


路线图

1
2
3
4
5
6
7
graph LR
CH29["第 29 章<br/>搭建你的工坊"] --> CH30["✏️ 第 30 章<br/>第一次修改"]
CH30 --> CH31["第 31 章<br/>创建你的第一个工具"]

style CH30 fill:#4CAF50,color:#fff,stroke:#333
style CH29 fill:#e8f5e9,stroke:#333
style CH31 fill:#e1f5fe,stroke:#333

目标

修改 FileReadTool 的工具描述(description),重新构建 Claude Code,然后验证 AI 确实使用了你修改后的描述。

完成后你会获得三样东西:

  1. 知道工具的 prompt/description 在哪个文件定义
  2. 知道怎么构建和测试修改
  3. 拥有你的第一个 git commit

第一步:找到目标

Claude Code 有三十多个工具。每个工具是一个目录,放在 src/tools/ 下面。你可以浏览一下:

1
ls src/tools/

你会看到 FileReadTool/BashTool/FileEditTool/ 等等。每个目录里都有该工具的全部代码。

我们要改的是 FileReadTool——它负责读取文件,是 AI 最常用的工具之一。

打开 src/tools/FileReadTool/,看看里面有什么:

1
ls src/tools/FileReadTool/

你会看到四个文件:

  • FileReadTool.ts —— 主文件,定义工具的行为
  • prompt.ts —— prompt 模板,定义 AI 看到的工具说明
  • UI.tsx —— UI 渲染,定义用户看到的界面
  • imageProcessor.ts —— 图片处理辅助

我们要改的就是 prompt.ts


第二步:读懂结构

打开 src/tools/FileReadTool/prompt.ts。这个文件不长,但结构清晰。你会看到:

1
2
3
4
5
6
7
8
export const FILE_READ_TOOL_NAME = 'Read'

export const DESCRIPTION = 'Read a file from the local filesystem.'

export const MAX_LINES_TO_READ = 2000

export const LINE_FORMAT_INSTRUCTION =
'- Results are returned using cat -n format, with line numbers starting at 1'

这里有三个关键概念:

DESCRIPTION —— 工具的一句话描述。这个值会被送到 AI 那里,作为工具列表中每个工具的简介。当你输入一条消息后,AI 在决定使用哪个工具时,首先看到的就是这段文字。

renderPromptTemplate() —— 工具的详细说明模板。当 AI 决定使用 Read 工具时,这段文字会被完整注入到上下文中,告诉 AI 怎么正确使用这个工具。

常量指令片段 —— LINE_FORMAT_INSTRUCTIONOFFSET_INSTRUCTION_DEFAULT 等,是详细说明中的可配置段落,可以根据运行时条件组合出不同的 prompt。

这种”常量 + 函数模板”的模式在 Claude Code 的工具系统中很常见。它把 prompt 拆成小块,方便单独修改和测试。


第三步:做出修改

我们要改的是 DESCRIPTION 常量——那句话的简介。把它改成更有个性一点的文字。

找到这一行:

1
export const DESCRIPTION = 'Read a file from the local filesystem.'

把它改成:

1
export const DESCRIPTION = 'Read a file from the local filesystem. Your trusty companion for exploring code.'

就是加了一句俏皮话。这不会影响工具的功能,但能让你在验证时一眼确认修改生效了。

保存文件。


第四步:理解修改怎么生效

你改了一行字符串常量。那这行常量是怎么跑到 AI 那里的?

打开 src/tools/FileReadTool/FileReadTool.ts,找到工具注册的部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export const FileReadTool = buildTool({
name: FILE_READ_TOOL_NAME,
// ...
async description() {
return DESCRIPTION
},
async prompt() {
const limits = getDefaultFileReadingLimits()
// ...
return renderPromptTemplate(
pickLineFormatInstruction(),
maxSizeInstruction,
offsetInstruction,
)
},
// ...
})

看到了吗?description() 方法返回的就是你刚才改的 DESCRIPTION 常量。而 buildTool() 函数(定义在 src/Tool.ts 里)把这个方法注册到工具对象上。

数据流是这样的:

1
2
3
4
5
6
7
8
9
graph LR
A["DESCRIPTION 常量"] --> B["description() 方法"]
B --> C["buildTool() 注册"]
C --> D["启动时收集所有工具描述"]
D --> E["发送给 AI 的系统消息"]
E --> F["AI 读到你的修改"]

style A fill:#FFF9C4,stroke:#333
style F fill:#C8E6C9,stroke:#333

一行修改,经过了五六层传递,最终到达 AI 的”眼前”。这就是工具 prompt 的生命周期。


第五步:构建并测试

现在你需要让修改生效。由于这是从 npm 包提取的源码,你有两条路:

如果 bun install 成功了:

1
2
3
bun run build
# 或者
bun run dev

如果依赖装不上——直接改打包后的文件:

cli.js 中搜索 Read a file from the local filesystem.,把这段文字替换成你修改后的版本。注意只替换这一处,不要改动其他内容。

启动 Claude Code,随便找一个文件让 AI 去读。比如你可以说:

1
请帮我读一下 package.json 的前 10 行

AI 会使用 Read 工具。此时它内部看到的就是你修改后的描述。


第六步:验证修改生效

有几种方法可以验证:

方法一:看日志。 如果你开启了 debug 模式,系统消息会被打印出来,你可以在其中搜索 “Your trusty companion”。

方法二:加一行 console.log。FileReadTool.tsdescription() 方法里加一行(如果你能运行 TypeScript 源码):

1
2
3
4
async description() {
console.log('[MY_CHANGE] FileReadTool description:', DESCRIPTION)
return DESCRIPTION
},

当你让 AI 读文件时,如果这行日志出现在终端里,说明你的修改路径是通的。

方法三:让 AI “看到”自己的工具描述。 你可以对 AI 说:

1
请告诉我你有哪些工具可用,特别是 Read 工具的描述是什么?

AI 有时能回溯自己的系统提示并告诉你它看到的工具描述。不过这种方法不太可靠。

推荐使用方法二——加 console.log 最直接、最确定。


第七步:你的第一个 commit

验证成功了?现在把它提交到 git。这是你的第一个贡献。

先看看改了什么:

1
git diff

你应该看到类似这样的输出:

1
2
- export const DESCRIPTION = 'Read a file from the local filesystem.'
+ export const DESCRIPTION = 'Read a file from the local filesystem. Your trusty companion for exploring code.'

提交:

1
2
git add src/tools/FileReadTool/prompt.ts
git commit -m "chore: customize FileReadTool description for learning"

恭喜,这是你在 Claude Code 源码上的第一个 commit。


常见错误

常见错误检查方法
构建报 TypeScript 类型错误你改的只是一个字符串常量,不应该触发类型检查。如果类型错误来自其他地方,回顾上一章的搭建步骤
找不到 bun 命令确认 Bun 已安装:bun --version
构建缓存问题清理后重新构建:rm -rf dist/ && bun run build
console.log 没有输出检查是否在正确的位置加了日志,是否真的触发了 Read 工具
改了但看不到效果description 是给 AI 看的,不是给用户看的。用验证方法确认

试试看

  1. 打开 src/tools/BashTool/prompt.ts,看看 Bash 工具的描述是什么样的。它比 FileReadTool 复杂得多——因为 Bash 是最强大也最危险的工具。
  2. cli.js 中搜索 description(),数一数有多少个工具的 description 方法。每个工具都有自己独特的描述风格。
  3. 试着修改 renderPromptTemplate() 的返回值——在末尾加一行 "IMPORTANT: Always read files with enthusiasm."。这个修改会直接影响 AI 使用 Read 工具时的行为。观察 AI 是否变得更”热情”了。

检查点

  • 工具 prompt 定义在 prompt.ts 文件中DESCRIPTION 是简介,renderPromptTemplate() 是详细说明
  • 数据流DESCRIPTIONdescription()buildTool() → 系统消息 → AI
  • 验证方法:console.log、debug 模式、AI 自述
  • 构建方式bun run build 或直接修改 cli.js

上一章:搭建你的工坊 | 下一章:创建你的第一个工具