老张在城南开了二十年红烧肉馆,靠一张泛黄的配方卡站稳了脚跟。上个月他决定来点“现代感”:把红烧肉改成低温慢煮加液氮急冻的分子料理。新品端上桌那天,客人的筷子刚碰到肉就放下了,外卖平台的差评跟着雪片一样飞来。老张没慌,转身进后厨,从配方柜最里层翻出那张写了三十年的老配方卡——十五分钟后,一锅热气腾腾的经典红烧肉重新上桌。这故事听起来是餐饮自救,其实是AI生产环境里最要紧的一个安全机制:模型回滚。 做AI的团队每天都在“上新菜”:换一批新数据、改一版网络结构、加一组新特征。可真实世界总有些想不到的意外,新模型一遇到真实流量,可能准确率大跌,甚至服务瘫痪。若工程师埋头现场修复,几小时的热抢修足以让用户全部跑光;而模型回滚就像翻出老菜谱,几分钟就能把流量切回上一个稳定版本,让服务满血复活。本文就带你从零搞懂模型回滚:什么时候该回滚、有哪几种回滚、版本怎么管、系统如何自动完成,以及回滚后怎样验证。走,一起进后厨看看。

岗位关联

模型回滚是MLOps工程里的“安全气囊”,掌握它意味着你能在线上事故中力挽狂澜,用分钟级恢复守住业务底线,这是AI工程师从“能调模型”走向“能扛生产”的关键一步。

目录
  1. 可视化演示
  2. 回滚概述:后厨里的“老菜谱”
  3. 触发条件:什么时候该判定“菜做砸了”
  4. 回滚类型:主厨拍板还是系统自动
  5. 版本管理:配方保险柜
  6. 自动回滚流程:厨房里的报警铃
  7. 回滚验证:让老食客先尝一口
  8. 最佳实践:把回滚练成肌肉记忆
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示自动回滚五步流程、三态版本管理(stable/canary/deprecated)以及流量权重路由切换的回滚执行过程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

自动回滚五步流程 异常检测触发告警 选择稳定版本回滚目标 流量切换并验证恢复 Alert → Select → Switch → Verify → Notify 五步自动回滚确保5分钟内恢复服务

回滚概述:后厨里的“老菜谱”

配方柜最里层那张老配方卡,就是老张的底气。只要它还在,任何新菜翻车都不过是十五分钟的插曲。AI模型团队也需要这样的底气:每次部署新模型之前,都确保上一个稳定版本随时能“重新上桌”。

把视线拉回MLOps生产线。模型训练完成后的部署,不是故事的终点,而是事故的高发起点。新模型在测试集上表现优异,可线上真实数据与训练环境往往存在差异——用户行为变了、数据分布漂了、外部接口慢了,任何一处都会让新模型“水土不服”。所以,模型回滚机制研究的是:当新版本扛不住真实流量时,如何以最快的速度回到稳定状态。

模型回滚,就是在这种场景下应运而生的安全机制:一旦监控发现线上服务的错误率、时延等关键指标明显劣化,系统可以立刻把流量从新版本切换回历史稳定版本。回滚的本质不是“删除新模型”,而是“流量改道”——新版本本体、日志、中间结果都会原样保留,方便后续做根因分析。它与现场修复最大的区别是速度:修复以小时计,回滚以分钟计;修复是外科手术,回滚是打开备用氧气瓶。

说到底,餐厅敢试新菜,是因为老配方卡锁在保险柜里;模型团队敢频繁迭代,也是因为回滚机制给了他们“试错后兜底”的底气。这份底气,正是AI工程化从“能跑”走向“稳跑”的分水岭。

SR=NsuccessNtotal\text{SR} = \frac{N_{\text{success}}}{N_{\text{total}}}
这个公式是判断一切模型好坏的“温度计”:成功率是成功请求在总请求中的占比,回滚的所有触发条件最终都会反映到这个数字上。
  1. 成功率 SR衡量模型服务是否健康的核心指标,取值在0到1之间,越接近1越健康。
    SR\text{SR}
  2. 分子 $N_{\text{success}}$统计窗口内正常返回结果的请求数量。
    NsuccessN_{\text{success}}
  3. 分母 $N_{\text{total}}$统计窗口内包含成功和失败在内的全部请求数量。
    NtotalN_{\text{total}}
  4. 整体运算方式用成功请求数除以总请求数,就得到当前模型版本的服务成功率,它既是评估基线,也是启动回滚的依据。
    NsuccessNtotal\frac{N_{\text{success}}}{N_{\text{total}}}

