AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 13|Tools 工具 · Tool 执行

Tool 执行是使用提供的输入参数调用 tool 并返回结果的过程。Tool 执行由 ToolCallingManager 接口处理,该接口负责管理 tool 执行生命周期。

public interface ToolCallingManager {

  /**
   * Resolve the tool definitions from the model's tool calling options.
   */
  List<ToolDefinition> resolveToolDefinitions(ToolCallingChatOptions chatOptions);

  /**
   * Execute the tool calls requested by the model.
   */
  ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse chatResponse);

}

如果您使用任何 Spring AI Spring Boot Starters,DefaultToolCallingManager 是 ToolCallingManager 接口的自动配置实现。您可以通过提供自己的 ToolCallingManager bean 来自定义 tool 执行行为。

@Bean
ToolCallingManager toolCallingManager() {
  return ToolCallingManager.builder().build();
}

默认情况下,Spring AI 在每个 ChatModel 实现内部透明地为您管理 tool 执行生命周期。但您可以选择退出此行为并自己控制 tool 执行。本节描述这两种场景。

框架控制的 Tool 执行

使用默认行为时,Spring AI 将自动拦截来自 model 的任何 tool call 请求,调用 tool 并将结果返回给 model。所有这些都由每个使用 ToolCallingManager 的 ChatModel 实现透明地为您完成。

框架控制的 tool 执行生命周期

  1. 当我们想要使 tool 可用于 model 时,我们在聊天请求(Prompt)中包含其定义,并调用将请求发送到 AI model 的 ChatModel API。
  2. 当 model 决定调用 tool 时,它发送带有 tool 名称和根据定义 schema 建模的输入参数的响应(ChatResponse)。
  3. ChatModel 将 tool call 请求发送到 ToolCallingManager API。
  4. ToolCallingManager 负责识别要调用的 tool 并使用提供的输入参数执行它。
  5. Tool call 的结果返回到 ToolCallingManager。
  6. ToolCallingManager 将 tool 执行结果返回给 ChatModel。
  7. ChatModel 将 tool 执行结果发送回 AI model(ToolResponseMessage)。
  8. AI model 使用 tool call 结果作为附加上下文生成最终响应,并通过 ChatClient 将其发送回调用者(ChatResponse)。

WARNING: 目前,与 model 交换的关于 tool 执行的内部消息不会暴露给用户。如果您需要访问这些消息,应该使用用户控制的 tool 执行方法。

确定 tool call 是否有资格执行的逻辑由 ToolExecutionEligibilityPredicate 接口处理。默认情况下,tool 执行资格通过检查 ToolCallingChatOptions 的 internalToolExecutionEnabled 属性是否设置为 true(默认值),以及 ChatResponse 是否包含任何 tool calls 来确定。

您可以在创建 ChatModel bean 时提供 ToolExecutionEligibilityPredicate 的自定义实现。

用户控制的 Tool 执行

在某些情况下,您可能希望自己控制 tool 执行生命周期。您可以通过将 ToolCallingChatOptions 的 internalToolExecutionEnabled 属性设置为 false 来执行此操作。

当您使用此选项调用 ChatModel 时,tool 执行将委托给调用者,让您完全控制 tool 执行生命周期。您有责任检查 ChatResponse 中的 tool calls 并使用 ToolCallingManager 执行它们。

以下示例演示了用户控制的 tool 执行方法的最小实现:

ChatModel chatModel = ...;
ToolCallingManager toolCallingManager = ToolCallingManager.builder().build();

ChatOptions chatOptions = ToolCallingChatOptions.builder()
  .toolCallbacks(new CustomerTools())
  .internalToolExecutionEnabled(false)
  .build();
Prompt prompt = new Prompt("Tell me more about the customer with ID 42", chatOptions);

ChatResponse chatResponse = chatModel.call(prompt);

while (chatResponse.hasToolCalls()) {
  ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(prompt, chatResponse);

  prompt = new Prompt(toolExecutionResult.conversationHistory(), chatOptions);

  chatResponse = chatModel.call(prompt);
}

System.out.println(chatResponse.getResult().getOutput().getText());

NOTE: 选择用户控制的 tool 执行方法时,我们建议使用 ToolCallingManager 来管理 tool calling 操作。这样,您可以受益于 Spring AI 为 tool 执行提供的内置支持。但是,没有什么可以阻止您实现自己的 tool 执行逻辑。

异常处理

当 tool call 失败时,异常作为 ToolExecutionException 传播,可以捕获以处理错误。ToolExecutionExceptionProcessor 可用于处理 ToolExecutionException,有两种结果:要么生成要发送回 AI model 的错误消息,要么抛出异常供调用者处理。

@FunctionalInterface
public interface ToolExecutionExceptionProcessor {

  /**
   * Convert an exception thrown by a tool to a String that can be sent back to the AI
   * model or throw an exception to be handled by the caller.
   */
  String process(ToolExecutionException exception);

}

如果您使用任何 Spring AI Spring Boot Starters,DefaultToolExecutionExceptionProcessor 是 ToolExecutionExceptionProcessor 接口的自动配置实现。默认情况下,RuntimeException 的错误消息会发送回 model,而检查异常和错误(例如,IOException、OutOfMemoryError)总是被抛出。DefaultToolExecutionExceptionProcessor 构造函数允许您将 alwaysThrow 属性设置为 true 或 false。如果为 true,将抛出异常而不是将错误消息发送回 model。

