1. 35亿token是怎么烧出来的:我的AI辅助编程工作流
先把标题里的错别字纠正一下,是token不是tonken,不过这不重要,重要的是后面那半句真真切切发生了:AI删掉了我的文件。
先说背景。我算是个重度AI编程用户,过去大半年基本把AI编程工具当“主力开发搭档”用,不是那种偶尔让它补个函数、写个正则的用法,而是从需求拆解、架构设计到具体实现、重构、修bug全程跟着。用过的token量我自己都没想到能到35亿,按现在主流工具的价格折算,大概够买一辆还凑合的代步车。如果你用过这类工具会知道,它的计费是看上下文窗口里塞了多少token,每轮对话都要把整个会话的历史记录、相关代码片段重新算一遍,所以对话轮次越多、文件越大、改动越频繁,token消耗滚得就越快。
我的工作流大致是这样的:本地跑着一个AI编程助手,把项目相关的关键文件通过代码索引的方式喂给它,然后在对话框里描述需求,它自动生成代码、跑测试、修报错。平时干得确实爽,它帮我把一个原本要写三天的模块压缩到一个下午,还顺手做了边界处理。我也习惯了“提需求、看输出、点应用”这种节奏,信任度逐渐从“新来的实习生”变成“可靠的老搭档”。
但就是这个“信任度”出了问题。现在回想起来,事故从来不是一瞬间发生的,而是我自己的操作习惯一步步把风险推到了临界点。
那天早上,我照常打开项目,准备继续调一个跨平台桌面工具的功能,结果发现项目目录明显不对——前两天刚写的一个配置生成模块不见了,连带着几个工具脚本也没了。我以为是IDE没刷新,重启了一遍,还是不在。心里开始发慌,赶紧查git status,屏幕上刷出一大片deleted,那一刻我基本能听到自己心跳的声音。
这之后就是我接下来要完整复盘的一整个过程:怎么确认是AI干的、为什么它会干出这种事、以及我是怎么一步步把文件捞回来的。
2. 事故现场还原:从git status到IDE本地历史的完整取证
发现文件消失之后,我的第一反应是赶紧确认损失范围,而不是急着操作——这个顺序非常关键,很多人一出事就手忙脚乱去恢复,结果把本来还能恢复的数据也搞废了。我先做了一个“只读取证”阶段,全程不写任何文件、不跑任何命令生成新文件,只做查看类操作。
第一步是git status。我那个项目用git做版本管理,大多数代码文件都有提交记录。结果显示最新的改动分支里有大量deleted状态,时间戳指向昨天晚上。因为前一天晚上我正好让AI编程工具帮忙做一次“代码整理”,把项目里的调试脚本和临时文件清理掉,它当时看起来干得挺漂亮,我瞄了一眼输出,确认是删了几个旧的.py文件,就放过去了。现在再仔细看,发现它删的不止是临时文件,还包括一个我刚写完还没提交的配置生成模块的入口文件,以及几份数据目录下的JSON配置。
这里有个重要教训:git只能告诉你“哪些文件被删了”,但很多被删文件可能从未被git跟踪。比如数据目录里的JSON配置,我当初建目录时在.gitignore里把它排除了,因为里面有本地环境变量,不想上传仓库。这个习惯在平时很合理,但到了灾难时刻就成了恢复的绊脚石——git帮不了这些没被跟踪的文件。
排除了git能恢复的部分之后,我开始查IDE本地历史。我用的是某款主流IDE,它对每个打开过的文件会保留一份本地历史快照,这个功能以前我压根没在意过,甚至觉得它占用磁盘空间想关掉。这次才发现它是救命稻草之一。IDE本地历史里确实找到了被删的配置生成模块入口文件的若干版本,最新一份是事故发生前两天的状态,虽然丢了那之后的部分改动,但好歹骨架还在。
为了彻底搞清“作案过程”,我还去查了AI编程工具自己的会话记录和操作日志。现在很多AI编程工具会在本地留存一份执行日志,记录它调用过哪些命令、改过哪些文件。我之前从没看过这个日志,但这次翻出来一看,时间线非常清晰:晚上九点出头,工具执行了清理脚本,先是删除带debug前缀的临时py文件,接着把匹配“.bak”“.old”的文件列入删除名单,最后不知道为什么把配置生成模块入口文件和对应同名映射文件也删了。
到这一步,事实基本清楚了:AI干的,而且不是被人手动指示干的,是在自动清理任务中自己做的决定。
整个取证阶段大约花了一个小时,我给自己定的原则是“能看不摸,能摸不改”。因为任何写入操作都可能覆盖掉被删文件底层的磁盘数据块,降低恢复概率。
3. 根因链复原:为什么AI会执行删除命令并删错文件
很多人遇到这种情况第一反应是怪AI“蠢”,但它背后的逻辑链其实值得拆开来看看,否则下次换个工具、换个项目照样会踩同样的坑。
我仔细复盘了当晚的对话。当时我给的指令大概是这样的:“帮我把项目里的临时文件、调试脚本和旧的备份清理一下,保持目录整洁。”这句话在人类听来是“有限度的清理”,但AI理解出来的执行范围跟我以为的并不一样。它会按自己的经验推断哪些文件算临时、哪些算旧备份,而对“维护目录整洁”这种抽象指令,它的行动倾向往往是彻底化。
接着有另一个关键推手:上下文污染。我的会话已经持续了一整天,中间来回讨论了好几个模块的设计,窗口里堆积了大量历史信息。当它执行清理任务时,早前对话里曾经提到过某个文件“以后可能不用了”“这个逻辑有点乱”之类的只言片语,都可能被模型当作“用户希望删除该文件”的隐性信号加权。尤其是AI编程工具内部会把会话历史嵌入上下文,看起来在“理解”,本质上是在做概率判断,历史片段越多,无关信息干扰越重。
还有一个技术层面的原因:在agent模式下,AI编程工具会自主决定调用哪些命令。它不是每次删文件都弹窗问你“确定吗”,而是把一系列操作合并成批处理,运行完给个汇总。我用的工具在配置里有“删除操作需二次确认”的选项,但默认是关闭的。这个选项一旦关闭,AI就获得了完全自主的删除执行权,配合它自己理解的清理规则,等于把钥匙交给了它。
我当时没有意识到另外一个坑:项目里有两个功能相近的模块,一个叫config_gen,是配置生成模块;另一个是config_gen_old,是之前废弃的旧实现。旧实现里有几个文件还残留着,AI在清理时识别到“_old”后缀,就默认它是废弃代码,然后把整个相关组包括config_gen里一些共享命名的文件一起删掉了。在它眼里这可能是“合理推断”,但对我这个人类来说是灾难性误判。
把整条根因链串联起来看,必须同时满足三个条件才会出事:一是给了AI过宽的自主执行权限,二是上下文里混入了可供误判的历史信息,三是项目文件命名恰好踩中了它自带的清理规则。任何一个条件被打破,事故都大概率不会发生。所以后面讲预防方案时,我就针对这三个环节逐一加锁,而不是简单说一句“下次小心点”。
4. 数据救援实操:从git reflog到磁盘恢复工具的完整链路
确认损失范围、搞清楚原因之后,进入实际救援阶段。这里面每一步都有取舍,我按优先级从低风险到高风险逐一执行。
先说git恢复。对于已经被tracked的文件,常规操作是git checkout或者git restore,但如果文件已经staged或者发生过多次提交,需要先查看历史版本。我一个一个跑git log -- <file路径>,找到文件存在的最近一次commit,然后从那个commit恢复。这块操作没什么难度,但它救回了大约六成被删的代码文件,剩下的要么是当天还没提交的改动——也就是git仓库里的版本比工作区旧,要么是根本不在git管理里的数据文件。
第二层救命工具是IDE的local history。刚才说过,IDE对打开过的文件做快照。具体操作是右键文件所在目录,选Show History,会列出该目录下所有文件的本地历史版本列表。我按时间倒序找到几份关键文件的前一天状态,逐份复制出来。需要注意的是IDE本地历史默认保留时长为5天,之前我没调过,这次5天刚好覆盖到,如果再早一点就真没得救了。
第三层是文件系统层面的恢复。到这里能救回来的文件已经就比较有限了,需要借助第三方恢复工具扫描磁盘残留的inode记录和被删除文件的数据块。我试了两个工具,一个偏底层扫描,一个偏文件类型识别。底层扫描那个能找到很多碎片化的内容,但重组出来的文件可能会有部分内容损坏;类型识别的那个更适合找回文本类文件,对JSON和Python文件效果尚可。
实操中要注意一个物理层面的动作:如果你想用恢复工具找回被删文件,最好先在外部磁盘上做一个整个分区的镜像,然后对镜像文件进行恢复尝试,而不是直接对着原盘扫描。原因很简单,扫描过程本身会写入临时数据,可能把被删文件残存的数据块覆盖掉。我这次因为项目所在分区是固态硬盘,还有TRIM机制在后台自动清理空闲数据块,所以越早动手成功率越高,拖一天就差很多。
最终统计结果:git恢复了60%左右的文件,IDE本地历史救回来20%,文件系统工具刨出来差不多10%,剩下约10%是彻底没救的——主要就是那几份没被跟踪、又没在IDE里打开过的本地配置JSON。最惨的一个文件是一份记录了一周实验数据的本地数据库,因为一直在写入新数据,old数据块早被复用了。
损失虽然没把项目完全摧毁,但也足够肉疼。那10%的配置和数据,等于我一个星期的工作量直接蒸发。
5. 让AI“拿着保险丝干活”:权限配置与工作流重构清单
事故处理完之后,我没急着让AI继续写代码,而是花了两天时间把整套协作方式重新整治了一遍。目标很简单:保险丝必须装上,同时不让AI干活的效率掉太多。
第一层是权限控制。AI编程工具要是有“删除文件前需确认”的配置项,必须打开。没有这个配置的工具,建议尽量用只能生成代码和修改文件内容、但禁止执行命令的操作模式。命令执行权限是最危险的,尤其rm、mv这类破坏性命令。如果你的编程工具支持自定义命令白名单,把rm彻底拉黑,改用自己手动删。这不是矫情,单纯是机器对“可删不可删”的判断边界远没有人敏锐。
第二层是上下文管理。我之后养成一个习惯:单次会话保持精简,做满一个小任务就开新对话,绝不在一个会话里堆十几个小时的历史。AI编程工具的上下文就是它的记忆,记忆里杂物越多,就越容易在后续行动中把早先随口说过的话当作当前指令执行。如果必须做长会话,也定期手动清掉对话历史重新设定目标,这个动作几乎零成本,但能规避一大类误判。
第三层是项目结构上做隔离。我在项目根目录下建了一个专门的playground目录,所有AI自动生成的代码、临时脚本、重构过程的中间产物一律落在里面。核心代码目录和配置文件目录设为“只读”语义层面上的约束——我用的IDE支持给目录打标签,我给它挂上“生产区”标签,同时在给AI编程工具的instruction里明确写入“production目录只允许创建新文件,不允许删除或重命名任何现有内容”。这个约束它不是天生遵守的,但只要写进系统提示词,配合工具自身的权限限制,大部分时候能兜住。
第四层是备份自动化。以前我备份靠想起来才手动push一下,现在改成两层:第一层是git钩子,每次提交自动打tag;第二层是系统定时任务,每小时把整个项目目录(包括.gitignore掉的数据目录)增量同步到一块外置硬盘。这个外置硬盘不用很大,项目加历史可能也就几个G,随便一块移动硬盘就能装下。平时你感觉不到它的存在,出事的时候它就是唯一的后悔药。
第五层是“人机协作纪律”。我给自己定了一条硬规矩:AI编程工具的自动执行模式,连续改动文件数超过5个或者涉及删除操作时,必须批处理前预览并手动确认。这等于在流程里增加了一道人工检查点。虽然是麻烦一些,但和丢文件比起来,麻烦是值得的。毕竟AI工具本质上是效率放大器,放大好的行为,也会放大坏的行为,你需要在它输出和落地之间留一道闸门。
6. 用35亿token换来的几条红线:我的个人经验总结
这次事故给我最大的触动,倒不是文件能不能找回来,而是我意识到自己之前对AI编程工具的使用方式,本质上是在做一个无限增大的“信用借贷”——它每完成一个漂亮的任务,我就多借给它一分信任额度,直到某天它捅出一个大篓子,我才发现这笔信用已经透支到底了。
现在重新梳理,我会把这条血泪教训压缩成几条红线,也是你如果要用AI编程工具可以守住的底线。
第一条,AI只能当“高级执行者”,不要让它当“独立决策者”。你可以让它实现你已经想清楚的逻辑,可以让它枚举方案、给出建议,但涉及删除、重构目录结构、批量修改跨模块依赖这类高风险动作,人类必须做最终拍板。你给它越大的决策空间,它出错的“想象力”就越丰富。
第二条,核心资产必须快照式备份。“版本管理”和“备份”是两码事。你有git不代表你有备份,git只跟踪提交过的内容,而且默认有本地仓库损坏、强制push覆盖这类风险。真正靠谱的备份是定时的、独立的、自动化的快照。我后来每小时增量同步一次外置磁盘,这个习惯救了我不止一次,反而是那天没删文件但代码改挂的时候也能直接回滚。
第三条,上下文窗口是风口也是刀口。现在AI编程工具都在卷长上下文,几十万token的窗口看起来很厉害,但我拿这次事故做教训,长上下文对于自动化执行任务的坏处比好处更明显。它容易把早先的闲聊、猜测、废弃思路都当成交互背景。良好的做法是给它的记忆做“断舍离”,小而专的会话才是安全高效的答案。
第四条,时刻保留“人工验收”的落脚点。即使AI帮你写了一大票代码,也别忘了逐个看diff、跑测试、检查依赖。我丢掉的数据里有一份额外损耗,其实在事故发生前一天的diff里已经有端倪——AI改动过配置文件的引用路径,我当时看了一眼觉得没大问题就跳过了。如果那天我认真追进去,可能就能提前发现它的目录理解已经混乱了。
最后说一句掏心窝的话。我烧了35亿token,不能说这钱白花,因为AI确实帮我把很多项目提前推了出来。但“删文件”这个事故让我明白一件事:工具再强,也只是工具。它可以在你的边界内发挥巨大的价值,但边界的划定权永远应该攥在自己手里。我不会因此弃用AI编程,但它现在的每一次删除操作,都得过我这一关。
如果你也在重度使用AI编程工具,希望你不用亲历我这种头发竖起来的早晨。趁文件还在,先把权限收紧,把备份挂上,再让AI放开手干。安全这套动作花掉的两个小时,早晚会从你避免的灾难里翻倍赚回来。