触发条件:什么时候该判定“菜做砸了”

老张给厨房定了一条铁规矩:一道菜端上桌,如果十分钟内有三桌客人皱眉,就必须换菜。判定“菜做砸了”不能靠感觉,要有看得见的信号——差评率、退菜率、空盘率。模型回滚也一样,需要一组明确的触发条件,而不是等用户开始骂街才后知后觉。

最常见的第一类信号是错误率报警。服务器返回5xx、模型抛出异常、推理结果为空,都属于“硬错误”。一旦在统计窗口内错误率超过设定阈值,新版本就进入了“待回滚”名单。第二类信号是时延飙升。模型本身可能没报错,但特征计算变慢、GPU排队加剧,用户感受到的“卡顿”同样是业务事故。第三类是资源饱和度:CPU、内存、GPU显存被打满,服务濒临雪崩,这时即使模型没错,也要考虑切回更轻量的旧版本。最后一类是人工介入——算法同学根据业务经验,发现新版本在特定客群上表现异常,即使指标还没跌破阈值,也可以主动按下回滚键。

为了让多种信号协同工作,生产环境通常把三个核心指标合并成一个“回滚触发得分”:

老张的“三桌皱眉”规则,本质是把经验量化成阈值;模型的回滚触发条件,也是把“服务要不行了”的直觉,翻译成机器可以执行的数字。有了这套数字,回滚就不再是慌乱的应急,而是从容的预案。

S=α⋅EtEbase+β⋅LtLbase+γ⋅QtS = \alpha \cdot \frac{E_t}{E_{\text{base}}} + \beta \cdot \frac{L_t}{L_{\text{base}}} + \gamma \cdot Q_t
这个公式把错误率、时延、饱和度三个信号加权成一个总分,总分超过预设阈值就启动回滚,避免单看一个指标造成误判。
  1. 错误率比值 $\frac{E_t}{E_{\text{base}}}$当前错误率 $E_t$ 除以基线错误率 $E_{\text{base}}$,衡量错误上升了多少倍。
    EtEbase\frac{E_t}{E_{\text{base}}}
  2. 时延比值 $\frac{L_t}{L_{\text{base}}}$当前时延与基线时延的比值,衡量响应变慢的程度。
    LtLbase\frac{L_t}{L_{\text{base}}}
  3. 饱和度 $Q_t$当前CPU、GPU或内存的使用饱和度,取值0到1,反映资源是否被打满。
    QtQ_t
  4. 权重 $\alpha, \beta, \gamma$分别给错误率、时延、饱和度分配不同权重,三个权重之和通常为1。
    α,β,γ\alpha, \beta, \gamma
  5. 综合得分 $S$三项加权求和后得到服务风险分,$S$ 越高说明服务越危险。
    S=α⋅EtEbase+β⋅LtLbase+γ⋅QtS = \alpha \cdot \frac{E_t}{E_{\text{base}}} + \beta \cdot \frac{L_t}{L_{\text{base}}} + \gamma \cdot Q_t
  6. 阈值比较当 $S > T$($T$ 为预设阈值,如0.85)时,系统判定需要回滚。
    S>TS > T

回滚类型:主厨拍板还是系统自动

餐馆里换菜有不同的决策方式。小馆子靠主厨拍板——有人喊“换”,才翻老菜谱;大酒楼则装了智能出菜系统,一旦传感器检测到翻台率骤降,系统自动把招牌菜切回老配方。模型回滚也分手动和自动两种风格,外加一种更精细的灰度回滚。

手动回滚是最朴素也最稳妥的方式:监控告警发出后,值班工程师登录控制台,确认异常真实存在,再点击“回滚”按钮。它把“要不要回滚”的决策权留给人,适合业务复杂、需要结合上下文判断的场景。自动回滚则把决策交给系统:监控组件持续采集指标,判定引擎将指标与阈值比对,一旦命中就自动执行流量切换。它响应最快,但需要精心设计阈值与防抖,避免误伤正常服务。灰度回滚介于两者之间:新版本先被分配小比例流量,如果小流量段表现异常,系统只回滚这一小部分,把爆炸半径控制在最小。

