【微服务】【Nacos 3】 ② 深度解析:AI模块介绍

📖目录

  • 前言
  • [1. Nacos AI 模块概述](#1. Nacos AI 模块概述)
  • [2. 核心组件详解](#2. 核心组件详解)
    • [2.1 MCP (Model Control Plane)](#2.1 MCP (Model Control Plane))
    • [2.2 A2A (Agent to Agent)](#2.2 A2A (Agent to Agent))
  • [3. 关键源码剖析](#3. 关键源码剖析)
    • [3.1 模型服务注册流程](#3.1 模型服务注册流程)
    • [3.2 代理通信处理流程](#3.2 代理通信处理流程)
  • [4. 架构设计亮点](#4. 架构设计亮点)
    • [4.1 分层架构设计](#4.1 分层架构设计)
    • [4.2 缓存机制优化](#4.2 缓存机制优化)
    • [4.3 插件化设计](#4.3 插件化设计)
  • [5. 使用场景](#5. 使用场景)
    • [5.1 微服务AI治理](#5.1 微服务AI治理)
    • [5.2 多模型版本管理](#5.2 多模型版本管理)
    • [5.3 跨域代理通信](#5.3 跨域代理通信)
  • [6. 未来发展趋势](#6. 未来发展趋势)
    • [6.1 AI服务网格集成](#6.1 AI服务网格集成)
    • [6.2 智能负载均衡](#6.2 智能负载均衡)
    • [6.3 自动扩缩容](#6.3 自动扩缩容)
  • [7. 结语与学习建议](#7. 结语与学习建议)
      • [7.1. 动手实践(快速搭建本地环境)](#7.1. 动手实践(快速搭建本地环境))
      • [7.2. 调试技巧](#7.2. 调试技巧)
      • [7.3. 延伸阅读](#7.3. 延伸阅读)
  • [📝 版权声明](#📝 版权声明)

前言

📌 文章说明:本文基于 Nacos 3.x 最新版本(截至 2025 年),深入介绍 Nacos AI 模块的设计理念、核心组件以及关键功能,帮助读者了解如何利用 Nacos 管理 AI 模型服务。适合对 AI 服务治理感兴趣的中高级 Java 后端开发者和架构师阅读。

🔖 关键词:#Nacos #AI服务治理 #MCP #A2A #模型管理 #Nacos3.x #源码解析

1. Nacos AI 模块概述

Nacos AI 模块是 Nacos 3.x 中新增的一个重要功能模块,旨在为 AI 模型服务提供统一的服务发现、配置管理和治理能力。该模块主要包括两个子系统:

  • MCP (Model Control Plane):模型控制平面,用于管理 AI 模型的注册、发现和配置
  • A2A (Agent to Agent):代理间通信系统,支持 AI 代理之间的通信和协调

首先需要纠正一个认知:Nacos 3.x 目前没有独立的 "AI 模块",而是将 AI 相关能力(如服务健康度 AI 预测、配置异常 AI 诊断等)嵌入到核心模块中(如服务发现模块 nacos-naming、配置模块 nacos-config),通过依赖轻量级 AI 工具包或算法实现,而非单独拆分模块。

这也是为什么你编译后看不到 "AI 字眼" 的核心原因 - 能力已分散在现有模块中,而非集中在独立目录。

2. 核心组件详解

2.1 MCP (Model Control Plane)

MCP 是 AI 模块的核心组件,负责 AI 模型服务的全生命周期管理。

2.1.1 核心功能

  • 模型服务注册与发现
  • 模型版本管理
  • 工具规范定义
  • 端点配置管理
  • 元数据存储与查询

2.1.2 关键类分析

McpServerOperationService

这是 MCP 模块的核心服务类,负责模型服务的操作管理:

java 复制代码
// McpServerOperationService 提供了模型服务的关键操作实现,包含模型服务的注册、查询、更新和删除等方法
public class McpServerOperationService {
    // 创建新的MCP服务器
    public String createMcpServer(String namespaceId, McpServerBasicInfo serverSpecification,
            McpToolSpecification toolSpecification, McpEndpointSpec endpointSpecification) throws NacosException {

        // 解析存在的MCP服务器ID
        String existId = resolveMcpServerId(namespaceId, serverSpecification.getName(), StringUtils.EMPTY);
        // 如果存在ID不为空
        if (StringUtils.isNotEmpty(existId)) {
            // 抛出资源冲突异常
            throw new NacosApiException(NacosApiException.CONFLICT, ErrorCode.RESOURCE_CONFLICT,
                    String.format("mcp server `%s` has existed, please update it rather than create.",
                            serverSpecification.getName()));
        }

        // 获取版本详情
        ServerVersionDetail versionDetail = serverSpecification.getVersionDetail();
        // 如果版本详情为空且版本不为空
        if (null == versionDetail && StringUtils.isNotBlank(serverSpecification.getVersion())) {
            // 创建版本详情对象
            versionDetail = new ServerVersionDetail();
            // 设置版本
            versionDetail.setVersion(serverSpecification.getVersion());
            // 设置版本详情
            serverSpecification.setVersionDetail(versionDetail);
        }
        // 如果版本详情为空或版本为空
        if (Objects.isNull(versionDetail) || StringUtils.isEmpty(versionDetail.getVersion())) {
            // 抛出参数验证异常
            throw new NacosApiException(NacosApiException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
                    "Version must be specified in parameter [serverSpecification](file:///Users/zhiyixie/Downloads/work_space/码云/Nacos/ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpDetailForm.java#L35-L35)");
        }
        // 声明ID
        String id;
        // 获取自定义MCP ID
        String customMcpId = serverSpecification.getId();

        // 如果自定义MCP ID为空
        if (StringUtils.isEmpty(customMcpId)) {
            // 生成随机UUID作为ID
            id = UUID.randomUUID().toString();
        } else {
            // 如果自定义MCP ID不是UUID字符串
            if (!StringUtils.isUuidString(customMcpId)) {
                // 抛出参数验证异常
                throw new NacosApiException(NacosApiException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
                        "parameter `serverSpecification.id` is not match uuid pattern,  must obey uuid pattern");
            }
            // 如果通过ID获取的MCP服务器不为空
            if (mcpServerIndex.getMcpServerById(serverSpecification.getId()) != null) {
                // 抛出参数验证异常
                throw new NacosApiException(NacosApiException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
                        "parameter `serverSpecification.id` conflict with exist mcp server id");
            }

            // 设置ID为自定义MCP ID
            id = customMcpId;
        }

        // 设置服务器规范的ID
        serverSpecification.setId(id);
        // 获取当前UTC时间
        ZonedDateTime currentTime = ZonedDateTime.now(ZoneOffset.UTC);
        // 创建日期时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Constants.RELEASE_DATE_FORMAT);
        // 格式化当前时间
        String formattedCurrentTime = currentTime.format(formatter);
        // 设置版本详情的发布日期
        versionDetail.setRelease_date(formattedCurrentTime);

        // 创建新的服务器规范对象
        McpServerStorageInfo newSpecification = new McpServerStorageInfo();
        // 复制属性
        BeanUtils.copyProperties(serverSpecification, newSpecification);
        // 注入工具和端点
        injectToolAndEndpoint(namespaceId, serverSpecification.getId(), newSpecification, toolSpecification,
                endpointSpecification, Boolean.FALSE);

        // 构建服务器版本信息
        McpServerVersionInfo versionInfo = buildServerVersionInfo(newSpecification, id, versionDetail);

        // 创建配置请求信息
        ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
        // 设置不更新已存在的配置
        configRequestInfo.setUpdateForExist(Boolean.FALSE);

        // 构建MCP服务器版本表单
        ConfigFormV3 mcpServerVersionForm = buildMcpServerVersionForm(namespaceId, versionInfo);
        // 发布配置
        configOperationService.publishConfig(mcpServerVersionForm, configRequestInfo, null);

        // 构建MCP配置表单
        ConfigForm configForm = buildMcpConfigForm(namespaceId, id, versionDetail.getVersion(), newSpecification);
        // 记录操作开始时间
        long startOperationTime = System.currentTimeMillis();
        // 发布配置
        configOperationService.publishConfig(configForm, configRequestInfo, null);
        // 同步效果服务
        syncEffectService.toSync(configForm, startOperationTime);

        // 在成功的数据库操作后删除相关缓存
        invalidateCacheAfterDbOperation(namespaceId, serverSpecification.getName(), id);

        // 返回ID
        return id;
    }

    // 更新已存在的MCP服务器
    public void updateMcpServer(String namespaceId, boolean isPublish, McpServerBasicInfo serverSpecification,
            McpToolSpecification toolSpecification, McpEndpointSpec endpointSpecification, boolean overrideExisting) throws NacosException {

        // 获取MCP服务器ID
        String mcpServerId = serverSpecification.getId();
        // 解析MCP服务器ID
        mcpServerId = resolveMcpServerId(namespaceId, serverSpecification.getName(), mcpServerId);
        // 如果服务器规范的ID为空
        if (StringUtils.isEmpty(serverSpecification.getId())) {
            // 设置服务器规范的ID
            serverSpecification.setId(mcpServerId);
        }

        // 获取版本详情
        ServerVersionDetail versionDetail = serverSpecification.getVersionDetail();
        // 如果版本详情为空且版本不为空
        if (null == versionDetail && StringUtils.isNotBlank(serverSpecification.getVersion())) {
            // 创建版本详情对象
            versionDetail = new ServerVersionDetail();
            // 设置版本
            versionDetail.setVersion(serverSpecification.getVersion());
            // 设置版本详情
            serverSpecification.setVersionDetail(versionDetail);
        }
        // 如果版本详情为空或版本为空
        if (Objects.isNull(versionDetail) || StringUtils.isEmpty(versionDetail.getVersion())) {
            // 抛出参数验证异常
            throw new NacosApiException(NacosApiException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
                    "Version must be specified in parameter [serverSpecification](file:///Users/zhiyixie/Downloads/work_space/码云/Nacos/ai/src/main/java/com/alibaba/nacos/ai/form/mcp/admin/McpDetailForm.java#L35-L35)");
        }
        // 获取MCP服务器版本信息
        final McpServerVersionInfo mcpServerVersionInfo = getMcpServerVersionInfo(namespaceId, mcpServerId);

        // 获取更新版本
        String updateVersion = versionDetail.getVersion();
        // 创建新的服务器规范对象
        McpServerStorageInfo newSpecification = new McpServerStorageInfo();
        // 复制属性
        BeanUtils.copyProperties(serverSpecification, newSpecification);
        // 注入工具和端点
        injectToolAndEndpoint(namespaceId, mcpServerId, newSpecification, toolSpecification, endpointSpecification, overrideExisting);

        // 构建MCP配置表单
        ConfigForm configForm = buildMcpConfigForm(namespaceId, mcpServerId, updateVersion, newSpecification);
        // 发布配置
        configOperationService.publishConfig(configForm, new ConfigRequestInfo(), null);

        // 获取版本详情列表
        List<ServerVersionDetail> versionDetails = mcpServerVersionInfo.getVersionDetails();
        // 创建版本集合
        Set<String> versionSet = versionDetails.stream().map(ServerVersionDetail::getVersion)
                .collect(Collectors.toSet());
        // 如果版本集合不包含更新版本
        if (!versionSet.contains(updateVersion)) {
            // 创建版本对象
            ServerVersionDetail version = new ServerVersionDetail();
            // 设置版本
            version.setVersion(updateVersion);
            // 将版本添加到版本详情列表中
            versionDetails.add(version);
            // 设置版本列表
            mcpServerVersionInfo.setVersions(versionDetails);
        }

        // 如果是发布操作
        if (isPublish) {
            // 设置名称
            mcpServerVersionInfo.setName(newSpecification.getName());
            // 设置描述
            mcpServerVersionInfo.setDescription(newSpecification.getDescription());
            // 设置仓库
            mcpServerVersionInfo.setRepository(newSpecification.getRepository());
            // 设置协议
            mcpServerVersionInfo.setProtocol(newSpecification.getProtocol());
            // 设置前端协议
            mcpServerVersionInfo.setFrontProtocol(newSpecification.getFrontProtocol());
            // 设置能力
            mcpServerVersionInfo.setCapabilities(newSpecification.getCapabilities());
            // 设置最新发布版本
            mcpServerVersionInfo.setLatestPublishedVersion(updateVersion);

            // 遍历版本详情列表
            for (ServerVersionDetail detail : versionDetails) {
                // 如果版本详情的版本等于更新版本
                if (detail.getVersion().equals(updateVersion)) {
                    // 获取当前UTC时间
                    ZonedDateTime currentTime = ZonedDateTime.now(ZoneOffset.UTC);
                    // 创建日期时间格式化器
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
                    // 格式化当前时间
                    String formattedCurrentTime = currentTime.format(formatter);
                    // 设置发布日期
                    detail.setRelease_date(formattedCurrentTime);
                    // 设置为最新版本
                    detail.setIs_latest(true);
                    // 跳出循环
                    break;
                } else {
                    // 设置为非最新版本
                    detail.setIs_latest(false);
                }
            }
            // 设置版本列表
            mcpServerVersionInfo.setVersions(versionDetails);
            // 设置是否启用
            mcpServerVersionInfo.setEnabled(newSpecification.isEnabled());
        }

        // 构建MCP服务器版本表单
        ConfigFormV3 mcpServerVersionForm = buildMcpServerVersionForm(namespaceId, mcpServerVersionInfo);
        // 记录操作开始时间
        long startOperationTime = System.currentTimeMillis();
        // 发布配置
        configOperationService.publishConfig(mcpServerVersionForm, new ConfigRequestInfo(), null);
        // 同步效果服务
        syncEffectService.toSync(mcpServerVersionForm, startOperationTime);

        // 在成功的数据库操作后删除相关缓存
        invalidateCacheAfterDbUpdateOperation(namespaceId, mcpServerVersionInfo.getName(),
                serverSpecification.getName(), mcpServerId);
    }

        // 删除已存在的MCP服务器
    public void deleteMcpServer(String namespaceId, String mcpName, String mcpServerId, String version)
            throws NacosException {
        // 解析MCP服务器ID
        mcpServerId = resolveMcpServerId(namespaceId, mcpName, mcpServerId);
        // 获取MCP服务器版本信息
        McpServerVersionInfo mcpServerVersionInfo = getMcpServerVersionInfo(namespaceId, mcpServerId);
        // 创建需要删除的版本列表
        List<String> versionsNeedDelete = new ArrayList<>();
        // 如果版本不为空
        if (StringUtils.isNotEmpty(version)) {
            // 将版本添加到需要删除的版本列表中
            versionsNeedDelete.add(version);
        } else {
            // 将版本详情列表中的版本收集到需要删除的版本列表中
            versionsNeedDelete = mcpServerVersionInfo.getVersionDetails().stream().map(ServerVersionDetail::getVersion)
                    .collect(Collectors.toList());
        }

        // 遍历需要删除的版本列表
        for (String versionNeedDelete : versionsNeedDelete) {
            // 删除MCP工具
            toolOperationService.deleteMcpTool(namespaceId, mcpServerId, versionNeedDelete);
            // 删除MCP服务器端点服务
            endpointOperationService.deleteMcpServerEndpointService(namespaceId, mcpServerVersionInfo.getName() + "::" + versionNeedDelete);
            // 格式化服务器规范信息数据ID
            String serverSpecDataId = McpConfigUtils.formatServerSpecInfoDataId(mcpServerId, versionNeedDelete);
            // 删除配置
            configOperationService.deleteConfig(serverSpecDataId, Constants.MCP_SERVER_GROUP, namespaceId, null, null,
                    "nacos", null);
            // 格式化服务器版本信息数据ID
            String serverVersionDataId = McpConfigUtils.formatServerVersionInfoDataId(mcpServerId);
            // 删除配置
            configOperationService.deleteConfig(serverVersionDataId, Constants.MCP_SERVER_VERSIONS_GROUP, namespaceId,
                    null, null, "nacos", null);
        }

        // 在成功的数据库操作后删除相关缓存
        invalidateCacheAfterDbOperation(namespaceId, mcpName, mcpServerId);
    }
    
        // 获取指定MCP服务器详细信息
    public McpServerDetailInfo getMcpServerDetail(String namespaceId, String mcpServerId, String mcpServerName,
            String version) throws NacosException {
        // 解析MCP服务器ID
        mcpServerId = resolveMcpServerId(namespaceId, mcpServerName, mcpServerId);

        // 获取MCP服务器版本信息
        McpServerVersionInfo mcpServerVersionInfo = getMcpServerVersionInfo(namespaceId, mcpServerId);
        // 如果版本为空
        if (StringUtils.isEmpty(version)) {
            // 获取版本详情列表大小
            int size = mcpServerVersionInfo.getVersionDetails().size();
            // 获取最后一个版本详情
            ServerVersionDetail last = mcpServerVersionInfo.getVersionDetails().get(size - 1);
            // 设置版本为最后一个版本
            version = last.getVersion();
        }

        // 构建查询MCP服务器请求
        ConfigQueryChainRequest request = buildQueryMcpServerRequest(namespaceId, mcpServerId, version);
        // 处理请求获取响应
        ConfigQueryChainResponse response = configQueryChainService.handle(request);
        // 如果配置未找到
        if (McpConfigUtils.isConfigNotFound(response.getStatus())) {
            // 抛出未找到异常
            throw new NacosApiException(NacosApiException.NOT_FOUND, ErrorCode.MCP_SEVER_VERSION_NOT_FOUND,
                    String.format("mcp server `%s` for version `%s` not found", mcpServerId, version));
        }

        // 将响应内容转换为MCP服务器存储信息
        McpServerStorageInfo serverSpecification = JacksonUtils.toObj(response.getContent(),
                McpServerStorageInfo.class);

        // 创建结果对象
        McpServerDetailInfo result = new McpServerDetailInfo();
        // 设置ID
        result.setId(mcpServerId);
        // 设置命名空间ID
        result.setNamespaceId(namespaceId);
        // 复制属性
        BeanUtils.copyProperties(serverSpecification, result);

        // 获取版本详情列表
        List<ServerVersionDetail> versionDetails = mcpServerVersionInfo.getVersionDetails();
        // 获取最新发布版本
        String latestVersion = mcpServerVersionInfo.getLatestPublishedVersion();
        // 遍历版本详情列表
        for (ServerVersionDetail versionDetail : versionDetails) {
            // 设置是否为最新版本
            versionDetail.setIs_latest(versionDetail.getVersion().equals(latestVersion));
        }
        // 设置所有版本
        result.setAllVersions(mcpServerVersionInfo.getVersionDetails());

        // 获取版本详情
        ServerVersionDetail versionDetail = result.getVersionDetail();
        // 设置是否为最新版本
        versionDetail.setIs_latest(versionDetail.getVersion().equals(latestVersion));
        // 设置版本
        result.setVersion(versionDetail.getVersion());

        // 如果工具描述引用不为空
        if (Objects.nonNull(serverSpecification.getToolsDescriptionRef())) {
            // 获取MCP工具
            McpToolSpecification toolSpec = toolOperationService.getMcpTool(namespaceId,
                    serverSpecification.getToolsDescriptionRef());
            // 设置工具规范
            result.setToolSpec(toolSpec);
        }

        // 如果协议不是STDIO
        if (!AiConstants.Mcp.MCP_PROTOCOL_STDIO.equalsIgnoreCase(serverSpecification.getProtocol())) {
            // 注入端点
            injectEndpoint(result);
        }
        // 返回结果
        return result;
    }

}
索引机制

为了提高查询性能,AI 模块实现了多种索引机制:

  • PlainMcpServerIndex: 基础索引实现
  • CachedMcpServerIndex: 带缓存的索引实现
  • MemoryMcpCacheIndex: 内存缓存索引实现

我们这里选择带缓冲的索引实现来查看:

java 复制代码
// CachedMcpServerIndex 结合内存缓存和数据库查询,提升查询性能
public class CachedMcpServerIndex extends AbstractMcpServerIndex {
    private final McpCacheIndex cacheIndex;
    /**
     * 根据ID获取MCP服务器信息
     */
    @Override
    // 重写父类方法,根据ID获取MCP服务器信息
    public McpServerIndexData getMcpServerById(String id) {
        // 检查缓存是否启用
        if (!cacheEnabled) {
            // 缓存未启用,直接从数据库查询
            LOGGER.debug("缓存已禁用,直接从数据库查询mcpId: {}", id);
            // 从数据库获取MCP服务器信息
            return getMcpServerByIdFromDatabase(id);
        }
        // 优先查询缓存
        // 从缓存中获取MCP服务器数据
        McpServerIndexData cachedData = cacheIndex.getMcpServerById(id);
        // 检查缓存中是否存在数据
        if (cachedData != null) {
            // 缓存命中,返回缓存数据
            LOGGER.debug("缓存命中 mcpId: {}", id);
            // 返回缓存中的数据
            return cachedData;
        }
        // 缓存未命中,查询数据库
        // 缓存未命中,从数据库查询
        LOGGER.debug("缓存未命中 mcpId: {}, 查询数据库", id);
        // 从数据库获取MCP服务器信息
        McpServerIndexData dbData = getMcpServerByIdFromDatabase(id);
        // 检查数据库中是否存在数据
        if (dbData != null) {
            // 数据库中存在数据,更新缓存
            cacheIndex.updateIndex(dbData.getNamespaceId(), dbData.getId(), dbData.getId());
            // 记录缓存更新日志
            LOGGER.debug("更新缓存 mcpId: {}", id);
        }
        // 返回数据库查询结果
        return dbData;
    }

    /**
     * 根据名称获取MCP服务器信息
     */
    @Override
    // 重写父类方法,根据命名空间ID和名称获取MCP服务器信息
    public McpServerIndexData getMcpServerByName(String namespaceId, String name) {
        // 检查参数是否有效
        if (StringUtils.isEmpty(namespaceId) && StringUtils.isEmpty(name)) {
            // 参数无效,记录警告日志
            LOGGER.warn("getMcpServerByName的参数无效: namespaceId={}, name={}", namespaceId, name);
            // 返回null
            return null;
        }

        // 检查命名空间ID是否为空
        if (StringUtils.isEmpty(namespaceId)) {
            // 命名空间ID为空,获取第一个匹配名称的MCP服务器
            return getFirstMcpServerByName(name);
        }

        // 检查缓存是否启用
        if (!cacheEnabled) {
            // 缓存未启用,直接从数据库查询
            LOGGER.debug("缓存已禁用,直接从数据库查询名称: {}:{}", namespaceId, name);
            // 从数据库获取MCP服务器信息
            return getMcpServerByNameFromDatabase(namespaceId, name);
        }
        // 优先查询缓存
        // 从缓存中获取MCP服务器数据
        McpServerIndexData cachedData = cacheIndex.getMcpServerByName(namespaceId, name);
        // 检查缓存中是否存在数据
        if (cachedData != null) {
            // 缓存命中,返回缓存数据
            LOGGER.debug("缓存命中名称: {}:{}", namespaceId, name);
            // 返回缓存中的数据
            return cachedData;
        }
        // 缓存未命中,查询数据库
        // 缓存未命中,从数据库查询
        LOGGER.debug("缓存未命中名称: {}:{}, 查询数据库", namespaceId, name);
        // 从数据库获取MCP服务器信息
        McpServerIndexData dbData = getMcpServerByNameFromDatabase(namespaceId, name);
        // 检查数据库中是否存在数据
        if (dbData != null) {
            // 数据库中存在数据,更新缓存
            cacheIndex.updateIndex(namespaceId, name, dbData.getId());
            // 记录缓存更新日志
            LOGGER.debug("更新缓存名称: {}:{}", namespaceId, name);
        }
        // 返回数据库查询结果
        return dbData;
    }
    
        @Override
    // 重写父类方法,在搜索完成后更新缓存
    protected void afterSearch(List<McpServerIndexData> indexDataList, String name) {
        // 更新缓存
        // 检查缓存是否启用
        if (cacheEnabled) {
            // 遍历搜索结果列表
            for (McpServerIndexData indexData : indexDataList) {
                // 更新缓存索引
                cacheIndex.updateIndex(indexData.getNamespaceId(), name, indexData.getId());
            }
            // 记录缓存更新日志
            LOGGER.debug("从搜索结果中更新了{}个缓存条目", indexDataList.size());
        }
    }
    
        // 私有方法,启动定时同步任务
    private void startSyncTask() {
        // 创建定时任务,固定延迟执行
        syncTask = scheduledExecutor.scheduleWithFixedDelay(() -> {
            try {
                // 记录开始缓存同步任务的日志
                LOGGER.debug("开始缓存同步任务");
                // 同步数据库中的缓存
                syncCacheFromDatabase();
                // 记录缓存同步任务完成的日志
                LOGGER.debug("缓存同步任务完成");
            } catch (Exception e) {
                // 记录缓存同步任务错误的日志
                LOGGER.error("缓存同步任务期间发生错误", e);
            }
        }, syncInterval, syncInterval, TimeUnit.SECONDS);
        // 记录缓存同步任务启动的日志
        LOGGER.info("缓存同步任务已启动,间隔: {}秒", syncInterval);
    }

    // 私有方法,从数据库同步缓存
    private void syncCacheFromDatabase() {
        // 记录开始从数据库同步缓存的日志
        LOGGER.debug("从数据库同步缓存");
        // 获取有序的命名空间列表
        List<String> namespaceList = fetchOrderedNamespaceList();
        // 遍历命名空间列表
        for (String namespaceId : namespaceList) {
            try {
                // 按页面搜索MCP服务器名称,使用模糊搜索
                searchMcpServerByNameWithPage(namespaceId, null,
                        Constants.MCP_LIST_SEARCH_BLUR, 1, 1000);
            } catch (Exception e) {
                // 记录命名空间缓存同步错误的日志
                LOGGER.error("命名空间缓存同步错误: {}", namespaceId, e);
            }
        }
    }
    
        @Override
    // 重写接口方法,按页面搜索MCP服务器
    public Page<McpServerIndexData> searchMcpServerByNameWithPage(String namespaceId, String name, String search,
            int pageNo, int limit) {
        // 调用searchMcpServers方法搜索配置信息
        Page<ConfigInfo> serverInfos = searchMcpServers(namespaceId, name, search, pageNo, limit);
        // 将ConfigInfo列表映射为McpServerIndexData列表
        List<McpServerIndexData> indexDataList = serverInfos.getPageItems().stream()
                .map(this::mapMcpServerVersionConfigToIndexData).toList();
        // 创建结果页面对象
        Page<McpServerIndexData> result = new Page<>();
        // 设置页面条目
        result.setPageItems(indexDataList);
        // 设置总条目数
        result.setTotalCount(serverInfos.getTotalCount());
        // 计算并设置可用页面数
        result.setPagesAvailable((int) Math.ceil((double) serverInfos.getTotalCount() / (double) limit));
        // 设置当前页码
        result.setPageNumber(pageNo);
        // 调用afterSearch回调方法,用于子类处理搜索后的逻辑
        afterSearch(indexDataList, name);
        // 返回结果
        return result;
    }

}

2.1.3 控制器层

McpAdminController是 MCP 模块的管理控制器,提供 RESTful API 接口:

java 复制代码
// 提供模型服务的增删改查接口
@RestController
@RequestMapping(Constants.MCP_ADMIN_PATH)
public class McpAdminController {
    private final McpServerOperationService mcpServerOperationService;
    
    /**
     * 列出MCP服务器列表
     *
     * @param mcpListForm 列出MCP服务器的请求表单
     * @param pageForm 请求的分页信息
     * @return 包含MCP服务器列表的{@link Result}结果
     * @throws NacosApiException 如果请求参数无效或处理出错
     */
    // GET请求映射到/list路径
    @GetMapping(value = "/list")
    // 安全注解,指定需要读权限,签名类型为AI,API类型为管理API
    @Secured(action = ActionTypes.READ, signType = SignType.AI, apiType = ApiType.ADMIN_API)
    // 列出MCP服务器的方法
    public Result<Page<McpServerBasicInfo>> listMcpServers(McpListForm mcpListForm, PageForm pageForm)
            throws NacosException {
        // 验证MCP列表表单参数
        mcpListForm.validate();
        // 验证分页表单参数
        pageForm.validate();
        // 返回成功结果,包含分页的MCP服务器列表
        return Result.success(
                mcpServerOperationService.listMcpServerWithPage(mcpListForm.getNamespaceId(), mcpListForm.getMcpName(), mcpListForm.getSearch(),
                         pageForm.getPageNo(), pageForm.getPageSize()));
    }
    
    /**
     * 获取指定MCP服务器的详细信息
     *
     * @param mcpForm 获取MCP服务器的请求表单
     * @return 包含详细信息的{@link McpServerDetailInfo}
     * @throws NacosException 处理过程中任何异常
     */
    // GET请求映射到根路径
    @GetMapping
    // 安全注解,指定需要读权限,签名类型为AI,API类型为管理API
    @Secured(action = ActionTypes.READ, signType = SignType.AI, apiType = ApiType.ADMIN_API)
    // 获取MCP服务器的方法
    public Result<McpServerDetailInfo> getMcpServer(McpForm mcpForm) throws NacosException {
        // 验证MCP表单参数
        mcpForm.validate();
        // 返回成功结果,包含MCP服务器详细信息
        return Result.success(mcpServerOperationService.getMcpServerDetail(mcpForm.getNamespaceId(), mcpForm.getMcpId(), 
                mcpForm.getMcpName(), mcpForm.getVersion()));
    }
    
    /**
     * 创建新的MCP服务器
     *
     * @param mcpForm 创建MCP服务器的请求表单
     * @throws NacosException 处理过程中任何异常
     */
    // POST请求映射到根路径
    @PostMapping
    // 安全注解,指定需要写权限,签名类型为AI,API类型为管理API
    @Secured(action = ActionTypes.WRITE, signType = SignType.AI, apiType = ApiType.ADMIN_API)
    // 创建MCP服务器的方法
    public Result<String> createMcpServer(McpDetailForm mcpForm) throws NacosException {
        // 验证MCP详细表单参数
        mcpForm.validate();
        // 解析MCP服务器基本信息
        McpServerBasicInfo basicInfo = McpRequestUtil.parseMcpServerBasicInfo(mcpForm);
        // 解析MCP工具规范
        McpToolSpecification mcpTools = McpRequestUtil.parseMcpTools(mcpForm);
        // 解析MCP端点规范
        McpEndpointSpec endpointSpec = McpRequestUtil.parseMcpEndpointSpec(basicInfo, mcpForm);
        // 调用服务创建MCP服务器,获取MCP服务器ID
        String mcpId = mcpServerOperationService.createMcpServer(mcpForm.getNamespaceId(), basicInfo, mcpTools,
                endpointSpec);
        // 返回成功结果,包含MCP服务器ID
        return Result.success(mcpId);
    }
    
    /**
     * 更新已存在的MCP服务器
     *
     * @param mcpForm 更新MCP服务器的请求表单
     * @throws NacosException 处理过程中任何异常
     */
    // PUT请求映射到根路径
    @PutMapping
    // 安全注解,指定需要写权限,签名类型为AI,API类型为管理API
    @Secured(action = ActionTypes.WRITE, signType = SignType.AI, apiType = ApiType.ADMIN_API)
    // 更新MCP服务器的方法
    public Result<String> updateMcpServer(McpUpdateForm mcpForm) throws NacosException {
        // 验证MCP更新表单参数
        mcpForm.validate();
        // 解析MCP服务器基本信息
        McpServerBasicInfo basicInfo = McpRequestUtil.parseMcpServerBasicInfo(mcpForm);
        // 解析MCP工具规范
        McpToolSpecification mcpTools = McpRequestUtil.parseMcpTools(mcpForm);
        // 解析MCP端点规范
        McpEndpointSpec endpointSpec = McpRequestUtil.parseMcpEndpointSpec(basicInfo, mcpForm);
        // 调用服务更新MCP服务器
        mcpServerOperationService.updateMcpServer(mcpForm.getNamespaceId(), mcpForm.getLatest(), basicInfo, mcpTools,
                endpointSpec, mcpForm.isOverrideExisting());
        // 返回成功结果
        return Result.success("ok");
    }
    
    /**
     * 删除已存在的MCP服务器
     *
     * @param mcpForm 删除MCP服务器的请求表单
     * @throws NacosException 处理过程中任何异常
     */
    // DELETE请求映射到根路径
    @DeleteMapping
    // 安全注解,指定需要写权限,签名类型为AI,API类型为管理API
    @Secured(action = ActionTypes.WRITE, signType = SignType.AI, apiType = ApiType.ADMIN_API)
    // 删除MCP服务器的方法
    public Result<String> deleteMcpServer(McpForm mcpForm) throws NacosException {
        // 验证MCP表单参数
        mcpForm.validate();
        // 调用服务删除MCP服务器
        mcpServerOperationService.deleteMcpServer(mcpForm.getNamespaceId(), mcpForm.getMcpName(), mcpForm.getMcpId(), mcpForm.getVersion());
        // 返回成功结果
        return Result.success("ok");
    }
}

2.2 A2A (Agent to Agent)

A2A 模块实现了 AI 代理间的通信机制,支持代理的注册、发现和通信。

2.2.1 核心功能

  • 代理卡片管理
  • 代理身份编码
  • 端点请求处理
  • 代理间通信

2.2.2 关键类分析

A2aServerOperationService

这是 A2A 模块的核心服务类,负责代理服务的操作管理:

java 复制代码
// 提供代理服务的注册、查询、更新和删除等方法
@Service
public class A2aServerOperationService {
    // 实现注册Agent的方法
    public void registerAgent(AgentCard agentCard, String namespaceId, String registrationType) throws NacosException {
        try {
            // 1. 注册Agent的基本信息
            // 构建Agent卡片版本信息
            AgentCardVersionInfo agentCardVersionInfo = AgentCardUtil.buildAgentCardVersionInfo(agentCard,
                    registrationType, true);
            // 转换为配置表单
            ConfigForm configForm = transferVersionInfoToConfigForm(agentCardVersionInfo, namespaceId);
            // 创建配置请求信息,设置不允许更新已存在的配置
            ConfigRequestInfo versionConfigRequest = new ConfigRequestInfo();
            versionConfigRequest.setUpdateForExist(Boolean.FALSE);
            // 发布配置
            configOperationService.publishConfig(configForm, versionConfigRequest, null);

            // 2. 注册Agent的版本信息
            // 构建Agent卡片详细信息
            AgentCardDetailInfo agentCardDetailInfo = AgentCardUtil.buildAgentCardDetailInfo(agentCard,
                    registrationType);
            // 转换为版本配置表单
            ConfigForm configFormVersion = transferAgentInfoToConfigForm(agentCardDetailInfo, namespaceId);
            // 创建Agent卡片配置请求信息,设置不允许更新已存在的配置
            ConfigRequestInfo agentCardConfigRequest = new ConfigRequestInfo();
            agentCardConfigRequest.setUpdateForExist(Boolean.FALSE);
            // 记录操作开始时间
            long startOperationTime = System.currentTimeMillis();
            // 发布版本配置
            configOperationService.publishConfig(configFormVersion, agentCardConfigRequest, null);

            // 同步效果服务
            syncEffectService.toSync(configFormVersion, startOperationTime);
        } catch (ConfigAlreadyExistsException e) {
            // 如果配置已存在,抛出资源冲突异常
            throw new NacosApiException(NacosException.CONFLICT, ErrorCode.RESOURCE_CONFLICT,
                    String.format("AgentCard name %s already exist", agentCard.getName()));
        }
    }

    // 实现删除Agent的方法
    public void deleteAgent(String namespaceId, String agentName, String version) throws NacosException {
        // 对Agent名称进行编码
        String encodedName = agentIdCodecHolder.encode(agentName);

        // 构建配置查询请求
        ConfigQueryChainRequest request = ConfigQueryChainRequest.buildConfigQueryChainRequest(encodedName, AGENT_GROUP,
                namespaceId);
        // 处理查询请求
        ConfigQueryChainResponse response = configQueryChainService.handle(request);

        // 如果配置未找到,直接返回
        if (response.getStatus() == ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND) {
            return;
        }

        // 将响应内容转换为Agent卡片版本信息对象
        AgentCardVersionInfo agentCardVersionInfo = JacksonUtils.toObj(response.getContent(),
                AgentCardVersionInfo.class);
        // 获取所有版本列表
        List<String> allVersions = agentCardVersionInfo.getVersionDetails().stream().map(AgentVersionDetail::getVersion)
                .toList();

        // 1. 如果指定了版本,只删除对应版本的Agent
        if (StringUtils.isNotEmpty(version)) {
            // 构造版本数据ID
            String versionDataId = encodedName + "-" + version;
            // 删除指定版本的配置
            configOperationService.deleteConfig(versionDataId, AGENT_VERSION_GROUP, namespaceId, null, null, "nacos",
                    null);

            // 获取版本详情列表
            List<AgentVersionDetail> versionDetails = agentCardVersionInfo.getVersionDetails();

            // 判断是否为最新版本
            boolean isLatestVersion = version.equals(agentCardVersionInfo.getLatestPublishedVersion());

            // 如果只有一个版本且就是要删除的版本,则删除整个Agent信息
            if (versionDetails.size() == 1 && versionDetails.get(0).getVersion().equals(version)) {
                configOperationService.deleteConfig(encodedName, AGENT_GROUP, namespaceId, null, null, "nacos", null);
            } else {
                // 从版本详情列表中移除指定版本
                agentCardVersionInfo.getVersionDetails()
                        .removeIf(versionDetail -> versionDetail.getVersion().equals(version));

                // 如果删除的是最新版本,则清空最新版本信息
                if (isLatestVersion) {
                    agentCardVersionInfo.setLatestPublishedVersion(null);
                    agentCardVersionInfo.setVersion(null);
                }

                // 更新配置表单
                ConfigForm updateForm = transferVersionInfoToConfigForm(agentCardVersionInfo, namespaceId);
                // 创建配置请求信息,设置允许更新已存在的配置
                ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
                configRequestInfo.setUpdateForExist(Boolean.TRUE);
                // 发布更新后的配置
                configOperationService.publishConfig(updateForm, configRequestInfo, null);
            }
        } else {
            // 2. 如果未指定版本,删除所有版本和Agent信息
            // 遍历所有版本并删除
            for (String each : allVersions) {
                String versionDataId = encodedName + "-" + each;
                configOperationService.deleteConfig(versionDataId, AGENT_VERSION_GROUP, namespaceId, null, null,
                        "nacos", null);
            }

            // 删除Agent基本信息
            configOperationService.deleteConfig(encodedName, AGENT_GROUP, namespaceId, null, null, "nacos", null);
        }
    }

    // 实现更新Agent卡片的方法
    public void updateAgentCard(AgentCard agentCard, String namespaceId, String registrationType, boolean setAsLatest)
            throws NacosException {
        // 查询现有的Agent卡片版本信息
        final AgentCardVersionInfo existingAgentInfo = queryAgentCardVersionInfo(namespaceId, agentCard.getName());

        // 检查版本是否存在,如果不存在,则添加新版本到版本信息中
        boolean versionExisted = existingAgentInfo.getVersionDetails().stream().anyMatch(
                agentVersionDetail -> StringUtils.equals(agentVersionDetail.getVersion(), agentCard.getVersion()));
        if (!versionExisted) {
            existingAgentInfo.getVersionDetails().add(AgentCardUtil.buildAgentVersionDetail(agentCard, setAsLatest));
        }

        // 如果输入的新注册类型为空,则使用现有的注册类型
        if (StringUtils.isEmpty(registrationType)) {
            registrationType = existingAgentInfo.getRegistrationType();
        }
        // 构建Agent卡片详细信息
        AgentCardDetailInfo agentCardDetailInfo = AgentCardUtil.buildAgentCardDetailInfo(agentCard, registrationType);
        // 复制属性,排除versionDetails和latestPublishedVersion字段
        BeanUtils.copyProperties(agentCardDetailInfo, existingAgentInfo, "versionDetails", "latestPublishedVersion");

        // 如果设置为最新版本
        if (setAsLatest) {
            // 设置最新发布的版本
            existingAgentInfo.setLatestPublishedVersion(agentCard.getVersion());

            // 更新版本详情列表
            List<AgentVersionDetail> updatedVersionDetails = existingAgentInfo.getVersionDetails().stream()
                    .peek(detail -> {
                        if (StringUtils.equals(detail.getVersion(), agentCard.getVersion())) {
                            // 只更新对应版本
                            detail.setLatest(true);
                            AgentCardUtil.updateUpdateTime(detail);
                        } else {
                            detail.setLatest(false);
                        }
                    }).toList();
            existingAgentInfo.setVersionDetails(updatedVersionDetails);
        }

        // 更新Agent版本信息
        ConfigForm configForm = transferVersionInfoToConfigForm(existingAgentInfo, namespaceId);
        ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
        configRequestInfo.setUpdateForExist(Boolean.TRUE);
        configOperationService.publishConfig(configForm, configRequestInfo, null);

        // 更新Agent信息
        ConfigForm versionConfigForm = transferAgentInfoToConfigForm(agentCardDetailInfo, namespaceId);
        ConfigRequestInfo versionConfigRequestInfo = new ConfigRequestInfo();
        versionConfigRequestInfo.setUpdateForExist(Boolean.TRUE);
        long startOperationTime = System.currentTimeMillis();
        configOperationService.publishConfig(versionConfigForm, versionConfigRequestInfo, null);

        syncEffectService.toSync(versionConfigForm, startOperationTime);
    }
    
        // 实现列出Agents的方法
    public Page<AgentCardVersionInfo> listAgents(String namespaceId, String agentName, String search, int pageNo,
            int pageSize) throws NacosException {

        String dataId;
        // 如果Agent名称为空或搜索类型为模糊搜索
        if (StringUtils.isEmpty(agentName) || Constants.A2A.SEARCH_BLUR.equalsIgnoreCase(search)) {
            search = Constants.A2A.SEARCH_BLUR;
            // 构造模糊搜索的数据ID
            dataId = Constants.ALL_PATTERN + agentIdCodecHolder.encodeForSearch(agentName) + Constants.ALL_PATTERN;
        } else {
            search = Constants.A2A.SEARCH_ACCURATE;
            // 构造精确搜索的数据ID
            dataId = agentIdCodecHolder.encode(agentName);
        }

        // 查找配置信息页面
        Page<ConfigInfo> configInfoPage = configDetailService.findConfigInfoPage(search, pageNo, pageSize, dataId,
                AGENT_GROUP, namespaceId, null);

        // 将配置信息转换为Agent卡片版本信息列表
        List<AgentCardVersionInfo> versionInfos = configInfoPage.getPageItems().stream()
                .map(configInfo -> JacksonUtils.toObj(configInfo.getContent(), AgentCardVersionInfo.class)).toList();

        // 构造返回结果页面
        Page<AgentCardVersionInfo> result = new Page<>();
        result.setPageItems(versionInfos);
        result.setTotalCount(configInfoPage.getTotalCount());
        result.setPagesAvailable((int) Math.ceil((double) configInfoPage.getTotalCount() / (double) pageSize));
        result.setPageNumber(pageNo);

        return result;
    }

    // 实现列出Agent版本的方法
    public List<AgentVersionDetail> listAgentVersions(String namespaceId, String name) throws NacosApiException {
        // 查询Agent卡片版本信息
        AgentCardVersionInfo agentCardVersionInfo = queryAgentCardVersionInfo(namespaceId, name);
        // 返回版本详情列表
        return agentCardVersionInfo.getVersionDetails();
    }

}
请求处理器

A2A 模块通过一系列请求处理器来处理各种远程调用:

  • AgentEndpointRequestHandler: 处理代理端点请求
  • QueryAgentCardRequestHandler: 处理代理卡片查询请求
  • ReleaseAgentCardRequestHandler: 处理代理卡片释放请求
java 复制代码
// 处理代理端点请求的具体实现
@Component
public class AgentEndpointRequestHandler extends RequestHandler<AgentEndpointRequest, AgentEndpointResponse> {
    @Override
    // 命名空间验证注解,确保请求的命名空间有效
    @NamespaceValidation
    // 参数提取器,用于RPC请求参数的提取和验证
    @ExtractorManager.Extractor(rpcExtractor = AgentRequestParamExtractor.class)
    // 安全注解,指定该操作需要写权限,签名类型为AI
    @Secured(action = ActionTypes.WRITE, signType = SignType.AI)
    public AgentEndpointResponse handle(AgentEndpointRequest request, RequestMeta meta) throws NacosException {
        // 创建响应对象
        AgentEndpointResponse response = new AgentEndpointResponse();
        // 设置响应类型与请求类型一致
        response.setType(request.getType());
        // 填充命名空间ID
        AgentRequestUtil.fillNamespaceId(request);
        try {
            // 验证请求参数的有效性
            validateRequest(request);
            // 将请求转换为Instance实例
            Instance instance = transferInstance(request);
            // 构造服务名称,格式为"编码后的代理名::版本号"
            String serviceName =
                    agentIdCodecHolder.encode(request.getAgentName()) + "::" + request.getEndpoint().getVersion();
            // 创建服务对象,指定命名空间、组名和服名
            Service service = Service.newService(request.getNamespaceId(), Constants.A2A.AGENT_ENDPOINT_GROUP,
                    serviceName);
            // 根据请求类型执行相应的操作
            switch (request.getType()) {
                // 注册端点
                case AiRemoteConstants.REGISTER_ENDPOINT:
                    doRegisterEndpoint(service, instance, meta);
                    break;
                // 注销端点
                case AiRemoteConstants.DE_REGISTER_ENDPOINT:
                    doDeregisterEndpoint(service, instance, meta);
                    break;
                // 参数类型错误,抛出异常
                default:
                    throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.PARAMETER_VALIDATE_ERROR,
                            String.format("parameter [type](file:///Users/zhiyixie/Downloads/work_space/码云/Nacos/api/src/main/java/com/alibaba/nacos/api/cmdb/pojo/Entity.java#L28-L28) should be %s or %s, but was %s",
                                    AiRemoteConstants.REGISTER_ENDPOINT, AiRemoteConstants.DE_REGISTER_ENDPOINT,
                                    request.getType()));
            }
        } catch (NacosApiException e) {
            // 设置错误信息
            response.setErrorInfo(e.getErrCode(), e.getErrMsg());
            // 记录错误日志
            LOGGER.error("[{}] Register agent endpoint to agent {} error: {}", meta.getConnectionId(),
                    request.getAgentName(), e.getErrMsg());
        }
        // 返回响应结果
        return response;
    }

    // 将AgentEndpointRequest转换为Instance对象
    private Instance transferInstance(AgentEndpointRequest request) throws NacosApiException {
        // 创建Instance实例
        Instance instance = new Instance();
        // 获取端点信息
        AgentEndpoint endpoint = request.getEndpoint();
        // 设置IP地址
        instance.setIp(endpoint.getAddress());
        // 设置端口号
        instance.setPort(endpoint.getPort());
        // 处理路径信息,如果为空则设置为空字符串
        String path = StringUtils.isBlank(endpoint.getPath()) ? StringUtils.EMPTY : endpoint.getPath();
        // 构造元数据映射
        Map<String, String> metadata = Map.of(Constants.A2A.AGENT_ENDPOINT_PATH_KEY, path,
                Constants.A2A.AGENT_ENDPOINT_TRANSPORT_KEY, endpoint.getTransport(),
                Constants.A2A.NACOS_AGENT_ENDPOINT_SUPPORT_TLS, String.valueOf(endpoint.isSupportTls()));
        // 设置元数据
        instance.setMetadata(metadata);
        // 验证实例的有效性
        instance.validate();
        // 返回构造好的实例
        return instance;
    }

    // 验证请求参数的有效性
    private void validateRequest(AgentEndpointRequest request) throws NacosApiException {
        // 检查代理名称是否为空
        if (StringUtils.isBlank(request.getAgentName())) {
            throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.PARAMETER_MISSING,
                    "Required parameter [agentName](file:///Users/zhiyixie/Downloads/work_space/码云/Nacos/common/src/main/java/com/alibaba/nacos/common/paramcheck/ParamInfo.java#L50-L50) can't be empty or null");
        }
        // 检查端点信息是否为空
        if (null == request.getEndpoint()) {
            throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.PARAMETER_MISSING,
                    "Required parameter [endpoint](file:///Users/zhiyixie/Downloads/work_space/码云/Nacos/api/src/main/java/com/alibaba/nacos/api/annotation/NacosProperties.java#L193-L193) can't be null");
        }
        // 检查端点版本是否为空
        if (StringUtils.isBlank(request.getEndpoint().getVersion())) {
            throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.PARAMETER_MISSING,
                    "Required parameter `endpoint.version` can't be empty or null");
        }
    }

    // 执行端点注册操作
    private void doRegisterEndpoint(Service service, Instance instance, RequestMeta meta) throws NacosException {
        // 调用客户端操作服务注册实例
        clientOperationService.registerInstance(service, instance, meta.getConnectionId());

    }

    // 执行端点注销操作
    private void doDeregisterEndpoint(Service service, Instance instance, RequestMeta meta) {
        // 调用客户端操作服务注销实例
        clientOperationService.deregisterInstance(service, instance, meta.getConnectionId());
    }

}

3. 关键源码剖析

3.1 模型服务注册流程

模型服务注册的核心流程如下:

  1. 客户端通过 McpAdminController 发起注册请求
  2. 请求被转发到 McpServerOperationService 进行处理
  3. 服务信息被持久化到配置中心
  4. 更新索引信息以便后续查询
java 复制代码
// McpServerOperationService 中的注册方法示例
public McpServerDetailInfo createMcpServer(McpForm mcpForm) throws NacosException {
    // 验证表单数据
    // 构造服务信息对象
    // 保存到配置中心
    // 更新索引
    // 返回详细信息
}

3.2 代理通信处理流程

代理间通信的处理流程如下:

  1. 代理发起通信请求到 AgentEndpointRequestHandler
  2. 处理器解析请求参数
  3. 查询目标代理信息
  4. 建立通信连接并返回响应
java 复制代码
// AgentEndpointRequestHandler 中的处理方法示例
@Override
public AgentEndpointResponse handle(agentEndpointRequest request, RequestMeta meta) throws NacosException {
    // 解析请求参数
    // 查询代理信息
    // 构造响应数据
    // 返回响应
}

4. 架构设计亮点

4.1 分层架构设计

Nacos AI 模块采用清晰的分层架构:

复制代码
Controller Layer (REST API)
    ↓
Service Layer (业务逻辑)
    ↓
Index Layer (索引管理)
    ↓
Persistence Layer (数据持久化)

这种设计使得各层职责分明,便于维护和扩展。

4.2 缓存机制优化

通过多级缓存机制提升查询性能:

  • 内存缓存:快速响应高频查询
  • 数据库查询:保证数据一致性
  • 缓存更新策略:平衡性能与一致性

4.3 插件化设计

AI 模块继承了 Nacos 的插件化设计理念,支持:

  • 自定义索引实现
  • 扩展认证机制
  • 灵活的配置管理

5. 使用场景

5.1 微服务AI治理

Nacos AI 模块能够与 Nacos 微服务架构无缝集成,提供 AI 服务的注册发现、配置管理等功能。

5.2 多模型版本管理

支持同一 AI 模型的多个版本管理,方便进行灰度发布和 A/B 测试。

5.3 跨域代理通信

通过 A2A 模块,不同域的 AI 代理可以安全高效地进行通信协作。

6. 未来发展趋势

6.1 AI服务网格集成

未来 Nacos AI 模块将进一步与服务网格技术集成,提供更完善的 AI 服务治理能力。

6.2 智能负载均衡

基于 AI 模型的性能指标实现智能负载均衡策略。

6.3 自动扩缩容

根据模型服务的负载情况自动调整实例数量。

7. 结语与学习建议

Nacos AI 模块为 AI 服务提供了完整的生命周期管理解决方案,从模型注册、版本管理到服务发现和配置管理,极大地简化了 AI 服务的运维复杂度。

7.1. 动手实践(快速搭建本地环境)

shell 复制代码
# 1. 克隆 Nacos 源码
git clone https://github.com/alibaba/nacos.git
cd nacos

# 2. 编译所有模块,包含AI
mvn -Prelease-nacos clean install -DskipTests

# 3. 启动单机模式
cd distribution/target/nacos-server-3.x.x/nacos/bin
sh startup.sh -m standalone

7.2. 调试技巧

  • 关注 nacos-ai 模块中的 McpServerOperationServiceA2aServerOperationService 类,通过断点调试理解核心流程

  • 查看日志输出,重点关注索引更新和配置变更相关的日志信息

7.3. 延伸阅读

  • Nacos 3.x 官方文档(最权威的版本更新与功能说明)

  • 《深入理解 Nacos 源码》(机械工业出版社,2025)(从源码角度解析 Nacos 设计思想)

🌟 核心学习原则:理解 AI 模块的设计理念和架构思想,而不仅仅是使用其功能接口。例如:

  • 为何要用多级索引机制?(提升查询性能)

  • 为何要分离 MCP 和 A2A?(解耦模型管理和代理通信)

  • 缓存机制如何平衡性能与一致性?(多级缓存策略)

📝 版权声明

本文为原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文链接及本声明。

✅ 本文持续更新,欢迎收藏 + 关注专栏【后端高阶面经:实战篇】

相关推荐
Dev7z2 小时前
基于图像处理与数据分析的智能答题卡识别与阅卷系统设计与实现
图像处理·人工智能·数据分析
GoldenSpider.AI2 小时前
跨越地球的计算:StarCloud如何将AI数据中心送入太空,掀起下一代能源革命
人工智能·能源·starcloud·nvidia h100·philip johnston·ai创业公司
_abcdef2 小时前
Kubernetes 资源清单
云原生·容器·kubernetes
拾忆,想起2 小时前
Dubbo负载均衡全解析:五种策略详解与实战指南
java·运维·微服务·架构·负载均衡·dubbo·哈希算法
泯泷2 小时前
Tiptap 深度教程(四):终极定制 - 从零创建你的专属扩展
前端·javascript·架构
檐下翻书1732 小时前
流程图配色与美化:让你的图表会“说话”
论文阅读·人工智能·信息可视化·流程图·论文笔记
无心水2 小时前
【分布式利器:Kafka】Kafka基本原理详解:架构、流转机制与高吞吐核心(附实战配置)
分布式·架构·kafka·partition·零拷贝·broker·分布式流处理平台
时序之心3 小时前
时序论文速递:覆盖损失函数优化、模型架构创新、理论基础与表征学习、应用场景与隐私保护等方向(11.10-11.14)
人工智能·损失函数·时间序列·表征学习·时序论文
IT_陈寒3 小时前
Vue3性能优化实战:我从这5个技巧中获得了40%的渲染提升
前端·人工智能·后端