此版本仍在开发中,尚不被认为是稳定的。对于最新的快照版本,请使用 Spring AI 1.0.1spring-doc.cadn.net.cn

工具调用

工具调用(也称为函数调用)是 AI 应用程序中的一种常见模式,允许模型与一组 API 或工具交互,从而增强其功能。spring-doc.cadn.net.cn

工具主要用于:spring-doc.cadn.net.cn

  • 信息检索。此类别中的工具可用于从外部源检索信息,例如数据库、Web 服务、文件系统或 Web 搜索引擎。目标是增强模型的知识,使其能够回答其他方式无法回答的问题。因此,它们可用于检索增强生成 (RAG) 方案。例如,工具可用于检索给定位置的当前天气、检索最新新闻文章或查询数据库中的特定记录。spring-doc.cadn.net.cn

  • 采取行动。此类别中的工具可用于在软件系统中执行作,例如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流。目标是自动执行原本需要人工干预或显式编程的任务。例如,工具可用于为与聊天机器人交互的客户预订航班,在网页上填写表单,或在代码生成场景中实现基于自动化测试 (TDD) 的 Java 类。spring-doc.cadn.net.cn

尽管我们通常将工具调用称为模型功能,但实际上由客户端应用程序提供工具调用逻辑。模型只能请求工具调用并提供输入参数,而应用程序负责从输入参数执行工具调用并返回结果。该模型永远无法访问作为工具提供的任何 API,这是一个关键的安全考虑因素。spring-doc.cadn.net.cn

Spring AI 提供了方便的 API 来定义工具、解析来自模型的工具调用请求以及执行工具调用。以下部分概述了 Spring AI 中的工具调用功能。spring-doc.cadn.net.cn

查看聊天模型比较,了解哪些 AI 模型支持工具调用调用。
按照指南从已弃用的 FunctionCallback 迁移到 ToolCallback API

快速入门

让我们看看如何开始在 Spring AI 中使用工具调用。我们将实现两个简单的工具:一个用于信息检索,一个用于采取行动。信息检索工具将用于获取用户时区的当前日期和时间。作工具将用于设置指定时间的闹钟。spring-doc.cadn.net.cn

信息检索

人工智能模型无法访问实时信息。任何假设了解当前日期或天气预报等信息的问题都无法由模型回答。但是,我们可以提供一个可以检索此信息的工具,并让模型在需要访问实时信息时调用此工具。spring-doc.cadn.net.cn

让我们实现一个工具来获取用户时区的当前日期和时间DateTimeTools类。该工具不会接受任何参数。这LocaleContextHolder来自 Spring Framework 可以提供用户的时区。该工具将被定义为一个用@Tool.为了帮助模型了解是否以及何时调用此工具,我们将提供工具功能的详细说明。spring-doc.cadn.net.cn

import java.time.LocalDateTime;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;

class DateTimeTools {