策略对比上没有绝对的优劣:手动回滚稳,自动回滚快,灰度回滚险。生产环境通常采用“灰度发布+自动回滚”的组合:先让新版本接收少量真实流量,一旦指标越界立刻自动切回。就像大酒楼不会把招牌菜的命运全押在传感器上,成熟的团队也不会只依赖一种回滚方式,而是把“人审+自动”结合起来,让安全网层层叠叠。

版本管理:配方保险柜

老张的配方柜里,每张配方卡都有编号:“红烧肉-1989版”“红烧肉-2005改良版”“红烧肉-2023分子料理试验版”。每次研发新口味,旧卡片绝不销毁,反而锁进保险柜。这就是模型世界的版本管理——没有它,回滚就无从谈起。

语义化版本号是第一个基本功。一个典型的版本号由三段组成:主版本号、次版本号、修订号。算法结构大改,主版本号递增;训练数据或调参策略变化,次版本号递增;Bug修复和补丁,修订号递增。这样团队看到版本号,就能立刻判断两个模型的差异幅度。第二个基本设施是模型注册表,它像一个集中式配方柜,登记每个版本的元信息:训练数据集、超参数、评估指标、上线时间、负责人。配合Docker镜像和权重文件存档,保证任何历史版本都能被精确重建。

最后一个要点是多环境一致性:从开发、测试到生产,三个环境使用的镜像和权重必须一一对应。否则开发环境修好的模型,到生产环境又会变成另一道“菜”——这会让回滚目标变得不可靠。版本管理做得越好,回滚就越像从保险柜里取那张卡:精确、无歧义、随时可复现。没有版本管理的回滚,就像记忆里的菜谱:今天想起来放两勺糖,明天放三勺,味道全凭运气。

自动回滚流程:厨房里的报警铃

老张后来给后厨装了一套“智能报警铃”:炒锅温度异常、排烟系统过载、传菜超时,铃一响,系统自动切回经典配方并通知大厨。整个过程不需要任何人守在锅边。自动回滚流程,就是这个报警铃的产品化。

自动回滚流程可以拆成四个环节。第一步是监控采集:旁路收集线上请求的成功率、错误率、时延、资源占用等指标,频率通常在秒级甚至毫秒级。第二步是异常判定:把实时指标喂给判定引擎,算出第二节的触发得分 $S$,并与阈值 $T$ 比较;为了防抖,系统一般要求连续N个采样点都越界,才真正触发。第三步是自动切换:通过负载均衡器或服务网格,把流量权重从新版本动态调整为0,将全部流量指回旧版本。第四步是告警通知:切换完成后立即向值班群推送消息,内容包括触发时间、指标截图、切换前后版本号,让负责人第一时间接手后续排查。

这套报警铃,本质上就是“把翻老菜谱的动作自动化”。它不聪明,但足够快——在人类还在揉眼睛看告警的时候,服务可能已经恢复了。自动回滚不是取代工程师,而是为工程师争取到宝贵的“先呼吸一口”的时间。

回滚验证:让老食客先尝一口

回滚完成不代表结束。老张每次换回经典配方,都会先请包间的老食客尝一口,确认“就是这个味”,才敢给全堂客人上菜。AI服务回滚后,同样需要验证。

最标准的验证方式是金丝雀验证。金丝雀的名字来自煤矿工人用金丝雀测瓦斯的传统:先放一只鸟进矿井,鸟没事,人才敢下去。回滚后,我们把5%到10%的流量切到回滚后的旧版本上,观察它的成功率、错误率、时延,与故障前的基线指标做对比。如果旧版本的表现恢复到了基线的95%以上,则验证通过;如果连旧版本也异常,说明问题不止在新模型,可能牵涉到底层数据管道或基础设施。

除了指标对比,还要检查数据一致性:模型产出的预测结果是否出现空值、格式错乱或业务字段缺失。最后,在验证通过后,正式向全量流量开放,并对外宣布“服务已恢复”。

老食客点头,老张才放心;金丝雀绿灯,模型团队才敢对全量用户说一句:各位放心,菜还是那个味。

