第 4 章 读文件、搜内容、找文件

Claude Code 把文件操作拆成了三个专门工具:FileReadTool 读取文件内容,GrepTool 按关键词搜索,GlobTool 按路径模式查找文件。三者各司其职,也经常配合使用。

为什么读文件不直接用 cat

最简单的做法是:让 agent 自己跑 catgrepfind。这完全可行,但 Claude Code 没有这么做。

原因是:直接用 shell 命令读文件,系统对这件事没有任何感知。不知道读了多少 token、不知道这个文件有没有超大、不知道路径是不是安全的,也没办法针对不同文件类型做特殊处理。出了问题,什么日志都没有。

所以 Claude Code 把读文件做成了专门的工具 FileReadTool,处理了一批 shell 命令处理不了的事情。

  • 路径安全/dev/zero/dev/random/dev/tty 等十几个特殊文件,读了要么无限阻塞进程,要么产生无穷输出,需要在读之前就识别并拦截。
  • Token 预算:大文件不能整块塞进上下文。默认每次最多读 2,000 行或 25,000 tokens,超出的部分建议用 offset/limit 分段读。
  • 文件类型处理:PDF(每次最多读 20 页)、Jupyter notebook、图片(超大图会逐级降质和缩小,直到塞得进上下文)——这些不能像普通文本一样处理,需要走各自的解析逻辑。
  • 读取事件通知:读文件这个动作会通知给其他服务,比如 context 预算追踪,这样系统能知道"刚才读了什么,花了多少 token"。

还有一个用户感知不到的优化:如果一个文件自上次读取后没有被修改过,Read 工具会直接告诉模型"文件没变",不再重复读取内容,省下不必要的 token 消耗。

搜索有两个专门工具

grepfind 也是同样的道理——Claude Code 没有让 agent 直接用它们,而是做了两个专门的搜索工具:GrepTool 和 GlobTool。

GrepTool 是"找内容":你知道要找什么,但不知道它在哪个文件里。比如想找所有调用了某个函数的地方,或者想确认某个变量名在哪里被定义。搜索范围只限于你自己的代码,不会把 node_modules 这类依赖目录里的东西也翻出来。匹配太多时会截断,防止把上下文打爆。

GlobTool 是"找文件":你知道要找什么类型的文件,但不知道具体有哪些。比如想列出所有测试文件(**/*.test.ts)、所有 React 组件(src/components/**/*.tsx),或者某个模块的所有入口文件(src/**/index.*)。结果按修改时间排序,最近改动的排在前面。

三个工具配合使用

实际使用中,FileReadTool、GrepTool、GlobTool 这三个工具经常配合:先用 GlobTool 找到相关文件列表,再用 GrepTool 确认哪些文件里有目标内容,最后用 FileReadTool 读取具体内容。

这个分层查找的过程减少了不必要的 token 消耗——不需要把每个可能相关的文件都读进来,而是先缩小范围再精读。