一次原本只想「关几个开机启动项」的任务,最后演变成 18GB 缓存清理、270 项废纸篓盘点、179MB 研究资产抢救。踩了 4 个坑之后,我把它沉淀成一套可复用的 Agent 文件安全工作流。
起点:一个失控的小任务
那天我只想问 AI 一句:「看看哪些开机启动项可以关掉?」
结果它顺藤摸瓜,最后交付的是:
清理本地缓存 18GB(其中约 10.9GB 真正释放) 盘点废纸篓 270 项文件,逐个溯源 抢救出 179MB 差点被误清的研究资产 还原 7 个匿名临时目录的真实归属 踩坑 4 次,破例 1 次

整个过程我最大的体会只有一句:
AI 处理批量文件操作时,「安全」比「高效」重要一万倍。
删错一个文件带来的损失,远大于多花十分钟带来的收益。这个不对称,决定了整套方法论的底层逻辑。
一、先立三条铁律
在让 AI 碰你的文件系统之前,规则必须写在配置文件里(Claude Code 是 CLAUDE.md,其他 Agent 同理),而不是靠临场提醒。
铁律 1:永不rm,只用trash
macOS 用 trash,Linux 用 trash-put。文件进回收站可恢复,rm 一去不回。这是唯一一条没有例外的规则。
铁律 2:永不独自彻底删除
rm -rf、rmdir、shred 全部列为禁区。不是「谨慎使用」,是「不使用」。
铁律 3:sudo 属于人类
系统级路径(/Library/... 之类)需要提权,一律交还给用户在终端手动执行。Agent 不碰。
工程上可以再加一层保险:配置 PreToolUse 钩子拦截 rm 类命令(直接 exit 2 阻断)。但说实话,模型的自觉比钩子更重要——钩子只能拦住你想到的模式,自觉才能覆盖你没想到的。
二、五步工作流
Step 1|只读盘点,不删任何东西
第一轮永远是「看」,不是「动」。
du -sh# 看大小find -maxdepth N -type d -name ”...”# 定位目标cat# 读小文件溯源归属file# 识别真实类型,防扩展名误导shasum -a 1# 哈希对比,确认是否真重复
关键习惯:任何删除动作之前,必须先跑完这一轮。盘点结果用任务列表追踪,让用户能实时看到进度,而不是面对一个黑箱。
Step 2|三色分类
黄色区域是整套流程的灵魂。「我不确定,所以先清掉」是最危险的思维模式,正确版本是「我不确定,所以先问」。
Step 3|拆任务 + 干跑
每个删除操作前三件事:
先 ls <path>列出实际会被影响的文件用 --help/man确认工具的真实行为边界检查目标位置是否冲突(比如 trash会拒绝已在废纸篓里的文件)
Step 4|小批量执行 + 立刻验证
trash ... && echo ”---verify---” && ls每批不超过 10 个。出错能立刻定位,绝不「一把梭」。批量越大,回溯成本越高。
Step 5|汇报 + 落 memory
收尾不只是报个数字:
给出实际释放量的前后对比 标出「没动但值得注意」的项目 把新发现的边界写进记忆文件,下次直接复用
三、这次踩的 4 个坑
坑 1:sudo 在 Agent 里没有 TTY
sudo trash /Library/LaunchAgents/xxx.plist# → sudo: a terminal is required to read the password
Agent 的 Bash 子进程没有分配交互式终端,sudo 弹不出密码输入。
正确绕过:让用户在终端手动执行。
绝对不要:echo '密码' | sudo -S ...。密码会同时进入 shell 历史和对话日志,这是拿安全换便利,血亏。
坑 2:trash 拒绝废纸篓里的文件
trash ~/.Trash/some_file# → ”The file doesn't exist”
这是设计使然——避免「回收站套娃」。
正确绕过:需要抢救的用 mv 搬到安全目录;需要彻底清空的让用户在 Finder 里操作。绝不用rm去处理废纸篓,那等于绕过自己立的规矩。
坑 3:包管理器的「幽灵进程」
发现同一个服务注册了两个 launchd 标签,以为是装重复了。实际一查:
which && ls -la $(which )# → /opt/homebrew/bin/xxx -> /Applications/Xxx.app/Contents/Resources/xxx
包管理器装的只是个软链接,指向图形版应用本体。brew services stop 只会停掉 brew 注册的那个标签,应用本体照跑不误。
教训:处理服务前先确认二进制的真实位置,别被两个名字骗了。
坑 4:废纸篓里的体积 ≠ 已释放的空间
清理完用户问「为什么废纸篓还这么大」,我第一反应是「可能有新文件」——其实那 13GB 就是我刚扔进去的。
trash 不是删除,只是搬家。真正释放需要用户手动清空回收站。
所以每次清理收尾必须明说:
这 X GB 现在在废纸篓里,需要你在 Finder 右键 →「立即清空」才能真正释放磁盘空间。
四、三个「先问后做」的高危场景
场景 A:废纸篓里可能藏着孤本
我看到一批同名不同大小的媒体文件,第一判断是「重复品」。实际是某个工具反复触发,每次生成的都是新版本——废纸篓里的反而可能比外面的新。
正确做法:
对废纸篓内外的同名文件做哈希对比 路径相同但哈希不同 → 废纸篓里的可能是更新版 用 mv先把疑似新版搬到安全位置,再考虑清空
场景 B:临时目录不等于可清目录
看到一批 tmp.XXXXXXXXXX/ 这种系统标准临时命名,最容易想当然。实际逐个 cat 关键文件后发现,它们分属两个完全不同的项目——一个是某桌面端的构建产物,一个是某服务的后端日志目录,都还在活跃使用中。
正确做法:先读内容再判断归属,不要凭目录名下结论。
场景 C:文件名会撒谎
废纸篓里有个文件名看起来像某个测试用例,实际 file 一查是 PDF(%PDF-1.5 文件头),后缀只是 mktemp 生成的随机残留。
正确做法:file 永远先看真实类型。扩展名是给人看的,不是给判断用的。
五、和 AI 协作的 5 个实践
1|把决策权交还给人
凡是「我不确定就清掉」的项,一律转成明确的选择题问用户。这次涉及的关键决策包括:保留哪个版本的重复服务、停掉哪些后台数据库、某类运行时缓存是否清理。这些都不该由 AI 单方面拍板。
2|让进度可见
多步骤任务开始前先建任务列表。这次会话创建了 28+ 个任务,覆盖启动项清理、缓存清理、废纸篓抢救、临时目录溯源四条线。用户随时能看到「现在走到哪一步」,而不是等一个大黑箱吐结果。
3|阶段性给对比数据
数字比形容词有说服力。
4|把经验落成记忆
每次发现新的「门禁边界」立刻写进记忆文件,命名带统一前缀,下次一条命令就能捞出来复用。踩过的坑只值得踩一次。
5|给用户可执行清单,而不是模糊承诺
不要说「我帮你清空废纸篓」(这本来就该用户手动做),要说:
打开 Finder → 侧栏废纸篓
右键 →「立即清空」
预计释放约 13 GB
六、工具速查表(不用记忆,因为有agent,但可以对照)
du -sh <path> | -s | |
du -sh *sort -rh 与 head -20 | ||
file <path> | ||
shasum -a 1 <f1> <f2> | ||
find <path> -mtime -1 | ||
trash <path> | ||
df -h | ||
launchctl list | ||
osascript -e 'tell application "System Events" to get the name of every login item' | ||
brew services list |
七、一句话总结
AI 处理批量文件 = 慢一点 + 多确认 + 全程 trash + 全部留痕。
速度从来不是这个场景的目标。让用户敢把文件系统交给你操作,才是。
可以把这篇文章交给你的agent,但谨慎的边界,还得自己守住。
夜雨聆风