SRcanary≥SRbaseline×0.95\text{SR}_{\text{canary}} \geq \text{SR}_{\text{baseline}} \times 0.95
公式说明:金丝雀流量上的成功率,至少要达到基线成功率的95%,才允许宣布回滚成功。
  1. 金丝雀成功率 $\text{SR}_{\text{canary}}$指把少量真实流量(比如5%)切到回滚后的旧版本上,统计出的成功率。
    SRcanary\text{SR}_{\text{canary}}
  2. 基线成功率 $\text{SR}_{\text{baseline}}$故障发生前旧版本的正常成功率,作为“健康参考线”。
    SRbaseline\text{SR}_{\text{baseline}}
  3. 判定条件 $\geq 0.95$回滚后的成功率只要不低到基线的95%以下,就算通过验证;若低于,说明回滚本身也有问题,需要进一步处理。
    SRcanary≥SRbaseline×0.95\text{SR}_{\text{canary}} \geq \text{SR}_{\text{baseline}} \times 0.95

最佳实践:把回滚练成肌肉记忆

老张每年会做两次“消防演习”:故意把新菜谱端上桌,看后厨多久能翻出老配方。第一次用时20分钟,第三次只用了5分钟。回滚也是这样,关键不是会,而是熟。

第一条实践是定期演练。生产环境不是排练厅,所以团队要在测试环境模拟线上故障,周期性检验回滚脚本和流程是否仍然有效,别等到真出事才发现按钮是坏的。第二条是稳定快照:每次发布前都把上一稳定版本连同镜像、配置、环境变量打包快照,真正做到“随时可回”。第三条是一键回滚:把手动操作的多个步骤封装成平台上的一个按钮,即使新人值班也能在最短时间内完成切换,减少人为出错。第四条是持续优化:每次回滚结束后开复盘会,把“为什么会触发”“哪里慢了”“阈值是否合理”反馈进监控和告警配置,让下一次自救更快、更准。

消防演习的意义,是让每个人在浓烟里也能凭肌肉记忆找到安全出口;回滚演练的意义,是让团队在告警轰炸中也能条件反射地完成自救。安全不是运气,是平时练出来的。

AI 应用场景

金融风控模型的紧急回滚

阶段:在线推理与部署运维

解决的问题:某银行的智能风控系统部署了新一代反欺诈模型,上线半小时内,线上交易误杀率从0.5%飙升至12%,大量正常用户的信用卡支付被拦截。如果靠人工排查修复,可能造成上亿元的交易损失。

具体案例:值班监控发现错误率指标连续10个采样点越界后,自动回滚触发,流量在两分钟内全量切回旧模型,交易恢复顺畅。事后排查发现,新模型的特征管道在某时段字段对齐出错,导致评分异常。新版本文件被完整保留,供离线继续分析。

电商大促期间的推荐系统自救

阶段:A/B实验与灰度发布

解决的问题:大促期间推荐模型直接影响成交额,传统“先跑半小时看效果”的方式太慢,等人工发现点击率下降时损失已经发生。

具体案例:某电商平台在大促前一天发布新召回模型,大促当天人均点击率反而下降20%。运营负责人根据业务经验,手动触发回滚,将流量切换到旧推荐策略,点击率在十分钟内恢复到促销预期水位。新模型被保存下来,大促结束后用离线数据重新评估,最终定位到新特征在高峰时段计算超时的问题。

智能客服的语义升级回滚

阶段:模型生命周期管理

解决的问题:大模型版本的语义理解效果难以在离线阶段完全评估,需要线上小流量验证,而一旦验证失败必须快速隔离影响。

具体案例:某在线教育公司的智能客服上线了基于大模型的语义理解新版本。团队采用灰度发布,先让5%的会话流量接入新版。监控发现意图识别置信度显著下降、用户转人工率升高,系统自动将该灰度分组切回旧版本。版本管理平台确认问题出在新版Prompt模板后,团队修复并重新发布。

Python 演示

