第 4 章 读文件、搜内容、找文件
Claude Code 把文件操作拆成了三个专门工具:FileReadTool 读取文件内容,GrepTool 按关键词搜索,GlobTool 按路径模式查找文件。三者各司其职,也经常配合使用。
为什么读文件不直接用 cat
最简单的做法是:让 agent 自己跑 cat、grep、find。这完全可行,但 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 消耗。
搜索有两个专门工具
grep 和 find 也是同样的道理——Claude Code 没有让 agent 直接用它们,而是做了两个专门的搜索工具:GrepTool 和 GlobTool。
GrepTool 是"找内容":你知道要找什么,但不知道它在哪个文件里。比如想找所有调用了某个函数的地方,或者想确认某个变量名在哪里被定义。搜索范围只限于你自己的代码,不会把 node_modules 这类依赖目录里的东西也翻出来。匹配太多时会截断,防止把上下文打爆。
GlobTool 是"找文件":你知道要找什么类型的文件,但不知道具体有哪些。比如想列出所有测试文件(**/*.test.ts)、所有 React 组件(src/components/**/*.tsx),或者某个模块的所有入口文件(src/**/index.*)。结果按修改时间排序,最近改动的排在前面。
三个工具配合使用
实际使用中,FileReadTool、GrepTool、GlobTool 这三个工具经常配合:先用 GlobTool 找到相关文件列表,再用 GrepTool 确认哪些文件里有目标内容,最后用 FileReadTool 读取具体内容。
这个分层查找的过程减少了不必要的 token 消耗——不需要把每个可能相关的文件都读进来,而是先缩小范围再精读。