您可以使用 spring.ai.tools.throw-exception-on-error 属性来控制 DefaultToolExecutionExceptionProcessor bean 的行为:

属性 描述 默认值
spring.ai.tools.throw-exception-on-error 如果为 true,tool calling 错误将作为异常抛出供调用者处理。如果为 false,错误将转换为消息并发送回 AI model,允许它处理并响应错误。 false
@Bean
ToolExecutionExceptionProcessor toolExecutionExceptionProcessor() {
  return new DefaultToolExecutionExceptionProcessor(true);
}

NOTE: 如果您定义了自己的 ToolCallback 实现,请确保在 call() 方法中作为 tool 执行逻辑的一部分发生错误时抛出 ToolExecutionException。

ToolExecutionExceptionProcessor 由默认 ToolCallingManager(DefaultToolCallingManager)内部使用,以处理 tool 执行期间的异常。

向 model 传递 tools 的主要方法是在调用 ChatClient 或 ChatModel 时提供 ToolCallback(s),使用前面描述的策略之一。

但是,Spring AI 还支持使用 ToolCallbackResolver 接口在运行时动态解析 tools。

public interface ToolCallbackResolver {

  /**
   * Resolve the {@link ToolCallback} for the given tool name.
   */
  @Nullable
  ToolCallback resolve(String toolName);

}

使用此方法时:

  • 在客户端,您向 ChatClient 或 ChatModel 提供 tool 名称,而不是 ToolCallback(s)。
  • 在服务器端,ToolCallbackResolver 实现负责将 tool 名称解析为相应的 ToolCallback 实例。

默认情况下,Spring AI 依赖于 DelegatingToolCallbackResolver,它将 tool 解析委托给 ToolCallbackResolver 实例列表:

  • SpringBeanToolCallbackResolver 从类型为 Function、Supplier、Consumer 或 BiFunction 的 Spring bean 解析 tools。
  • StaticToolCallbackResolver 从 ToolCallback 实例的静态列表解析 tools。使用 Spring Boot 自动配置时,此解析器会自动配置应用程序上下文中定义的所有类型为 ToolCallback 的 bean。

如果您依赖 Spring Boot 自动配置,可以通过提供自定义 ToolCallbackResolver bean 来自定义解析逻辑。

@Bean
ToolCallbackResolver toolCallbackResolver(List<ToolCallback> toolCallbacks) {
  StaticToolCallbackResolver staticToolCallbackResolver = new StaticToolCallbackResolver(toolCallbacks);
  return new DelegatingToolCallbackResolver(List.of(staticToolCallbackResolver));
}

ToolCallbackResolver 由 ToolCallingManager 内部使用,以在运行时动态解析 tools,支持框架控制的 Tool 执行和用户控制的 Tool 执行。

Tool calling 包括可观测性支持,使用 spring.ai.tool 观察来测量完成时间并传播跟踪信息。请参阅 Tool Calling 可观测性。

可选地,Spring AI 可以将 tool call 参数和结果导出为 span 属性,默认情况下出于敏感性原因禁用。详细信息:Tool Call 参数和结果数据。

日志记录

Tool calling 功能的所有主要操作都在 DEBUG 级别记录。您可以通过将 org.springframework.ai 包的日志级别设置为 DEBUG 来启用日志记录。

自定义工具属性

自定义工具名称

默认情况下,工具名称来自函数名称。当你需要更具描述性的内容时,可以覆盖它:

ToolCallback searchTool = FunctionToolCallback
  .builder("web_search", new SearchFunction())  // 自定义名称
  .description("Search the web for information")
  .inputType(String.class)
  .build();

System.out.println(searchTool.getName());  // web_search
// 推荐:使用 ToolDefinition 提取名称
System.out.println(searchTool.getToolDefinition().name());  // web_search

自定义工具描述

覆盖自动生成的工具描述以提供更清晰的模型指导:

ToolCallback calculatorTool = FunctionToolCallback
  .builder("calculator", new CalculatorFunction())
  .description("Performs arithmetic calculations. Use this for any math problems.")
  .inputType(String.class)
  .build();

高级模式定义

使用 Java 类或 JSON schemas 定义复杂的输入:

使用 Java 记录类(Record):

import org.springframework.ai.tool.annotation.ToolParam;

public record WeatherInput(
  @ToolParam(description = "City name or coordinates") String location,
  @ToolParam(description = "Temperature unit preference") Unit units,
  @ToolParam(description = "Include 5-day forecast") boolean includeForecast
) {}

public enum Unit { CELSIUS, FAHRENHEIT }

public class WeatherFunction implements Function<WeatherInput, String> {
  @Override
  public String apply(WeatherInput input) {
      double temp = input.units() == Unit.CELSIUS ? 22 : 72;
      String result = String.format(
          "Current weather in %s: %.0f degrees %s",
          input.location(),
          temp,
          input.units().toString().substring(0, 1).toUpperCase()
      );

      if (input.includeForecast()) {
          result += "
Next 5 days: Sunny";
      }

      return result;
  }
}

ToolCallback weatherTool = FunctionToolCallback
  .builder("get_weather", new WeatherFunction())
  .description("Get current weather and optional forecast")
  .inputType(WeatherInput.class)
  .build();

本文整理自 Spring AI Alibaba 官方文档《Tools 工具》:https://java2ai.com/docs/frameworks/agent-framework/tutorials/tools

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 13|Tools 工具 · Tool 执行

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册