python74 行
import random  class ModelRegistry:    def __init__(self):        self.models = {}     def register(self, name, model):        self.models[name] = model     def get(self, name):        return self.models[name]  class AutoRollbackDeploy:    def __init__(self, registry, threshold=0.2, window=20):        self.registry = registry        self.threshold = threshold        self.window = window        self.history = []        self.current = None        self.previous = None     def deploy(self, name):        self.previous = self.current        self.current = name     def serve(self, x):        pred = self.registry.get(self.current)(x)        self.history.append(1 if pred == "error" else 0)        if len(self.history) > self.window:            self.history.pop(0)        return pred     def health_check(self):        if len(self.history) < 5:            return False        error_rate = sum(self.history) / len(self.history)        if error_rate > self.threshold:            self.rollback()            return True        return False     def rollback(self):        if self.previous is None:            return        print("自动回滚: {} -> {}".format(self.current, self.previous))        self.current = self.previous        self.previous = None        self.history.clear()  def build_model(name):    def model(x):        if name == "v2.0-risky" and x % 3 == 0:            return "error"        return "ok-{}".format(x)    return model  if __name__ == "__main__":    reg = ModelRegistry()    reg.register("v1.0-stable", build_model("v1.0-stable"))    reg.register("v2.0-risky", build_model("v2.0-risky"))     auto = AutoRollbackDeploy(reg, threshold=0.2)    auto.deploy("v1.0-stable")    auto.deploy("v2.0-risky")     for i in range(100):        auto.serve(i)        if auto.health_check():            print("第 {} 次请求后检测到异常,已恢复".format(i))            break
目的:模拟一个带滑动窗口健康检查的自动回滚部署器——新版本每3次请求报错1次,错误率超过20%阈值后自动切回上一个稳定版本。
  1. class ModelRegistry:用字典登记所有模型版本,相当于后厨的“配方柜”。
  2. auto = AutoRollbackDeploy(reg, threshold=0.2)创建部署对象,设定错误率阈值20%。
  3. auto.deploy("v2.0-risky")切到新版本,模拟一次风险上线。
  4. self.history.append(1 if pred == "error" else 0)把每次请求的结果记进滑动窗口。
  5. error_rate = sum(self.history) / len(self.history)用滑动窗口实时计算错误率。
  6. if error_rate > self.threshold: self.rollback()错误率超过阈值就自动回滚,无需人工。
  7. self.current = self.previous把当前版本指针切回上一个稳定版本,完成流量改道。
  8. self.history.clear()回滚后清空窗口,重新开始健康评估。

常见误区

误区“回滚就是把新模型删掉,一了百了。既然它有问题,留着也没用,直接清理掉还能省存储空间。”

正解回滚的本质是“流量改道”,新版本的文件、日志、权重全都保留,只是不再对外服务。这就像老张把失败的分子料理配方卡留在柜子里,而不是撕掉——下次研发还要拿它当反面教材。删除会摧毁排查线索,让故障原因永远无法定位。

为何常见:很多人把回滚类比成“撤销”操作,自然以为要把修改痕迹一并抹除,却忽略了生产环境必须保留现场用于复盘。

误区“出问题时应该先花时间定位根因,把问题彻底修好再决定要不要换版本,这样才不会反复折腾。”

正解生产和开发环境完全不同,线上故障每多一秒都在流失用户和收入。正确顺序是“先恢复,后排查”——立刻回滚让服务稳定,再从容分析新版本的日志和数据。老张换菜绝不会跟客人解释分子料理的原理,而是先把老菜端上桌。

为何常见:工程师长期在开发环境养成“根因优先”的思维习惯,忽略了生产故障的时效成本。

误区“自动回滚阈值设得越高越好,指标波动是常有的事,阈值设高点能避免误触发,让系统更稳定。”

正解阈值太高会让自动回滚形同虚设——等指标突破高阈值时,故障往往已经蔓延。合理做法是设置中等敏感度阈值,并叠加“连续N次采样越界”等防抖手段,既避免误伤又保证及时。这就像烟感报警器,太灵敏会乱响,太迟钝则会烧穿房顶。

为何常见:经历过一次误回滚的团队容易矫枉过正,把系统安全建立在“少动”上,反而失去了自动化的意义。

误区“回滚按钮点下去,流量切回旧版本,警报声停了,这事就算结束了,可以安心下班。”

正解回滚后必须做金丝雀验证和指标对比,确认旧版本真的恢复到了基线水平。如果底层数据管道同时坏了,旧版本也可能跟着异常。老张把老菜端上桌前,也得先让老食客尝一口——吃完点头才算数。

为何常见:人容易把“完成动作”误认为“完成目标”,回滚动作只是切换流量,回滚目标则是服务真正恢复。

面试题

Q1. 模型回滚的核心目标是什么?

