Spirng AI 工具调用:方法工具

方法工具顾名思义就是将类的方法作为 AI 大模型可以调用的工具(此调用并非真实的调用,而是 AI 可以知道你提供了哪些工具,可以根据需要选择合适的工具,并且提供参数,由 Spring AI 根据 AI 响应的内容去调用)。但是 AI 大模型怎么知道那些方法是工具呢?为此,Spring AI 为方法转工具(即 ToolCallback)提供两种内置方式:

  • 声明式:通过 @Tool 注解实现。

  • 编程式:通过底层的 MethodToolCallback 实现。

声明式:@Tool 注解

声明式方式非常简单,你只需为方法添加 @Tool 注解,即可将其转换为工具。例如:

public class DateTimeTools {

    @Tool(description = "获取用户所在时区的当前日期和时间")
    public String getCurrentDateTime() {
        return LocalDateTime.now().atZone(
            LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

上述示例将 getCurrentDateTime() 转换成了一个工具,该工具用来获取用户所在时区的当前日期和时间,其中 description 属性用来描述工具的作用。注意,描述一定要准确清晰,AI 大模型才能更精确的识别出要调用的工具。

@Tool 注解的定义

@Tool 注解用于将普通方法标记为 Spring AI 可调用的工具。定义如下:

package org.springframework.ai.tool.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.ai.tool.execution.DefaultToolCallResultConverter;
import org.springframework.ai.tool.execution.ToolCallResultConverter;

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Tool {

    /**
     * 工具的名称,用于在AI模型中标识该工具
     * 默认为空字符串,此时通常会使用方法名作为工具名称
     *
     * @return 工具名称
     */
    String name() default "";

    /**
     * 工具的描述信息,用于向AI模型说明该工具的功能和用途
     * 帮助AI模型判断何时需要调用该工具,以及如何正确使用
     *
     * @return 工具描述
     */
    String description() default "";

    /**
     * 指定工具调用结果是否直接返回给用户,而不经过AI模型二次处理
     * 默认为false,表示结果需要返回给AI模型,由模型生成最终响应
     * 如果设为true,则工具执行结果将直接作为对用户的回应
     *
     * @return 是否直接返回结果
     */
    boolean returnDirect() default false;

    /**
     * 工具调用结果的转换器类型,用于将方法返回值转换为AI模型可处理的格式
     * 默认为 DefaultToolCallResultConverter,提供基础的结果转换功能
     * 可自定义实现 ToolCallResultConverter 接口以处理特殊格式转换需求
     *
     * @return 结果转换器类
     */
    Class<? extends ToolCallResultConverter> resultConverter() default DefaultToolCallResultConverter.class;
}

基于上述定义,@Tool 注解允许你配置以下关键工具信息:

  • name:工具名称。如果不指定,默认使用方法名称。AI 模型通过此名称识别并调用工具,因此不允许在同一类中存在同名工具,及不要进行方法重载。注意,模型处理单个聊天请求时,所有可用工具的名称必须保持全局唯一。

  • description:工具描述,用于指导模型判断何时及如何调用该工具。如果未指定,默认使用方法名称作为工具描述。强烈建议提供详细描述信息,因为这对模型理解工具的用途和使用方式非常重要。如果描述不充分,可能导致模型本应该调用工具时而未调用,或错误调用工具。

  • returnDirect:控制工具结果直接返回客户端(true)还是传回模型(false)。

  • resultConverter:用于将工具调用结果转换为字符串对象的 ToolCallResultConverter 实现,该字符串将返回至 AI 模型。

📢注意,被 @Tool 注解修饰的方法既可以是静态方法也可以是实例方法,并且可具有任意可见性(public、protected、package-private 或 private)。包含该方法的类既可以是顶级类也可以是嵌套类,同样支持任意可见性(只要在计划实例化的位置可访问即可)。

Spring AI 为使用 @Tool 注解的方法提供内置的 AOT(提前编译)支持,前提是包含这些方法的类必须是 Spring Bean(例如使用 @Component 注解)。否则,你需要为 GraalVM 编译器提供必要的配置,例如通过使用 @RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_METHODS) 注解标记该类。

你还可以为方法(即工具)定义任意数量的参数(包括无参数),支持大多数类型(基本类型、POJO、枚举、List、数组、Map 等)。同样,方法可以返回大多数类型,包括 void。若方法有返回值,则返回类型必须是可序列化类型,因为结果将被序列化并发送回模型。

Spring AI 将自动为 @Tool 注解方法的输入参数生成 JSON Schema。该 Schema 供模型理解如何调用工具及准备工具请求。你可使用 @ToolParam 注解为输入参数提供额外信息(如描述、是否必需等),默认情况下所有输入参数均为必填参数。例如:

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

public class DateTimeTools {

    @Tool(description = "为给定时间设置用户闹钟")
    public void setAlarm(@ToolParam(description = "ISO-8601格式的时间") String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("闹钟设置为 " + alarmTime);
    }

}

@ToolParam 注解允许你配置工具参数的关键信息,描述工具方法参数元信息。配合 @Tool 注解使用,为 AI 模型提供工具参数的约束和说明,帮助模型正确传递参数。

@ToolParam 注解定义如下:

package org.springframework.ai.tool.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ToolParam {

    /**
     * 指定该参数是否为必填项
     * 默认为true,表示参数必须提供,否则工具调用可能失败
     * 若设为false,AI模型可根据实际情况选择是否传递该参数
     *
     * @return 参数是否必填
     */
    boolean required() default true;

    /**
     * 参数的描述信息,用于向AI模型说明该参数的含义、取值范围或格式要求
     * 帮助AI模型理解如何正确填充参数值,提高工具调用的准确性
     *
     * @return 参数描述文本
     */
    String description() default "";
}

注意,如果参数标注了 @Nullable 注解,则该参数将被视为可选参数,除非通过 @ToolParam 显式标记为必填参数。除 @ToolParam 注解外,你还可使用 Swagger 的 @Schema 或 Jackson 的 @JsonProperty 注解。

为 ChatClient 添加工具

当使用声明式配置方案时,你可以在调用 ChatClient 时通过 tools() 方法传入工具类实例。此类工具仅在添加它们的特定聊天请求中可用。例如:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        return ChatClient.create(chatModel)
                .prompt("明天是星期几?")
                // 设置可用的工具给大模型,让大模型知道有哪些工具可以使用
                .tools(new DateTimeTools())
                .call().content();
    }

}

