函数回调
本页面描述了旧版本的 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
实现。这对于定义函数回调特别有用,你可以在运行时以编程方式将这些回调注册到你的 ChatClient
或 ChatModel
模型调用中。
使用 FunctionCallback.builder()
方法创建一个新的构建器实例,并通过链式调用配置方法来设置函数名称、描述、输入类型和其他属性。FunctionCallback.Builder
是一个具有以下结构的层次结构:
函数调用方法
将任何 java.util.function.Function
、BiFunction
、Supplier
或 Consumer
转换为可以由 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();
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();
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();
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();
泛型输入类型
使用 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();
方法调用方式
支持通过反射进行方法调用,同时自动处理 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();
对象实例方法调用
你可以通过提供方法名、参数类型和目标对象实例来引用类中的实例方法。
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()
,你可以设置一个与方法名不同的自定义函数名称。
常见配置
你可以使用以下几种常见配置来自定义函数回调。
模式类型
该框架支持不同的模式类型,用于生成输入参数的模式:
-
JSON Schema(默认)
-
OpenAPI Schema(用于 Vertex AI 兼容性)
FunctionCallback.builder()
.schemaType(SchemaType.OPEN_API_SCHEMA)
// ... other configuration
.build();
自定义响应处理
你可以提供一个自定义的响应转换器,以便在将函数响应发送回 AI 模型之前对其进行格式化。大多数 AI 模型期望接收文本响应,因此你需要负责将函数响应转换为文本格式。默认情况下,响应会被转换为字符串。
许多模型能够很好地处理 JSON 响应,因此你可以返回一个 JSON 字符串。
FunctionCallback.builder()
.responseConverter(response ->
customResponseFormatter.format(response))
// ... other configuration
.build();
自定义对象映射
Spring AI 使用 ObjectMapper
进行 JSON 的序列化和反序列化。你可以提供一个自定义的 ObjectMapper
来处理自定义的对象映射:
FunctionCallback.builder()
.objectMapper(customObjectMapper)
// ... other configuration
.build();
最佳实践
描述性名称和描述
-
提供唯一的函数名称
-
编写全面的描述,以帮助模型理解何时调用该函数
输入类型与模式
-
对于函数调用方法,明确地定义输入类型,并使用
ParameterizedTypeReference
来处理泛型类型。 -
当自动生成的 schema 无法满足需求时,考虑使用自定义 schema。
错误处理
-
在函数实现中实现适当的错误处理,并在响应中返回错误信息
-
在需要时,可以使用
ToolContext
来提供额外的错误上下文
工具上下文使用
-
当需要额外的状态或上下文时,而这些状态或上下文是由用户提供且不属于 AI 模型生成的函数输入部分时,请使用 ToolContext。
-
使用
BiFunction<I, ToolContext, O>
在函数调用方法中访问 ToolContext,并在方法调用方法中添加ToolContext
参数。
关于模式生成的注意事项
-
该框架能够自动从 Java 类型生成 JSON 模式
-
对于函数调用,模式是基于需要设置输入类型的函数的输入类型生成的,使用
inputType(TYPE)
进行设置。对于泛型类型,请使用ParameterizedTypeReference
-
生成的模式会遵循模型类上的 Jackson 注解
-
您可以通过使用
inputTypeSchema()
提供自定义模式来绕过自动生成
常见陷阱与避免方法
缺乏描述
-
始终提供明确的描述,而不是依赖自动生成的描述
-
清晰的描述可以提高模型选择函数的准确性
模式不匹配
-
确保输入类型与函数的输入参数类型匹配。
-
对于泛型类型,使用
ParameterizedTypeReference
。