单选题 · easy

  • A.立即删除新模型
  • B.快速恢复稳定服务← 正确答案
  • C.重新训练全部数据
  • D.增加更多GPU机器

答案:B。回滚的目标是用最快速度让服务恢复稳定,好比餐厅换下失败的菜、端回老菜。删除新模型会丢失排查现场,重训和扩容都耗时太长,都不是第一时间该做的事。

Q2. 下列哪一项最像触发模型回滚的线上信号?

单选题 · mid

  • A.训练集准确率指标下滑
  • B.线上服务错误率突然飙升← 正确答案
  • C.模型参数量越来越大
  • D.日志存储空间即将写满

答案:B。回滚触发条件必须来自线上真实流量信号。错误率飙升就像客人开始退菜,是“新菜不行了”的最直接证据;训练集指标下滑是离线问题,参数量大不一定是故障,日志写满属于基础设施问题。

Q3. 下列哪项是模型版本管理的核心工具?

单选题 · easy

  • A.模型注册表← 正确答案
  • B.Git 代码仓库
  • C.监控告警面板
  • D.容器编排平台

答案:A。模型注册表专门登记模型版本元信息和存档,如同配方保险柜;Git管理代码,监控面板负责报警,容器编排管调度,都不是版本管理的核心工具。

Q4. 自动回滚流程包含哪些环节?

多选题 · hard

  • A.实时指标采集← 正确答案
  • B.阈值异常判定← 正确答案
  • C.流量自动切换← 正确答案
  • D.重新部署GPU集群

答案:ABC。自动回滚四环节是监控采集→异常判定→自动切换→告警通知,前三个都包含在选项中。重新部署GPU集群属于扩容操作,不是回滚流程的一部分。

Q5. 回滚后最适合采用哪种验证方式?

单选题 · mid

  • A.直接翻看线上日志
  • B.金丝雀小流量验证← 正确答案
  • C.等待用户主动投诉
  • D.信任平台自动完成

答案:B。金丝雀验证是把少量流量切到旧版本,观察指标是否恢复,如老食客试菜。翻日志只能看到表象,等用户投诉太被动,监控自动完成是回滚动作本身而非验证。

Q6. 灰度发布的核心好处是什么?

单选题 · easy

  • A.缩小故障爆炸半径← 正确答案
  • B.减少模型参数数量
  • C.加快容器镜像构建
  • D.免去配套监控告警

答案:A。灰度发布只让新版本接一小部分流量,即便出问题也只影响少数用户,如同先请包间客人试菜。它不会减少参数量或加速构建,更不能代替监控。

Q7. 下列哪些属于回滚最佳实践?

多选题 · mid

  • A.定期开展回滚演练← 正确答案
  • B.每个版本保留快照← 正确答案
  • C.回滚操作做成单点← 正确答案
  • D.仅能依赖人工判断

答案:ABC。最佳实践包括定期演练、稳定快照、一键回滚和持续优化,A、B、C都是正确项。D把命运全押在人工上,违背自动化的理念。

Q8. 语义化版本号 1.2.3 中的数字 2 代表什么?

单选题 · mid

  • A.大版本号
  • B.次版本号← 正确答案
  • C.修订版本号
  • D.构建流水号

答案:B。语义化版本号三段式:主版本号表示不兼容的大改动,次版本号表示向后兼容的新功能或数据更新,修订号表示补丁修复。所以1.2.3中的2是次版本号。

Q9. 回滚触发得分 S 中通常综合了哪些信号?

多选题 · extreme

  • A.错误率信号← 正确答案
  • B.时延波动信号← 正确答案
  • C.资源饱和度← 正确答案
  • D.团队人员数量

答案:ABC。触发得分S综合错误率、时延、饱和度三类信号,分别对应公式中的E、L、Q,并按权重加权求和。团队人数属于管理信息,不参与模型健康评分。

Q10. 回滚后的新版本模型文件应如何处理?

单选题 · hard

  • A.立即彻底删除掉
  • B.保留并继续排查← 正确答案
  • C.覆盖回旧版本库
  • D.换个目录再上线

答案:B。回滚是流量切换而非删除,新版本文件要连同日志、中间结果一起保留,供后续根因分析。删除会毁掉线索,覆盖会丢失现场,换目录再上线更是危险操作。