在底层实现中,ChatClient 将根据工具类实例中每个被 @Tool 注解修饰的方法来生成对应的 ToolCallback,并将其传递给模型。如下图:

Spirng AI 工具调用:方法工具

若你希望自己生成 ToolCallback,可使用 ToolCallbacks 工具类。如下:

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

为 ChatClient 添加默认工具

当使用声明式配置方案时,你可以通过向 ChatClient.Builder 的 defaultTools() 方法传入工具类实例来添加默认工具。若同时提供默认工具和运行时工具(通过 tools() 方法传入的工具 ),运行时工具将完全覆盖默认工具。

注意:默认工具在所有基于同一 ChatClient.Builder 构建的 ChatClient 实例执行的聊天请求间共享。此类工具适用于跨聊天请求的通用功能,但若使用不当可能存在风险 —— 导致工具在不该出现的场景中可用。

简单示例:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        ChatClient chatClient = ChatClient.builder(chatModel)
                .defaultTools(new DateTimeTools())
                .build();

        return chatClient.prompt("明天是星期几?")
                .call().content();
    }

}

为 ChatModel 添加工具

当使用声明式配置方案时,你可以通过调用 ChatModel 时使用的 ToolCallingChatOptions 中的 toolCallbacks() 方法传入工具类实例。此类工具仅在添加它们的特定聊天请求中可用。例如:

class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // 使用 ToolCallbacks 工具类将对象中使用 @Tool 的方法转换为 TooCallback
        ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
        ChatOptions chatOptions = ToolCallingChatOptions.builder()
                .toolCallbacks(dateTimeTools)
                .build();
        Prompt prompt = new Prompt("明天是星期几?", chatOptions);
        return chatModel.call(prompt).getResult().getOutput().getText();
    }

}

为 ChatModel 添加默认工具

