开发实践 / Spring AI 实战

Spring AI 2.0 Agent Skills:接入 Nacos,跑通热更新与回滚

接入 Nacos Skill Registry,集中维护 Skill,理解多实例场景下的热更新与版本回滚。

大家好,我是一言,继续更新 Spring AI 2.0 系列。

前两篇,我们用 SKILL.md 编排了订单操作,又把退款规则、计算脚本和客服模板拆进了 Skill 目录。

这些 Skill 都放在项目本地。Agent 部署成多个实例后,规则更新要重新发版,各实例还可能加载不同版本。

Nacos 3.2 开始提供 Skill Registry,可以集中存储、审核、发布和分发 Skill。这篇继续订单退款案例,只跑 Skill 的交付链路。

整个测试过程中 Java 进程没有重启:

Nacos Skill 热更新与回滚:stable 从 1.0.0 切换到 1.1.0,Spring AI 重建 SkillsTool,再切回 1.0.0 完成回滚|
Nacos Skill 热更新与回滚:stable 从 1.0.0 切换到 1.1.0,Spring AI 重建 SkillsTool,再切回 1.0.0 完成回滚|

Nacos 管版本,SkillsTool 管加载#

Nacos Skill Registry 负责 Skill 包、版本和标签,SkillsTool 负责把 Skill 暴露给模型。两者之间的 Java 适配由本文实现:

text
Nacos → ZIP / 变更事件 → Java 适配 → SkillsTool → ChatClient

实测版本为 Java 21、Spring AI 2.0.1、spring-ai-agent-utils 0.12.0 和 Nacos 3.2.3。

我发布了同一个 order-refund Skill 的两个版本:

版本 退款规则
1.0.0 统一进入标准审核
1.1.0 金额达到 200 元时进入 MANAGER_REVIEW
Nacos 3.2.3 Skill 管理:order-refund 已启用,当前版本为 1.1.0,共有两个上线版本
Nacos 3.2.3 Skill 管理:order-refund 已启用,当前版本为 1.1.0,共有两个上线版本

stable 可以理解成一个“当前使用版本”的开关。把它从 1.0.0 拨到 1.1.0,应用会自动换上新规则;新规则有问题,再拨回 1.0.0。整个过程不用重启应用。

Spring 应用订阅 stable#

java
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
properties.setProperty(PropertyKeyConst.NAMESPACE, "public");
properties.setProperty("nacosAiTransportMode", "http");

AiService aiService = AiFactory.createAiService(properties);
ReloadableSkillTool reloadableSkill = new ReloadableSkillTool();

AbstractNacosSkillListener listener = new AbstractNacosSkillListener() {
    @Override
    public void onEvent(NacosSkillEvent event) {
        reloadableSkill.replace(buildSkill(event.getZipBytes()));
    }
};

byte[] initialZip = aiService.subscribeSkill(
        "order-refund", null, "stable", listener);

if (initialZip == null) {
    throw new IllegalStateException("stable Skill not found");
}
reloadableSkill.replace(buildSkill(initialZip));

订阅成功时,subscribeSkill 返回当前 ZIP;Skill 不存在时可能返回 null。标签指向或包内容发生变化后,监听器会收到新 ZIP、resolvedVersion 和 md5。

完成本文的回滚测试后,两个版本仍处于上线状态,stable 已重新指向 1.0.0。

Nacos 3.2.3 版本历史:1.0.0 和 1.1.0 均已上线,stable 标签指向 1.0.0
Nacos 3.2.3 版本历史:1.0.0 和 1.1.0 均已上线,stable 标签指向 1.0.0

buildSkill 将 ZIP 解压到新目录,再构建一个 SkillsTool:

java
ToolCallback buildSkill(byte[] zipBytes) {
    Path skillDirectory = unzipAndValidate(zipBytes);
    return SkillsTool.builder()
            .addSkillsDirectory(skillDirectory.toString())
            .build();
}

ChatClient 只注册一次 reloadableSkill:

java
ChatClient chatClient = builder
        .defaultToolCallbacks(reloadableSkill)
        .build();

ReloadableSkillTool 内部用 AtomicReference<ToolCallback> 保存当前 SkillsTool。它的元数据和调用方法都转发给当前对象,版本变化时只执行一次 current.set(next)。

实测遇到两个坑#

第一个是传输模式。Nacos 3.2.3 的 AiService 默认选择 gRPC,这个版本的 Skill 查询会直接报错:

text
ErrCode:501
Skill query is only supported via HTTP transport.

在 3.2.3 里要显式切到 HTTP:

java
properties.setProperty("nacosAiTransportMode", "http");

第二个是 SkillsTool 的加载时机。Builder 会读取 Skill 元数据和正文,已构建的 Tool 会继续使用旧内容。收到新 ZIP 后,要重建 SkillsTool 并替换 delegate。

真实 Nacos 跑一次#

Nacos 控制台可以直接比较两个版本。这个案例只修改了 SKILL.md,Diff 标出了 refund-v1 到 refund-v2,以及新增的 200 元审核规则。

Nacos 3.2.3 版本 Diff:对比 order-refund 1.0.0 与 1.1.0,SKILL.md 新增 200 元以上进入 MANAGER_REVIEW 的规则
Nacos 3.2.3 版本 Diff:对比 order-refund 1.0.0 与 1.1.0,SKILL.md 新增 200 元以上进入 MANAGER_REVIEW 的规则

我在本地启动 Nacos 3.2.3,通过真实 Console API 发布两个版本,再用真实 Java SDK 订阅 stable:

bash
RUN_NACOS_TEST=true mvn \
  -Dtest=NacosSkillRegistryIntegrationTest test

实测跑完了首次加载、热更新和回滚三步:

Nacos Skill 热更新实测流程:stable 从 1.0.0 切到 1.1.0,重建 SkillsTool 后加载 refund-v2,再切回 1.0.0 完成回滚
Nacos Skill 热更新实测流程:stable 从 1.0.0 切到 1.1.0,重建 SkillsTool 后加载 refund-v2,再切回 1.0.0 完成回滚
Nacos Skill 集成测试:stable 标签完成 1.0.0、1.1.0 切换和回滚,刷新后 SkillsTool 读到新规则,JUnit 返回 BUILD SUCCESS
Nacos Skill 集成测试:stable 标签完成 1.0.0、1.1.0 切换和回滚,刷新后 SkillsTool 读到新规则,JUnit 返回 BUILD SUCCESS

这次测试只验证 Nacos 发布、ZIP 分发、变更事件和 SkillsTool 刷新。模型选择 Skill 和调用 Tool 的链路,前两篇已经跑过。

最后#

单个应用、少量 Skill,继续放本地目录就够了。

多实例、多环境或多团队共用 Skill 时,Nacos 可以统一发布、按标签升级和快速回滚。更新 Skill 时,应用端不需重新打包。

Skill 的执行质量仍然取决于流程、Tool 和模型。Nacos 解决了一套 Skill 怎么稳定地交付给多个 Agent。

参考资料#

  • Nacos 官方:Skill Registry
  • Nacos 官方:Java SDK Skill 用法
  • Spring Blog:Agent Skills 在 Spring AI 中的实现
  • Nacos 3.2.3:NacosAiService
  • Nacos 3.2.3:AiGrpcClient

公众号同名

微信搜索「雷一言说」

关注公众号,继续看我的文章。

手机阅读时,可以保存二维码后在微信中识别。

雷一言说微信公众号二维码
扫码关注公众号