Spring AI Alibaba 1.x 系列【40】多智能体核心模式 - 智能体作为工具(Agent as Tool)

文章目录

  • [1. 概述](#1. 概述)
  • [2. 案例演示](#2. 案例演示)
    • [2.1 创建子智能体](#2.1 创建子智能体)
      • [2.1.1 选题 Agent(生成热点选题)](#2.1.1 选题 Agent(生成热点选题))
      • [2.1.2 文案创作 Agent(基于选题写初稿)](#2.1.2 文案创作 Agent(基于选题写初稿))
      • [2.1.3 内容润色 Agent(优化文案质感)](#2.1.3 内容润色 Agent(优化文案质感))
      • [2.1.4 敏感词合规检测 Agent( 校验违规内容)](#2.1.4 敏感词合规检测 Agent( 校验违规内容))
      • [2.1.5 格式排版 Agent( 适配平台格式)](#2.1.5 格式排版 Agent( 适配平台格式))
    • [2.2 主管调度 Agent](#2.2 主管调度 Agent)
    • [2.3 效果测试](#2.3 效果测试)
  • [3. AgentTool](#3. AgentTool)
    • [3.1 对外入口方法](#3.1 对外入口方法)
    • [3.2 反射获取执行方法](#3.2 反射获取执行方法)
    • [3.3 获取原始入参 Schema](#3.3 获取原始入参 Schema)
    • [3.4 构建标准工具定义](#3.4 构建标准工具定义)
    • [3.5 包装原始 Schema](#3.5 包装原始 Schema)
    • [3.6 创建工具执行器实例](#3.6 创建工具执行器实例)
    • [3.7 构建 MethodToolCallback](#3.7 构建 MethodToolCallback)
    • [3.8 执行](#3.8 执行)

1. 概述

Agent as Tool 模式中,一个 Agent (控制器)将其他 Agent 视为工具(AgentTool),在需要时调用。控制器 Agent 管理编排,而工具 Agent 执行特定任务并返回结果。

执行流程

  1. 控制器接收输入并决定调用哪个工具(子 Agent
  2. 工具 Agent 根据控制器的指令运行其任务
  3. 工具 Agent 将结果返回给控制器
  4. 控制器决定下一步或完成任务

提示 :作为工具使用的 Agent 通常不期望与用户继续对话。它们的角色是执行任务并将结果返回给控制器 Agent。如果需要子 Agent 能够与用户对话,请改用交接HandOff模式

2. 案例演示

实现「新媒体文案全流程自动化生产」,所有子 Agent 仅执行专项任务、返回结果,不与用户直接交互,全流程由主管 Agent 统一编排、汇总输出。

流程闭环

2.1 创建子智能体

2.1.1 选题 Agent(生成热点选题)

核心职责 :基于行业方向,生成 3 个可落地的新媒体选题,包含选题标题、核心切入点、适配平台。

java 复制代码
        // 选题Agent(工具)
        ReactAgent topicAgent = ReactAgent.builder()
                .name("topic_agent")
                .model(dashScopeChatModel)
                .description("""
                        新媒体选题生成工具,专注于生成贴合热点、可落地的文案选题,
                        输出3个选项,包含选题标题、核心切入点、适配平台(公众号/小红书/抖音)
                        """)
                .instruction("""
                        你是专业的新媒体选题专家,结合当前热点和用户给定的行业方向,生成3个优质选题。
                        要求:
                        1. 选题有话题性,易传播;
                        2. 每个选题包含「标题+核心切入点+适配平台」;
                        3. 语言简洁,不冗余;
                        4. 适配新媒体用户喜好,避免过于官方。
                        """)
                .build();

2.1.2 文案创作 Agent(基于选题写初稿)

核心职责 :根据主管 Agent 选定的选题,生成完整文案初稿,适配对应平台文风。

java 复制代码
        // 文案创作Agent(工具)
        ReactAgent writeAgent = ReactAgent.builder()
                .name("write_agent")
                .model(dashScopeChatModel)
                .description("""
                        新媒体文案创作工具,根据给定的选题、平台,生成完整文案初稿,
                        贴合平台文风(公众号偏详细、小红书偏活泼、抖音偏简洁)
                        """)
                .instruction("""
                        你是专业的新媒体文案写手,根据用户提供的「选题标题+核心切入点+适配平台」,生成完整文案初稿。
                        要求:
                        1. 贴合平台文风,不偏离选题;
                        2. 结构清晰,有开头、主体、结尾;
                        3. 语言流畅,符合新媒体用户阅读习惯;
                        4. 无需添加格式,仅输出纯文本初稿。
                        """)
                .build();

2.1.3 内容润色 Agent(优化文案质感)

核心职责:打磨文案语句、调整语气、优化逻辑,提升可读性和传播性,不改变核心内容。

java 复制代码
        // 内容润色Agent(工具)
        ReactAgent polishAgent = ReactAgent.builder()
                .name("polish_agent")
                .model(dashScopeChatModel)
                .description("""
                        文案润色工具,优化文案语句流畅度、调整语气、优化逻辑,
                        提升可读性和传播性,不改变原文核心内容和平台适配性
                        """)
                .instruction("""
                        你是专业的文案润色专家,对给定的新媒体文案初稿进行润色。
                        要求:
                        1. 修正语病、优化语句,让表达更流畅;
                        2. 调整语气,贴合对应平台文风(公众号温和详细、小红书活泼有网感、抖音简洁有力);
                        3. 优化段落逻辑,让内容更有层次感;
                        4. 不改变原文核心观点和内容;
                        5. 保留原文结构,不新增/删减核心信息。
                        """)
                .build();

2.1.4 敏感词合规检测 Agent( 校验违规内容)

核心职责:检测文案中的敏感词、违规词、不合规表述,返回检测结果(是否通过、违规词)。

java 复制代码
        // 敏感词合规检测Agent(工具)
        ReactAgent complianceAgent = ReactAgent.builder()
                .name("compliance_agent")
                .model(dashScopeChatModel)
                .description("""
                        文案合规检测工具,检测文案中的敏感词、违规词、不合规表述。
                        必须返回明确结论:【合规通过】或【合规不通过】+ 原因
                        """)
                .instruction("""
                        你是专业的文案合规检测专家,对给定文案进行全面的合规检测。

                        检测范围:
                        1. 政治敏感类:涉政人物、事件、机构的不当表述,国家主权相关问题
                        3. 低俗不良类:色情低俗、暴力血腥、封建迷信、歧视性内容

                        输出格式(必须严格遵守):
                        - 若文案合规,输出:【合规通过】文案无违规内容。
                        - 若文案不合规,输出:【合规不通过】发现以下违规问题:1) [具体违规词/表述] - [违规类型];2) ...

                        注意:检测要严格但不苛刻,正常商业表述不要过度拦截。
                        """)
                .build();

2.1.5 格式排版 Agent( 适配平台格式)

核心职责:根据文案适配平台,添加对应格式(标题加粗、分段、表情、话题标签等),输出可直接发布的版本。

java 复制代码
        // 格式排版Agent(工具)
        ReactAgent formatAgent = ReactAgent.builder()
                .name("format_agent")
                .model(dashScopeChatModel)
                .description("""
                        文案格式排版工具,根据给定的文案和适配平台,添加对应格式
                        (标题、分段、表情、话题标签等),输出可直接发布的版本
                        """)
                .instruction("""
                        你是专业的新媒体排版专家,根据文案和适配平台,进行格式优化。
                        要求:
                        1. 公众号:标题加粗(用##)、分段清晰、关键句子加粗、结尾添加引导语;
                        2. 小红书:标题吸睛(加emoji)、分段简短、每段1-2句话、结尾添加3-5个相关话题标签(#XXX);
                        3. 抖音:标题简短有力(加emoji)、分段极短、重点句子加粗、结尾添加互动引导;
                        4. 不改变文案核心内容,仅优化格式。输入格式:文案内容|适配平台。
                        """)
                .build();

2.2 主管调度 Agent

核心职责:

  1. 接收用户输入(行业方向),统一调度所有子 Agent
  2. 按「选题→创作→润色→合规→排版」顺序调用工具;
  3. 处理子 Agent 返回结果(如合规检测失败,终止流程并提示);
  4. 汇总最终排版后的文案,返回给用户。
java 复制代码
        // 主管调度Agent(核心,集中式管控全流程)
        ReactAgent supervisorAgent = ReactAgent.builder()
                .name("supervisor_agent")
                .model(dashScopeChatModel)
                .description("""
                        新媒体文案生产主管,统一调度选题、创作、润色、合规检测、排版工具,
                        按流程完成文案生产,汇总最终结果返回用户,
                        不直接执行具体任务,仅负责调度和结果整合
                        """)
                .instruction("""
                        你的职责是作为新媒体文案生产主管,按以下流程调度工具,完成文案生产:
                        1. 第一步:调用 topic_agent 工具,传入用户给定的行业方向,获取3个选题;
                        2. 第二步:从3个选题中选择最优1个(贴合热点、易传播、适配平台清晰),
                           调用 write_agent 工具,传入该选题信息,生成文案初稿;
                        3. 第三步:调用 polish_agent 工具,传入文案初稿,进行润色优化;
                        4. 第四步:调用 compliance_agent 工具,传入润色后的文案,进行合规检测;
                           - 若结果包含【合规通过】,执行下一步;
                           - 若结果包含【合规不通过】,终止流程,返回违规提示和具体违规问题;
                        5. 第五步:调用 format_agent 工具,传入润色后合规的文案 + 选题中的适配平台,进行格式排版;
                        6. 最终:汇总排版后的文案,返回给用户,同时附上选题说明和合规检测结果。

                        注意事项:
                        - 严格按顺序调用工具,不跳过任何步骤;
                        - 每个工具调用后,必须获取结果,再进行下一步;
                        - 工具返回的结果,仅提取核心信息,不冗余;
                        - 若任何工具调用失败,返回具体失败原因。
                        """)
                .tools(
                        AgentTool.getFunctionToolCallback(topicAgent),
                        AgentTool.getFunctionToolCallback(writeAgent),
                        AgentTool.getFunctionToolCallback(polishAgent),
                        AgentTool.getFunctionToolCallback(complianceAgent),
                        AgentTool.getFunctionToolCallback(formatAgent)
                )
                .build();

2.3 效果测试

对话输入:

java 复制代码
美妆行业,聚焦平价彩妆,面向18-25岁女生,贴合学生党需求

依次调用工具:

最终生成结果(仅测试):

3. AgentTool

Agent 转换为工具后,也是个 ToolCallback ,其加载、执行流程和 Tool Calling 那一套也是一样一样的,之前也都说过了。

所以,这里重点关注一下 AgentTool 是如何将 ReactAgent 封装为可调用的工具(ToolCallback),实现 Agent 的工具化调用的。

核心流程

  1. 业务创建 ReactAgent
  2. 调用 AgentTool.create(agent)
  3. 反射获取 executeAgent 方法
  4. 包装入参 JSON Schema
  5. 生成 Spring AI 标准 ToolDefinition
  6. 创建 AgentToolExecutor 实例
  7. 构建 MethodToolCallback 并返回
  8. 大模型发起工具调用 → 执行 executeAgent
  9. 解析入参 → 执行 Agent 图 → 返回助手消息

源码结构:

java 复制代码
public class AgentTool {

	/**
	 * 工具调用结果转换器
	 */
	private static final ToolCallResultConverter CONVERTER = new MessageToolCallResultConverter();

	/**
	 * 获取 Agent 工具回调(快捷方法)
	 */
	public static ToolCallback getFunctionToolCallback(ReactAgent agent) {
		//.........
	}

	/**
	 * 创建 Agent 工具回调
	 */
	public static ToolCallback create(ReactAgent agent) {
		//.........
	}

	/**
	 * 包装参数 Schema
	 */
	private static String wrapSchemaInInputParameter(String originalSchema) {
		//.........
	}

	/**
	 * Agent 工具执行器
	 */
	public static class AgentToolExecutor {

		private final ReactAgent agent;

		/**
		 * 构造方法
		 */
		public AgentToolExecutor(ReactAgent agent) {
			//.........
		}

		/**
		 * 执行 Agent 逻辑
		 */
		public AssistantMessage executeAgent(String input, ToolContext toolContext) {
			//.........
		}

		/**
		 * 提取入参值
		 */
		private String extractInputValue(String input) {
			//.........
		}
	}
}

3.1 对外入口方法

对外提供的工具创建方法:

java 复制代码
	/**
	 * 获取 Agent 对应的函数工具回调(快捷入口)
	 * @param agent ReactAgent 实例
	 * @return 可直接注册给大模型的 Spring AI ToolCallback
	 */
	public static ToolCallback getFunctionToolCallback(ReactAgent agent) {
		return AgentTool.create(agent);
	}

核心方法源码:

java 复制代码
	/**
	 * 核心方法
	 *
	 * @param agent ReactAgent 实例
	 * @return Spring AI 标准工具回调
	 * @throws IllegalStateException 未找到 executeAgent 方法时抛出
	 */
	public static ToolCallback create(ReactAgent agent) {
		// 反射获取执行方法,脱离 @Tool 注解依赖
		java.lang.reflect.Method method = ReflectionUtils.findMethod(AgentToolExecutor.class,
				"executeAgent", String.class, ToolContext.class);

		if (method == null) {
			throw new IllegalStateException("Could not find executeAgent method in AgentToolExecutor class");
		}

		// 获取原始入参 Schema(优先 inputSchema,其次根据 inputType 自动生成)
		String originalSchema = StringUtils.hasLength(agent.getInputSchema())
				? agent.getInputSchema()
				: (agent.getInputType() != null)
				? JsonSchemaGenerator.generateForType(agent.getInputType())
				: null;

		// 构建工具定义:名称、描述、入参格式
		DefaultToolDefinition.Builder builder = ToolDefinitions.builder(method)
				.name(agent.name())
				.description(agent.description());

		// 包装 Schema 为标准 input 格式
		if (StringUtils.hasLength(originalSchema)) {
			String wrappedInputSchema = wrapSchemaInInputParameter(originalSchema);
			builder.inputSchema(wrappedInputSchema);
		}

		ToolDefinition toolDefinition = builder.build();

		// 创建工具执行器
		AgentToolExecutor executor = new AgentToolExecutor(agent);

		// 构建并返回 Spring AI 标准工具回调
		return MethodToolCallback.builder()
				.toolDefinition(toolDefinition)
				.toolMethod(method)
				.toolObject(executor)
				.toolCallResultConverter(CONVERTER)
				.build();
	}

3.2 反射获取执行方法

通过 Spring 提供的 ReflectionUtils 反射获取 AgentToolExecutorexecuteAgent 方法对象:

java 复制代码
java.lang.reflect.Method method = ReflectionUtils.findMethod(
    AgentToolExecutor.class,   // 要在哪个类里找方法
    "executeAgent",            // 要找的方法名字
    String.class,              // 方法第1个参数类型
    ToolContext.class          // 方法第2个参数类型
);

AgentToolExecutorAgentTool 的内部类,定位为 Agent 工具执行器,负责真正执行 Agent 工具:

java 复制代码
	public static class AgentToolExecutor {

		/**
		 * 持有的 ReactAgent 实例
		 */
		private final ReactAgent agent;

		/**
		 * 构造方法
		 * @param agent ReactAgent 实例
		 */
		public AgentToolExecutor(ReactAgent agent) {
			this.agent = agent;
		}

		/**
		 * 工具执行入口:反射调用
		 * <p>
		 * 执行流程:
		 * <ol>
		 *     <li>解析AI传入的 input 参数</li>
		 *     <li>构建指令消息 + 用户消息</li>
		 *     <li>执行 Agent 图工作流</li>
		 *     <li>返回最终助手消息</li>
		 * </ol>
		 *
		 * @param input 大模型传入的参数(JSON格式)
		 * @param toolContext Spring AI 自动注入的工具上下文(状态、配置等)
		 * @return Agent 执行结果(AssistantMessage)
		 */
		public AssistantMessage executeAgent(String input, ToolContext toolContext) {
			// 提取真实用户输入
			String actualInput = extractInputValue(input);

			// 构建消息列表:指令 + 用户输入
			List<Message> messagesToAdd = new ArrayList<>();
			if (StringUtils.hasLength(agent.instruction())) {
				messagesToAdd.add(AgentInstructionMessage.builder().text(agent.instruction()).build());
			}
			messagesToAdd.add(new UserMessage(actualInput));

			// 执行 Agent 图
			Optional<OverAllState> resultState = agent.getAndCompileGraph().invoke(Map.of("messages", messagesToAdd));

			// 获取执行结果并返回最后一条助手消息
			Optional<List> messages = resultState.flatMap(overAllState -> overAllState.value("messages", List.class));
			if (messages.isPresent()) {
				@SuppressWarnings("unchecked")
				List<Message> messageList = (List<Message>) messages.get();
				return (AssistantMessage) messageList.get(messageList.size() - 1);
			}

			throw new RuntimeException("Failed to execute agent tool or failed to get agent tool result");
		}

		/**
		 * 从 {"input": "实际内容"} 格式中提取真实入参
		 * <p>
		 * 兼容:标准JSON、非法JSON、纯字符串,解析失败直接返回原字符串。
		 *
		 * @param input 工具入参
		 * @return 提取后的实际输入
		 */
		private String extractInputValue(String input) {
			if (!StringUtils.hasText(input)) {
				return input;
			}

			try {
				ObjectMapper objectMapper = JsonParser.getObjectMapper();
				Map<String, Object> jsonMap = objectMapper.readValue(input, new TypeReference<HashMap<String, Object>>() {});

				if (jsonMap != null && jsonMap.containsKey("input")) {
					Object inputValue = jsonMap.get("input");
					if (inputValue != null) {
						if (inputValue instanceof String) {
							return (String) inputValue;
						}
						// 非字符串类型序列化为JSON
						return JsonParser.getObjectMapper().writeValueAsString(inputValue);
					}
				}
			}
			catch (Exception e) {
				// 解析失败直接使用原始输入
			}

			return input;
		}
	}

3.3 获取原始入参 Schema

ReacAgent 构建时支持定义 AI 智能体的入参格式:

  • inputSchema:用户手动写的 JSON Schema(入参格式描述)
  • inputType:用户传一个 Java 类,框架自动生成 JSON Schema


inputSchema 示例:

java 复制代码
{
  "type": "object",
  "properties": {
    "query": { "type": "string" },
    "userId": { "type": "string" }
  },
  "required": ["query"]
}

AgentTool 会先获取原始入参 Schema

java 复制代码
		// 获取原始入参 Schema(优先 inputSchema,其次根据 inputType 自动生成)
		String originalSchema = StringUtils.hasLength(agent.getInputSchema())
				? agent.getInputSchema()
				: (agent.getInputType() != null)
				? JsonSchemaGenerator.generateForType(agent.getInputType())
				: null;

3.4 构建标准工具定义

Agent 的名称、描述封装为 Spring AI 工具定义:

java 复制代码
DefaultToolDefinition.Builder builder = ToolDefinitions.builder(method)
        .name(agent.name())
        .description(agent.description());

3.5 包装原始 Schema

将原始 Schema 包装为统一的入参格式,不管你传入什么 Schema,最终都会变成:

json 复制代码
{
  "type": "object",
  "properties": {
    "input": 【你的原始Schema】
  },
  "required": ["input"]
}

设计关键:

  • 统一 AI 工具入参格式:AI 永远只需要读取 input 字段,不用关心用户传了什么。
  • 格式永远合法:不会出现无效 JSON、无效 Schema

AgentTool 中会先进行包装,然后设置给 ToolDefinition

java 复制代码
		if (StringUtils.hasLength(originalSchema)) {
			String wrappedInputSchema = wrapSchemaInInputParameter(originalSchema);
			builder.inputSchema(wrappedInputSchema);
		}

包装方法:

java 复制代码
	/**
	 * @param originalSchema 原始入参Schema
	 * @return 包装后的标准Schema字符串
	 */
	private static String wrapSchemaInInputParameter(String originalSchema) {
		ObjectMapper objectMapper = JsonParser.getObjectMapper();

		try {
			// 解析原始Schema,解析失败则默认使用 string 类型
			Map<String, Object> originalSchemaMap = null;
			if (StringUtils.hasLength(originalSchema)) {
				try {
					originalSchemaMap = objectMapper.readValue(originalSchema, new TypeReference<HashMap<String, Object>>() {});
				}
				catch (Exception e) {
					originalSchemaMap = Map.of("type", "string");
				}
			}
			else {
				originalSchemaMap = Map.of("type", "string");
			}

			// 构建标准包装结构
			Map<String, Object> wrappedSchema = new HashMap<>();
			wrappedSchema.put("type", "object");

			Map<String, Object> properties = new HashMap<>();
			properties.put("input", originalSchemaMap);
			wrappedSchema.put("properties", properties);

			wrappedSchema.put("required", List.of("input"));

			return objectMapper.writeValueAsString(wrappedSchema);
		}
		catch (Exception e) {
			// 异常降级:返回最简可用Schema
			return String.format("""
					{
						"type": "object",
						"properties": {
							"input": {
								"type": "string"
							}
						},
						"required": ["input"]
					}
					""");
		}
	}

示例,传入:

json 复制代码
{
  "type": "object",
  "properties": {
    "username": { "type": "string" },
    "age": { "type": "number" }
  }
}

包装后:

json 复制代码
{
  "type": "object",
  "properties": {
    "input": {
      "type": "object",
      "properties": {
        "username": { "type": "string" },
        "age": { "type": "number" }
      }
    }
  },
  "required": ["input"]
}

3.6 创建工具执行器实例

调用 AgentToolExecutor 构造函数,传入 Agent 实例对象:

java 复制代码
		AgentToolExecutor executor = new AgentToolExecutor(agent);
		
		public AgentToolExecutor(ReactAgent agent) {
			this.agent = agent;
		}

3.7 构建 MethodToolCallback

构建方法型工具并返回:

java 复制代码
		// Build MethodToolCallback
		return MethodToolCallback.builder()
				.toolDefinition(toolDefinition)
				.toolMethod(method)
				.toolObject(executor)
				.toolCallResultConverter(CONVERTER) // 结果转换器
				.build();

3.8 执行

工具绑定的 Method 对象是 AgentToolExecutor#executeAgent 方法,所以工具反射执行时,也就进入到了这里。

executeAgent 是工具执行入口,执行流程:

  • 解析 AI 传入的 input 参数
  • 构建指令消息 + 用户消息
  • 执行 Agent 图工作流
  • 返回最终助手消息

源码如下:

java 复制代码
		/**
		 * 工具执行入口:反射调用
		 *
		 * @param input 大模型传入的参数(JSON格式)
		 * @param toolContext Spring AI 自动注入的工具上下文(状态、配置等)
		 * @return Agent 执行结果(AssistantMessage)
		 */
		public AssistantMessage executeAgent(String input, ToolContext toolContext) {
			// 提取真实用户输入
			String actualInput = extractInputValue(input);

			// 构建消息列表:指令 + 用户输入
			List<Message> messagesToAdd = new ArrayList<>();
			if (StringUtils.hasLength(agent.instruction())) {
				messagesToAdd.add(AgentInstructionMessage.builder().text(agent.instruction()).build());
			}
			messagesToAdd.add(new UserMessage(actualInput));

			// 执行 Agent 图
			Optional<OverAllState> resultState = agent.getAndCompileGraph().invoke(Map.of("messages", messagesToAdd));

			// 获取执行结果并返回最后一条助手消息
			Optional<List> messages = resultState.flatMap(overAllState -> overAllState.value("messages", List.class));
			if (messages.isPresent()) {
				@SuppressWarnings("unchecked")
				List<Message> messageList = (List<Message>) messages.get();
				return (AssistantMessage) messageList.get(messageList.size() - 1);
			}

			throw new RuntimeException("Failed to execute agent tool or failed to get agent tool result");
		}

		/**
		 * 从 {"input": "实际内容"} 格式中提取真实入参
		 * <p>
		 * 兼容:标准JSON、非法JSON、纯字符串,解析失败直接返回原字符串。
		 *
		 * @param input 工具入参
		 * @return 提取后的实际输入
		 */
		private String extractInputValue(String input) {
			if (!StringUtils.hasText(input)) {
				return input;
			}

			try {
				ObjectMapper objectMapper = JsonParser.getObjectMapper();
				Map<String, Object> jsonMap = objectMapper.readValue(input, new TypeReference<HashMap<String, Object>>() {});

				if (jsonMap != null && jsonMap.containsKey("input")) {
					Object inputValue = jsonMap.get("input");
					if (inputValue != null) {
						if (inputValue instanceof String) {
							return (String) inputValue;
						}
						// 非字符串类型序列化为JSON
						return JsonParser.getObjectMapper().writeValueAsString(inputValue);
					}
				}
			}
			catch (Exception e) {
				// 解析失败直接使用原始输入
			}

			return input;
		}

因为配置了 MessageToolCallResultConverter 工具调用结果转换器,还会将工具执行后的任意返回值,转换为 AI 模型能识别的字符串格式(纯文本 / JSON):

java 复制代码
public class MessageToolCallResultConverter implements ToolCallResultConverter {

	private static final Logger logger = LoggerFactory.getLogger(MessageToolCallResultConverter.class);

	/**
	 * 转换工具执行结果
	 *
	 * 说明:
	 * 由于 Spring AI 的 ToolResponseMessage 目前只支持文本类型,
	 * 所以本方法统一返回 String,未来可扩展支持图片/音频/文件等类型。
	 *
	 * @param result 工具执行的原始结果
	 * @param returnType 工具方法的返回类型
	 * @return 转换后的字符串结果(文本或JSON)
	 */
	public String convert(@Nullable Object result, @Nullable Type returnType) {

		// 1. 如果工具返回类型是 void(无返回值)
		if (returnType == Void.TYPE) {
			logger.debug("工具无返回值,转换为默认响应:Done");
			return JsonParser.toJson("Done");
		}

		// 2. 如果工具返回的是 AI 助手消息(AssistantMessage)
		else if (result instanceof AssistantMessage assistantMessage) {

			// 优先取消息文本内容
			if (StringUtils.hasLength(assistantMessage.getText())) {
				return assistantMessage.getText();
			}

			// 如果消息包含媒体资源(图片/音频等)→ 暂不支持
			else if (CollectionUtils.isNotEmpty(assistantMessage.getMedia())) {
				throw new UnsupportedOperationException(
					"当前 Spring AI ToolResponseMessage 仅支持文本类型," +
					"图片/音频/视频/文件类型将在未来支持。"
				);
			}

			// 空消息 → 返回默认完成标识
			logger.warn("工具返回了空的 AssistantMessage,转换为默认响应:Done");
			return JsonParser.toJson("Done");
		}

		// 3. 其他所有类型(对象、List、Map、字符串等)→ 转为 JSON
		else {
			logger.debug("将工具结果转为 JSON 格式");
			return JsonParser.toJson(result);
		}
	}
}

最终,子 Agent 工具在【工具执行节点】完成后,返回来当前也是工具响应对象:

工具执行结果返回给【模型执行节点】,直到无需工具调用后,整个流程结束。

相关推荐
大龄程序员狗哥1 小时前
第33篇:超参数调优实战——用网格搜索与随机搜索为模型“精调”(项目实战)
人工智能
卷Java2 小时前
Agent架构设计:规划器、工具、记忆、评估器如何协同工作
人工智能
Claw开发者2 小时前
Hermes 接 LiteLLM 缓存不生效踩坑记录
人工智能·agent
测试员周周2 小时前
【踩坑系列3】飞书机器人集体“失联“?3 个 Gateway 进程让我差点崩溃!一个测试老兵的排查实录
java·python
aq55356002 小时前
Laravel9.x新特性全解析
java·开发语言·数据库
齿轮2 小时前
Agent 管理范式演进:从管一句话到管整个系统
人工智能·后端
AIGCmagic社区2 小时前
AI多模态理论基础高频考点
人工智能
亦暖筑序2 小时前
AI 客服系统升级实战:多 Agent 路由 + 多轮记忆 + 敏感词过滤
java·后端
珹洺2 小时前
C++AI多模型聊天系统(三)AI多模型(豆包/Kimi/千问)接入与实现
开发语言·c++·人工智能