当使用声明式配置方案时,你可以在构建 ChatModel 时通过 ToolCallingChatOptions 实例的 toolCallbacks() 方法传入工具类实例来添加默认工具。若同时提供默认工具和运行时工具,运行时工具将完全覆盖默认工具。

注意:默认工具在该 ChatModel 实例执行的所有聊天请求间共享。此类工具适用于跨请求的通用功能,但需谨慎使用 — 否则可能导致工具在不该被调用的场景下可用。

@RestController
class MyController {

    @Value("${spring.ai.openai.base-url}")
    private String baseUrl;

    @Value("${spring.ai.openai.api-key}")
    private String apiKey;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // 使用 ToolCallbacks 工具类将对象中使用 @Tool 的方法转换为 TooCallback
        ToolCallback[] dateTimeTools = ToolCallbacks.from(new DateTimeTools());
        ChatModel chatModel = OpenAiChatModel.builder()
                .openAiApi(OpenAiApi.builder().baseUrl(baseUrl).apiKey(apiKey).build())
                // 看这里,使用 OpenAiChatOptions 的 toolCallbacks() 方法去设置默认的 ToolCallback
                .defaultOptions(OpenAiChatOptions.builder()
                        .model(OpenAiApi.ChatModel.GPT_4_TURBO) // 模型名
                        .toolCallbacks(dateTimeTools)
                        .build()
                )
                .build();
        return chatModel.call("明天是星期几?");
    }

}

  

编程式:MethodToolCallback

除了上述的 @Tool 注解外,你还可以通过编程的方式去构建 MethodToolCallback,将方法转换为工具。下面是一个普通的类:

public class DateTimeTools {

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

}

要手动构建 MethodToolCallback,需要用到如下 Builder:

MethodToolCallback.Builder

MethodToolCallback.Builder 是用于构建 MethodToolCallback 实例的建造类。MethodToolCallback 用于定义当 AI 模型需要调用特定方法工具时的回调逻辑,包括方法执行、结果处理等,而 Builder 则通过链式 API 简化了这一对象的创建过程。

MethodToolCallback.Builder 定义如下:

Spirng AI 工具调用:方法工具

字段说明:

  • toolDefinition:定义工具名称、描述及输入模式的 ToolDefinition 实例(必需项),可通过 ToolDefinition.Builder 类构建。

  • toolMetadata:定义额外设置的 ToolMetadata 实例(如是否将结果直接返回客户端、使用的结果转换器等),可通过 ToolMetadata.Builder 类构建。

  • toolMethod:表示工具方法的 Method 实例(必需项)。

  • toolObject:包含工具方法的对象实例(若方法为静态方法则可省略此参数)。

  • toolCallResultConverter:用于将工具调用结果转换为 String 对象并返回 AI 模型的 ToolCallResultConverter 实例(未配置时默认使用 DefaultToolCallResultConverter)。

简单实例:

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
MethodToolCallback toolCallback = MethodToolCallback.builder()
        // 工具定义
        .toolDefinition(ToolDefinition.builder().build())
        // 工具元信息
        .toolMetadata(ToolMetadata.from(method))
        // 工具方法的 Method 实例
        .toolMethod(method)
        // 包含工具的对象
        .toolObject(new DateTimeTools())
        // 工具调用结果转换器
        .toolCallResultConverter(new DefaultToolCallResultConverter())
        .build();

ToolDefinition.Builder

ToolDefinition.Builder 是构建 ToolDefinition 实例的核心建造类,用于定义 AI 模型可调用的工具元数据(Metadata)。ToolDefinition 是工具调用(Tool Calling)机制的基础,它向 AI 模型描述工具的功能、参数格式、调用方式等信息,而 Builder 则通过链式 API 简化了这一对象的创建过程,让开发者能更灵活地配置工具属性。

ToolDefinition.Builder 的定义如下:

Spirng AI 工具调用:方法工具

