Spring AI Alibaba A2A 使用指南

Spring AI Alibaba A2A 使用指南

目录

  • [1. A2A 概述](#1. A2A 概述)
    • [1.1 什么是 A2A](#1.1 什么是 A2A)
    • [1.2 为什么需要 A2A](#1.2 为什么需要 A2A)
    • [1.3 应用场景](#1.3 应用场景)
    • [1.4 核心特性](#1.4 核心特性)
  • [2. A2A 架构](#2. A2A 架构)
    • [2.1 整体架构](#2.1 整体架构)
    • [2.2 核心组件](#2.2 核心组件)
    • [2.3 工作原理](#2.3 工作原理)
    • [2.4 通信协议](#2.4 通信协议)
  • [3. 快速开始](#3. 快速开始)
    • [3.1 环境准备](#3.1 环境准备)
    • [3.2 创建服务提供者](#3.2 创建服务提供者)
    • [3.3 创建服务消费者](#3.3 创建服务消费者)
    • [3.4 运行示例](#3.4 运行示例)
  • [4. 核心概念详解](#4. 核心概念详解)
    • [4.1 AgentCard](#4.1 AgentCard)
    • [4.2 AgentCardProvider](#4.2 AgentCardProvider)
    • [4.3 A2aRemoteAgent](#4.3 A2aRemoteAgent)
    • [4.4 注册中心](#4.4 注册中心)
  • [5. Nacos 集成](#5. Nacos 集成)
    • [5.1 Nacos 介绍](#5.1 Nacos 介绍)
    • [5.2 Nacos 安装与配置](#5.2 Nacos 安装与配置)
    • [5.3 服务注册配置](#5.3 服务注册配置)
    • [5.4 服务发现配置](#5.4 服务发现配置)
  • [6. 配置详解](#6. 配置详解)
    • [6.1 完整配置示例](#6.1 完整配置示例)
    • [6.2 注册配置参数](#6.2 注册配置参数)
    • [6.3 发现配置参数](#6.3 发现配置参数)
    • [6.4 网络配置](#6.4 网络配置)
  • [7. 服务注册](#7. 服务注册)
    • [7.1 自动注册(推荐)](#7.1 自动注册(推荐))
    • [7.2 手动注册](#7.2 手动注册)
    • [7.3 AgentCard 详解](#7.3 AgentCard 详解)
    • [7.4 注册生命周期](#7.4 注册生命周期)
  • [8. 服务发现](#8. 服务发现)
    • [8.1 发现机制](#8.1 发现机制)
    • [8.2 查询服务](#8.2 查询服务)
    • [8.3 负载均衡](#8.3 负载均衡)
    • [8.4 健康检查](#8.4 健康检查)
  • [9. 远程智能体调用](#9. 远程智能体调用)
    • [9.1 创建远程智能体代理](#9.1 创建远程智能体代理)
    • [9.2 同步调用](#9.2 同步调用)
    • [9.3 异步调用](#9.3 异步调用)
    • [9.4 流式调用](#9.4 流式调用)
  • [10. 多智能体协作模式](#10. 多智能体协作模式)
    • [10.1 点对点通信](#10.1 点对点通信)
    • [10.2 发布订阅模式](#10.2 发布订阅模式)
    • [10.3 请求响应模式](#10.3 请求响应模式)
    • [10.4 工作流编排](#10.4 工作流编排)
  • [11. 高级特性](#11. 高级特性)
    • [11.1 安全认证](#11.1 安全认证)
    • [11.2 限流与熔断](#11.2 限流与熔断)
    • [11.3 链路追踪](#11.3 链路追踪)
    • [11.4 灰度发布](#11.4 灰度发布)
  • [12. 实战案例](#12. 实战案例)
    • [12.1 分布式客服系统](#12.1 分布式客服系统)
    • [12.2 多专家咨询系统](#12.2 多专家咨询系统)
    • [12.3 智能工作流引擎](#12.3 智能工作流引擎)
    • [12.4 跨部门协作平台](#12.4 跨部门协作平台)
  • [13. REST API 规范](#13. REST API 规范)
    • [13.1 接口定义](#13.1 接口定义)
    • [13.2 请求格式](#13.2 请求格式)
    • [13.3 响应格式](#13.3 响应格式)
    • [13.4 错误处理](#13.4 错误处理)
  • [14. 最佳实践](#14. 最佳实践)
    • [14.1 服务拆分策略](#14.1 服务拆分策略)
    • [14.2 性能优化](#14.2 性能优化)
    • [14.3 故障处理](#14.3 故障处理)
    • [14.4 监控告警](#14.4 监控告警)
  • [15. 常见问题](#15. 常见问题)
  • [16. 附录](#16. 附录)

1. A2A 概述

1.1 什么是 A2A

A2A (Agent-to-Agent) 是 Spring AI Alibaba 提供的智能体间通信协议和框架,允许不同的智能体通过网络进行发现、通信和协作。

A2A 解决了以下核心问题:

  • 服务发现:智能体如何找到其他智能体?
  • 远程调用:如何像调用本地智能体一样调用远程智能体?
  • 负载均衡:如何在多个智能体实例间分配请求?
  • 故障恢复:如何处理网络故障和服务不可用?

核心理念:让分布式智能体系统的开发像单体应用一样简单。

1.2 为什么需要 A2A

在现代 AI 应用中,单个智能体往往无法解决所有问题。A2A 提供了构建分布式智能体系统的能力:

1.2.1 专业化分工

不同的智能体可以专注于不同的领域:

复制代码
用户请求 → 路由智能体 → ┬→ 技术专家智能体
                        ├→ 商业专家智能体
                        ├→ 法律专家智能体
                        └→ 金融专家智能体

每个专家智能体可以:

  • 使用专门的模型
  • 配置特定的工具
  • 优化特定的提示词
  • 独立部署和扩展
1.2.2 资源隔离

不同的智能体服务可以:

  • 部署在不同的服务器上
  • 使用不同的计算资源
  • 设置不同的 API 配额
  • 独立扩容和缩容
1.2.3 团队协作

大型 AI 应用可以由多个团队并行开发:

  • 每个团队负责特定的智能体服务
  • 通过统一的 A2A 协议进行集成
  • 独立测试和发布
1.2.4 可复用性

通用智能体可以被多个应用复用:

复制代码
应用 A ─┐
应用 B ─┼→ 通用翻译智能体
应用 C ─┘

应用 D ─┐
应用 E ─┼→ 通用计算智能体
应用 F ─┘

1.3 应用场景

1.3.1 企业级智能客服
复制代码
┌─────────────────────────────────────────────┐
│              客户请求                         │
└─────────────────┬───────────────────────────┘
                  ↓
         ┌────────────────┐
         │  路由智能体     │ (识别问题类型)
         └───────┬────────┘
                 │
      ┌──────────┼──────────┐
      ↓          ↓           ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 订单服务 │ │ 技术支持 │ │ 售后服务 │
│ 智能体   │ │ 智能体   │ │ 智能体   │
└─────────┘ └─────────┘ └─────────┘
1.3.2 多专家咨询系统
复制代码
用户问题:"我应该如何投资这笔钱?"
     ↓
协调智能体
     ↓
     ├→ 金融专家:分析投资方案
     ├→ 税务专家:评估税务影响
     ├→ 法律专家:审查合规性
     └→ 风险专家:评估风险等级
     ↓
汇总智能体 → 综合建议
1.3.3 智能研究助手
复制代码
研究主题
     ↓
┌─────────────┐
│ 规划智能体   │ (制定研究计划)
└─────┬───────┘
      │
      ├→ 文献检索智能体 (查找相关论文)
      ├→ 数据收集智能体 (收集数据)
      ├→ 分析智能体     (数据分析)
      ├→ 撰写智能体     (撰写报告)
      └→ 审阅智能体     (审查修改)
      ↓
   研究报告
1.3.4 跨部门协作
复制代码
项目需求
     ↓
项目管理智能体
     ↓
     ├→ 开发部门智能体 (技术方案)
     ├→ 设计部门智能体 (UI/UX 设计)
     ├→ 测试部门智能体 (测试计划)
     ├→ 运维部门智能体 (部署方案)
     └→ 产品部门智能体 (需求分析)

1.4 核心特性

1.4.1 透明的远程调用

调用远程智能体就像调用本地智能体一样简单:

java 复制代码
// 本地智能体
ReactAgent localAgent = ...;
localAgent.invoke("你好");

// 远程智能体 - 完全相同的 API
A2aRemoteAgent remoteAgent = ...;
remoteAgent.invoke("你好");
1.4.2 自动服务发现

智能体自动注册和发现,无需手动配置:

java 复制代码
// 服务提供者:智能体自动注册
@Bean
public ReactAgent myAgent() {
    return ReactAgent.builder()
        .name("my_agent")
        .model(chatModel)
        .build();
}

// 服务消费者:自动发现并调用
A2aRemoteAgent remote = A2aRemoteAgent.builder()
    .name("my_agent")  // 通过名称发现
    .agentCardProvider(provider)
    .build();
1.4.3 负载均衡

自动在多个智能体实例间分配请求:

复制代码
请求 → Nacos → ┬→ 实例 1 (权重 60%)
               ├→ 实例 2 (权重 30%)
               └→ 实例 3 (权重 10%)
1.4.4 健康检查

自动检测智能体服务的健康状态:

复制代码
Nacos
  ├→ agent-1: ✓ 健康 (响应时间: 100ms)
  ├→ agent-2: ✓ 健康 (响应时间: 120ms)
  └→ agent-3: ✗ 不健康 (超时) → 自动摘除
1.4.5 版本管理

支持多版本智能体共存:

复制代码
my_agent:1.0.0 → 稳定版本
my_agent:1.1.0 → 新功能版本
my_agent:2.0.0 → 重大升级版本
1.4.6 灰度发布

逐步将流量切换到新版本:

复制代码
旧版本 (90%) ──┐
              ├→ 用户流量
新版本 (10%) ──┘

2. A2A 架构

2.1 整体架构

复制代码
┌─────────────────────────────────────────────────────────┐
│                    应用层                                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐               │
│  │智能体 A   │  │智能体 B   │  │智能体 C   │               │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘               │
└───────┼─────────────┼─────────────┼──────────────────────┘
        │             │             │
┌───────┼─────────────┼─────────────┼──────────────────────┐
│       │    A2A 框架层             │                       │
│       ↓                           ↓                       │
│  ┌─────────┐                ┌─────────┐                  │
│  │ A2A     │                │ A2A     │                  │
│  │ Server  │                │ Client  │                  │
│  └────┬────┘                └────┬────┘                  │
│       │ (注册)                   │ (发现)                 │
└───────┼──────────────────────────┼──────────────────────┘
        │                          │
        │      ┌───────────────────┤
        ↓      ↓                   ↓
┌───────────────────────────────────────────────────────┐
│                  注册中心 (Nacos)                       │
│  ┌─────────────────┐    ┌──────────────────┐          │
│  │   服务注册表     │    │   配置中心        │          │
│  │                 │    │                  │          │
│  │ - agent_a:8081  │    │ - A2A 配置       │          │
│  │ - agent_b:8082  │    │ - 路由规则       │          │
│  │ - agent_c:8083  │    │ - 限流策略       │          │
│  └─────────────────┘    └──────────────────┘          │
└───────────────────────────────────────────────────────┘
        ↑                          ↑
        │ (HTTP/REST)              │
        │                          │
┌───────┴──────────────────────────┴──────────────────────┐
│                  网络传输层                               │
│              (HTTP, gRPC, WebSocket)                    │
└─────────────────────────────────────────────────────────┘

2.2 核心组件

2.2.1 A2A Server(服务端)

职责

  • 暴露本地智能体为 REST API
  • 向注册中心注册服务
  • 发送心跳保持在线状态
  • 处理远程调用请求

核心类

  • A2aServerAutoConfiguration - 自动配置
  • A2aAgentEndpoint - REST 端点
  • NacosAgentRegistry - Nacos 注册器

工作流程

复制代码
应用启动
    ↓
1. 扫描 ReactAgent Bean
    ↓
2. 为每个 Agent 创建 REST 端点
    ↓
3. 构造 AgentCard (服务元数据)
    ↓
4. 向 Nacos 注册服务
    ↓
5. 启动心跳线程
    ↓
服务就绪,等待请求
2.2.2 A2A Client(客户端)

职责

  • 从注册中心发现服务
  • 创建远程智能体代理
  • 发起 HTTP 调用
  • 处理响应和异常

核心类

  • A2aRemoteAgent - 远程智能体代理
  • AgentCardProvider - 服务发现提供者
  • NacosAgentDiscovery - Nacos 服务发现

工作流程

复制代码
创建 A2aRemoteAgent
    ↓
1. 根据名称查询 AgentCard
    ↓
2. 获取服务端点地址
    ↓
3. 构造 HTTP 请求
    ↓
4. 发送到远程服务
    ↓
5. 接收并解析响应
    ↓
返回结果
2.2.3 AgentCard(服务元数据)

AgentCard 包含智能体的所有元信息:

java 复制代码
public class AgentCard {
    private String name;           // 智能体名称
    private String description;    // 描述
    private String version;        // 版本号
    private String endpoint;       // 服务端点 (http://host:port)
    private List<String> capabilities;  // 能力列表
    private Map<String, String> metadata;  // 扩展元数据
}

示例

json 复制代码
{
  "name": "customer_service",
  "description": "智能客服机器人",
  "version": "1.0.0",
  "endpoint": "http://192.168.1.10:8081",
  "capabilities": ["tool_calling", "streaming", "chinese"],
  "metadata": {
    "team": "customer-support",
    "owner": "zhangsan@example.com",
    "max_concurrent": "100"
  }
}
2.2.4 AgentCardProvider(服务发现)

提供服务发现接口:

java 复制代码
public interface AgentCardProvider {
    // 获取指定名称的智能体卡片
    Optional<AgentCard> getAgentCard(String agentName);

    // 列出所有可用的智能体
    List<AgentCard> listAgentCards();

    // 按条件过滤智能体
    List<AgentCard> findAgentCards(Predicate<AgentCard> filter);
}

实现类

  • NacosAgentCardProvider - 基于 Nacos 的服务发现
  • StaticAgentCardProvider - 静态配置的服务列表(用于测试)

2.3 工作原理

2.3.1 服务注册流程
复制代码
┌──────────────┐
│ 服务启动      │
└──────┬───────┘
       ↓
┌──────────────────────────────────┐
│ 1. Spring Boot 应用启动          │
│    - 加载配置                     │
│    - 初始化 Bean                  │
└──────┬───────────────────────────┘
       ↓
┌──────────────────────────────────┐
│ 2. A2aServerAutoConfiguration    │
│    - 检查是否启用 A2A Server      │
│    - 扫描 ReactAgent Bean         │
└──────┬───────────────────────────┘
       ↓
┌──────────────────────────────────┐
│ 3. 为每个 ReactAgent 创建端点    │
│    POST /api/a2a/{agentName}     │
└──────┬───────────────────────────┘
       ↓
┌──────────────────────────────────┐
│ 4. 构造 AgentCard                │
│    - name: Agent.name()          │
│    - endpoint: http://host:port  │
│    - description, version 等      │
└──────┬───────────────────────────┘
       ↓
┌──────────────────────────────────┐
│ 5. 注册到 Nacos                  │
│    NacosNamingService.register() │
│    - namespace: 配置的命名空间    │
│    - group: 配置的分组            │
│    - serviceName: agent 名称      │
│    - instance: IP + Port          │
└──────┬───────────────────────────┘
       ↓
┌──────────────────────────────────┐
│ 6. 启动心跳线程                   │
│    每 5 秒发送一次心跳            │
└──────┬───────────────────────────┘
       ↓
┌──────────────┐
│ 服务就绪      │
└──────────────┘
2.3.2 服务发现流程
复制代码
┌──────────────────────┐
│ 创建 A2aRemoteAgent   │
└──────┬───────────────┘
       ↓
┌──────────────────────────────────────┐
│ 1. 调用 provider.getAgentCard(name)  │
└──────┬───────────────────────────────┘
       ↓
┌──────────────────────────────────────┐
│ 2. NacosAgentCardProvider 查询       │
│    NacosNamingService.selectInstance │
│    - 获取服务实例列表                 │
│    - 应用负载均衡策略                 │
│    - 选择一个健康实例                 │
└──────┬───────────────────────────────┘
       ↓
┌──────────────────────────────────────┐
│ 3. 构造 AgentCard                    │
│    从 Nacos 元数据构造                │
└──────┬───────────────────────────────┘
       ↓
┌──────────────────────────────────────┐
│ 4. 缓存 AgentCard                    │
│    缓存 30 秒,减少 Nacos 查询        │
└──────┬───────────────────────────────┘
       ↓
┌──────────────┐
│ 返回 AgentCard│
└──────────────┘
2.3.3 远程调用流程
复制代码
┌───────────────────┐
│ remoteAgent.invoke│
└─────┬─────────────┘
      ↓
┌─────────────────────────────────────┐
│ 1. 获取 AgentCard (从缓存或 Nacos)   │
└─────┬───────────────────────────────┘
      ↓
┌─────────────────────────────────────┐
│ 2. 构造 HTTP 请求                    │
│    POST {endpoint}/api/a2a/{name}   │
│    Content-Type: application/json   │
│    Body: {                          │
│      "messages": [...],             │
│      "config": {...}                │
│    }                                │
└─────┬───────────────────────────────┘
      ↓
┌─────────────────────────────────────┐
│ 3. 发送请求到远程服务                 │
│    RestTemplate.postForObject()     │
└─────┬───────────────────────────────┘
      ↓
┌─────────────────────────────────────┐
│ 4. 远程服务处理                      │
│    - 查找本地 ReactAgent             │
│    - 调用 agent.invoke()             │
│    - 返回 OverAllState               │
└─────┬───────────────────────────────┘
      ↓
┌─────────────────────────────────────┐
│ 5. 接收响应                          │
│    解析 JSON → OverAllState          │
└─────┬───────────────────────────────┘
      ↓
┌─────────────────────────────────────┐
│ 6. 错误处理                          │
│    - 连接超时: 重试                  │
│    - 服务不可用: 切换实例             │
│    - 业务错误: 返回异常               │
└─────┬───────────────────────────────┘
      ↓
┌───────────────┐
│ 返回结果       │
└───────────────┘

2.4 通信协议

2.4.1 REST API

A2A 使用标准的 REST API 进行通信:

端点POST /api/a2a/{agentName}

请求格式

json 复制代码
{
  "messages": [
    {
      "role": "user",
      "content": "你好,请帮我查询订单"
    }
  ],
  "config": {
    "threadId": "session_123",
    "metadata": {
      "userId": "user_001"
    }
  }
}

响应格式

json 复制代码
{
  "messages": [
    {
      "role": "user",
      "content": "你好,请帮我查询订单"
    },
    {
      "role": "assistant",
      "content": "好的,请提供您的订单号。"
    }
  ],
  "metadata": {
    "nodeId": "agent_llm_node",
    "duration": 523
  }
}
2.4.2 流式响应

对于流式调用,使用 Server-Sent Events (SSE):

端点POST /api/a2a/{agentName}/stream

响应

复制代码
data: {"nodeName":"agent_llm_node","state":{"messages":[...]}}

data: {"nodeName":"agent_tool_node","state":{"messages":[...]}}

data: {"nodeName":"agent_llm_node","state":{"messages":[...]}}

data: [DONE]

3. 快速开始

3.1 环境准备

3.1.1 系统要求
  • JDK 17 或更高版本
  • Maven 3.6+ 或 Gradle 7+
  • Nacos 2.0+(用于服务注册与发现)
3.1.2 安装 Nacos

方式 1:使用 Docker(推荐)

bash 复制代码
# 启动 Nacos Server
docker run -d \
  --name nacos \
  -e MODE=standalone \
  -p 8848:8848 \
  -p 9848:9848 \
  nacos/nacos-server:latest

方式 2:下载独立版本

bash 复制代码
# 下载
wget https://github.com/alibaba/nacos/releases/download/2.4.3/nacos-server-2.4.3.tar.gz

# 解压
tar -xzf nacos-server-2.4.3.tar.gz

# 启动(单机模式)
cd nacos/bin
./startup.sh -m standalone

验证 Nacos 启动

访问 http://localhost:8848/nacos

默认用户名密码:nacos / nacos

3.2 创建服务提供者

3.2.1 创建 Maven 项目
bash 复制代码
mkdir a2a-provider
cd a2a-provider

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.8</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>a2a-provider</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
        <spring-ai-alibaba.version>1.1.0.0-RC1</spring-ai-alibaba.version>
    </properties>

    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Agent Framework -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-agent-framework</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>

        <!-- DashScope -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>

        <!-- A2A with Nacos -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-a2a-nacos</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
3.2.2 配置文件

application.yml

yaml 复制代码
server:
  port: 8081

spring:
  application:
    name: math-agent-service

  ai:
    dashscope:
      api-key: ${AI_DASHSCOPE_API_KEY}
      chat:
        options:
          model: qwen-max

    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848
          registry:
            enabled: true
            namespace: dev
            group: DEFAULT_GROUP
          discovery:
            enabled: true
            namespace: dev
            group: DEFAULT_GROUP
        server:
          enabled: true
          card:
            name: math_agent
            description: "数学计算智能体"
            version: "1.0.0"

logging:
  level:
    com.alibaba.cloud.ai: DEBUG
3.2.3 创建智能体

MathAgentConfig.java

java 复制代码
package com.example.provider;

import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import com.alibaba.cloud.ai.graph.agent.ReactAgent;

@Configuration
public class MathAgentConfig {

    @Bean
    public ReactAgent mathAgent(ChatModel chatModel, MathTools mathTools) {
        return ReactAgent.builder()
            .name("math_agent")
            .description("专业的数学计算智能体,可以进行加减乘除和复杂计算")
            .model(chatModel)
            .instruction("""
                你是一个专业的数学助手。

                职责:
                1. 解答数学问题
                2. 使用计算工具进行精确计算
                3. 解释计算过程

                回答要求:
                - 简洁明了
                - 给出计算步骤
                - 验证结果的正确性
                """)
            .tools(mathTools)
            .build();
    }
}

@Component
class MathTools {

    @Tool(description = "计算两个数的和")
    public double add(
        @ToolParam(description = "第一个数") double a,
        @ToolParam(description = "第二个数") double b
    ) {
        return a + b;
    }

    @Tool(description = "计算两个数的差")
    public double subtract(
        @ToolParam(description = "被减数") double a,
        @ToolParam(description = "减数") double b
    ) {
        return a - b;
    }

    @Tool(description = "计算两个数的积")
    public double multiply(
        @ToolParam(description = "第一个数") double a,
        @ToolParam(description = "第二个数") double b
    ) {
        return a * b;
    }

    @Tool(description = "计算两个数的商")
    public double divide(
        @ToolParam(description = "被除数") double a,
        @ToolParam(description = "除数") double b
    ) {
        if (b == 0) {
            throw new IllegalArgumentException("除数不能为零");
        }
        return a / b;
    }

    @Tool(description = "计算数的平方")
    public double square(@ToolParam(description = "数值") double x) {
        return x * x;
    }

    @Tool(description = "计算数的平方根")
    public double sqrt(@ToolParam(description = "数值") double x) {
        if (x < 0) {
            throw new IllegalArgumentException("不能计算负数的平方根");
        }
        return Math.sqrt(x);
    }
}
3.2.4 启动类

ProviderApplication.java

java 复制代码
package com.example.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}
3.2.5 启动服务
bash 复制代码
# 设置 API Key
export AI_DASHSCOPE_API_KEY=your-api-key

# 启动
mvn spring-boot:run

检查注册状态

访问 Nacos 控制台:http://localhost:8848/nacos

在"服务管理 → 服务列表"中应该看到 math_agent 服务。

3.3 创建服务消费者

3.3.1 创建项目
bash 复制代码
mkdir a2a-consumer
cd a2a-consumer

pom.xml:(与 provider 类似,只需要 A2A 客户端依赖)

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.8</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>a2a-consumer</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
        <spring-ai-alibaba.version>1.1.0.0-RC1</spring-ai-alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-agent-framework</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-a2a-nacos</artifactId>
            <version>${spring-ai-alibaba.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
3.3.2 配置文件

application.yml

yaml 复制代码
server:
  port: 8082

spring:
  application:
    name: consumer-service

  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848
          discovery:
            enabled: true
            namespace: dev
            group: DEFAULT_GROUP

logging:
  level:
    com.alibaba.cloud.ai: DEBUG
3.3.3 创建消费者服务

MathConsumerService.java

java 复制代码
package com.example.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.agent.a2a.A2aRemoteAgent;
import com.alibaba.cloud.ai.graph.agent.a2a.AgentCardProvider;

import java.util.Optional;

@Service
public class MathConsumerService {

    @Autowired
    private AgentCardProvider agentCardProvider;

    public String calculate(String question) {
        // 创建远程数学智能体代理
        A2aRemoteAgent mathAgent = A2aRemoteAgent.builder()
            .name("math_agent")
            .agentCardProvider(agentCardProvider)
            .build();

        // 调用远程智能体
        Optional<OverAllState> result = mathAgent.invoke(question);

        // 获取回复
        return result.flatMap(state -> state.getLastMessage())
            .map(msg -> msg.getContent())
            .orElse("未获取到响应");
    }
}
3.3.4 创建 REST 控制器

MathController.java

java 复制代码
package com.example.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/math")
public class MathController {

    @Autowired
    private MathConsumerService mathService;

    @PostMapping("/calculate")
    public CalculateResponse calculate(@RequestBody CalculateRequest request) {
        String answer = mathService.calculate(request.question());
        return new CalculateResponse(request.question(), answer);
    }
}

record CalculateRequest(String question) {}

record CalculateResponse(String question, String answer) {}
3.3.5 启动类

ConsumerApplication.java

java 复制代码
package com.example.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

3.4 运行示例

3.4.1 启动服务

终端 1 - 启动 Nacos

bash 复制代码
# 如果使用 Docker
docker start nacos

# 或者使用独立版本
cd nacos/bin
./startup.sh -m standalone

终端 2 - 启动 Provider

bash 复制代码
cd a2a-provider
export AI_DASHSCOPE_API_KEY=your-api-key
mvn spring-boot:run

终端 3 - 启动 Consumer

bash 复制代码
cd a2a-consumer
mvn spring-boot:run
3.4.2 测试调用
bash 复制代码
# 测试计算
curl -X POST http://localhost:8082/api/math/calculate \
  -H "Content-Type: application/json" \
  -d '{
    "question": "计算 123 + 456 的结果"
  }'

响应

json 复制代码
{
  "question": "计算 123 + 456 的结果",
  "answer": "好的,我来帮你计算。使用加法工具:123 + 456 = 579。所以结果是 579。"
}

更复杂的测试

bash 复制代码
curl -X POST http://localhost:8082/api/math/calculate \
  -H "Content-Type: application/json" \
  -d '{
    "question": "先计算 100 的平方,然后除以 50"
  }'

响应

json 复制代码
{
  "question": "先计算 100 的平方,然后除以 50",
  "answer": "好的,让我分步计算:\n1. 首先计算 100 的平方:100² = 10000\n2. 然后用 10000 除以 50:10000 ÷ 50 = 200\n\n最终结果是 200。"
}
3.4.3 查看调用链路

Provider 日志

复制代码
2024-01-20 10:30:15.123 DEBUG [a2a-provider] Received A2A request for agent: math_agent
2024-01-20 10:30:15.125 DEBUG [a2a-provider] Invoking ReactAgent with message: 计算 123 + 456 的结果
2024-01-20 10:30:15.456 DEBUG [a2a-provider] Agent called tool: add(123.0, 456.0)
2024-01-20 10:30:15.457 DEBUG [a2a-provider] Tool returned: 579.0
2024-01-20 10:30:15.789 DEBUG [a2a-provider] Agent response completed

Consumer 日志

复制代码
2024-01-20 10:30:15.100 DEBUG [a2a-consumer] Discovering agent: math_agent
2024-01-20 10:30:15.110 DEBUG [a2a-consumer] Found agent at: http://192.168.1.10:8081
2024-01-20 10:30:15.120 DEBUG [a2a-consumer] Sending request to remote agent
2024-01-20 10:30:15.790 DEBUG [a2a-consumer] Received response from remote agent

4. 核心概念详解

4.1 AgentCard

AgentCard 是智能体的"名片",包含了智能体的所有元信息。

4.1.1 字段说明
java 复制代码
public class AgentCard {
    // 必需字段
    private String name;           // 智能体唯一标识
    private String endpoint;       // 服务端点地址

    // 可选字段
    private String description;    // 智能体描述
    private String version;        // 版本号
    private List<String> capabilities;  // 能力列表
    private Map<String, String> metadata;  // 自定义元数据
}

字段详解

字段 类型 必需 说明 示例
name String 智能体名称,必须唯一 "customer_service"
endpoint String REST API 端点 "http://192.168.1.10:8081"
description String 智能体功能描述 "智能客服机器人"
version String 版本号,支持语义化版本 "1.0.0", "2.1.3-beta"
capabilities List 支持的能力列表 ["tool_calling", "streaming"]
metadata Map 扩展元数据 {"team": "support", "max_qps": "100"}
4.1.2 创建 AgentCard

方式 1:通过配置自动生成(推荐)

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        server:
          card:
            name: my_agent
            description: "我的智能体"
            version: "1.0.0"

框架会自动创建 AgentCard 并注册到 Nacos。

方式 2:手动创建 Bean

java 复制代码
@Configuration
public class AgentCardConfig {

    @Bean
    public AgentCard myAgentCard() {
        return AgentCard.builder()
            .name("my_agent")
            .description("我的智能体")
            .version("1.0.0")
            .endpoint("http://localhost:8081")
            .capabilities(List.of("tool_calling", "streaming", "chinese"))
            .metadata(Map.of(
                "team", "ai-team",
                "owner", "zhangsan@example.com",
                "max_concurrent", "50",
                "timeout", "30s"
            ))
            .build();
    }
}
4.1.3 AgentCard 最佳实践

1. 命名规范

java 复制代码
// 好的命名
"customer_service"      // 清晰的业务含义
"code_reviewer"         // 功能明确
"data_analyzer_v2"      // 包含版本信息

// 不好的命名
"agent1"                // 无意义
"my-agent"              // 使用连字符(推荐使用下划线)
"CustomerService"       // 使用驼峰(推荐使用蛇形命名)

2. 版本管理

使用语义化版本:主版本.次版本.修订号

java 复制代码
"1.0.0"     // 初始版本
"1.1.0"     // 新增功能,向后兼容
"1.1.1"     // 修复 bug
"2.0.0"     // 重大变更,可能不向后兼容
"2.1.0-beta"  // 测试版本

3. 能力声明

在 capabilities 中声明智能体支持的特性:

java 复制代码
capabilities = List.of(
    "tool_calling",     // 支持工具调用
    "streaming",        // 支持流式响应
    "chinese",          // 支持中文
    "english",          // 支持英文
    "multimodal",       // 支持多模态(图片、音频等)
    "long_context"      // 支持长上下文
)

消费者可以根据能力筛选智能体:

java 复制代码
List<AgentCard> chineseAgents = agentCardProvider.findAgentCards(
    card -> card.getCapabilities().contains("chinese")
);

4. 元数据扩展

使用 metadata 存储额外信息:

java 复制代码
metadata = Map.of(
    // 团队信息
    "team", "customer-support",
    "owner", "zhangsan@example.com",
    "contact", "support@example.com",

    // 性能指标
    "max_qps", "100",           // 最大 QPS
    "avg_latency", "500ms",     // 平均延迟
    "timeout", "30s",           // 超时时间

    // 业务信息
    "business_domain", "ecommerce",
    "supported_languages", "zh-CN,en-US",

    // 部署信息
    "region", "cn-hangzhou",
    "environment", "production",
    "deploy_time", "2024-01-20T10:00:00Z"
)

4.2 AgentCardProvider

AgentCardProvider 是服务发现的核心接口,负责查询和管理 AgentCard。

4.2.1 接口定义
java 复制代码
public interface AgentCardProvider {
    /**
     * 根据名称获取智能体卡片
     * @param agentName 智能体名称
     * @return AgentCard,如果不存在返回 empty
     */
    Optional<AgentCard> getAgentCard(String agentName);

    /**
     * 列出所有可用的智能体
     * @return 智能体列表
     */
    List<AgentCard> listAgentCards();

    /**
     * 按条件查找智能体
     * @param filter 过滤条件
     * @return 匹配的智能体列表
     */
    default List<AgentCard> findAgentCards(Predicate<AgentCard> filter) {
        return listAgentCards().stream()
            .filter(filter)
            .collect(Collectors.toList());
    }
}
4.2.2 实现类

NacosAgentCardProvider

基于 Nacos 的动态服务发现:

java 复制代码
@Component
public class NacosAgentCardProvider implements AgentCardProvider {

    @Autowired
    private NamingService nacosNamingService;

    @Override
    public Optional<AgentCard> getAgentCard(String agentName) {
        try {
            // 从 Nacos 查询服务实例
            Instance instance = nacosNamingService.selectOneHealthyInstance(agentName);

            // 构造 AgentCard
            return Optional.of(buildAgentCard(instance));
        } catch (NacosException e) {
            return Optional.empty();
        }
    }

    @Override
    public List<AgentCard> listAgentCards() {
        try {
            // 获取所有服务列表
            ListView<String> services = nacosNamingService.getServicesOfServer(1, 100);

            return services.getData().stream()
                .map(this::getAgentCard)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toList());
        } catch (NacosException e) {
            return List.of();
        }
    }

    private AgentCard buildAgentCard(Instance instance) {
        Map<String, String> metadata = instance.getMetadata();

        return AgentCard.builder()
            .name(instance.getServiceName())
            .endpoint("http://" + instance.getIp() + ":" + instance.getPort())
            .description(metadata.get("description"))
            .version(metadata.get("version"))
            .capabilities(parseCapabilities(metadata.get("capabilities")))
            .metadata(metadata)
            .build();
    }
}

StaticAgentCardProvider

基于静态配置的服务发现(用于测试):

java 复制代码
@Component
public class StaticAgentCardProvider implements AgentCardProvider {

    private final Map<String, AgentCard> cards = new HashMap<>();

    public StaticAgentCardProvider() {
        // 配置静态服务列表
        cards.put("math_agent", AgentCard.builder()
            .name("math_agent")
            .endpoint("http://localhost:8081")
            .description("数学计算智能体")
            .version("1.0.0")
            .build());

        cards.put("weather_agent", AgentCard.builder()
            .name("weather_agent")
            .endpoint("http://localhost:8082")
            .description("天气查询智能体")
            .version("1.0.0")
            .build());
    }

    @Override
    public Optional<AgentCard> getAgentCard(String agentName) {
        return Optional.ofNullable(cards.get(agentName));
    }

    @Override
    public List<AgentCard> listAgentCards() {
        return new ArrayList<>(cards.values());
    }
}
4.2.3 使用示例

基础用法

java 复制代码
@Service
public class AgentDiscoveryService {

    @Autowired
    private AgentCardProvider agentCardProvider;

    public void discoverAgents() {
        // 1. 获取特定智能体
        Optional<AgentCard> mathAgent = agentCardProvider.getAgentCard("math_agent");
        mathAgent.ifPresent(card -> {
            System.out.println("找到智能体: " + card.getName());
            System.out.println("端点: " + card.getEndpoint());
            System.out.println("描述: " + card.getDescription());
        });

        // 2. 列出所有智能体
        List<AgentCard> allAgents = agentCardProvider.listAgentCards();
        System.out.println("共发现 " + allAgents.size() + " 个智能体");
        allAgents.forEach(card -> {
            System.out.println("- " + card.getName() + ": " + card.getDescription());
        });

        // 3. 按条件查找
        List<AgentCard> chineseAgents = agentCardProvider.findAgentCards(
            card -> card.getCapabilities() != null &&
                    card.getCapabilities().contains("chinese")
        );

        // 4. 按版本查找
        List<AgentCard> v2Agents = agentCardProvider.findAgentCards(
            card -> card.getVersion() != null &&
                    card.getVersion().startsWith("2.")
        );
    }
}

高级用法 - 智能路由

java 复制代码
@Service
public class IntelligentRouter {

    @Autowired
    private AgentCardProvider agentCardProvider;

    public A2aRemoteAgent selectBestAgent(String task) {
        // 获取所有客服智能体
        List<AgentCard> customerServiceAgents = agentCardProvider.findAgentCards(
            card -> card.getName().startsWith("customer_service_")
        );

        // 按负载排序(从 metadata 中获取当前 QPS)
        AgentCard bestAgent = customerServiceAgents.stream()
            .min(Comparator.comparingInt(card -> {
                String qps = card.getMetadata().get("current_qps");
                return qps != null ? Integer.parseInt(qps) : 0;
            }))
            .orElseThrow(() -> new RuntimeException("没有可用的客服智能体"));

        // 创建远程代理
        return A2aRemoteAgent.builder()
            .name(bestAgent.getName())
            .agentCardProvider(agentCardProvider)
            .build();
    }
}

4.3 A2aRemoteAgent

A2aRemoteAgent 是远程智能体的本地代理,提供与 ReactAgent 相同的接口。

4.3.1 创建远程智能体

基础用法

java 复制代码
@Service
public class RemoteAgentService {

    @Autowired
    private AgentCardProvider agentCardProvider;

    public A2aRemoteAgent createRemoteAgent(String agentName) {
        return A2aRemoteAgent.builder()
            .name(agentName)
            .agentCardProvider(agentCardProvider)
            .build();
    }
}

完整配置

java 复制代码
A2aRemoteAgent remoteAgent = A2aRemoteAgent.builder()
    .name("math_agent")                     // 远程智能体名称
    .agentCardProvider(agentCardProvider)   // 服务发现提供者
    .connectTimeout(Duration.ofSeconds(10)) // 连接超时
    .readTimeout(Duration.ofSeconds(30))    // 读取超时
    .maxRetries(3)                          // 最大重试次数
    .retryDelay(Duration.ofSeconds(1))      // 重试延迟
    .build();
4.3.2 调用方法

同步调用

java 复制代码
// 简单调用
Optional<OverAllState> result = remoteAgent.invoke("你好");

// 带配置的调用
RunnableConfig config = RunnableConfig.builder()
    .threadId("session_123")
    .metadata(Map.of("userId", "user_001"))
    .build();

Optional<OverAllState> result = remoteAgent.invoke("计算 100 + 200", config);

// 获取响应
String response = result
    .flatMap(state -> state.getLastMessage())
    .map(msg -> msg.getContent())
    .orElse("未获取到响应");

异步调用

java 复制代码
CompletableFuture<Optional<OverAllState>> future =
    CompletableFuture.supplyAsync(() -> remoteAgent.invoke("你好"));

future.thenAccept(result -> {
    result.flatMap(state -> state.getLastMessage())
          .ifPresent(msg -> System.out.println(msg.getContent()));
});

流式调用

java 复制代码
Flux<NodeOutput> stream = remoteAgent.stream("讲一个故事");

stream.subscribe(
    output -> {
        output.state().getLastMessage().ifPresent(msg -> {
            System.out.print(msg.getContent());
        });
    },
    error -> System.err.println("错误: " + error.getMessage()),
    () -> System.out.println("\n完成")
);
4.3.3 错误处理
java 复制代码
public String callRemoteAgent(String message) {
    try {
        Optional<OverAllState> result = remoteAgent.invoke(message);
        return result.flatMap(state -> state.getLastMessage())
                     .map(msg -> msg.getContent())
                     .orElse("未获取到响应");

    } catch (A2aException e) {
        // A2A 特定异常
        if (e instanceof AgentNotFoundException) {
            return "智能体未找到";
        } else if (e instanceof AgentUnavailableException) {
            return "智能体暂时不可用,请稍后重试";
        } else if (e instanceof A2aTimeoutException) {
            return "请求超时";
        } else {
            return "调用失败: " + e.getMessage();
        }

    } catch (Exception e) {
        // 其他异常
        return "系统错误: " + e.getMessage();
    }
}

4.4 注册中心

4.4.1 为什么需要注册中心?

注册中心解决了分布式系统中的核心问题:

  1. 服务发现:服务消费者如何找到服务提供者?
  2. 负载均衡:如何在多个服务实例间分配请求?
  3. 健康检查:如何及时发现并摘除故障实例?
  4. 动态扩缩容:如何自动适应服务实例的增减?

没有注册中心的问题

java 复制代码
// 硬编码服务地址
String endpoint = "http://192.168.1.10:8081";

// 问题:
// 1. IP 地址变更需要修改代码
// 2. 无法实现负载均衡
// 3. 实例下线无法感知
// 4. 无法动态扩容

使用注册中心

java 复制代码
// 通过名称发现服务
AgentCard card = agentCardProvider.getAgentCard("math_agent");

// 优势:
// 1. 自动发现可用实例
// 2. 自动负载均衡
// 3. 自动健康检查
// 4. 支持动态扩缩容
4.4.2 Nacos 核心概念

服务(Service)

服务是一组提供相同功能的实例的逻辑集合:

复制代码
math_agent 服务
  ├─ 实例 1: 192.168.1.10:8081
  ├─ 实例 2: 192.168.1.11:8081
  └─ 实例 3: 192.168.1.12:8081

实例(Instance)

实例是服务的具体运行单元:

java 复制代码
Instance {
    ip: "192.168.1.10",
    port: 8081,
    healthy: true,
    weight: 1.0,
    metadata: {
        "version": "1.0.0",
        "description": "数学计算智能体"
    }
}

命名空间(Namespace)

用于隔离不同环境的服务:

复制代码
├─ dev 命名空间
│  ├─ math_agent (开发环境)
│  └─ weather_agent (开发环境)
├─ test 命名空间
│  ├─ math_agent (测试环境)
│  └─ weather_agent (测试环境)
└─ prod 命名空间
   ├─ math_agent (生产环境)
   └─ weather_agent (生产环境)

分组(Group)

在同一命名空间内进一步分组:

复制代码
prod 命名空间
├─ DEFAULT_GROUP
│  ├─ math_agent
│  └─ weather_agent
├─ PAYMENT_GROUP
│  ├─ payment_agent
│  └─ refund_agent
└─ ORDER_GROUP
   ├─ order_agent
   └─ inventory_agent
4.4.3 服务注册流程
复制代码
应用启动
    ↓
1. 读取配置
   - Nacos 地址
   - 命名空间
   - 分组
    ↓
2. 创建 NamingService
   NamingFactory.createNamingService(properties)
    ↓
3. 构造实例信息
   Instance instance = new Instance();
   instance.setIp(getLocalIp());
   instance.setPort(serverPort);
   instance.setHealthy(true);
   instance.setMetadata(buildMetadata());
    ↓
4. 注册到 Nacos
   namingService.registerInstance(serviceName, instance);
    ↓
5. 启动心跳线程
   每 5 秒发送一次心跳
    ↓
服务注册成功
4.4.4 服务发现流程
复制代码
查询服务
    ↓
1. 调用 getAgentCard(name)
    ↓
2. 从 Nacos 获取实例列表
   List<Instance> instances =
       namingService.getAllInstances(name);
    ↓
3. 过滤健康实例
   instances.stream()
       .filter(Instance::isHealthy)
    ↓
4. 应用负载均衡
   - 加权随机
   - 轮询
   - 一致性哈希
    ↓
5. 选择一个实例
   Instance selected = loadBalancer.select(instances);
    ↓
6. 构造 AgentCard
   AgentCard card = buildCard(selected);
    ↓
7. 缓存结果(30 秒)
    ↓
返回 AgentCard
4.4.5 健康检查机制

心跳检查

服务实例每 5 秒向 Nacos 发送一次心跳:

复制代码
实例 ──(每 5秒)──> Nacos

如果 15 秒未收到心跳:
  - 标记为不健康
  - 但不删除

如果 30 秒未收到心跳:
  - 删除实例

主动健康检查

Nacos 也会主动检查实例:

复制代码
Nacos ──(HTTP GET)──> 实例的健康检查端点

如果响应 200:
  - 标记为健康

如果超时或错误:
  - 标记为不健康

在 Spring Boot 中配置健康检查端点:

java 复制代码
@RestController
public class HealthController {

    @GetMapping("/actuator/health")
    public Map<String, Object> health() {
        return Map.of(
            "status", "UP",
            "timestamp", System.currentTimeMillis()
        );
    }
}

(继续编写后续章节...由于内容非常长,我会分多次生成)

5. Nacos 集成

5.1 Nacos 介绍

Nacos (Dynamic Naming and Configuration Service) 是阿里巴巴开源的动态服务发现、配置管理和服务管理平台。

核心功能

  • 服务注册与发现
  • 动态配置管理
  • 服务健康监测
  • 动态 DNS 服务

为什么选择 Nacos?

  1. 阿里巴巴背书:经过双 11 大促验证
  2. 功能全面:集成注册中心和配置中心
  3. 高可用:支持集群部署
  4. 易于使用:提供 Web 控制台
  5. Spring Cloud 集成:与 Spring 生态无缝集成

5.2 Nacos 安装与配置

5.2.1 Docker 部署(单机模式)
bash 复制代码
# 拉取镜像
docker pull nacos/nacos-server:latest

# 启动容器
docker run -d \
  --name nacos \
  -e MODE=standalone \
  -e PREFER_HOST_MODE=hostname \
  -p 8848:8848 \
  -p 9848:9848 \
  -p 9849:9849 \
  nacos/nacos-server:latest
5.2.2 Docker Compose 部署(集群模式)

docker-compose.yml

yaml 复制代码
version: '3'
services:
  nacos1:
    image: nacos/nacos-server:latest
    container_name: nacos1
    environment:
      - MODE=cluster
      - NACOS_SERVERS=nacos1:8848 nacos2:8848 nacos3:8848
      - MYSQL_SERVICE_HOST=mysql
      - MYSQL_SERVICE_DB_NAME=nacos
      - MYSQL_SERVICE_USER=nacos
      - MYSQL_SERVICE_PASSWORD=nacos
    ports:
      - "8848:8848"
      - "9848:9848"
      - "9849:9849"
    depends_on:
      - mysql

  nacos2:
    image: nacos/nacos-server:latest
    container_name: nacos2
    environment:
      - MODE=cluster
      - NACOS_SERVERS=nacos1:8848 nacos2:8848 nacos3:8848
      - MYSQL_SERVICE_HOST=mysql
      - MYSQL_SERVICE_DB_NAME=nacos
      - MYSQL_SERVICE_USER=nacos
      - MYSQL_SERVICE_PASSWORD=nacos
    ports:
      - "8849:8848"
    depends_on:
      - mysql

  nacos3:
    image: nacos/nacos-server:latest
    container_name: nacos3
    environment:
      - MODE=cluster
      - NACOS_SERVERS=nacos1:8848 nacos2:8848 nacos3:8848
      - MYSQL_SERVICE_HOST=mysql
      - MYSQL_SERVICE_DB_NAME=nacos
      - MYSQL_SERVICE_USER=nacos
      - MYSQL_SERVICE_PASSWORD=nacos
    ports:
      - "8850:8848"
    depends_on:
      - mysql

  mysql:
    image: mysql:8.0
    container_name: nacos-mysql
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=nacos
      - MYSQL_USER=nacos
      - MYSQL_PASSWORD=nacos
    volumes:
      - ./mysql:/var/lib/mysql
      - ./nacos-mysql.sql:/docker-entrypoint-initdb.d/nacos-mysql.sql
    ports:
      - "3306:3306"

启动集群:

bash 复制代码
docker-compose up -d
5.2.3 独立部署
bash 复制代码
# 下载
wget https://github.com/alibaba/nacos/releases/download/2.4.3/nacos-server-2.4.3.tar.gz

# 解压
tar -xzf nacos-server-2.4.3.tar.gz
cd nacos

# 配置(可选)
# 编辑 conf/application.properties
# 修改数据库连接等配置

# 启动(单机模式)
sh bin/startup.sh -m standalone

# 启动(集群模式)
sh bin/startup.sh

# 停止
sh bin/shutdown.sh
5.2.4 访问控制台

访问:http://localhost:8848/nacos

默认账号:nacos / nacos

5.3 服务注册配置

5.3.1 基础配置
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          # Nacos 服务器地址
          server-addr: 127.0.0.1:8848

          # 服务注册配置
          registry:
            enabled: true              # 启用注册
            namespace: dev             # 命名空间
            group: DEFAULT_GROUP       # 分组
            cluster-name: DEFAULT      # 集群名称
            weight: 1.0                # 权重(0.0-1.0)

        # A2A Server 配置
        server:
          enabled: true
          card:
            name: my_agent
            description: "我的智能体"
            version: "1.0.0"
5.3.2 完整配置示例
yaml 复制代码
spring:
  application:
    name: agent-service

  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: 192.168.1.100:8848,192.168.1.101:8848,192.168.1.102:8848
          username: nacos          # Nacos 用户名
          password: nacos          # Nacos 密码

          registry:
            enabled: true
            namespace: prod        # 生产环境命名空间
            group: AI_AGENT_GROUP  # 自定义分组
            cluster-name: hz-cluster  # 杭州集群
            weight: 1.0

            # 元数据
            metadata:
              team: "ai-team"
              owner: "zhangsan@example.com"
              version: "1.0.0"
              region: "cn-hangzhou"

        server:
          enabled: true
          port: ${server.port}  # 使用 Spring Boot 端口

          card:
            name: ${spring.application.name}
            description: "生产环境智能体服务"
            version: "1.0.0"
            capabilities:
              - tool_calling
              - streaming
              - chinese
              - english

server:
  port: 8081
5.3.3 多环境配置

application.yml(公共配置)

yaml 复制代码
spring:
  application:
    name: agent-service

  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}

  ai:
    alibaba:
      a2a:
        server:
          enabled: true
          card:
            name: ${spring.application.name}

application-dev.yml(开发环境)

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848
          registry:
            enabled: true
            namespace: dev
            group: DEFAULT_GROUP
            weight: 1.0
        server:
          card:
            description: "开发环境智能体"
            version: "1.0.0-dev"

server:
  port: 8081

application-test.yml(测试环境)

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: nacos-test.example.com:8848
          registry:
            enabled: true
            namespace: test
            group: DEFAULT_GROUP
            weight: 1.0
        server:
          card:
            description: "测试环境智能体"
            version: "1.0.0-test"

server:
  port: 8081

application-prod.yml(生产环境)

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: nacos-1.prod.example.com:8848,nacos-2.prod.example.com:8848,nacos-3.prod.example.com:8848
          username: ${NACOS_USERNAME}
          password: ${NACOS_PASSWORD}
          registry:
            enabled: true
            namespace: prod
            group: AI_AGENT_GROUP
            cluster-name: ${CLUSTER_NAME:default}
            weight: 1.0
        server:
          card:
            description: "生产环境智能体"
            version: "1.0.0"

server:
  port: 8081

5.4 服务发现配置

5.4.1 基础配置
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848

          # 服务发现配置
          discovery:
            enabled: true
            namespace: dev
            group: DEFAULT_GROUP
5.4.2 高级配置
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: 192.168.1.100:8848
          username: nacos
          password: nacos

          discovery:
            enabled: true
            namespace: prod
            group: AI_AGENT_GROUP

            # 负载均衡策略
            load-balance-strategy: weighted-random  # weighted-random, round-robin, random

            # 缓存配置
            cache-enabled: true
            cache-ttl: 30s  # 缓存时间

            # 健康检查
            healthy-only: true  # 只返回健康实例

            # 监听配置变更
            watch-delay: 5s  # 监听延迟

6. 配置详解

6.1 完整配置示例

yaml 复制代码
server:
  port: 8081

spring:
  application:
    name: intelligent-agent-service

  ai:
    # DashScope 配置
    dashscope:
      api-key: ${AI_DASHSCOPE_API_KEY}
      chat:
        options:
          model: qwen-max
          temperature: 0.7

    alibaba:
      # A2A 配置
      a2a:
        # Nacos 配置
        nacos:
          # 服务器地址(支持多个地址,逗号分隔)
          server-addr: nacos-1.prod.com:8848,nacos-2.prod.com:8848,nacos-3.prod.com:8848

          # 认证信息
          username: ${NACOS_USERNAME:nacos}
          password: ${NACOS_PASSWORD:nacos}

          # 命名空间
          namespace: ${NACOS_NAMESPACE:prod}

          # 服务注册配置
          registry:
            enabled: true
            group: AI_AGENT_GROUP
            cluster-name: ${CLUSTER_NAME:default}
            weight: 1.0

            # 心跳配置
            heart-beat-interval: 5s
            heart-beat-timeout: 15s

            # IP 配置
            ip: ${SERVICE_IP:}  # 为空则自动检测
            prefer-ip-address: true

            # 元数据
            metadata:
              team: "ai-team"
              owner: "admin@example.com"
              version: "${project.version}"
              environment: "production"
              max_concurrent_requests: "100"
              avg_response_time: "500ms"

          # 服务发现配置
          discovery:
            enabled: true
            group: AI_AGENT_GROUP

            # 负载均衡
            load-balance-strategy: weighted-random

            # 缓存
            cache-enabled: true
            cache-ttl: 30s
            cache-max-size: 1000

            # 健康检查
            healthy-only: true

            # 监听配置变更
            watch-enabled: true
            watch-delay: 5s

        # A2A Server 配置
        server:
          enabled: true
          port: ${server.port}
          context-path: /api/a2a

          # 服务卡片
          card:
            name: ${spring.application.name}
            description: "智能代理服务"
            version: "1.0.0"
            capabilities:
              - tool_calling
              - streaming
              - chinese
              - english
              - long_context

          # 线程池配置
          executor:
            core-pool-size: 10
            max-pool-size: 50
            queue-capacity: 100
            thread-name-prefix: "a2a-server-"

          # 超时配置
          timeout:
            connect: 10s
            read: 30s
            write: 30s

        # A2A Client 配置
        client:
          # 连接池配置
          connection-pool:
            max-total: 200
            max-per-route: 20
            connection-timeout: 10s
            socket-timeout: 30s

          # 重试配置
          retry:
            enabled: true
            max-attempts: 3
            backoff:
              initial-interval: 1s
              multiplier: 2
              max-interval: 10s

          # 熔断配置
          circuit-breaker:
            enabled: true
            failure-rate-threshold: 50
            slow-call-rate-threshold: 50
            slow-call-duration-threshold: 5s
            sliding-window-size: 100
            minimum-number-of-calls: 10
            wait-duration-in-open-state: 60s

# 日志配置
logging:
  level:
    com.alibaba.cloud.ai: DEBUG
    com.alibaba.nacos: INFO
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

# 监控配置
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  metrics:
    tags:
      application: ${spring.application.name}

6.2 注册配置参数

参数 类型 默认值 说明
spring.ai.alibaba.a2a.nacos.registry.enabled Boolean false 是否启用服务注册
spring.ai.alibaba.a2a.nacos.registry.namespace String public 命名空间 ID
spring.ai.alibaba.a2a.nacos.registry.group String DEFAULT_GROUP 服务分组
spring.ai.alibaba.a2a.nacos.registry.cluster-name String DEFAULT 集群名称
spring.ai.alibaba.a2a.nacos.registry.weight Double 1.0 权重(0.0-1.0)
spring.ai.alibaba.a2a.nacos.registry.ip String 自动检测 服务 IP 地址
spring.ai.alibaba.a2a.nacos.registry.port Integer server.port 服务端口
spring.ai.alibaba.a2a.nacos.registry.prefer-ip-address Boolean true 优先使用 IP 注册
spring.ai.alibaba.a2a.nacos.registry.heart-beat-interval Duration 5s 心跳间隔
spring.ai.alibaba.a2a.nacos.registry.heart-beat-timeout Duration 15s 心跳超时
spring.ai.alibaba.a2a.nacos.registry.metadata Map {} 元数据

6.3 发现配置参数

参数 类型 默认值 说明
spring.ai.alibaba.a2a.nacos.discovery.enabled Boolean false 是否启用服务发现
spring.ai.alibaba.a2a.nacos.discovery.namespace String public 命名空间 ID
spring.ai.alibaba.a2a.nacos.discovery.group String DEFAULT_GROUP 服务分组
spring.ai.alibaba.a2a.nacos.discovery.healthy-only Boolean true 只返回健康实例
spring.ai.alibaba.a2a.nacos.discovery.load-balance-strategy String weighted-random 负载均衡策略
spring.ai.alibaba.a2a.nacos.discovery.cache-enabled Boolean true 启用缓存
spring.ai.alibaba.a2a.nacos.discovery.cache-ttl Duration 30s 缓存过期时间
spring.ai.alibaba.a2a.nacos.discovery.cache-max-size Integer 1000 缓存最大条目数
spring.ai.alibaba.a2a.nacos.discovery.watch-enabled Boolean true 监听配置变更
spring.ai.alibaba.a2a.nacos.discovery.watch-delay Duration 5s 监听延迟

6.4 网络配置

6.4.1 超时配置
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        client:
          # 连接超时
          connection-timeout: 10s

          # 读取超时
          read-timeout: 30s

          # 写入超时
          write-timeout: 30s

          # 总体超时(连接 + 读取)
          request-timeout: 40s
6.4.2 连接池配置
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        client:
          connection-pool:
            # 最大连接数
            max-total: 200

            # 每个路由的最大连接数
            max-per-route: 20

            # 连接空闲时间(超过则关闭)
            idle-timeout: 30s

            # 连接存活时间
            time-to-live: 5m
6.4.3 重试配置
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        client:
          retry:
            enabled: true
            max-attempts: 3

            # 可重试的异常
            retryable-exceptions:
              - java.net.ConnectException
              - java.net.SocketTimeoutException
              - org.springframework.web.client.ResourceAccessException

            # 退避策略
            backoff:
              initial-interval: 1s
              multiplier: 2
              max-interval: 10s

由于文档非常长,我会继续生成剩余章节。让我继续完成这个详细的 A2A 文档...

7. 服务注册

7.1 自动注册(推荐)

Spring AI Alibaba 提供了自动注册机制,只需配置即可自动注册智能体服务。

7.1.1 配置步骤

步骤 1:添加依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter-a2a-nacos</artifactId>
    <version>1.1.0.0-RC1</version>
</dependency>

步骤 2:配置文件

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          server-addr: 127.0.0.1:8848
          registry:
            enabled: true
        server:
          enabled: true
          card:
            name: my_agent
            description: "我的智能体"
            version: "1.0.0"

步骤 3:定义智能体

java 复制代码
@Bean
public ReactAgent myAgent(ChatModel chatModel) {
    return ReactAgent.builder()
        .name("my_agent")  // 名称必须与配置中的 card.name 一致
        .model(chatModel)
        .build();
}

应用启动后,智能体会自动注册到 Nacos。

7.1.2 自动注册原理
复制代码
应用启动
    ↓
Spring Boot 启动完成事件
    ↓
A2aServerAutoConfiguration 初始化
    ↓
扫描所有 ReactAgent Bean
    ↓
为每个 Agent 创建 REST 端点
  POST /api/a2a/{agentName}
  POST /api/a2a/{agentName}/stream
    ↓
构造 AgentCard
  - name: 从配置或 Bean 获取
  - endpoint: http://{ip}:{port}
  - description, version 等
    ↓
注册到 Nacos
  NamingService.registerInstance()
    ↓
启动心跳线程
  每 5 秒发送一次心跳
    ↓
注册完成
7.1.3 验证注册

方式 1:通过 Nacos 控制台

  1. 访问 http://localhost:8848/nacos
  2. 进入"服务管理" → "服务列表"
  3. 查找你的服务名称(如 my_agent
  4. 查看实例列表和健康状态

方式 2:通过 Nacos Open API

bash 复制代码
curl "http://localhost:8848/nacos/v1/ns/instance/list?serviceName=my_agent"

响应:

json 复制代码
{
  "name": "DEFAULT_GROUP@@my_agent",
  "hosts": [
    {
      "ip": "192.168.1.10",
      "port": 8081,
      "healthy": true,
      "weight": 1.0,
      "metadata": {
        "name": "my_agent",
        "description": "我的智能体",
        "version": "1.0.0"
      }
    }
  ]
}

方式 3:通过应用日志

复制代码
2024-01-20 10:00:15.123 INFO  c.a.c.a.a2a.registry.NacosAgentRegistry  : Registering agent: my_agent
2024-01-20 10:00:15.456 INFO  c.a.c.a.a2a.registry.NacosAgentRegistry  : Agent registered successfully: my_agent at http://192.168.1.10:8081
2024-01-20 10:00:15.457 INFO  c.a.c.a.a2a.server.A2aServerEndpoint     : A2A endpoint created: POST /api/a2a/my_agent

7.2 手动注册

在某些场景下,你可能需要手动控制注册过程。

7.2.1 使用 AgentRegistry
java 复制代码
@Service
public class ManualRegistrationService {

    @Autowired
    private AgentRegistry agentRegistry;

    @Autowired
    private ReactAgent myAgent;

    @PostConstruct
    public void registerAgent() {
        // 构造 AgentCard
        AgentCard card = AgentCard.builder()
            .name(myAgent.name())
            .description("手动注册的智能体")
            .version("1.0.0")
            .endpoint("http://localhost:8081")
            .capabilities(List.of("tool_calling", "streaming"))
            .metadata(Map.of(
                "team", "ai-team",
                "environment", "production"
            ))
            .build();

        // 注册
        agentRegistry.register(card);

        System.out.println("智能体已注册: " + card.getName());
    }

    @PreDestroy
    public void unregisterAgent() {
        // 注销
        agentRegistry.unregister(myAgent.name());
        System.out.println("智能体已注销: " + myAgent.name());
    }
}
7.2.2 动态注册和注销
java 复制代码
@RestController
@RequestMapping("/api/registry")
public class RegistryController {

    @Autowired
    private AgentRegistry agentRegistry;

    @PostMapping("/register")
    public ResponseEntity<String> register(@RequestBody AgentCard card) {
        try {
            agentRegistry.register(card);
            return ResponseEntity.ok("注册成功: " + card.getName());
        } catch (Exception e) {
            return ResponseEntity.status(500).body("注册失败: " + e.getMessage());
        }
    }

    @PostMapping("/unregister/{agentName}")
    public ResponseEntity<String> unregister(@PathVariable String agentName) {
        try {
            agentRegistry.unregister(agentName);
            return ResponseEntity.ok("注销成功: " + agentName);
        } catch (Exception e) {
            return ResponseEntity.status(500).body("注销失败: " + e.getMessage());
        }
    }

    @GetMapping("/status/{agentName}")
    public ResponseEntity<Map<String, Object>> getStatus(@PathVariable String agentName) {
        boolean registered = agentRegistry.isRegistered(agentName);
        return ResponseEntity.ok(Map.of(
            "agentName", agentName,
            "registered", registered
        ));
    }
}

7.3 AgentCard 详解

7.3.1 完整示例
java 复制代码
AgentCard card = AgentCard.builder()
    // 必需字段
    .name("customer_service")
    .endpoint("http://192.168.1.10:8081")

    // 基本信息
    .description("智能客服机器人,提供7x24小时服务")
    .version("2.1.0")

    // 能力列表
    .capabilities(List.of(
        "tool_calling",      // 支持工具调用
        "streaming",         // 支持流式响应
        "chinese",           // 支持中文
        "english",           // 支持英文
        "multimodal",        // 支持多模态
        "long_context"       // 支持长上下文
    ))

    // 扩展元数据
    .metadata(Map.of(
        // 团队信息
        "team", "customer-support",
        "owner", "zhangsan@example.com",
        "contact", "support@example.com",

        // 性能指标
        "max_qps", "200",
        "avg_latency_ms", "500",
        "p99_latency_ms", "2000",
        "timeout_seconds", "30",

        // 业务信息
        "business_domain", "ecommerce",
        "supported_channels", "web,mobile,wechat",

        // 部署信息
        "region", "cn-hangzhou",
        "availability_zone", "cn-hangzhou-b",
        "environment", "production",
        "cluster", "prod-cluster-1",
        "instance_type", "8core-16gb",

        // 版本信息
        "git_commit", "a1b2c3d4",
        "build_time", "2024-01-20T10:00:00Z",
        "deploy_time", "2024-01-20T12:00:00Z"
    ))

    .build();
7.3.2 Capabilities 使用场景

场景 1:按能力筛选智能体

java 复制代码
// 查找支持中文的智能体
List<AgentCard> chineseAgents = agentCardProvider.findAgentCards(
    card -> card.getCapabilities() != null &&
            card.getCapabilities().contains("chinese")
);

// 查找支持流式响应的智能体
List<AgentCard> streamingAgents = agentCardProvider.findAgentCards(
    card -> card.getCapabilities() != null &&
            card.getCapabilities().contains("streaming")
);

// 查找同时支持中文和工具调用的智能体
List<AgentCard> advancedAgents = agentCardProvider.findAgentCards(
    card -> {
        List<String> caps = card.getCapabilities();
        return caps != null &&
               caps.contains("chinese") &&
               caps.contains("tool_calling");
    }
);

场景 2:客户端能力协商

java 复制代码
public class CapabilityNegotiationService {

    public A2aRemoteAgent selectAgent(List<String> requiredCapabilities) {
        // 查找满足所有要求的智能体
        List<AgentCard> candidates = agentCardProvider.findAgentCards(
            card -> {
                List<String> caps = card.getCapabilities();
                return caps != null &&
                       caps.containsAll(requiredCapabilities);
            }
        );

        if (candidates.isEmpty()) {
            throw new RuntimeException("没有满足要求的智能体");
        }

        // 选择第一个候选
        AgentCard selected = candidates.get(0);

        return A2aRemoteAgent.builder()
            .name(selected.getName())
            .agentCardProvider(agentCardProvider)
            .build();
    }
}

// 使用
A2aRemoteAgent agent = service.selectAgent(
    List.of("chinese", "tool_calling", "streaming")
);
7.3.3 Metadata 最佳实践

类别 1:性能指标

java 复制代码
metadata.put("max_qps", "200");              // 最大 QPS
metadata.put("avg_latency_ms", "500");       // 平均延迟
metadata.put("p95_latency_ms", "1000");      // P95 延迟
metadata.put("p99_latency_ms", "2000");      // P99 延迟
metadata.put("timeout_seconds", "30");        // 超时时间
metadata.put("max_concurrent", "100");        // 最大并发数

类别 2:业务信息

java 复制代码
metadata.put("business_domain", "finance");       // 业务领域
metadata.put("supported_languages", "zh,en");     // 支持的语言
metadata.put("data_classification", "internal");  // 数据分类
metadata.put("sla_level", "gold");                // SLA 等级

类别 3:路由信息

java 复制代码
metadata.put("region", "cn-hangzhou");        // 地域
metadata.put("availability_zone", "zone-a");  // 可用区
metadata.put("isp", "aliyun");                // 云服务商
metadata.put("weight", "1.0");                // 权重

类别 4:监控和调试

java 复制代码
metadata.put("log_level", "INFO");            // 日志级别
metadata.put("trace_enabled", "true");        // 是否启用追踪
metadata.put("metrics_endpoint", "/metrics"); // 监控端点
metadata.put("health_endpoint", "/health");   // 健康检查端点

7.4 注册生命周期

7.4.1 生命周期事件
复制代码
应用启动
    ↓
┌─────────────────────────────┐
│ BEFORE_REGISTER             │  注册前
│ - 构造 AgentCard             │
│ - 验证配置                   │
└──────────┬──────────────────┘
           ↓
┌─────────────────────────────┐
│ REGISTERING                 │  注册中
│ - 连接 Nacos                 │
│ - 注册实例                   │
└──────────┬──────────────────┘
           ↓
┌─────────────────────────────┐
│ REGISTERED                  │  已注册
│ - 启动心跳线程               │
│ - 开始接收请求               │
└──────────┬──────────────────┘
           │
           │ (运行中)
           │
           ↓
┌─────────────────────────────┐
│ BEFORE_UNREGISTER           │  注销前
│ - 停止接收新请求             │
│ - 等待现有请求完成           │
└──────────┬──────────────────┘
           ↓
┌─────────────────────────────┐
│ UNREGISTERING               │  注销中
│ - 停止心跳线程               │
│ - 从 Nacos 注销实例          │
└──────────┬──────────────────┘
           ↓
┌─────────────────────────────┐
│ UNREGISTERED                │  已注销
│ - 清理资源                   │
│ - 关闭连接                   │
└─────────────────────────────┘
7.4.2 监听生命周期事件
java 复制代码
@Component
public class AgentLifecycleListener {

    @EventListener
    public void onRegistered(AgentRegisteredEvent event) {
        AgentCard card = event.getAgentCard();
        System.out.println("智能体已注册: " + card.getName());
        System.out.println("端点: " + card.getEndpoint());

        // 执行注册后的操作
        // 例如:发送通知、记录日志、启动监控等
    }

    @EventListener
    public void onUnregistered(AgentUnregisteredEvent event) {
        String agentName = event.getAgentName();
        System.out.println("智能体已注销: " + agentName);

        // 执行注销后的操作
        // 例如:清理缓存、关闭连接、发送通知等
    }

    @EventListener
    public void onRegistrationFailed(AgentRegistrationFailedEvent event) {
        System.err.println("注册失败: " + event.getAgentName());
        System.err.println("原因: " + event.getCause().getMessage());

        // 执行失败处理
        // 例如:重试注册、发送告警、记录错误等
    }
}
7.4.3 优雅关闭

确保应用关闭时正确注销服务:

java 复制代码
@Component
public class GracefulShutdown {

    @Autowired
    private AgentRegistry agentRegistry;

    @Autowired
    private List<ReactAgent> agents;

    @PreDestroy
    public void shutdown() {
        System.out.println("开始优雅关闭...");

        // 1. 停止接收新请求
        stopAcceptingNewRequests();

        // 2. 等待现有请求完成(最多等待 30 秒)
        waitForActiveRequests(30);

        // 3. 注销所有智能体
        agents.forEach(agent -> {
            try {
                agentRegistry.unregister(agent.name());
                System.out.println("已注销: " + agent.name());
            } catch (Exception e) {
                System.err.println("注销失败: " + agent.name() + ", " + e.getMessage());
            }
        });

        System.out.println("优雅关闭完成");
    }

    private void stopAcceptingNewRequests() {
        // 实现停止接收新请求的逻辑
    }

    private void waitForActiveRequests(int maxWaitSeconds) {
        // 实现等待现有请求完成的逻辑
    }
}

8. 服务发现

8.1 发现机制

8.1.1 发现流程
复制代码
客户端请求 getAgentCard("math_agent")
    ↓
┌─────────────────────────────────┐
│ 1. 检查本地缓存                  │
│    if (cache.contains(name))    │
│        return cache.get(name)   │
└──────────┬──────────────────────┘
           ↓ (未命中)
┌─────────────────────────────────┐
│ 2. 查询 Nacos                    │
│    instances =                  │
│      nacos.getAllInstances(name)│
└──────────┬──────────────────────┘
           ↓
┌─────────────────────────────────┐
│ 3. 过滤健康实例                  │
│    healthy = instances.stream() │
│      .filter(i -> i.isHealthy())│
└──────────┬──────────────────────┘
           ↓
┌─────────────────────────────────┐
│ 4. 应用负载均衡                  │
│    selected =                   │
│      loadBalancer.select(healthy)│
└──────────┬──────────────────────┘
           ↓
┌─────────────────────────────────┐
│ 5. 构造 AgentCard                │
│    card = buildCard(selected)   │
└──────────┬──────────────────────┘
           ↓
┌─────────────────────────────────┐
│ 6. 缓存结果                      │
│    cache.put(name, card, 30s)   │
└──────────┬──────────────────────┘
           ↓
        返回 AgentCard
8.1.2 缓存机制

为什么需要缓存?

  1. 减少 Nacos 查询:避免每次调用都查询 Nacos
  2. 提高性能:本地缓存查询速度远快于网络请求
  3. 降低延迟:减少服务发现的延迟
  4. 减轻 Nacos 压力:降低 Nacos 服务器的负载

缓存配置

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          discovery:
            cache-enabled: true
            cache-ttl: 30s        # 缓存过期时间
            cache-max-size: 1000  # 最大缓存条目数

缓存失效策略

  1. TTL 过期:缓存条目在 30 秒后自动过期
  2. 主动刷新:收到 Nacos 推送的变更通知时刷新
  3. 失败重试:调用失败时尝试刷新缓存

8.2 查询服务

8.2.1 基本查询
java 复制代码
@Service
public class AgentQueryService {

    @Autowired
    private AgentCardProvider agentCardProvider;

    // 查询单个智能体
    public Optional<AgentCard> getAgent(String agentName) {
        return agentCardProvider.getAgentCard(agentName);
    }

    // 列出所有智能体
    public List<AgentCard> listAllAgents() {
        return agentCardProvider.listAgentCards();
    }

    // 按条件查找
    public List<AgentCard> findAgents(Predicate<AgentCard> filter) {
        return agentCardProvider.findAgentCards(filter);
    }
}
8.2.2 高级查询

按版本查询

java 复制代码
// 查找特定版本
public List<AgentCard> findByVersion(String version) {
    return agentCardProvider.findAgentCards(
        card -> version.equals(card.getVersion())
    );
}

// 查找主版本号匹配的所有版本
public List<AgentCard> findByMajorVersion(String majorVersion) {
    return agentCardProvider.findAgentCards(
        card -> card.getVersion() != null &&
                card.getVersion().startsWith(majorVersion + ".")
    );
}

// 查找最新版本
public Optional<AgentCard> findLatestVersion(String agentBaseName) {
    return agentCardProvider.listAgentCards().stream()
        .filter(card -> card.getName().startsWith(agentBaseName))
        .max(Comparator.comparing(card -> parseVersion(card.getVersion())));
}

按能力查询

java 复制代码
// 查找具有特定能力的智能体
public List<AgentCard> findByCapability(String capability) {
    return agentCardProvider.findAgentCards(
        card -> {
            List<String> caps = card.getCapabilities();
            return caps != null && caps.contains(capability);
        }
    );
}

// 查找具有多个能力的智能体
public List<AgentCard> findByCapabilities(List<String> requiredCapabilities) {
    return agentCardProvider.findAgentCards(
        card -> {
            List<String> caps = card.getCapabilities();
            return caps != null && caps.containsAll(requiredCapabilities);
        }
    );
}

按元数据查询

java 复制代码
// 按团队查找
public List<AgentCard> findByTeam(String team) {
    return agentCardProvider.findAgentCards(
        card -> team.equals(card.getMetadata().get("team"))
    );
}

// 按地域查找
public List<AgentCard> findByRegion(String region) {
    return agentCardProvider.findAgentCards(
        card -> region.equals(card.getMetadata().get("region"))
    );
}

// 按 SLA 等级查找
public List<AgentCard> findBySLA(String slaLevel) {
    return agentCardProvider.findAgentCards(
        card -> slaLevel.equals(card.getMetadata().get("sla_level"))
    );
}
8.2.3 查询优化

批量查询

java 复制代码
public Map<String, AgentCard> batchGetAgents(List<String> agentNames) {
    return agentNames.stream()
        .collect(Collectors.toMap(
            name -> name,
            name -> agentCardProvider.getAgentCard(name).orElse(null),
            (a, b) -> a
        ));
}

预加载缓存

java 复制代码
@Component
public class AgentCacheWarmer {

    @Autowired
    private AgentCardProvider agentCardProvider;

    @EventListener(ApplicationReadyEvent.class)
    public void warmupCache() {
        System.out.println("预热智能体缓存...");

        // 预加载常用智能体
        List<String> commonAgents = List.of(
            "customer_service",
            "math_agent",
            "weather_agent"
        );

        commonAgents.forEach(name -> {
            agentCardProvider.getAgentCard(name);
            System.out.println("已预加载: " + name);
        });

        System.out.println("缓存预热完成");
    }
}

8.3 负载均衡

8.3.1 负载均衡策略

加权随机(Weighted Random)

根据权重随机选择实例,权重越高被选中的概率越大。

复制代码
实例 A (权重 3) ───┐
实例 B (权重 2) ───┼→ 选择概率: A=60%, B=40%
                  │

轮询(Round Robin)

依次选择每个实例,确保流量均匀分配。

复制代码
请求 1 → 实例 A
请求 2 → 实例 B
请求 3 → 实例 C
请求 4 → 实例 A  (循环)

一致性哈希(Consistent Hash)

根据请求的某个属性(如用户 ID)选择实例,确保同一属性的请求总是路由到同一实例。

复制代码
user_001 → 实例 A
user_002 → 实例 B
user_001 → 实例 A  (相同用户)
8.3.2 配置负载均衡
yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          discovery:
            # 负载均衡策略
            load-balance-strategy: weighted-random  # weighted-random, round-robin, consistent-hash
8.3.3 自定义负载均衡
java 复制代码
public interface LoadBalancer {
    /**
     * 从实例列表中选择一个
     * @param instances 可用实例列表
     * @param context 上下文信息
     * @return 选中的实例
     */
    Instance select(List<Instance> instances, LoadBalanceContext context);
}

实现自定义负载均衡器

java 复制代码
@Component
public class LatencyBasedLoadBalancer implements LoadBalancer {

    @Override
    public Instance select(List<Instance> instances, LoadBalanceContext context) {
        // 选择延迟最低的实例
        return instances.stream()
            .min(Comparator.comparingInt(this::getLatency))
            .orElseThrow(() -> new RuntimeException("没有可用实例"));
    }

    private int getLatency(Instance instance) {
        // 从元数据中获取延迟信息
        String latency = instance.getMetadata().get("avg_latency_ms");
        return latency != null ? Integer.parseInt(latency) : Integer.MAX_VALUE;
    }
}

注册自定义负载均衡器

java 复制代码
@Configuration
public class LoadBalancerConfig {

    @Bean
    public LoadBalancer customLoadBalancer() {
        return new LatencyBasedLoadBalancer();
    }
}

8.4 健康检查

8.4.1 健康检查机制

心跳检查

服务实例定期发送心跳给 Nacos:

复制代码
实例 ──(每 5秒)──> Nacos

Nacos 判断:
- 收到心跳: 标记为健康
- 15 秒未收到: 标记为不健康
- 30 秒未收到: 删除实例

主动健康检查

Nacos 定期检查实例的健康端点:

复制代码
Nacos ──(HTTP GET)──> 实例的 /actuator/health

如果返回 200 且 status=UP:
  - 标记为健康
否则:
  - 标记为不健康
8.4.2 配置健康检查

Spring Boot Actuator 配置

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include: health,info
  endpoint:
    health:
      show-details: always
  health:
    nacos:
      enabled: true
8.4.3 自定义健康指标
java 复制代码
@Component
public class AgentHealthIndicator implements HealthIndicator {

    @Autowired
    private ChatModel chatModel;

    @Autowired
    private List<ReactAgent> agents;

    @Override
    public Health health() {
        try {
            // 检查模型连接
            boolean modelHealthy = checkModelConnection();

            // 检查智能体状态
            Map<String, String> agentStatus = agents.stream()
                .collect(Collectors.toMap(
                    ReactAgent::name,
                    agent -> "UP"
                ));

            if (modelHealthy) {
                return Health.up()
                    .withDetail("model", "connected")
                    .withDetail("agents", agentStatus)
                    .build();
            } else {
                return Health.down()
                    .withDetail("model", "disconnected")
                    .withDetail("agents", agentStatus)
                    .build();
            }

        } catch (Exception e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
    }

    private boolean checkModelConnection() {
        try {
            // 发送一个简单的测试请求
            chatModel.call("test");
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
8.4.4 故障实例处理

自动摘除不健康实例

yaml 复制代码
spring:
  ai:
    alibaba:
      a2a:
        nacos:
          discovery:
            healthy-only: true  # 只返回健康实例

手动摘除实例

java 复制代码
@RestController
@RequestMapping("/api/management")
public class InstanceManagementController {

    @Autowired
    private NamingService nacosNamingService;

    @PostMapping("/instance/offline")
    public ResponseEntity<String> offlineInstance(
        @RequestParam String serviceName,
        @RequestParam String ip,
        @RequestParam int port
    ) {
        try {
            // 将实例标记为不健康
            Instance instance = nacosNamingService.getInstance(serviceName, ip, port);
            instance.setHealthy(false);
            nacosNamingService.registerInstance(serviceName, instance);

            return ResponseEntity.ok("实例已下线");
        } catch (Exception e) {
            return ResponseEntity.status(500).body("下线失败: " + e.getMessage());
        }
    }

    @PostMapping("/instance/online")
    public ResponseEntity<String> onlineInstance(
        @RequestParam String serviceName,
        @RequestParam String ip,
        @RequestParam int port
    ) {
        try {
            // 将实例标记为健康
            Instance instance = nacosNamingService.getInstance(serviceName, ip, port);
            instance.setHealthy(true);
            nacosNamingService.registerInstance(serviceName, instance);

            return ResponseEntity.ok("实例已上线");
        } catch (Exception e) {
            return ResponseEntity.status(500).body("上线失败: " + e.getMessage());
        }
    }
}

9. 远程智能体调用

9.1 创建远程智能体代理

9.1.1 基础创建
java 复制代码
@Service
public class RemoteAgentFactory {

    @Autowired
    private AgentCardProvider agentCardProvider;

    public A2aRemoteAgent createRemoteAgent(String agentName) {
        return A2aRemoteAgent.builder()
            .name(agentName)
            .agentCardProvider(agentCardProvider)
            .build();
    }
}
9.1.2 完整配置
java 复制代码
A2aRemoteAgent remoteAgent = A2aRemoteAgent.builder()
    // 必需配置
    .name("math_agent")
    .agentCardProvider(agentCardProvider)

    // 超时配置
    .connectTimeout(Duration.ofSeconds(10))   // 连接超时
    .readTimeout(Duration.ofSeconds(30))      // 读取超时
    .writeTimeout(Duration.ofSeconds(30))     // 写入超时

    // 重试配置
    .maxRetries(3)                            // 最大重试次数
    .retryDelay(Duration.ofSeconds(1))        // 重试延迟

    // 熔断配置
    .circuitBreakerEnabled(true)              // 启用熔断
    .failureRateThreshold(50)                 // 失败率阈值 50%
    .slowCallDurationThreshold(Duration.ofSeconds(5))  // 慢调用阈值

    // 其他配置
    .followRedirects(true)                    // 跟随重定向
    .bufferRequestBody(false)                 // 不缓冲请求体(流式传输)

    .build();
9.1.3 使用 Bean 注入
java 复制代码
@Configuration
public class RemoteAgentConfig {

    @Autowired
    private AgentCardProvider agentCardProvider;

    @Bean
    public A2aRemoteAgent mathAgent() {
        return A2aRemoteAgent.builder()
            .name("math_agent")
            .agentCardProvider(agentCardProvider)
            .connectTimeout(Duration.ofSeconds(10))
            .readTimeout(Duration.ofSeconds(30))
            .build();
    }

    @Bean
    public A2aRemoteAgent weatherAgent() {
        return A2aRemoteAgent.builder()
            .name("weather_agent")
            .agentCardProvider(agentCardProvider)
            .build();
    }
}

// 使用
@Service
public class MyService {

    @Autowired
    @Qualifier("mathAgent")
    private A2aRemoteAgent mathAgent;

    @Autowired
    @Qualifier("weatherAgent")
    private A2aRemoteAgent weatherAgent;

    public void useAgents() {
        mathAgent.invoke("计算 1 + 1");
        weatherAgent.invoke("北京天气");
    }
}

9.2 同步调用

9.2.1 简单调用
java 复制代码
// 最简单的调用
Optional<OverAllState> result = remoteAgent.invoke("你好");

// 获取响应内容
String response = result
    .flatMap(state -> state.getLastMessage())
    .map(msg -> msg.getContent())
    .orElse("未获取到响应");
9.2.2 带配置的调用
java 复制代码
// 创建配置
RunnableConfig config = RunnableConfig.builder()
    .threadId("session_123")              // 会话 ID
    .metadata(Map.of(                     // 元数据
        "userId", "user_001",
        "clientType", "web",
        "timestamp", System.currentTimeMillis()
    ))
    .build();

// 调用
Optional<OverAllState> result = remoteAgent.invoke("计算 100 + 200", config);

// 获取完整状态
result.ifPresent(state -> {
    // 消息列表
    List<Message> messages = state.getMessages();

    // 自定义数据
    Object customData = state.getValue("custom_key");

    // 最后一条消息
    Optional<Message> lastMsg = state.getLastMessage();
});
9.2.3 错误处理
java 复制代码
public String callRemoteAgentSafely(String message) {
    try {
        Optional<OverAllState> result = remoteAgent.invoke(message);
        return result
            .flatMap(state -> state.getLastMessage())
            .map(msg -> msg.getContent())
            .orElse("未获取到响应");

    } catch (AgentNotFoundException e) {
        // 智能体未找到
        return "错误:智能体不存在";

    } catch (AgentUnavailableException e) {
        // 智能体不可用
        return "错误:智能体暂时不可用,请稍后重试";

    } catch (A2aTimeoutException e) {
        // 超时
        return "错误:请求超时";

    } catch (A2aException e) {
        // 其他 A2A 异常
        return "错误:" + e.getMessage();

    } catch (Exception e) {
        // 未知异常
        log.error("调用远程智能体失败", e);
        return "系统错误,请联系管理员";
    }
}
9.2.4 超时控制
java 复制代码
// 方式 1:创建时配置
A2aRemoteAgent agent = A2aRemoteAgent.builder()
    .name("math_agent")
    .agentCardProvider(provider)
    .readTimeout(Duration.ofSeconds(30))
    .build();

// 方式 2:使用 CompletableFuture 控制总体超时
CompletableFuture<Optional<OverAllState>> future =
    CompletableFuture.supplyAsync(() -> agent.invoke(message));

try {
    Optional<OverAllState> result = future.get(30, TimeUnit.SECONDS);
    // 处理结果
} catch (TimeoutException e) {
    future.cancel(true);
    System.err.println("调用超时");
}

9.3 异步调用

9.3.1 使用 CompletableFuture
java 复制代码
// 异步调用
CompletableFuture<Optional<OverAllState>> future =
    CompletableFuture.supplyAsync(() ->
        remoteAgent.invoke("计算 1 + 1")
    );

// 处理结果
future.thenAccept(result -> {
    result.flatMap(state -> state.getLastMessage())
          .ifPresent(msg -> {
              System.out.println("结果: " + msg.getContent());
          });
});

// 或者阻塞等待
Optional<OverAllState> result = future.get();
9.3.2 并发调用多个智能体
java 复制代码
public Map<String, String> callMultipleAgents(String message) {
    List<CompletableFuture<Map.Entry<String, String>>> futures = List.of(
        CompletableFuture.supplyAsync(() -> {
            String response = mathAgent.invoke(message)
                .flatMap(state -> state.getLastMessage())
                .map(msg -> msg.getContent())
                .orElse("");
            return Map.entry("math", response);
        }),

        CompletableFuture.supplyAsync(() -> {
            String response = weatherAgent.invoke(message)
                .flatMap(state -> state.getLastMessage())
                .map(msg -> msg.getContent())
                .orElse("");
            return Map.entry("weather", response);
        }),

        CompletableFuture.supplyAsync(() -> {
            String response = codeAgent.invoke(message)
                .flatMap(state -> state.getLastMessage())
                .map(msg -> msg.getContent())
                .orElse("");
            return Map.entry("code", response);
        })
    );

    // 等待所有完成
    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

    // 收集结果
    return futures.stream()
        .map(CompletableFuture::join)
        .collect(Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue
        ));
}
9.3.3 异步回调
java 复制代码
public void callWithCallback(String message, Consumer<String> callback) {
    CompletableFuture.supplyAsync(() -> remoteAgent.invoke(message))
        .thenApply(result -> result
            .flatMap(state -> state.getLastMessage())
            .map(msg -> msg.getContent())
            .orElse("未获取到响应"))
        .thenAccept(callback)
        .exceptionally(throwable -> {
            System.err.println("调用失败: " + throwable.getMessage());
            callback.accept("错误: " + throwable.getMessage());
            return null;
        });
}

// 使用
callWithCallback("你好", response -> {
    System.out.println("收到响应: " + response);
});

9.4 流式调用

9.4.1 基础流式调用
java 复制代码
// 创建流
Flux<NodeOutput> stream = remoteAgent.stream("讲一个故事");

// 订阅流
stream.subscribe(
    output -> {
        // 处理每个输出
        output.state().getLastMessage().ifPresent(msg -> {
            System.out.print(msg.getContent());
        });
    },
    error -> {
        // 处理错误
        System.err.println("错误: " + error.getMessage());
    },
    () -> {
        // 完成
        System.out.println("\n完成");
    }
);
9.4.2 带配置的流式调用
java 复制代码
RunnableConfig config = RunnableConfig.builder()
    .threadId("session_123")
    .build();

Flux<NodeOutput> stream = remoteAgent.stream("讲一个故事", config);

stream.subscribe(output -> {
    System.out.println("节点: " + output.nodeName());
    System.out.println("内容: " + output.state().getLastMessage()
        .map(msg -> msg.getContent())
        .orElse(""));
});
9.4.3 流式输出到前端

后端代码

java 复制代码
@RestController
@RequestMapping("/api/agent")
public class StreamingController {

    @Autowired
    private A2aRemoteAgent remoteAgent;

    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamResponse(@RequestParam String message) {
        return remoteAgent.stream(message)
            .mapNotNull(output -> output.state().getLastMessage().orElse(null))
            .map(msg -> "data: " + msg.getContent() + "\n\n");
    }
}

前端代码(JavaScript)

javascript 复制代码
const eventSource = new EventSource('/api/agent/stream?message=' + encodeURIComponent('讲一个故事'));

eventSource.onmessage = (event) => {
    const content = event.data;
    // 追加到页面
    document.getElementById('output').innerHTML += content;
};

eventSource.onerror = (error) => {
    console.error('流式传输错误:', error);
    eventSource.close();
};

// 完成后关闭连接
eventSource.addEventListener('done', () => {
    eventSource.close();
});
9.4.4 流式调用高级用法

限流

java 复制代码
// 限制每秒最多 10 个事件
Flux<NodeOutput> stream = remoteAgent.stream(message)
    .limitRate(10);

超时

java 复制代码
// 30 秒超时
Flux<NodeOutput> stream = remoteAgent.stream(message)
    .timeout(Duration.ofSeconds(30));

重试

java 复制代码
// 失败时重试 3 次
Flux<NodeOutput> stream = remoteAgent.stream(message)
    .retry(3);

组合多个流

java 复制代码
Flux<String> combined = Flux.merge(
    agent1.stream("问题 1").map(out -> "Agent1: " + out),
    agent2.stream("问题 2").map(out -> "Agent2: " + out),
    agent3.stream("问题 3").map(out -> "Agent3: " + out)
);

combined.subscribe(System.out::println);

相关推荐
啊阿狸不会拉杆2 小时前
《数字图像处理》第7章:小波变换和其他图像变换
图像处理·人工智能·python·算法·机器学习·计算机视觉·数字图像处理
yiersansiwu123d2 小时前
生成式AI重构内容生态,人机协同定义创作新范式
大数据·人工智能·重构
老蒋新思维2 小时前
创客匠人:从个人IP到知识变现,如何构建可持续的内容生态?
大数据·网络·人工智能·网络协议·tcp/ip·创客匠人·知识变现
HyperAI超神经2 小时前
GPT-5全面领先,OpenAI发布FrontierScience,「推理+科研」双轨检验大模型能力
人工智能·gpt·ai·openai·benchmark·基准测试·gpt5.2
rannn_1112 小时前
【Git教程】概述、常用命令、Git-IDEA集成
java·git·后端·intellij-idea
我家领养了个白胖胖2 小时前
向量化和向量数据库redisstack使用
java·后端·ai编程
老蒋新思维2 小时前
创客匠人洞察:从“个人品牌”到“系统物种”——知识IP的终极进化之路
网络·人工智能·网络协议·tcp/ip·重构·创客匠人·知识变现
阿杰学AI2 小时前
AI核心知识57——大语言模型之MoE(简洁且通俗易懂版)
人工智能·ai·语言模型·aigc·ai-native·moe·混合专家模型
AI大模型2 小时前
大模型相关术语和框架总结|LLM、MCP、Prompt、RAG、vLLM、Token、数据蒸馏
程序员·llm·agent