先记住这个答案
通过为每个读取的文件记录哈希(如 SHA-256)或版本号,在每次编辑前重新校验;若发现变更,则重读文件并让 Agent 根据最新内容重新规划修改,必要时放弃未落地的旧补丁。
- 每次编辑前校验文件哈希,不信任缓存副本。
- 发现变更后先重读,再让 Agent 重新生成补丁。
- 处理冲突需结合编辑位置和变更内容判断。
基于哈希与重读的一致性机制
编码 Agent 在读取文件后,应保存文件内容的 SHA-256 哈希及对应的读取时间。在每次生成编辑指令之前,先重新计算当前磁盘文件的哈希,若与记录不一致,则说明文件已外部改动。此时不能直接应用基于旧内容的编辑,否则可能产生错误补丁。
处理流程是:先废弃旧副本,重新读取文件内容并更新哈希记录,然后让 Agent 基于新内容重新分析任务目标,生成新的编辑计划。若改动发生在 Agent 已生成补丁但尚未应用时,则直接丢弃补丁重做;若已应用部分修改,则需将旧补丁的意图与新内容合并,避免覆盖外部改动。
多轮修改中文件被外部格式化
假设 Agent 正在修改 src/utils.ts,第一轮读取后生成了修改函数 A 的补丁并成功应用。此时另一个进程将文件整体格式化为 2 空格缩进并提交。Agent 继续第二轮,它持有的内存副本仍是旧格式。若无检测,它会生成一个基于旧内容的 search/replace 块,其中上下文缩进不匹配,应用时可能失败或错位;如果实现还依赖绝对行号,则会直接错位。
正确的做法是:在第二轮编辑前重新哈希,发现不一致后,Agent 重读文件,得到新缩进的内容。然后它需重新定位到目标函数,由于函数体位置可能因缩进变化而偏移,但结构仍清晰,Agent 能正确修改。若外部改动还改了函数逻辑,则 Agent 需对比新旧内容,判断是否保留自己的修改意图,必要时提醒用户冲突。
检测失效条件与处理代价
哈希校验只覆盖完全相同的字节,若外部改动是行尾符转换或编码变化,哈希会变但语义不变,导致不必要的重读。相反,若文件被触摸但内容未变(如 touch 更新 mtime),基于 mtime 的检测会误报。因此推荐用内容哈希,但需在文件较大时权衡性能:每轮都计算整个文件哈希可能昂贵,可只对关键文件或编辑目标区域使用。
另一种边界是外部改动发生在 Agent 已应用补丁但尚未校验的间隙,此时补丁可能已写入,但哈希是旧值。检测到后重读会看到自己刚写入的内容,误认为外部改动。解决方法是区分“自己写入”和“外部写入”:写入后立即更新哈希记录,或记录文件状态变化的事件。若无事件机制,则至少将重读后的内容与预期写入内容比对,若一致则视为正常。
容易答错的地方
- 仅依赖文件行号做编辑
- 有些 Agent 以行号定位编辑位置,但外部改动会导致行号偏移,产生错位修改。正确做法应基于内容块匹配(如 search/replace),而不是绝对行号。
- 每次都全量重写文件
- 为规避过期上下文而每次重写整个文件,会放大覆盖范围,容易夹带意外改动,且掩盖了外部修改。应只重写必要部分,并用哈希检测。
面试官还会怎么问?
如何区分外部改动是自己上一轮写入的?
在应用补丁后立即更新记录的哈希为写入后内容,或维护一个已应用操作日志。若检测到哈希变化且内容与自己写的一致,则继续;否则视为冲突。
外部改动发生在编辑过程中,如何避免覆盖?
采用乐观锁:编辑前记录基线哈希,写入前再次校验,不一致则放弃写入并提示用户重新合并。可参照版本控制系统的 update-then-write 流程。
什么情况下重读文件仍不够?
当文件被移动或替换,重读可能读到不完整内容。需要同时校验文件存在性和元数据(如 inode),必要时报错并中止任务。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。