字段说明:

  • name:工具名称。如果未指定,默认使用方法名称。AI 模型通过此名称识别调用工具,因此不允许在同一类中存在同名工具。模型处理单个聊天请求时,所有可用工具的名称必须保持全局唯一。

  • description:工具描述,用于帮助模型理解何时及如何调用该工具。如果未提供,将使用方法名称作为工具描述。但强烈建议提供详细描述,因为这对模型理解工具的用途及使用方法至关重要。如果描述不充分,可能导致模型在该调用工具时未调用,或错误调用工具。

  • inputSchema:工具输入参数的 JSON Schema(一种用于描述和验证 JSON 数据结构的规范。它定义了 JSON 数据应遵循的格式、类型、约束等规则,相当于 JSON 数据的 "蓝图" 或 "契约",能够确保不同系统之间交换的 JSON 数据符合预期结构)。如果未提供,将根据方法参数自动生成。你可使用 @ToolParam 注解提供输入参数的额外信息(如描述、是否必需等),默认情况下所有输入参数均为必需参数。

简单示例:

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
String jsonSchema = JsonSchemaGenerator.generateForMethodInput(method);
MethodToolCallback toolCallback = MethodToolCallback.builder()
        // 工具定义
        .toolDefinition(ToolDefinition.builder()
                .name("getCurrentDateTime")
                .description("获取用户所在时区的当前日期和时间")
                .inputSchema("""
                        {
                          "$schema" : "https://json-schema.org/draft/2020-12/schema",
                          "type" : "object",
                          "properties" : { },
                          "required" : [ ],
                          "additionalProperties" : false
                        }
                        """)
                .build())
        // 工具元信息
        .toolMetadata(ToolMetadata.from(method))
        // 工具方法的 Method 实例
        .toolMethod(method)
        // 包含工具的对象
        .toolObject(new DateTimeTools())
        // 工具调用结果转换器
        .toolCallResultConverter(new DefaultToolCallResultConverter())
        .build();

注意,如果你不想自己手动编写 inputSchema,可以通过 JsonSchemaGenerator 帮你自动生成,如下:

Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
String inputSchema = JsonSchemaGenerator.generateForMethodInput(method);
//....

ToolMetadata.Builder

ToolMetadata.Builder 是用于构建 ToolMetadata 实例的建造者类,主要用于定义工具的元数据信息。ToolMetadata 包含了工具的核心描述信息,帮助 AI 模型理解工具的用途、参数要求和调用方式,是工具调用(Tool Calling)机制中连接 AI 模型与实际工具逻辑的重要桥梁。

ToolMetadata.Builder 定义如下:

Spirng AI 工具调用:方法工具

字段说明:

  • returnDirect:控制是否将工具结果直接返回客户端(true)还是传回模型(false)。

下面是一个通过编程方式定义 MethodToolCallback 的完整例子:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // ReflectionUtils 是 Spring 提供的工具方法,获取指定类中某个方法的 Method 实例
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        // 手动定义 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                // 工具定义
                .toolDefinition(ToolDefinition.builder()
                        .name(method.getName())
                        .description("获取用户所在时区的当前日期和时间")
                        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                        .build())
                // 工具对应的方法实例
                .toolMethod(method)
                // 工具所属对象
                .toolObject(new DateTimeTools())
                .build();

        Prompt prompt = new Prompt("明天是星期几?", ToolCallingChatOptions.builder()
                .toolCallbacks(toolCallback)
                .build());
        return chatModel.call(prompt).getResult().getOutput().getText();
    }

}

注意,工具方法既可以是静态方法也可以是实例方法,并且可具有任意可见性(public、protected、package-private 或 private)。包含该方法的类既可以是顶级类也可以是嵌套类,同样支持任意可见性(只要在计划实例化的位置可访问即可)。

Spring AI 为工具方法提供内置的 AOT(提前编译)支持,前提是包含这些方法的类必须是 Spring Bean(例如使用 @Component 注解)。否则,你需要为 GraalVM 编译器提供必要的配置,例如通过使用 @RegisterReflection(memberCategories = MemberCategory.INVOKE_DECLARED_METHODS) 注解标记该类。

你还可以为工具方法定义任意数量的参数(包括无参数),支持大多数类型(基本类型、POJO、枚举、List、数组、Map 等)。同样,方法可以返回大多数类型,包括 void。若方法有返回值,则返回类型必须是可序列化类型,因为结果将被序列化并发送回模型。

如果方法为静态方法,则可省略 toolObject() 方法,例如:

public class DateTimeTools {

