Skill 热加载,难点不在加载

Skill 热加载生命周期示意图

Skill 热加载听起来像一个技术动作:把新文件加载进来,不重启服务。真正做起来会发现,加载本身反而不是最难的。

难的是这些问题:

  • 老任务还在跑,新版本能不能直接替换?
  • 新 Skill 依赖的库和旧版本冲突怎么办?
  • 卸载 Skill 时,线程、连接、缓存有没有清干净?
  • 新版本出问题,能不能快速切回旧版本?

所以热加载不是“动态加载文件”,而是一套运行时发布机制。

本文要点

  • 热加载的重点是不中断服务地升级 Skill。
  • 真正的难点是隔离、状态、卸载和回滚。
  • 正在执行的任务不要强行切到新版本。
  • 没有监控和回滚,就不要开放生产热加载。

为什么需要热加载

如果 Agent 平台只有几个固定 Skill,重启发布也能接受。

但当平台开始支持很多团队、很多业务线时,问题就来了。一个团队想更新“文章发布 Skill”,另一个团队正在跑“代码审查 Skill”。如果每次更新都要重启整个平台,会影响所有人。

热加载的价值是让 Skill 像插件一样独立升级:

  • 新增 Skill 不影响已有 Skill。
  • 更新 Skill 不打断正在执行的任务。
  • 出问题可以只回滚某个 Skill。
  • 不同项目可以暂时使用不同版本。

这很适合多租户 Agent 平台,但前提是底层隔离做得足够好。

难点在哪里

第一个难点是依赖隔离

两个 Skill 可能依赖同一个库的不同版本。如果共享同一套运行环境,新版本可能把旧版本冲坏。解决办法是给 Skill 独立运行空间,至少做到依赖、配置和资源边界清楚。

第二个难点是状态一致

一个任务开始时使用 Skill v1,执行到一半时 v2 发布了。这个任务应该继续用 v1,而不是中途切到 v2。否则同一个任务前后行为可能不一致。

第三个难点是资源清理

Skill 可能打开连接、启动定时器、注册事件监听器。卸载时如果不清理,系统会慢慢泄漏资源。热加载系统一定要有 startstopdispose 这类生命周期钩子。

第四个难点是失败隔离

新 Skill 加载失败,不能拖垮整个平台。某个 Skill 执行异常,也不应该影响其他 Skill。

正确生命周期

热加载应该像一次小型发布,而不是直接覆盖文件。

Skill 热加载发布生命周期
热加载要先校验,再影子运行,再切流,最后观察和保留回滚路径。

推荐流程如下。

第一步,上传新版本。平台先保存新版本,但不立即使用。

第二步,静态校验。检查 manifest、权限声明、依赖版本、输入输出格式、危险操作。

第三步,加载到隔离环境。新版本在独立空间启动,不能直接影响线上流量。

第四步,影子运行。拿真实输入跑新版本,但真实结果仍然使用旧版本。比较两边差异。

第五步,小流量切换。先让少量任务使用新版本,观察错误率、耗时和用户反馈。

第六步,全量切换。确认稳定后,新任务使用新版本。老任务继续用启动时绑定的版本。

第七步,延迟卸载旧版本。等老任务结束后,再释放旧版本资源。

怎么回滚

回滚要提前设计,不能出事后再想。

一个可回滚的 Skill 平台至少要做到:

  • 每个 Skill 版本都有唯一编号。
  • 新旧版本可以短时间共存。
  • 路由层可以把新任务切回旧版本。
  • 已经执行中的任务不强行迁移。
  • 回滚后能验证核心功能是否恢复。

回滚触发条件也要写清楚。比如:

  • 错误率超过 5%。
  • P95 耗时超过旧版本 2 倍。
  • 人工接管率明显上升。
  • 出现安全或权限异常。

这些阈值不一定固定,但一定要提前定义。

什么时候不要用

热加载不是所有系统都需要。

如果你的平台只有少量内部 Skill,发布窗口可控,重启成本也低,普通发布流程可能更简单。

如果 Skill 会修改数据库结构、改变核心权限模型、影响全局配置,也不适合直接热加载。这类变更需要完整发布流程和人工审批。

如果没有监控、没有版本隔离、没有回滚能力,更不应该在生产环境开放热加载。否则你只是把“重启风险”换成了“运行时不可控风险”。

结论

Skill 热加载的核心不是加载,而是安全地替换能力。

能不能加载新文件只是第一步。真正决定质量的是:旧任务怎么处理、依赖怎么隔离、资源怎么释放、失败怎么回滚。把这些问题想清楚,热加载才是平台能力;想不清楚,它就是线上事故入口。