函数回调

Spring AI 中的接口提供了一种标准化的方式来实现大型语言模型 (LLM) 函数调用功能。它允许开发人员注册自定义函数,当在提示中检测到特定条件或意图时,AI 模型可以调用这些函数。FunctionCallbackspring-doc.cn

该接口定义了几个关键方法:FunctionCallbackspring-doc.cn

  • getName():返回 AI 模型上下文中的唯一函数名称spring-doc.cn

  • getDescription():提供可帮助模型决定何时调用函数的描述spring-doc.cn

  • getInputTypeSchema():定义函数输入参数的 JSON 架构spring-doc.cn

  • call(String functionArguments):处理实际的函数执行spring-doc.cn

  • call(String functionArguments, ToolContext toolContext):支持其他工具上下文的扩展版本spring-doc.cn

Builder 模式

Spring AI 提供了一个 Fluent Builder API 用于创建实现。 这对于定义函数回调特别有用,您可以务实地、动态地使用 or model 调用注册这些回调。FunctionCallbackChatClientChatModelspring-doc.cn

使用该方法创建新的生成器实例,并链接配置方法以设置函数名称、描述、输入类型和其他属性。 这是一个层次结构,具有以下结构:FunctionCallback.builder()FunctionCallback.Builderspring-doc.cn

函数调用方法

将任何 、 或 转换为 AI 模型可调用的 a。java.util.function.FunctionBiFunctionSupplierConsumerFunctionCallbackspring-doc.cn

您可以使用 lambda 表达式或方法引用来定义函数逻辑,但必须使用 .inputType(TYPE)

函数<I, O>

FunctionCallback callback = FunctionCallback.builder()
    .function("processOrder", (Order order) -> processOrderLogic(order))
    .description("Process a new order")
    .inputType(Order.class)
    .build();

BiFunction<I、ToolContext、O>

将 Function 与输入类型 <I> 和其他 ToolContext 参数一起使用:spring-doc.cn

FunctionCallback callback = FunctionCallback.builder()
    .function("processOrder", (Order order, ToolContext context) ->
        processOrderWithContext(order, context))
    .description("Process a new order with context")
    .inputType(Order.class)
    .build();

供应商<O>

使用 or 定义不接受任何输入的函数:java.util.Supplier<O>java.util.function.Function<Void, O>spring-doc.cn

FunctionCallback.builder()
	.function("turnsLight", () -> state.put("Light", "ON"))
    .description("Turns light on in the living room")
    .inputType(Void.class)
	.build();

消费者<I>

使用 or 定义不产生输出的函数:java.util.Consumer<I>java.util.function.Function<I, Void>spring-doc.cn

record LightInfo(String roomName, boolean isOn) {}

FunctionCallback.builder()
	.function("turnsLight", (LightInfo lightInfo) -> {
				logger.info("Turning light to [" + lightInfo.isOn + "] in " + lightInfo.roomName());
			})
    .description("Turns light on/off in a selected room")
    .inputType(LightInfo.class)
	.build();

泛型输入类型

使用 定义具有通用输入类型的函数:ParameterizedTypeReferencespring-doc.cn

record TrainSearchRequest<T>(T data) {}

record TrainSearchSchedule(String from, String to, String date) {}

record TrainSearchScheduleResponse(String from, String to, String date, String trainNumber) {}

FunctionCallback.builder()
	.function("trainSchedule", (TrainSearchRequest<TrainSearchSchedule> request) -> {
        logger.info("Schedule: " + request.data().from() + " to " + request.data().to());
        return new TrainSearchScheduleResponse(request.data().from(), request.  data().to(), "", "123");
    })
    .description("Schedule a train reservation")
    .inputType(new ParameterizedTypeReference<TrainSearchRequest<TrainSearchSchedule>>() {})
	.build();

方法调用方法

通过反射启用方法调用,同时自动处理 JSON 架构生成和参数转换。它对于将 Java 方法作为可调用函数集成到 AI 模型交互中特别有用。spring-doc.cn

调用方法实现接口并提供:FunctionCallbackspring-doc.cn