    // 静态方法
    public static String getCurrentDateTime() {
        return LocalDateTime.now().atZone(
            LocaleContextHolder.getTimeZone().toZoneId()).toString();
    }

}

使用 MethodToolCallback 手动转换工具方法:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // ReflectionUtils 是 Spring 提供的工具方法,获取指定类中某个方法的 Method 实例
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        // 手动定义 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                // 工具定义
                .toolDefinition(ToolDefinition.builder()
                        .name(method.getName())
                        .description("获取用户所在时区的当前日期和时间")
                        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                        .build())
                // 工具对应的方法实例
                .toolMethod(method)
                // .toolObject(new DateTimeTools()) // 不需要了
                .build();

        Prompt prompt = new Prompt("明天是星期几?", ToolCallingChatOptions.builder()
                .toolCallbacks(toolCallback)
                .build());
        return chatModel.call(prompt).getResult().getOutput().getText();
    }

}

注意,记得使用 JsonSchemaGenerator.generateForMethodInput(method) 生成方法参数的 JSON Schema,并通过 inputSchema() 设置,否则将抛出如下错误信息:

java.lang.IllegalArgumentException: inputSchema cannot be null or empty
	at org.springframework.util.Assert.hasText(Assert.java:253) ~[spring-core-6.2.7.jar:6.2.7]
	at org.springframework.ai.tool.definition.DefaultToolDefinition.<init>(DefaultToolDefinition.java:34) ~[spring-ai-model-1.0.0.jar:1.0.0]
	at org.springframework.ai.tool.definition.DefaultToolDefinition$Builder.build(DefaultToolDefinition.java:72) ~[spring-ai-model-1.0.0.jar:1.0.0]

你可使用 @ToolParam 注解为输入参数提供额外信息(如描述、是否必需等),默认情况下所有输入参数均为必需参数。例如:

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

class DateTimeTools {

    void setAlarm(@ToolParam(description = "ISO-8601格式的时间") String time) {
        LocalDateTime alarmTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("闹钟设置为 " + alarmTime);
    }

}

@ToolParam 注解允许你配置工具参数的以下关键信息:

  • description:参数描述,用于帮助模型更准确地理解如何使用该参数。例如:参数格式要求、允许取值范围等。

  • required:指定参数是否为必需项(默认值:true,即所有参数默认必需)。

如果参数标注了 @Nullable 注解,则该参数将被视为可选参数,除非通过 @ToolParam 显式标记为必需参数。除 @ToolParam 注解外,你还可使用 Swagger 的 @Schema 或 Jackson 的 @JsonProperty 注解。

为 ChatClient 与 ChatModel 添加工具

当使用编程式配置方案时,你可以通过 ChatClient 的 tools() 方法传入 MethodToolCallback 实例。该工具仅在添加它的特定聊天请求中可用。例如:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // ReflectionUtils 是 Spring 提供的工具方法,获取指定类中某个方法的 Method 实例
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        // 手动定义 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                // 工具定义
                .toolDefinition(ToolDefinition.builder()
                        .name(method.getName())
                        .description("获取用户所在时区的当前日期和时间")
                        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                        .build())
                // 工具对应的方法实例
                .toolMethod(method)
                // 工具所属对象
                .toolObject(new DateTimeTools())
                .build();

        return ChatClient.create(chatModel)
                .prompt("明天是星期几?")
                .toolCallbacks(toolCallback) // 将 ToolCallback 设置给 ChatClient
                .call()
                .content();
    }

}

为 ChatClient 添加默认工具

当使用编程式配置方案时,你可以通过向 ChatClient.Builder 的 defaultTools() 方法传入 MethodToolCallback 实例来添加默认工具。若同时提供默认工具和运行时工具,运行时工具将完全覆盖默认工具。

默认工具在所有基于同一 ChatClient.Builder 构建的 ChatClient 实例执行的聊天请求间共享。此类工具适用于跨聊天请求的通用功能,但若使用不当可能存在风险 — 导致工具在不该出现的场景中可用。

