Nacos AI 资源生命周期管理规范深度解析:从草稿到在线的版本状态机与发布流水线
导读
本文围绕 AI 资源生命周期规范 展开,系统讲解 Nacos AI 注册中心(AI Registry)中版本化 AI 资源(Agent、AgentSpec、Skill、Prompt、MCP Server 等)的通用生命周期规则:从 draft 草稿、reviewing 审核、reviewed 待发布到 online 在线,再到 offline 下线的完整状态机。文章不仅完整继承规范中的状态定义、标准流程与操作约束,还结合 ai 模块 的源码实现(CAS 指针管理、流水线结果归一化、latest 标签服务端托管、删除时的存储清理顺序、审计追踪)进行逐层印证。读完本文,你将掌握 Nacos AI 资源的生命周期 API 契约、发布流水线的交互语义,以及如何在源码层面定位每个状态迁移的具体实现。
1. 为什么需要统一的 AI 资源生命周期
在 Nacos 的 AI 云原生架构中,Agent、AgentSpec、Skill、Prompt、MCP Server 等 AI 资源都具有"版本化"的共性需求:内容需要反复编辑、经过审核后发布、按标签路由、支持下线与回滚。若每种资源各自实现一套版本逻辑,必然导致行为不一致、维护成本飙升。
因此 Nacos 在 AI Registry 之上定义了一套跨类型的通用生命周期规则,即本规范。各类型专属规范(如 Agent 管理规范、MCP Server 规范)只在此基础上做细化,不得随意打破通用语义。例如,Agent 类型只为兼容旧的 A2A 直连上线门面做了例外,MCP 类型也只为其历史 API 版本保留了一个受审计的兼容通道——这些例外都被显式声明,而不是悄悄改规则。
2. 状态模型:元数据状态与版本状态的双层设计
生命周期规范将状态分为两层:元数据(Metadata)状态与版本(Version)状态。二者职责完全不同,一个描述"资源整体是否可用",一个描述"某个具体版本处于什么阶段"。
2.1 元数据状态
| 状态 | 含义 |
|---|---|
enable |
资源可见且至少存在一个可查询版本时,该资源可用。 |
disable |
资源在元数据层面被禁用;具体查询行为由类型规范定义。 |
在源码中,这两个常量定义于 AiResourceConstants.java:
public static final String META_STATUS_ENABLE = "enable";
public static final String META_STATUS_DISABLE = "disable";
元数据启用/禁用操作通过 CAS 更新元数据行,且不触碰版本信息,见 AiResourceManager.java 中 metaEnableDisable 的实现:冲突刷新回调只保留 desc、bizTags、ext 字段,明确排除 versionInfo。
2.2 版本状态
| 状态 | 含义 |
|---|---|
draft |
正在编辑、尚未提交的版本。 |
reviewing |
已提交,正在等待发布流水线(publish pipeline)审核。 |
reviewed |
流水线审核已完成,等待显式的 publish、force-publish、redraft 或重新 submit。 |
online |
已发布,可被查询。 |
offline |
已从常规运行时路由中移除的既有版本。 |
对应常量同样集中在 AiResourceConstants.java:VERSION_STATUS_ONLINE、VERSION_STATUS_DRAFT、VERSION_STATUS_REVIEWING、VERSION_STATUS_REVIEWED、VERSION_STATUS_OFFLINE。状态判定工具方法(isDraftVersion、isReviewingVersion、isReviewedVersion)位于 AiResourceManager.java。
3. 标准生命周期流程
规范的完整标准流程如下:
create/upload draft
-> update draft
-> submit
-> reviewing
-> reviewed
-> publish
-> online
-> offline/online toggle or delete
关键点在于 submit 与 publish 是两个分离的动作:
- submit 把版本送入审核流程(进入
reviewing); - publish 把已审核版本真正发布为
online。
无流水线直发:如果未启用发布流水线,或流水线中没有匹配该资源类型的节点,则根据类型实现,submit 可能直接完成发布。这一语义为小型部署(无需人工审核)保留了轻量路径。
force-publish(强制发布):绕过流水线校验,必须作为管理操作保留。它只接受 draft、reviewing、reviewed 三种状态的版本;对 online 和 offline 版本必须拒绝。
在源码中,直接发布(绕过流水线)由 directPublishVersion 实现(AiResourceManager.java),其原子化地完成四件事:
- 将版本行状态更新为
online; - 清空指向该版本的
editingVersion/reviewingVersion指针; onlineCnt自增(为null时初始化为 1);- 在标签映射中写入
latest指向该版本。
public void directPublishVersion(String namespaceId, AiResource meta, ResourceVersionInfo info,
String version, boolean updateLatestLabel) throws NacosException {
// 1. 版本行置为 online
aiResourceVersionPersistService.updateStatus(namespaceId, name, type, version,
AiResourceConstants.VERSION_STATUS_ONLINE);
// 2-4. CAS 更新版本信息:清指针、onlineCnt++、latest 标签
updateVersionInfoCas(namespaceId, meta, info, latestInfo -> {
if (StringUtils.equals(latestInfo.getEditingVersion(), version)) {
latestInfo.setEditingVersion(null);
}
if (StringUtils.equals(latestInfo.getReviewingVersion(), version)) {
latestInfo.setReviewingVersion(null);
}
Integer cnt = latestInfo.getOnlineCnt();
latestInfo.setOnlineCnt(cnt == null ? 1 : (cnt + 1));
if (latestInfo.getLabels() == null) {
latestInfo.setLabels(new HashMap<>(4));
}
latestInfo.getLabels().put(AiResourceConstants.LABEL_LATEST, version);
return latestInfo;
});
}
updateLatestLabel 参数被注释为"为兼容而保留并忽略,latest 始终更新"——这与规范中"该参数已废弃,新客户端不得发送"的要求一致。
4. 草稿规则:一个资源至多一个工作草稿
草稿是版本生命周期的起点,规范规定了以下行为:
- 一个资源最多应有一个工作草稿,除非类型规范定义了覆盖(overwrite)或多草稿行为;
- 创建草稿可以新建一条元数据行,也可以从某个 online 版本 fork 出来;
- 草稿更新只能修改当前草稿版本,不能误改其他版本;
- 删除草稿会清空元数据中的
editingVersion指针,并删除草稿版本行及其存储内容; - 上传(upload)操作可能因类型而异,但除非是显式的 bootstrap/import 操作,否则也应产生草稿版本。
editingVersion 指针与 reviewingVersion、onlineCnt、labels 一起构成资源版本信息的核心结构,定义在 ResourceVersionInfo.java:
public class ResourceVersionInfo {
private String editingVersion; // 当前工作草稿指针
private String reviewingVersion; // 正在审核的版本指针
private Integer onlineCnt; // 累计在线版本数
private Map<String, String> labels; // 版本标签映射
}
创建草稿时通过 markEditingVersionCas(AiResourceManager.java)以 CAS 方式写入 editingVersion:冲突重试时会重新读取最新版本信息并再次校验"未出现工作版本",从而保证并发生命周期/标签更新不会被过期版本信息覆盖。
requireDraftVersion(AiResourceManager.java)则强制要求目标版本处于 draft 状态,否则抛出 INVALID_PARAM 级别的 NacosApiException,错误信息为 "Current editing version is not draft: " + version。
5. 审核与发布规则:最复杂的状态迁移语义
这是整个规范的核心章节,包含了提交、重提、幂等、latest 标签、兼容投影等大量细节。
5.1 Submit 的目标解析与合法性
- Submit 解析目标版本的顺序为:显式指定的版本 → 当前
editingVersion→reviewing或reviewed状态下的reviewingVersion; - 无 draft、reviewing 或 reviewed 目标时必须失败;
- Submit 接受
draft、reviewing、reviewed三种状态的目标:draft/reviewed目标进入审核/直发流程;reviewed目标视为重新提交(resubmission),必须经过流水线,不得绕过流水线直接进入发布流程;reviewing目标是幂等空操作,直接返回当前版本,不重复启动流水线;
- 对
online或offline版本调用 submit 必须返回INVALID_PARAM,且不得变更版本状态或元数据指针。
resolveSubmitTarget 的实现(AiResourceManager.java)严格遵循上述解析顺序,找不到目标时抛出 NOT_FOUND:
public String resolveSubmitTarget(ResourceVersionInfo info, String version, String type,
String name) throws NacosException {
String target = version;
if (StringUtils.isBlank(target)) {
target = info.getEditingVersion();
}
if (StringUtils.isBlank(target)) {
target = info.getReviewingVersion();
}
if (StringUtils.isBlank(target)) {
throw new NacosApiException(NacosException.NOT_FOUND, ErrorCode.RESOURCE_NOT_FOUND,
"No draft, reviewing, or reviewed version to submit for " + type + ": " + name);
}
return target;
}
requireSubmitVersion(AiResourceManager.java)负责合法性校验:只允许 draft、reviewing、reviewed 三种状态被提交。
5.2 中断完成迁移的归一化与历史流水线结果
规范处理了一个易被忽视的边界情况:
- 停留在
reviewing版本上的当前终态流水线结果(APPROVED或REJECTED),被视为一次"被中断的完成迁移"(即流水线已落库结果但未完成状态迁移),在重新提交前归一化为reviewed; - 标记为
historical=true的结果属于上一轮审核周期,不得用于完成当前审核,此时 submit 保持幂等。
这一定义与 PublishPipelineInfo.java 中的 historical 字段一一对应——该字段的 Javadoc 明确写道:"为 true 时,流水线结果不得用于 draft 版本的 force-publish 资格判定":
public class PublishPipelineInfo {
private String executionId;
private PipelineExecutionStatus status; // IN_PROGRESS / APPROVED / REJECTED 等
private List<PipelineNodeResult> pipeline;
private Boolean historical; // 是否属于上一轮审核周期
}
prepareSubmitVersion(AiResourceManager.java)实现了归一化逻辑:仅当版本处于 reviewing、流水线信息非空且非 historical、状态为终态的 APPROVED 或 REJECTED 时,才把版本行更新为 reviewed。
5.3 审核中的指针与流水线状态落库
- 处于审核中的版本必须在元数据中记录为
reviewingVersion; - 流水线执行状态可写入
publishPipelineInfo与pipeline_execution; - 审核通过与拒绝的结果都会把版本迁移到
reviewed;被拒绝后如需继续编辑,用户必须显式 redraft 该版本。
moveToReviewing(AiResourceManager.java)在把版本置为 reviewing 的同时,通过 CAS 确保没有其他工作版本存在,将 editingVersion 清空并写入 reviewingVersion,最后发出 SUBMIT_REVIEW 追踪事件。流水线启动时则调用 writePipelineInfoInProgress(AiResourceManager.java)写入 IN_PROGRESS 状态的执行记录;流水线不可用的边界情况由 clearPipelineInfo 清空流水线信息。
5.4 Publish 的状态迁移与 latest 标签管理
发布操作将版本置为 online、清空工作指针、按需递增 onlineCnt,并由服务端根据资源类型规范管理 latest 标签。规范对 latest 的默认规则是:
- 除非类型规范定义了确定性细化,成功发布或上线后目标版本即成为
latest; - 当当前 latest 版本被删除或下线时,默认替换为剩余版本号最大的在线版本;若无在线版本,服务端移除
latest; - 类型细化仍必须保持
latest由服务端管理、指向在线版本,并定义删除/下线回退。
从源码看,doPublish(AiResourceManager.java)与 directPublishVersion 均以 CAS 方式统一维护 latest 标签,服务端托管语义贯穿始终。updateLatestLabel 仅为历史兼容保留,新客户端不应发送。
5.5 兼容性投影与收敛失败重试
规范针对"独立兼容性服务投影"(separate compatibility serving projection)给出了强一致约束:
- 生命周期行是持久化的期望状态(durable desired state);
- 投影收敛跟随生命周期变更,投影校验通过后操作才报告成功;
- 收敛失败时保留生命周期行,以便幂等重试或 reconciler 完成投影。
这一"先留行、后清理、失败可重试"的锚点思想,同样贯穿第 6 节的删除规则。
5.6 类型规范的两处兼容例外
规范明确了两类类型的兼容性门面,均为审计过的例外,不得扩散到标准 API:
- Agent 类型:仅在其遗留 A2A 直连上线门面上,
setAsLatest=false可保留当前有效指针;标准 Agent 发布/上线仍移动latest,删除或下线当前指针时选择剩余最大的在线 Agent 版本。详见 Agent 管理规范 与 A2A Agent 规范。 - MCP 类型:历史 API 的 Version 会立即变为 online,其遗留 latest 标志可保留当前有效指针;历史更新门面还可能覆盖已存在的精确 Version(受审计的例外),但规范的 draft/lifecycle API 绝不复用这一放宽。标准 MCP 发布、强制发布、上线仍移动
latest;latest 回退优先级为:最大 SemVer → 最大数字vN→ 最大稳定大小写敏感字符串。详见 MCP Server 规范。
流水线的扩展行为由 AI 发布流水线插件规范 定义,本域规范只负责说明 AI 资源生命周期如何响应流水线结果。
6. 标签(Labels)规则
latest是保留的默认标签,指向最新发布版本;latest由服务端管理:手动标签更新请求可出于兼容性包含latest,但服务端必须忽略客户端提供的latest值,并把当前服务端管理的latest值合并回有效标签映射;- 标签映射到版本字符串,不得指向
draft或reviewing版本; - 修改标签本身不改变版本内容或版本状态;
- 按标签的运行时查询必须在请求时实时解析标签。
常量 LABEL_LATEST = "latest" 定义于 AiResourceConstants.java。标签语义与版本信息中的 labels 字段(ResourceVersionInfo.java)配合,所有标签变更都发生在 draft/reviewing 之外的安全边界上。
7. 删除规则:先清存储,后删元数据
删除是生命周期中风险最高的操作,规范给出的顺序约束非常严格:
- 删除版本:应移除该版本行与类型持有的该版本存储;
- 删除资源:应移除元数据、全部版本行与全部类型持有的存储;
- 删除资源前必须加载每个 Version 的存储描述符,存储清理必须路由到每个描述符中持久化的 provider,并尝试清理所有被引用的内容对象;
- 加载完所有描述符后,类型可先把 Resource 及其 Versions 移到非服务生命周期状态,再收敛外部兼容投影、开始物理清理;保留的行是清理完成前的持久化重试锚点;
- 元数据与 Version 行只有在所有被引用存储内容成功清理后才能删除;任何清理失败都必须报告失败并保留可重试的行与描述符;
- 删除操作仅在公共 API 契约声明"资源缺失即成功"时才是幂等的;
- 删除在线版本时,若类型实现支持,应更新
onlineCnt或标签; - 类型持有的物理清理必须参与类型存储删除回调,并在元数据行移除前完成。特别地,MCP 持有的 Direct Naming 清理与 MCP Version Config 清理遵循同样的"行保留"规则:任一失败都将删除报告为未完成,并保留 Resource/Version 行与描述符供重试。普通被引用的 Service 与客户端持有的 Runtime 状态不是类型持有的清理目标。
在 AiResourceManager.java 中可以看到 deleteVersion、deleteVersionsByNameAndType、deleteMeta 三个删除入口的并列设计,印证了"版本级删除 / 批量版本删除 / 元数据删除"三种粒度各自独立、按序执行的架构。
8. 追踪与计数器:全操作审计
8.1 应追踪的操作清单
AI 资源操作应为以下动作发出 trace/audit 事件:
创建草稿(create draft)、更新草稿(update draft)、提交(submit)、审核通过/拒绝(review approved/rejected)、发布(publish)、强制发布(force publish)、上线/下线(online/offline)、删除(delete)、标签更新(label update)、描述更新(description update)、作用域更新(scope update)以及下载(download)。
在 AiResourceTraceService.java 中,这些操作被一一映射为字符串常量:OP_CREATE_DRAFT、OP_UPDATE_DRAFT、OP_DELETE_DRAFT、OP_UPLOAD、OP_SUBMIT_REVIEW、OP_REVIEW_APPROVED、OP_REVIEW_REJECTED、OP_REVIEW_FORCE_SKIP、OP_REDRAFT、OP_PUBLISH、OP_FORCE_PUBLISH、OP_OFFLINE_VERSION、OP_ONLINE_VERSION、OP_DELETE_VERSION、OP_DELETE_RESOURCE、OP_SET_LABEL、OP_REMOVE_LABEL、OP_UPDATE_LABELS、OP_UPDATE_SCOPE、OP_UPDATE_DESCRIPTION、OP_UPDATE_BIZ_TAGS、OP_UPDATE_RESOURCE、OP_ENABLE、OP_DISABLE 等。
8.2 追踪事件与默认落盘
AI 资源追踪使用 AiResourceTraceEvent。该事件类定义于 common 模块,字段包括:
public class AiResourceTraceEvent extends TraceEvent {
private final String operator; // 操作者
private final String resourceType; // 资源类型
private final String resourceId; // 资源 ID
private final String version; // 版本
private final String operation; // 操作
private final String status; // 状态
private final String clientIp; // 客户端 IP
private final String ext; // 扩展信息
}
默认的 AI 资源追踪插件将 JSON 行审计日志写入 ai-resource-trace.log,同时允许外部追踪订阅者消费同一事件流。日志滚动配置在 distribution/conf/nacos-logback.xml 中,输出文件为 ${LOG_HOME}/ai-resource-trace.log,按天与序号滚动(ai-resource-trace.log.%d{yyyy-MM-dd}.%i)。典型日志行格式如下(来自 AiResourceTraceService.java 的 Javadoc 示例):
{"timestamp":"2026-03-30T10:15:30Z","operator":"admin","resource_type":"skill",
"resource_id":"my-skill","version":"v1.0","operation":"PUBLISH",
"status":"SUCCESS","ip":"192.168.1.1"}
该 JSON 行格式专为 ELK/Loki 等日志采集链路设计。追踪插件的扩展行为由 追踪插件规范 定义。计数器仅用于诊断,不得用于定义授权或生命周期状态——这是规范划出的一条硬边界:审计与指标永远只是观察者,不能反过来成为状态机的输入。
9. 演进说明:状态机的未来扩展
规范在结尾明确指出,随着 AI 发布工作流成熟,生命周期状态可能扩展,例如支持:
- 审批链(approval chains)
- 分阶段发布(staged rollout)
- 策略评估(policy evaluation)
- 签名(signing)
- 制品扫描(artifact scanning)
所有新状态都必须定义与既有 draft、reviewing、reviewed、online、offline 行为的兼容性。这意味着现有状态机是一个"可演进的核心",任何扩展都不能破坏既有 API 契约与存量资源的状态迁移路径。
10. 实践要点小结
- 两态分离:
enable/disable管资源可用性,五个版本状态管版本阶段,二者互不干扰; - 提交与发布分离:
submit进流水线,publish真正上线;无流水线时 submit 可直接直发; - reviewed 是"待命"态:审核通过/拒绝后版本停在
reviewed,用户必须显式触发发布、强制发布、redraft 或重新提交; - reviewing 提交是幂等的:重复 submit 不会重复启动流水线;历史流水线结果(
historical=true)不会完成当前审核; - latest 永远服务端托管:客户端提供的
latest值一律被忽略,删除/下线时的回退规则由服务端统一执行; - 删除先清存储后删行:所有版本存储描述符加载完毕、物理清理成功之后,才允许删除元数据与版本行,失败即保留行以待重试;
- 全操作审计:从创建草稿到下载的每个动作都产出
AiResourceTraceEvent,默认落到ai-resource-trace.log,便于审计与可观测性接入。
如需进一步深入,可继续阅读 Agent 管理规范、MCP Server 规范、AI 发布流水线插件规范,或直接研读 AiResourceManager.java 中从 markEditingVersionCas 到 doPublish 的完整状态机实现。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00