第 5 章 改文件与 Diff 展示
精准替换,而不是整文件覆盖
Claude Code 改文件的主要方式是精准替换:你提供要改的旧内容和新内容,工具找到旧内容在文件里的位置,替换掉。
这个设计选择背后有一个重要约束:old_string 必须在文件里唯一存在。如果同样的内容出现了两次,工具会拒绝执行,而不是随便改其中一处。
这一条规则防止了很多"改错地方"的情况。如果模型写出了一段模糊的 old_string,系统直接拒绝,而不是悄悄改了一个错误的位置然后让用户事后发现。
不过如果精确匹配失败,系统还会做一次行尾符归一化的重试——把 CRLF 统一成 LF 后再找一遍。这解决了一个常见的跨平台问题:从 Windows 同事那拿到的文件,行尾符可能和你看到的不一样,编辑不应该因此失败。
整文件覆盖(FileWriteTool)也存在,但主要用于新建文件或者真的要完全重写的情况。一般的修改都应该用精准替换,改动范围更小,diff 更可读。
编辑之前要过的关
在真正写文件之前,FileEditTool 会做一批前置检查:
- 路径别名展开:先把
~/、相对路径等各种形式统一成绝对路径,防止路径别名绕过后续的权限规则。 - 权限检查:看用户的规则里这个路径是否允许写入。
- 必须先读过文件:如果这个文件从来没被 Read 工具读取过,编辑直接被拒。这是"先看再改"的硬性要求,确保模型不会凭想象修改一个它没看过的文件。
- 文件状态检查:如果文件在上次读取之后被外部程序修改了,工具会拒绝覆盖,而不是强行写入。这保护了用户在另一个窗口里做的改动。
- 大文件保护:超过 1GB 的文件直接拒绝,防止内存问题。
这些检查都在写入之前做完。如果任何一项不通过,操作失败,原文件不变。
Diff 是信任的基础
每次成功的编辑,diff 都会出现在消息流里。用户不需要自己去比对,也不需要运行 git diff,直接在会话界面就能看到改了哪几行。
这个设计不只是方便,而是系统可信度的基础。你不需要相信"agent 说它改对了"——你可以直接看改了什么。如果改得不对,当场就能发现,而不是等到跑测试才知道。
改完文件之后,如果代码有类型错误或语法问题,这些报错也会一起出现在消息流里,不需要再切到编辑器里手动检查。