静态方法调用

您可以通过提供方法名称、参数类型和目标类来引用类中的静态方法。spring-doc.cn

public class WeatherService {
    public static String getWeather(String city, TemperatureUnit unit) {
        return "Temperature in " + city + ": 20" + unit;
    }
}

FunctionCallback callback = FunctionCallback.builder()
    .method("getWeather", String.class, TemperatureUnit.class)
    .description("Get weather information for a city")
    .targetClass(WeatherService.class)
    .build();

对象实例方法调用

您可以通过提供方法名称、参数类型和目标对象实例来引用类中的实例方法。spring-doc.cn

public class DeviceController {
    public void setDeviceState(String deviceId, boolean state, ToolContext context) {
        Map<String, Object> contextData = context.getContext();
        // Implementation using context data
    }
}

DeviceController controller = new DeviceController();

String response = ChatClient.create(chatModel).prompt()
    .user("Turn on the living room lights")
    .functions(FunctionCallback.builder()
        .method("setDeviceState", String.class,boolean.class,ToolContext.class)
        .description("Control device state")
        .targetObject(controller)
        .build())
    .toolContext(Map.of("location", "home"))
    .call()
    .content();
(可选)使用 ,您可以设置与方法名称不同的自定义函数名称。.name()

常见配置

您可以使用几种常见配置来自定义函数回调。spring-doc.cn

架构类型

该框架支持不同的架构类型来为输入参数生成架构:spring-doc.cn

FunctionCallback.builder()
    .schemaType(SchemaType.OPEN_API_SCHEMA)
    // ... other configuration
    .build();

自定义响应处理

您可以提供自定义响应转换器,以便在将函数响应发送回 AI 模型之前设置函数响应的格式。 大多数 AI 模型都需要文本响应,因此您有责任将函数响应转换为文本格式。 默认情况下,响应将转换为 String。spring-doc.cn

许多模型可以很好地处理 JSON 响应,因此您可以返回 JSON 字符串。
FunctionCallback.builder()
    .responseConverter(response ->
        customResponseFormatter.format(response))
    // ... other configuration
    .build();

自定义对象映射

Spring AI 使用 ObjectMapper 进行 JSON 序列化和反序列化。 您可以提供自定义 ObjectMapper 来处理自定义对象映射:spring-doc.cn

FunctionCallback.builder()
    .objectMapper(customObjectMapper)
    // ... other configuration
    .build();

最佳实践

描述性名称和描述

输入类型和架构

  • 对于函数调用方法,显式定义输入类型并用于泛型类型。ParameterizedTypeReferencespring-doc.cn

  • 当自动生成的 schema 不满足要求时,请考虑使用自定义 schema。spring-doc.cn

错误处理

  • 在函数实现中实现正确的错误处理,并在响应中返回错误消息spring-doc.cn

  • 您可以在需要时使用 ToolContext 提供额外的错误上下文spring-doc.cn

工具上下文使用

  • 当需要 User 提供的其他状态或上下文,而不是 AI 模型生成的函数输入的一部分时,请使用 ToolContextspring-doc.cn

  • 用于在函数调用方法中访问 ToolContext,并在方法调用方法中添加参数。BiFunction<I, ToolContext, O>ToolContextspring-doc.cn

Schema 生成说明

  • 框架会自动从 Java 类型生成 JSON 架构spring-doc.cn

  • 对于函数调用,架构是根据需要设置的函数的输入类型生成的。用于泛型类型。inputType(TYPE)ParameterizedTypeReferencespring-doc.cn

  • 生成的架构遵循模型类上的 Jackson 注释spring-doc.cn

  • 您可以通过使用inputTypeSchema()spring-doc.cn

要避免的常见陷阱

缺少描述

  • 始终提供明确的描述,而不是依赖自动生成的描述spring-doc.cn

  • 清晰的描述提高了模型的函数选择准确性spring-doc.cn

架构不匹配

  • 确保输入类型与函数的输入参数类型匹配。spring-doc.cn

  • 用于泛型类型。ParameterizedTypeReferencespring-doc.cn