例如:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // ReflectionUtils 是 Spring 提供的工具方法,获取指定类中某个方法的 Method 实例
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        // 手动定义 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                // 工具定义
                .toolDefinition(ToolDefinition.builder()
                        .name(method.getName())
                        .description("获取用户所在时区的当前日期和时间")
                        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                        .build())
                // 工具对应的方法实例
                .toolMethod(method)
                // 工具所属对象
                .toolObject(new DateTimeTools())
                .build();

        ChatClient chatClient = ChatClient.builder(chatModel)
                .defaultToolCallbacks(toolCallback)
                .build();
        return chatClient.prompt("明天是星期几?").call().content();
    }

}

为 ChatModel 添加工具

当使用编程式配置方案时,你可以通过调用 ChatModel 时使用的 ToolCallingChatOptions 中的 toolCallbacks() 方法传入 MethodToolCallback 实例。该工具仅在添加它的特定聊天请求中可用。

例如:

@RestController
class MyController {

    @Autowired
    private ChatModel chatModel;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // ReflectionUtils 是 Spring 提供的工具方法,获取指定类中某个方法的 Method 实例
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        // 手动定义 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                // 工具定义
                .toolDefinition(ToolDefinition.builder()
                        .name(method.getName())
                        .description("获取用户所在时区的当前日期和时间")
                        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                        .build())
                // 工具对应的方法实例
                .toolMethod(method)
                // 工具所属对象
                .toolObject(new DateTimeTools())
                .build();

        ChatOptions chatOptions = ToolCallingChatOptions.builder()
                .toolCallbacks(toolCallback)
                .build();
        Prompt prompt = new Prompt("明天是星期几?", chatOptions);
        return chatModel.call(prompt).getResult().getOutput().getText();
    }

}

为 ChatModel 添加默认工具

使用编程式配置方案时,你可以在构建 ChatModel 时,通过用于创建 ChatModel 的 ToolCallingChatOptions 实例的 toolCallbacks() 方法传入 MethodToolCallback 实例来添加默认工具。若同时提供默认工具和运行时工具,运行时工具将完全覆盖默认工具。

默认工具在该 ChatModel 实例处理的所有聊天请求间共享。此类工具适用于跨聊天请求的通用功能,但若使用不当,可能导致工具在不该出现的场景中被调用。

例如:

@RestController
class MyController {

    @Value("${spring.ai.openai.base-url}")
    private String baseUrl;

    @Value("${spring.ai.openai.api-key}")
    private String apiKey;

    // 模型使用 gpt-4-turbo
    // GPT-4 全面支持工具调用功能,且在处理复杂度、准确性和灵活性上显著优于 GPT-3.5-turbo
    // http://localhost:8080/ai
    @GetMapping(value = "/ai",produces = "text/html; charset=UTF-8")
    public String ai() {
        // ReflectionUtils 是 Spring 提供的工具方法,获取指定类中某个方法的 Method 实例
        Method method = ReflectionUtils.findMethod(DateTimeTools.class, "getCurrentDateTime");
        // 手动定义 ToolCallback
        ToolCallback toolCallback = MethodToolCallback.builder()
                // 工具定义
                .toolDefinition(ToolDefinition.builder()
                        .name(method.getName())
                        .description("获取用户所在时区的当前日期和时间")
                        .inputSchema(JsonSchemaGenerator.generateForMethodInput(method))
                        .build())
                // 工具对应的方法实例
                .toolMethod(method)
                // 工具所属对象
                .toolObject(new DateTimeTools())
                .build();

        ChatModel chatModel = OpenAiChatModel.builder()
                .openAiApi(OpenAiApi.builder().baseUrl(baseUrl).apiKey(apiKey).build())
                // 看这里,使用 OpenAiChatOptions 的 toolCallbacks() 方法去设置默认的 ToolCallback
                .defaultOptions(OpenAiChatOptions.builder()
                        .model(OpenAiApi.ChatModel.GPT_4_TURBO) // 模型名
                        .toolCallbacks(toolCallback)
                        .build()
                )
                .build();
        return chatModel.call("明天是星期几?");
    }

}

方法工具的限制

以下类型目前不支持作为工具方法的参数或返回类型:

  • Optional

  • 异步类型(如 CompletableFuture、Future)

  • 响应式类型 (如 Flow、Mono、Flux)

  • 函数式类型(如 Function、Supplier、Consumer)

注意,函数式类型在基于函数的工具规范方法中受支持。

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号