    @Tool(description = "Get the current date and time in the user's timezone")
    String getCurrentDateTime() {
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

接下来,让我们使该工具可用于模型。在此示例中,我们将使用ChatClient与模型交互。我们将通过传递DateTimeTools通过tools()方法。当模型需要知道当前日期和时间时,它将请求调用工具。在内部,ChatClient将调用该工具并将结果返回给模型,然后模型将使用该工具调用结果生成对原始问题的最终响应。spring-doc.cadn.net.cn

ChatModel chatModel = ...

String response = ChatClient.create(chatModel)
        .prompt("What day is tomorrow?")
        .tools(new DateTimeTools())
        .call()
        .content();

System.out.println(response);

输出将如下所示:spring-doc.cadn.net.cn

Tomorrow is 2015-10-21.

您可以重试再次询问相同的问题。这一次,不要向模型提供工具。输出将如下所示:spring-doc.cadn.net.cn

I am an AI and do not have access to real-time information. Please provide the current date so I can accurately determine what day tomorrow will be.

如果没有该工具,模型将不知道如何回答问题,因为它无法确定当前日期和时间。spring-doc.cadn.net.cn

采取行动

人工智能模型可用于生成实现某些目标的计划。例如,模型可以生成预订丹麦旅行的计划。但是,该模型不具备执行计划的能力。这就是工具的用武之地:它们可用于执行模型生成的计划。spring-doc.cadn.net.cn

在前面的示例中,我们使用了一个工具来确定当前日期和时间。在此示例中,我们将定义第二个工具,用于在特定时间设置闹钟。目标是设置从现在起 10 分钟的闹钟,因此我们需要为模型提供这两种工具来完成此任务。spring-doc.cadn.net.cn

我们将把新工具添加到DateTimeTools和以前一样上课。新工具将采用单个参数,即 ISO-8601 格式的时间。然后,该工具将向控制台打印一条消息,指示警报已设置给定时间。和以前一样,该工具被定义为一个用@Tool,我们还使用它来提供详细的描述,以帮助模型了解何时以及如何使用该工具。spring-doc.cadn.net.cn

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.context.i18n.LocaleContextHolder;

class DateTimeTools {

    @Tool(description = "Get the current date and time in the user's timezone")
    String getCurrentDateTime() {
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

    @Tool(description = "Set a user alarm for the given time, provided in ISO-8601 format")
    void setAlarm(String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("Alarm set for " + alarmTime);
    }

}

接下来,让我们使这两个工具都可用于模型。我们将使用ChatClient与模型交互。我们将通过传递DateTimeTools通过tools()方法。当我们要求在 10 分钟后设置闹钟时,模型首先需要知道当前日期和时间。然后,它将使用当前日期和时间来计算闹钟时间。最后,它将使用报警工具设置报警。在内部,ChatClient将处理来自模型的任何工具调用请求,并将任何工具调用执行结果发送回给它,以便模型可以生成最终响应。spring-doc.cadn.net.cn

ChatModel chatModel = ...

String response = ChatClient.create(chatModel)
        .prompt("Can you set an alarm 10 minutes from now?")
        .tools(new DateTimeTools())
        .call()
        .content();

System.out.println(response);

在应用程序日志中,您可以检查警报是否在正确的时间设置。spring-doc.cadn.net.cn

概述

Spring AI 通过一组灵活的抽象支持工具调用,允许您以一致的方式定义、解析和执行工具。本节概述了 Spring AI 中工具调用的主要概念和组件。spring-doc.cadn.net.cn

工具调用的主要作顺序
  1. 当我们想使工具可供模型使用时,我们会在聊天请求中包含其定义。每个工具定义都包含输入参数的名称、描述和架构。spring-doc.cadn.net.cn

  2. 当模型决定调用工具时,它会发送一个响应,其中包含工具名称和根据定义的架构建模的输入参数。spring-doc.cadn.net.cn

  3. 应用程序负责使用工具名称来识别和执行具有提供的输入参数的工具。spring-doc.cadn.net.cn

  4. 工具调用的结果由应用程序处理。spring-doc.cadn.net.cn

  5. 应用程序将工具调用结果发送回模型。spring-doc.cadn.net.cn

  6. 该模型使用工具调用结果作为附加上下文生成最终响应。spring-doc.cadn.net.cn

工具是工具调用的构建块,它们由ToolCallback接口。Spring AI 提供对指定ToolCallback(s) 来自方法和函数,但您始终可以定义自己的ToolCallback实现以支持更多用例。spring-doc.cadn.net.cn

ChatModel实现透明地将工具调用请求分派到相应的ToolCallback实现,并将工具调用结果发送回模型,最终生成最终响应。他们使用ToolCallingManager接口,负责管理工具执行生命周期。spring-doc.cadn.net.cn

ChatClientChatModel接受列表ToolCallback对象,使工具可用于模型,并且ToolCallingManager最终会处决他们。spring-doc.cadn.net.cn

除了传递ToolCallback对象,您还可以传递工具名称列表,这些列表将使用ToolCallbackResolver接口。spring-doc.cadn.net.cn

以下部分将详细介绍所有这些概念和 API,包括如何自定义和扩展它们以支持更多用例。spring-doc.cadn.net.cn

方法作为工具

Spring AI 提供了对指定工具(即ToolCallback(s)) 以两种方式从方法:spring-doc.cadn.net.cn

声明性规范:@Tool

您可以通过使用@Tool.spring-doc.cadn.net.cn

class DateTimeTools {

    @Tool(description = "Get the current date and time in the user's timezone")
    String getCurrentDateTime() {
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

@Tool注释允许您提供有关该工具的关键信息:spring-doc.cadn.net.cn

  • name:工具的名称。如果未提供,则将使用方法名称。AI 模型在调用工具时使用此名称来标识工具。因此,不允许在同一类中有两个同名的工具。该名称在模型可用于特定聊天请求的所有工具中必须是唯一的。spring-doc.cadn.net.cn

  • description:工具的描述,模型可以使用它来了解何时以及如何调用该工具。如果未提供,方法名称将用作工具描述。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。spring-doc.cadn.net.cn

  • returnDirect:是将工具结果直接返回给客户端还是传递回模型。有关更多详细信息,请参阅直接退货spring-doc.cadn.net.cn

  • resultConverter:这ToolCallResultConverter用于将工具调用结果转换为String object发送回 AI 模型。有关更多详细信息,请参阅结果转换spring-doc.cadn.net.cn

该方法可以是静态的,也可以是实例的,并且可以具有任何可见性(public、protected、package-private 或 private)。包含该方法的类可以是顶级类,也可以是嵌套类,它也可以具有任何可见性(只要它可以在您计划实例化它的位置访问)。spring-doc.cadn.net.cn

Spring AI 为 AOT 编译提供了内置支持@Tool-annotated 方法,只要包含这些方法的类是 Spring bean(例如@Component).否则,您需要向 GraalVM 编译器提供必要的配置。例如,通过使用@RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_METHODS).

您可以使用大多数类型(基元、POJO、枚举、列表、数组、映射等)为方法定义任意数量的参数(包括无参数)。同样,该方法可以返回大多数类型,包括void.如果该方法返回一个值,则返回类型必须是可序列化类型,因为结果将被序列化并发送回模型。spring-doc.cadn.net.cn

不支持某些类型。有关更多详细信息,请参阅方法工具限制

Spring AI 将为@Tool-annotated 方法。模型使用架构来了解如何调用工具并准备工具请求。这@ToolParam注释可用于提供有关输入参数的附加信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。spring-doc.cadn.net.cn

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;

class DateTimeTools {

    @Tool(description = "Set a user alarm for the given time")
    void setAlarm(@ToolParam(description = "Time in ISO-8601 format") String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("Alarm set for " + alarmTime);
    }

}

@ToolParam注释允许您提供有关工具参数的关键信息:spring-doc.cadn.net.cn

  • description:参数的描述,模型可以使用它来更好地理解如何使用它。例如,参数应采用什么格式、允许使用哪些值等。spring-doc.cadn.net.cn

  • required:参数是必填还是可选。默认情况下,所有参数都被视为必需参数。spring-doc.cadn.net.cn

如果参数注释为@Nullable,除非使用@ToolParam注解。spring-doc.cadn.net.cn

除了@ToolParam注释,也可以使用@Schema来自 Swagger 的注释或@JsonProperty来自Jackson。有关更多详细信息,请参阅 JSON 架构spring-doc.cadn.net.cn

将工具添加到ChatClient

使用声明式规范方法时,可以将工具类实例传递给tools()调用ChatClient.此类工具仅适用于添加它们的特定聊天请求。spring-doc.cadn.net.cn

ChatClient.create(chatModel)
    .prompt("What day is tomorrow?")
    .tools(new DateTimeTools())
    .call()
    .content();

在引擎盖下,ChatClient将生成一个ToolCallback从每个@Tool-annotated 方法,并将它们传递给模型。如果您更喜欢生成ToolCallback(s) 自己,您可以使用ToolCallbacks实用程序类。spring-doc.cadn.net.cn

ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());

将默认工具添加到ChatClient

使用声明式规范方法时,可以将默认工具添加到ChatClient.Builder通过将工具类实例传递给defaultTools()方法。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在所有ChatClient从同一构建的实例ChatClient.Builder.它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ChatModel chatModel = ...
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultTools(new DateTimeTools())
    .build();

将工具添加到ChatModel

使用声明式规范方法时,可以将工具类实例传递给toolCallbacks()方法ToolCallingChatOptions您过去用来调用ChatModel.此类工具仅适用于添加它们的特定聊天请求。spring-doc.cadn.net.cn

ChatModel chatModel = ...
ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(dateTimeTools)
    .build();
Prompt prompt = new Prompt("What day is tomorrow?", chatOptions);
chatModel.call(prompt);

将默认工具添加到ChatModel

使用声明式规范方法时,可以将默认工具添加到ChatModel在构造时,通过将工具类实例传递给toolCallbacks()方法ToolCallingChatOptions实例,用于创建ChatModel. 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在由该工具执行的所有聊天请求中共享ChatModel实例。它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
ChatModel chatModel = OllamaChatModel.builder()
    .ollamaApi(OllamaApi.builder().build())
    .defaultOptions(ToolCallingChatOptions.builder()
            .toolCallbacks(dateTimeTools)
            .build())
    .build();

程序化规范:MethodToolCallback

您可以通过构建一个MethodToolCallback编程。spring-doc.cadn.net.cn

class DateTimeTools {

    String getCurrentDateTime() {
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

MethodToolCallback.Builder允许您构建一个MethodToolCallback实例,并提供有关该工具的关键信息:spring-doc.cadn.net.cn

  • toolDefinition:这ToolDefinition定义工具名称、描述和输入架构的实例。您可以使用ToolDefinition.Builderclass. 必填。spring-doc.cadn.net.cn

  • toolMetadata:这ToolMetadata定义其他设置的实例,例如是否应将结果直接返回给客户端,以及要使用的结果转换器。您可以使用ToolMetadata.Builder类。spring-doc.cadn.net.cn

  • toolMethod:这Method表示工具方法的实例。必填。spring-doc.cadn.net.cn

  • toolObject:包含工具方法的对象实例。如果该方法是静态的,则可以省略此参数。spring-doc.cadn.net.cn

  • toolCallResultConverter:这ToolCallResultConverter用于将工具调用结果转换为String对象发送回 AI 模型。如果未提供,则将使用默认转换器 (DefaultToolCallResultConverter).spring-doc.cadn.net.cn

ToolDefinition.Builder允许您构建一个ToolDefinition实例并定义工具名称、描述和输入模式:spring-doc.cadn.net.cn

  • name:工具的名称。如果未提供,则将使用方法名称。AI 模型在调用工具时使用此名称来标识工具。因此,不允许在同一类中有两个同名的工具。该名称在模型可用于特定聊天请求的所有工具中必须是唯一的。spring-doc.cadn.net.cn

  • description:工具的描述,模型可以使用它来了解何时以及如何调用该工具。如果未提供,方法名称将用作工具描述。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。spring-doc.cadn.net.cn

  • inputSchema:工具输入参数的 JSON 架构。如果未提供,则将根据方法参数自动生成架构。您可以使用@ToolParam注释,以提供有关输入参数的其他信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。有关更多详细信息,请参阅 JSON 架构spring-doc.cadn.net.cn

ToolMetadata.Builder允许您构建一个ToolMetadata实例并定义工具的其他设置:spring-doc.cadn.net.cn

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolCallback toolCallback = MethodToolCallback.builder()
    .toolDefinition(ToolDefinitions.builder(method)
            .description("Get the current date and time in the user's timezone")
            .build())
    .toolMethod(method)
    .toolObject(new DateTimeTools())
    .build();

该方法可以是静态的,也可以是实例的,并且可以具有任何可见性(public、protected、package-private 或 private)。包含该方法的类可以是顶级类,也可以是嵌套类,它也可以具有任何可见性(只要它可以在您计划实例化它的位置访问)。spring-doc.cadn.net.cn

Spring AI 为工具方法的 AOT 编译提供了内置支持,只要包含方法的类是 Spring bean(例如@Component).否则,您需要向 GraalVM 编译器提供必要的配置。例如,通过使用@RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_METHODS).

您可以使用大多数类型(基元、POJO、枚举、列表、数组、映射等)为方法定义任意数量的参数(包括无参数)。同样,该方法可以返回大多数类型,包括void.如果该方法返回一个值,则返回类型必须是可序列化类型,因为结果将被序列化并发送回模型。spring-doc.cadn.net.cn

不支持某些类型。有关更多详细信息,请参阅方法工具限制

如果该方法是静态的,则可以省略toolObject()方法,因为它不需要。spring-doc.cadn.net.cn

class DateTimeTools {

    static String getCurrentDateTime() {
        return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}
Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolCallback toolCallback = MethodToolCallback.builder()
    .toolDefinition(ToolDefinitions.builder(method)
            .description("Get the current date and time in the user's timezone")
            .build())
    .toolMethod(method)
    .build();

Spring AI 将自动为方法的输入参数生成 JSON 模式。模型使用架构来了解如何调用工具并准备工具请求。这@ToolParam注释可用于提供有关输入参数的附加信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。spring-doc.cadn.net.cn

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.ai.tool.annotation.ToolParam;

class DateTimeTools {

    void setAlarm(@ToolParam(description = "Time in ISO-8601 format") String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("Alarm set for " + alarmTime);
    }

}

@ToolParam注释允许您提供有关工具参数的关键信息:spring-doc.cadn.net.cn

  • description:参数的描述,模型可以使用它来更好地理解如何使用它。例如,参数应采用什么格式、允许使用哪些值等。spring-doc.cadn.net.cn

  • required:参数是必填还是可选。默认情况下,所有参数都被视为必需参数。spring-doc.cadn.net.cn

如果参数注释为@Nullable,除非使用@ToolParam注解。spring-doc.cadn.net.cn

除了@ToolParam注释,也可以使用@Schema来自 Swagger 的注释或@JsonProperty来自Jackson。有关更多详细信息,请参阅 JSON 架构spring-doc.cadn.net.cn

将工具添加到ChatClientChatModel

使用编程规范方法时,可以将MethodToolCallbackinstance 添加到toolCallbacks()方法ChatClient. 该工具仅适用于添加它的特定聊天请求。spring-doc.cadn.net.cn

ToolCallback toolCallback = ...
ChatClient.create(chatModel)
    .prompt("What day is tomorrow?")
    .toolCallbacks(toolCallback)
    .call()
    .content();

将默认工具添加到ChatClient

使用编程规范方法时,可以将默认工具添加到ChatClient.Builder通过传递MethodToolCallbackinstance 添加到defaultToolCallbacks()方法。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在所有ChatClient从同一构建的实例ChatClient.Builder.它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ChatModel chatModel = ...
ToolCallback toolCallback = ...
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultToolCallbacks(toolCallback)
    .build();

将工具添加到ChatModel

使用编程规范方法时,可以将MethodToolCallbackinstance 添加到toolCallbacks()方法ToolCallingChatOptions您过去用来调用ChatModel.该工具仅适用于添加它的特定聊天请求。spring-doc.cadn.net.cn

ChatModel chatModel = ...
ToolCallback toolCallback = ...
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(toolCallback)
    .build():
Prompt prompt = new Prompt("What day is tomorrow?", chatOptions);
chatModel.call(prompt);

将默认工具添加到ChatModel

使用编程规范方法时,可以将默认工具添加到ChatModel在施工时通过传递MethodToolCallbackinstance 添加到toolCallbacks()方法ToolCallingChatOptions实例,用于创建ChatModel. 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在由该工具执行的所有聊天请求中共享ChatModel实例。它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ToolCallback toolCallback = ...
ChatModel chatModel = OllamaChatModel.builder()
    .ollamaApi(OllamaApi.builder().build())
    .defaultOptions(ToolCallingChatOptions.builder()
            .toolCallbacks(toolCallback)
            .build())
    .build();

方法工具限制

当前不支持以下类型作为用作工具的方法的参数或返回类型:spring-doc.cadn.net.cn

使用基于函数的工具规范方法支持函数类型。有关更多详细信息,请参阅函数作为工具。spring-doc.cadn.net.cn

作为工具的功能

Spring AI 提供了内置支持,用于从函数中指定工具,可以使用低级FunctionToolCallback实现或动态为@Bean(s) 在运行时解析。spring-doc.cadn.net.cn

程序化规范:FunctionToolCallback

您可以将功能类型 (Function,Supplier,ConsumerBiFunction) 通过构建FunctionToolCallback编程。spring-doc.cadn.net.cn

public class WeatherService implements Function<WeatherRequest, WeatherResponse> {
    public WeatherResponse apply(WeatherRequest request) {
        return new WeatherResponse(30.0, Unit.C);
    }
}

public enum Unit { C, F }
public record WeatherRequest(String location, Unit unit) {}
public record WeatherResponse(double temp, Unit unit) {}

FunctionToolCallback.Builder允许您构建一个FunctionToolCallback实例,并提供有关该工具的关键信息:spring-doc.cadn.net.cn

  • name:工具的名称。AI 模型在调用工具时使用此名称来标识工具。因此,不允许在同一上下文中使用两个具有相同名称的工具。该名称在模型可用于特定聊天请求的所有工具中必须是唯一的。必填。spring-doc.cadn.net.cn

  • toolFunction:表示工具方法(Function,Supplier,ConsumerBiFunction).必填。spring-doc.cadn.net.cn

  • description:工具的描述,模型可以使用它来了解何时以及如何调用该工具。如果未提供,方法名称将用作工具描述。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。spring-doc.cadn.net.cn

  • inputType:函数输入的类型。必填。spring-doc.cadn.net.cn

  • inputSchema:工具输入参数的 JSON 架构。如果未提供,则将根据inputType.您可以使用@ToolParam注释,以提供有关输入参数的其他信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。有关更多详细信息,请参阅 JSON 架构spring-doc.cadn.net.cn

  • toolMetadata:这ToolMetadata定义其他设置的实例,例如是否应将结果直接返回给客户端,以及要使用的结果转换器。您可以使用ToolMetadata.Builder类。spring-doc.cadn.net.cn

  • toolCallResultConverter:这ToolCallResultConverter用于将工具调用结果转换为String对象发送回 AI 模型。如果未提供,则将使用默认转换器 (DefaultToolCallResultConverter).spring-doc.cadn.net.cn

ToolMetadata.Builder允许您构建一个ToolMetadata实例并定义工具的其他设置:spring-doc.cadn.net.cn

ToolCallback toolCallback = FunctionToolCallback
    .builder("currentWeather", new WeatherService())
    .description("Get the weather in location")
    .inputType(WeatherRequest.class)
    .build();

函数输入和输出可以是Void或 POJO。输入和输出 POJO 必须是可序列化的,因为结果将被序列化并发送回模型。函数以及输入和输出类型必须是公共的。spring-doc.cadn.net.cn

不支持某些类型。有关更多详细信息,请参阅函数工具限制

将工具添加到ChatClient

使用编程规范方法时,可以将FunctionToolCallbackinstance 添加到toolCallbacks()方法ChatClient.该工具仅适用于添加它的特定聊天请求。spring-doc.cadn.net.cn

ToolCallback toolCallback = ...
ChatClient.create(chatModel)
    .prompt("What's the weather like in Copenhagen?")
    .toolCallbacks(toolCallback)
    .call()
    .content();

将默认工具添加到ChatClient

使用编程规范方法时,可以将默认工具添加到ChatClient.Builder通过传递FunctionToolCallbackinstance 添加到defaultToolCallbacks()方法。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在所有ChatClient从同一构建的实例ChatClient.Builder.它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ChatModel chatModel = ...
ToolCallback toolCallback = ...
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultToolCallbacks(toolCallback)
    .build();

将工具添加到ChatModel

使用编程规范方法时,可以将FunctionToolCallbackinstance 添加到toolCallbacks()方法ToolCallingChatOptions.该工具仅适用于添加它的特定聊天请求。spring-doc.cadn.net.cn

ChatModel chatModel = ...
ToolCallback toolCallback = ...
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(toolCallback)
    .build():
Prompt prompt = new Prompt("What's the weather like in Copenhagen?", chatOptions);
chatModel.call(prompt);

将默认工具添加到ChatModel

使用编程规范方法时,可以将默认工具添加到ChatModel在施工时通过传递FunctionToolCallbackinstance 添加到toolCallbacks()方法ToolCallingChatOptions实例,用于创建ChatModel. 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在由该工具执行的所有聊天请求中共享ChatModel实例。它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ToolCallback toolCallback = ...
ChatModel chatModel = OllamaChatModel.builder()
    .ollamaApi(OllamaApi.builder().build())
    .defaultOptions(ToolCallingChatOptions.builder()
            .toolCallbacks(toolCallback)
            .build())
    .build();

动态规格:@Bean

您可以将工具定义为 Spring bean,并让 Spring AI 在运行时使用ToolCallbackResolver接口(通过SpringBeanToolCallbackResolver实现)。此选项使您可以使用任何Function,Supplier,ConsumerBiFunctionbean 作为工具。bean 名称将用作工具名称,并且@DescriptionSpring Framework 中的注释可用于为工具提供描述,模型使用它来了解何时以及如何调用该工具。如果未提供说明,则方法名称将用作工具说明。但是,强烈建议提供详细的描述,因为这对于模型理解工具的用途以及如何使用它至关重要。未能提供良好的描述可能会导致模型在应该使用的工具时没有使用或错误地使用该工具。spring-doc.cadn.net.cn

@Configuration(proxyBeanMethods = false)
class WeatherTools {

    WeatherService weatherService = new WeatherService();

	@Bean
	@Description("Get the weather in location")
	Function<WeatherRequest, WeatherResponse> currentWeather() {
		return weatherService;
	}

}
不支持某些类型。有关更多详细信息,请参阅函数工具限制

将自动生成工具输入参数的 JSON 模式。您可以使用@ToolParam注释,以提供有关输入参数的其他信息,例如描述或参数是必需的还是可选的。默认情况下,所有输入参数都被视为必需。有关更多详细信息,请参阅 JSON 架构spring-doc.cadn.net.cn

record WeatherRequest(@ToolParam(description = "The name of a city or a country") String location, Unit unit) {}

这种工具规范方法的缺点是不能保证类型安全,因为工具解析是在运行时完成的。为了缓解这种情况,您可以使用@Bean注释并将值存储在常量中,以便您可以在聊天请求中使用它,而不是对工具名称进行硬编码。spring-doc.cadn.net.cn

@Configuration(proxyBeanMethods = false)
class WeatherTools {

    public static final String CURRENT_WEATHER_TOOL = "currentWeather";

	@Bean(CURRENT_WEATHER_TOOL)
	@Description("Get the weather in location")
	Function<WeatherRequest, WeatherResponse> currentWeather() {
		...
	}

}

将工具添加到ChatClient

使用动态规范方法时,您可以将工具名称(即函数 bean 名称)传递给tools()方法ChatClient. 该工具仅适用于添加它的特定聊天请求。spring-doc.cadn.net.cn

ChatClient.create(chatModel)
    .prompt("What's the weather like in Copenhagen?")
    .toolNames("currentWeather")
    .call()
    .content();

将默认工具添加到ChatClient

使用动态规范方法时,可以将默认工具添加到ChatClient.Builder通过将工具名称传递给defaultToolNames()方法。 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在所有ChatClient从同一构建的实例ChatClient.Builder.它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ChatModel chatModel = ...
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultToolNames("currentWeather")
    .build();

将工具添加到ChatModel

使用动态规范方法时,可以将工具名称传递给toolNames()方法ToolCallingChatOptions您过去用来调用ChatModel.该工具仅适用于添加它的特定聊天请求。spring-doc.cadn.net.cn

ChatModel chatModel = ...
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolNames("currentWeather")
    .build();
Prompt prompt = new Prompt("What's the weather like in Copenhagen?", chatOptions);
chatModel.call(prompt);

将默认工具添加到ChatModel

使用动态规范方法时,可以将默认工具添加到ChatModel在施工时,通过将工具名称传递给toolNames()方法ToolCallingChatOptions实例,用于创建ChatModel. 如果同时提供默认工具和运行时工具,则运行时工具将完全覆盖默认工具。spring-doc.cadn.net.cn

默认工具在由该工具执行的所有聊天请求中共享ChatModel实例。它们对于在不同聊天请求中常用的工具很有用,但如果使用不当,它们也可能很危险,可能会在不应该提供它们时提供它们。
ChatModel chatModel = OllamaChatModel.builder()
    .ollamaApi(OllamaApi.builder().build())
    .defaultOptions(ToolCallingChatOptions.builder()
            .toolNames("currentWeather")
            .build())
    .build();

函数工具限制

当前不支持以下类型作为用作工具的函数的输入或输出类型:spring-doc.cadn.net.cn

使用基于方法的工具规范方法支持基元类型和集合。有关更多详细信息,请参阅方法作为工具。spring-doc.cadn.net.cn

工具规格

在 Spring AI 中,工具是通过ToolCallback接口。 在前面的部分中,我们已经了解了如何使用 Spring AI 提供的内置支持从方法和函数定义工具(请参阅方法作为工具和函数作为工具)。本节将更深入地探讨工具规范以及如何自定义和扩展它以支持更多用例。spring-doc.cadn.net.cn

工具回调

ToolCallback接口提供了一种定义可由 AI 模型调用的工具的方法,包括定义和执行逻辑。当您想要从头开始定义工具时,它是要实现的主要接口。例如,您可以定义一个ToolCallback从 MCP 客户端(使用模型上下文协议)或ChatClient(构建模块化代理应用程序)。spring-doc.cadn.net.cn

该接口提供以下方法:spring-doc.cadn.net.cn

public interface ToolCallback {

	/**
	 * Definition used by the AI model to determine when and how to call the tool.
	 */
	ToolDefinition getToolDefinition();

	/**
	 * Metadata providing additional information on how to handle the tool.
	 */
	ToolMetadata getToolMetadata();

    /**
	 * Execute tool with the given input and return the result to send back to the AI model.
	 */
	String call(String toolInput);

    /**
	 * Execute tool with the given input and context, and return the result to send back to the AI model.
	 */
	String call(String toolInput, ToolContext tooContext);

}

Spring AI 为工具方法(MethodToolCallback) 和工具函数 (FunctionToolCallback).spring-doc.cadn.net.cn

刀具定义

ToolDefinition接口为 AI 模型提供了解工具可用性所需的信息,包括工具名称、描述和输入模式。每ToolCallback实现必须提供ToolDefinition实例来定义工具。spring-doc.cadn.net.cn

该接口提供以下方法:spring-doc.cadn.net.cn

public interface ToolDefinition {

	/**
	 * The tool name. Unique within the tool set provided to a model.
	 */
	String name();

	/**
	 * The tool description, used by the AI model to determine what the tool does.
	 */
	String description();

	/**
	 * The schema of the parameters used to call the tool.
	 */
	String inputSchema();

}
有关输入架构的更多详细信息,请参阅 JSON 架构

ToolDefinition.Builder允许您构建一个ToolDefinition使用默认实现 (DefaultToolDefinition).spring-doc.cadn.net.cn

ToolDefinition toolDefinition = ToolDefinition.builder()
    .name("currentWeather")
    .description("Get the weather in location")
    .inputSchema("""
        {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string"
                },
                "unit": {
                    "type": "string",
                    "enum": ["C", "F"]
                }
            },
            "required": ["location", "unit"]
        }
    """)
    .build();

方法工具定义

从方法构建工具时,ToolDefinition会自动为您生成。如果您更喜欢生成ToolDefinition您自己,可以使用这个方便的构建器。spring-doc.cadn.net.cn

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolDefinition toolDefinition = ToolDefinitions.from(method);

ToolDefinition从方法生成的方法包括作为工具名称的方法名称、作为工具描述的方法名称以及方法输入参数的 JSON 模式。如果该方法用@Tool,如果已设置,则工具名称和描述将取自注释。spring-doc.cadn.net.cn

有关更多详细信息,请参阅方法作为工具。

如果您希望显式提供部分或全部属性,则可以使用ToolDefinition.Builder构建自定义ToolDefinition实例。spring-doc.cadn.net.cn

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
ToolDefinition toolDefinition = ToolDefinitions.builder(method)
    .name("currentDateTime")
    .description("Get the current date and time in the user's timezone")
    .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
    .build();

功能工具定义

从函数构建工具时,ToolDefinition会自动为您生成。当您使用FunctionToolCallback.Builder构建一个FunctionToolCallback实例中,您可以提供工具名称、描述和输入模式,用于生成ToolDefinition.有关更多详细信息,请参阅函数作为工具。spring-doc.cadn.net.cn

JSON 架构

向 AI 模型提供工具时,模型需要知道调用工具的输入类型的架构。该架构用于了解如何调用该工具并准备该工具请求。Spring AI 提供了内置支持,用于通过JsonSchemaGenerator类。架构作为ToolDefinition.spring-doc.cadn.net.cn

有关ToolDefinition以及如何将输入模式传递给它。

JsonSchemaGeneratorclass 用于在后台为方法或函数的输入参数生成 JSON 模式,使用方法作为工具和函数作为工具中描述的任何策略。JSON 架构生成逻辑支持一系列注释,您可以对方法和函数的输入参数使用这些注释来自定义生成的架构。spring-doc.cadn.net.cn

本节介绍在为工具的输入参数生成 JSON 架构时可以自定义的两个主要选项:描述和必需状态。spring-doc.cadn.net.cn

描述

除了提供工具本身的描述外,还可以提供工具的输入参数的描述。描述可用于提供有关输入参数的关键信息,例如参数应采用什么格式、允许哪些值等。这对于帮助模型理解输入架构以及如何使用它非常有用。Spring AI 提供内置支持,用于使用以下注解之一生成输入参数的描述:spring-doc.cadn.net.cn

此方法适用于方法和函数,您可以递归地将其用于嵌套类型。spring-doc.cadn.net.cn

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.context.i18n.LocaleContextHolder;

class DateTimeTools {

    @Tool(description = "Set a user alarm for the given time")
    void setAlarm(@ToolParam(description = "Time in ISO-8601 format") String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("Alarm set for " + alarmTime);
    }

}

必需/可选

默认情况下,每个输入参数都被视为必需参数,这会强制 AI 模型在调用工具时为其提供值。但是,您可以使用以下注释之一将输入参数设为可选,按此优先级顺序排列:spring-doc.cadn.net.cn

此方法适用于方法和函数,您可以递归地将其用于嵌套类型。spring-doc.cadn.net.cn

class CustomerTools {

    @Tool(description = "Update customer information")
    void updateCustomerInfo(Long id, String name, @ToolParam(required = false) String email) {
        System.out.println("Updated info for customer with id: " + id);
    }

}
为输入参数定义正确的所需状态对于降低幻觉风险并确保模型在调用工具时提供正确的输入至关重要。在前面的示例中,emailparameter 是可选的,这意味着模型可以调用该工具而无需为其提供值。如果参数是必需的,则模型在调用工具时必须为其提供值。如果不存在值,模型可能会编造一个值,从而导致幻觉。

结果转换

工具调用的结果使用ToolCallResultConverter然后发回 AI 模型。这ToolCallResultConverter接口提供了一种将工具调用结果转换为String对象。spring-doc.cadn.net.cn

接口提供以下方法:spring-doc.cadn.net.cn

@FunctionalInterface
public interface ToolCallResultConverter {

	/**
	 * Given an Object returned by a tool, convert it to a String compatible with the
	 * given class type.
	 */
	String convert(@Nullable Object result, @Nullable Type returnType);

}

结果必须是可序列化类型。默认情况下,结果使用 Jackson (DefaultToolCallResultConverter),但您可以通过提供自己的序列化过程来自定义序列化过程ToolCallResultConverter实现。spring-doc.cadn.net.cn

Spring AI 依赖于ToolCallResultConverter在方法和函数工具中。spring-doc.cadn.net.cn

方法工具调用结果转换

使用声明式方法从方法生成工具时,可以提供自定义ToolCallResultConverter要用于该工具,请将resultConverter()属性的@Tool注解。spring-doc.cadn.net.cn

class CustomerTools {

    @Tool(description = "Retrieve customer information", resultConverter = CustomToolCallResultConverter.class)
    Customer getCustomerInfo(Long id) {
        return customerRepository.findById(id);
    }

}

如果使用编程方法,则可以提供自定义ToolCallResultConverter要用于该工具,请将resultConverter()属性的MethodToolCallback.Builder.spring-doc.cadn.net.cn

有关更多详细信息,请参阅方法作为工具。spring-doc.cadn.net.cn

函数工具调用结果转换

使用编程方法从函数构建工具时,可以提供自定义ToolCallResultConverter要用于该工具,请将resultConverter()属性的FunctionToolCallback.Builder.spring-doc.cadn.net.cn

有关更多详细信息,请参阅函数作为工具。spring-doc.cadn.net.cn

工具上下文

Spring AI 支持通过ToolContext应用程序接口。此功能允许您提供额外的用户提供的数据,这些数据可用于工具执行以及 AI 模型传递的工具参数。spring-doc.cadn.net.cn

向工具提供其他上下文信息
class CustomerTools {

    @Tool(description = "Retrieve customer information")
    Customer getCustomerInfo(Long id, ToolContext toolContext) {
        return customerRepository.findById(id, toolContext.getContext().get("tenantId"));
    }

}

ToolContext填充了用户在调用时提供的数据ChatClient.spring-doc.cadn.net.cn

ChatModel chatModel = ...

String response = ChatClient.create(chatModel)
        .prompt("Tell me more about the customer with ID 42")
        .tools(new CustomerTools())
        .toolContext(Map.of("tenantId", "acme"))
        .call()
        .content();

System.out.println(response);
中没有提供任何数据ToolContext被发送到 AI 模型。

同样,您可以在调用ChatModel径直。spring-doc.cadn.net.cn

ChatModel chatModel = ...
ToolCallback[] customerTools = ToolCallbacks.from(new CustomerTools());
ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(customerTools)
    .toolContext(Map.of("tenantId", "acme"))
    .build();
Prompt prompt = new Prompt("Tell me more about the customer with ID 42", chatOptions);
chatModel.call(prompt);

如果toolContext选项在默认选项和运行时选项中都设置了,结果ToolContext将是两者的合并,其中运行时选项优先于默认选项。spring-doc.cadn.net.cn

直接返回

默认情况下,工具调用的结果将作为响应发送回模型。然后,模型可以使用结果继续对话。spring-doc.cadn.net.cn

在某些情况下,您宁愿将结果直接返回给调用方,而不是将其发送回模型。例如,如果您构建了一个依赖于 RAG 工具的代理,您可能希望将结果直接返回给调用方,而不是将其发送回模型进行不必要的后处理。或者,您可能有某些工具应该结束代理的推理循环。spring-doc.cadn.net.cn

ToolCallback实现可以定义工具调用的结果是应直接返回给调用方还是发送回模型。默认情况下,结果将发送回模型。但是,您可以根据每个工具更改此行为。spring-doc.cadn.net.cn

ToolCallingManager,负责管理工具执行生命周期,负责处理returnDirect属性。如果属性设置为true,则工具调用的结果将直接返回给调用者。否则,结果将发送回模型。spring-doc.cadn.net.cn

如果一次请求多个工具调用,则returnDirect属性必须设置为true将结果直接返回给调用者。否则,结果将发送回模型。
将工具调用结果直接返回给调用方
  1. 当我们想使工具可供模型使用时,我们会在聊天请求中包含其定义。如果我们希望工具执行的结果直接返回给调用者,我们将returnDirect属性设置为true.spring-doc.cadn.net.cn

  2. 当模型决定调用工具时,它会发送一个响应,其中包含工具名称和根据定义的架构建模的输入参数。spring-doc.cadn.net.cn

  3. 应用程序负责使用工具名称来识别和执行具有提供的输入参数的工具。spring-doc.cadn.net.cn

  4. 工具调用的结果由应用程序处理。spring-doc.cadn.net.cn

  5. 应用程序将工具调用结果直接发送给调用方,而不是将其发送回模型。spring-doc.cadn.net.cn

方法:直接返回

使用声明式方法从方法生成工具时,可以通过将returnDirect属性的@Tool注释到true.spring-doc.cadn.net.cn

class CustomerTools {

    @Tool(description = "Retrieve customer information", returnDirect = true)
    Customer getCustomerInfo(Long id) {
        return customerRepository.findById(id);
    }

}

如果使用编程方法,您可以将returnDirect属性通过ToolMetadata接口并将其传递给MethodToolCallback.Builder.spring-doc.cadn.net.cn

ToolMetadata toolMetadata = ToolMetadata.builder()
    .returnDirect(true)
    .build();

有关更多详细信息,请参阅方法作为工具。spring-doc.cadn.net.cn

函数 返回直接

使用编程方法从函数构建工具时,可以将returnDirect属性通过ToolMetadata接口并将其传递给FunctionToolCallback.Builder.spring-doc.cadn.net.cn

ToolMetadata toolMetadata = ToolMetadata.builder()
    .returnDirect(true)
    .build();

有关更多详细信息,请参阅函数作为工具。spring-doc.cadn.net.cn

工具执行

工具执行是使用提供的输入参数调用工具并返回结果的过程。工具执行由ToolCallingManager接口,负责管理工具执行生命周期。spring-doc.cadn.net.cn

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,DefaultToolCallingManagerToolCallingManager接口。您可以通过提供自己的工具执行行为来自定义工具执行行为ToolCallingManager豆。spring-doc.cadn.net.cn

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

默认情况下,Spring AI 从每个ChatModel实现。但是,您可以选择退出此行为并自行控制工具执行。本节介绍这两种方案。spring-doc.cadn.net.cn

框架控制的工具执行

使用默认行为时,Spring AI 会自动拦截来自模型的任何工具调用请求,调用工具并将结果返回给模型。所有这一切都由每个人为您透明地完成ChatModel使用ToolCallingManager.spring-doc.cadn.net.cn

框架控制的工具执行生命周期
  1. 当我们想使工具可供模型使用时,我们将其定义包含在聊天请求中(Prompt) 并调用ChatModelAPI 将请求发送到 AI 模型。spring-doc.cadn.net.cn

  2. 当模型决定调用工具时,它会发送响应 (ChatResponse)替换为工具名称和根据定义的模式建模的输入参数。spring-doc.cadn.net.cn

  3. ChatModel将工具调用请求发送到ToolCallingManager应用程序接口。spring-doc.cadn.net.cn

  4. ToolCallingManager负责识别要调用的工具并使用提供的输入参数执行它。spring-doc.cadn.net.cn

  5. 工具调用的结果将返回给ToolCallingManager.spring-doc.cadn.net.cn

  6. ToolCallingManager将工具执行结果返回给ChatModel.spring-doc.cadn.net.cn

  7. ChatModel将工具执行结果发送回 AI 模型(ToolResponseMessage).spring-doc.cadn.net.cn

  8. AI 模型使用工具调用结果作为附加上下文生成最终响应,并将其发送回调用者 (ChatResponse) 通过ChatClient.spring-doc.cadn.net.cn

目前,与模型交换的有关工具执行的内部消息不会向用户公开。如果需要访问这些消息,则应使用用户控制的工具执行方法。

确定工具调用是否符合执行条件的逻辑由ToolExecutionEligibilityPredicate接口。默认情况下,工具执行资格是通过检查internalToolExecutionEnabled属性ToolCallingChatOptions设置为true(默认值),如果ChatResponse包含任何工具调用。spring-doc.cadn.net.cn

public class DefaultToolExecutionEligibilityPredicate implements ToolExecutionEligibilityPredicate {

	@Override
	public boolean test(ChatOptions promptOptions, ChatResponse chatResponse) {
		return ToolCallingChatOptions.isInternalToolExecutionEnabled(promptOptions) && chatResponse != null
				&& chatResponse.hasToolCalls();
	}

}

您可以提供自定义实现ToolExecutionEligibilityPredicate创建ChatModel豆。spring-doc.cadn.net.cn

用户控制的工具执行

在某些情况下,您宁愿自己控制工具执行生命周期。您可以通过将internalToolExecutionEnabled属性ToolCallingChatOptionsfalse.spring-doc.cadn.net.cn

当您调用ChatModel使用此选项,工具执行将委托给调用方,从而完全控制工具执行生命周期。您负责检查ChatResponse并使用ToolCallingManager.spring-doc.cadn.net.cn

以下示例演示了用户控制的工具执行方法的最小实现:spring-doc.cadn.net.cn

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());
在选择用户控制的工具执行方法时,我们建议使用ToolCallingManager以管理工具调用作。这样,您就可以受益于 Spring AI 为工具执行提供的内置支持。但是,没有什么能阻止您实现自己的工具执行逻辑。

接下来的示例展示了用户控制的工具执行方法的最小实现,并结合了ChatMemory应用程序接口:spring-doc.cadn.net.cn

ToolCallingManager toolCallingManager = DefaultToolCallingManager.builder().build();
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
String conversationId = UUID.randomUUID().toString();

ChatOptions chatOptions = ToolCallingChatOptions.builder()
    .toolCallbacks(ToolCallbacks.from(new MathTools()))
    .internalToolExecutionEnabled(false)
    .build();
Prompt prompt = new Prompt(
        List.of(new SystemMessage("You are a helpful assistant."), new UserMessage("What is 6 * 8?")),
        chatOptions);
chatMemory.add(conversationId, prompt.getInstructions());

Prompt promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions);
ChatResponse chatResponse = chatModel.call(promptWithMemory);
chatMemory.add(conversationId, chatResponse.getResult().getOutput());

while (chatResponse.hasToolCalls()) {
    ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(promptWithMemory,
            chatResponse);
    chatMemory.add(conversationId, toolExecutionResult.conversationHistory()
        .get(toolExecutionResult.conversationHistory().size() - 1));
    promptWithMemory = new Prompt(chatMemory.get(conversationId), chatOptions);
    chatResponse = chatModel.call(promptWithMemory);
    chatMemory.add(conversationId, chatResponse.getResult().getOutput());
}

UserMessage newUserMessage = new UserMessage("What did I ask you earlier?");
chatMemory.add(conversationId, newUserMessage);

ChatResponse newResponse = chatModel.call(new Prompt(chatMemory.get(conversationId)));

异常处理

当工具调用失败时,异常将传播为ToolExecutionException可以捕获它来处理错误。 一个ToolExecutionExceptionProcessor可用于处理ToolExecutionException有两个结果:生成要发送回 AI 模型的错误消息或抛出要由调用者处理的异常。spring-doc.cadn.net.cn

@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,DefaultToolExecutionExceptionProcessorToolExecutionExceptionProcessor接口。 默认情况下,错误消息RuntimeException被发送回模型,同时检查异常和错误(例如IOException,OutOfMemoryError) 总是被抛出。 这DefaultToolExecutionExceptionProcessor构造函数允许您将alwaysThrow属性设置为truefalse. 如果true,则将抛出异常,而不是将错误消息发送回模型。spring-doc.cadn.net.cn

您可以使用`spring.ai.tools.throw-exception-on-error属性来控制DefaultToolExecutionExceptionProcessor豆:spring-doc.cadn.net.cn

属性 描述 默认值

spring.ai.tools.throw-exception-on-errorspring-doc.cadn.net.cn

如果true,则工具调用错误将作为异常引发,供调用方处理。如果false,错误被转换为消息并发送回 AI 模型,使其能够处理和响应错误。spring-doc.cadn.net.cn

falsespring-doc.cadn.net.cn

@Bean
ToolExecutionExceptionProcessor toolExecutionExceptionProcessor() {
    return new DefaultToolExecutionExceptionProcessor(true);
}
如果您定义了自己的ToolCallback实现时,请确保抛出一个ToolExecutionException当工具执行逻辑的一部分发生错误时,在call()方法。

ToolExecutionExceptionProcessor默认情况下在内部使用ToolCallingManager (DefaultToolCallingManager) 来处理工具执行期间的异常。有关工具执行生命周期的更多详细信息,请参阅工具执行spring-doc.cadn.net.cn

工具分辨率

将工具传递给模型的主要方法是提供ToolCallback(s) 当调用ChatClientChatModel, 使用方法作为工具和函数作为工具中描述的策略之一。spring-doc.cadn.net.cn

但是,Spring AI 还支持在运行时使用ToolCallbackResolver接口。spring-doc.cadn.net.cn

public interface ToolCallbackResolver {

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

}

使用此方法时:spring-doc.cadn.net.cn

  • 在客户端,您可以向ChatClientChatModel而不是ToolCallback(s)。spring-doc.cadn.net.cn

  • 在服务器端,一个ToolCallbackResolver实现负责将工具名称解析为对应的ToolCallback实例。spring-doc.cadn.net.cn

默认情况下,Spring AI 依赖于DelegatingToolCallbackResolver将工具解析委托给ToolCallbackResolver实例:spring-doc.cadn.net.cn

  • SpringBeanToolCallbackResolver解析类型Function,Supplier,ConsumerBiFunction.看动态规格:@Bean了解更多详情。spring-doc.cadn.net.cn

  • StaticToolCallbackResolver从静态列表中解析工具ToolCallback实例。使用 Spring Boot Autoconfiguration 时,此解析器会自动配置所有类型的 beanToolCallback在应用程序上下文中定义。spring-doc.cadn.net.cn

如果您依赖于 Spring Boot Autoconfiguration,则可以通过提供自定义ToolCallbackResolver豆。spring-doc.cadn.net.cn

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

ToolCallbackResolverToolCallingManager在运行时动态解析工具,支持框架控制的工具执行用户控制的工具执行spring-doc.cadn.net.cn

可观察性

工具调用包括对 spring.ai.tool 观察的可观察性支持,这些观察可测量测量时间并传播跟踪信息。请参阅工具调用可观测性spring-doc.cadn.net.cn

或者,Spring AI 可以将工具调用参数和结果导出为 span 属性,默认情况下出于敏感性原因禁用。详细信息:工具调用参数和结果数据spring-doc.cadn.net.cn

Logging

工具调用功能的所有主要作都记录在DEBUG水平。您可以通过将日志级别设置为DEBUG对于org.springframework.ai包。spring-doc.cadn.net.cn