跳到主要内容

函数回调

DeepSeek V3 中英对照 FunctionCallback API (Deprecated) FunctionCallback

注意

本页面描述了旧版本的 Function Calling API,该版本已被弃用,并将在下一个版本中移除。当前版本可在 Tool Calling 找到。更多信息请参阅 迁移指南

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

FunctionCallback 接口定义了以下几个关键方法:

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

  • getDescription(): 提供一个描述,帮助模型决定何时调用该函数

  • getInputTypeSchema(): 定义函数输入参数的 JSON 模式

  • call(String functionArguments): 处理实际的函数执行

  • call(String functionArguments, ToolContext toolContext): 支持额外 工具上下文 的扩展版本

建造者模式

Spring AI 提供了一个流畅的构建器 API,用于创建 FunctionCallback 实现。这对于定义函数回调特别有用,你可以在运行时以编程方式将这些回调注册到你的 ChatClientChatModel 模型调用中。

使用 FunctionCallback.builder() 方法创建一个新的构建器实例,并通过链式调用配置方法来设置函数名称、描述、输入类型和其他属性。FunctionCallback.Builder 是一个具有以下结构的层次结构:

  • FunctionCallback.Builder - 用于配置共享属性的根构建器接口。

  • FunctionInvokingSpec - 函数调用的构建器接口。

  • MethodInvokingSpec - 方法调用的构建器接口。

函数调用方法

将任何 java.util.function.FunctionBiFunctionSupplierConsumer 转换为可以由 AI 模型调用的 FunctionCallback

备注

你可以使用 lambda 表达式或方法引用来定义函数逻辑,但必须使用 inputType(TYPE) 提供函数的输入类型。

Function<I, O>

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

BiFunction<I, ToolContext, O>

使用带有输入类型 <I> 和额外 ToolContext 参数的函数:

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

Supplier<O>

使用 java.util.Supplier<O>java.util.function.Function<Void, O> 来定义不需要任何输入的函数:

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

Consumer<I>

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

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();
java

泛型输入类型

使用 ParameterizedTypeReference 来定义具有泛型输入类型的函数:

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();
java

方法调用方式

支持通过反射进行方法调用,同时自动处理 JSON 模式生成和参数转换。这对于将 Java 方法集成为 AI 模型交互中的可调用函数特别有用。

方法调用实现了 FunctionCallback 接口,并提供:

  • 自动为方法参数生成 JSON schema

  • 支持静态方法和实例方法

  • 任意数量的参数(包括无参数)和返回值(包括 void)

  • 任意参数/返回类型(基本类型、对象、集合)

  • ToolContext 参数的特殊处理

静态方法调用

你可以通过提供方法名、参数类型和目标类来引用类中的静态方法。

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();
java

对象实例方法调用

你可以通过提供方法名、参数类型和目标对象实例来引用类中的实例方法。

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();
java
提示

可选地,使用 .name(),你可以设置一个与方法名不同的自定义函数名称。

常见配置

你可以使用以下几种常见配置来自定义函数回调。

模式类型

该框架支持不同的模式类型,用于生成输入参数的模式:

  • JSON Schema(默认)

  • OpenAPI Schema(用于 Vertex AI 兼容性)

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

自定义响应处理

你可以提供一个自定义的响应转换器,以便在将函数响应发送回 AI 模型之前对其进行格式化。大多数 AI 模型期望接收文本响应,因此你需要负责将函数响应转换为文本格式。默认情况下,响应会被转换为字符串。

提示

许多模型能够很好地处理 JSON 响应,因此你可以返回一个 JSON 字符串。

FunctionCallback.builder()
.responseConverter(response ->
customResponseFormatter.format(response))
// ... other configuration
.build();
java

自定义对象映射

Spring AI 使用 ObjectMapper 进行 JSON 的序列化和反序列化。你可以提供一个自定义的 ObjectMapper 来处理自定义的对象映射:

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

最佳实践

描述性名称和描述

  • 提供唯一的函数名称

  • 编写全面的描述,以帮助模型理解何时调用该函数

输入类型与模式

  • 对于函数调用方法,明确地定义输入类型,并使用 ParameterizedTypeReference 来处理泛型类型。

  • 当自动生成的 schema 无法满足需求时,考虑使用自定义 schema。

错误处理

  • 在函数实现中实现适当的错误处理,并在响应中返回错误信息

  • 在需要时,可以使用 ToolContext 来提供额外的错误上下文

工具上下文使用

  • 当需要额外的状态或上下文时,而这些状态或上下文是由用户提供且不属于 AI 模型生成的函数输入部分时,请使用 ToolContext

  • 使用 BiFunction<I, ToolContext, O> 在函数调用方法中访问 ToolContext,并在方法调用方法中添加 ToolContext 参数。

关于模式生成的注意事项

  • 该框架能够自动从 Java 类型生成 JSON 模式

  • 对于函数调用,模式是基于需要设置输入类型的函数的输入类型生成的,使用 inputType(TYPE) 进行设置。对于泛型类型,请使用 ParameterizedTypeReference

  • 生成的模式会遵循模型类上的 Jackson 注解

  • 您可以通过使用 inputTypeSchema() 提供自定义模式来绕过自动生成

常见陷阱与避免方法

缺乏描述

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

  • 清晰的描述可以提高模型选择函数的准确性

模式不匹配

  • 确保输入类型与函数的输入参数类型匹配。

  • 对于泛型类型,使用 ParameterizedTypeReference