Spring AI的函数调用(Function Calling),具体怎么实现?
Spring AI 的 函数调用(Function Calling) 功能允许大语言模型(LLM)在生成回答时触发预定义的外部函数,从而实现动态数据获取或业务逻辑操作(如查询数据库、调用 API 等)。以下是其核心机制和实现方式:
1. 函数调用的核心流程
- 定义函数:声明可供模型调用的函数(名称、描述、参数结构)。
- 模型交互:将函数信息与用户输入一起发送给模型,模型决定是否需要调用函数。
- 执行函数:解析模型的函数调用请求,执行对应的业务逻辑。
- 返回结果:将函数执行结果返回给模型,生成最终回答。
2. Spring AI 中的实现步骤
2.1 定义函数接口
使用 @Function
注解标记方法,描述函数的作用和参数:
public class WeatherService {
@Function(
name = "getCurrentWeather",
description = "获取指定城市的当前天气",
inputType = @Function.Parameter(
type = "object",
properties = {
@Function.ParameterProperty(name = "location", type = "string", description = "城市名称")
}
)
)
public String getWeather(@RequestParam String location) {
// 调用真实天气 API(示例)
return "{\"location\": \"" + location + "\", \"temperature\": 25, \"condition\": \"晴\"}";
}
}
2.2 注册函数到模型
在 Spring 配置中将函数注册到 ChatClient
:
@Configuration
public class FunctionConfig {
@Bean
public FunctionCallback weatherFunctionCallback(WeatherService weatherService) {
return new FunctionCallbackWrapper<>(
"getCurrentWeather",
"获取天气信息",
weatherService::getWeather,
new WeatherRequestConverter() // 参数解析器(将模型请求转为Java对象)
);
}
@Bean
public ChatClient chatClient(OpenAiChatClient chatClient, List<FunctionCallback> functionCallbacks) {
// 将函数回调注册到 ChatClient
chatClient.setFunctionCallbacks(functionCallbacks);
return chatClient;
}
}
2.3 触发函数调用
在对话请求中启用函数调用:
@RestController
public class ChatController {
@Autowired
private ChatClient chatClient;
@PostMapping("/chat")
public String chat(@RequestBody String userMessage) {
// 构造包含函数调用选项的请求
ChatOptions options = OpenAiChatOptions.builder()
.withFunctionCallbacks(List.of("getCurrentWeather")) // 允许调用的函数
.build();
// 发送请求
ChatResponse response = chatClient.call(
new UserMessage(userMessage, options)
);
return response.getResult().getOutput().getContent();
}
}
3. 处理函数调用结果
模型可能返回两种结果:
- 直接回答:无需调用函数时,直接生成文本。
- 函数调用请求:模型返回函数名称和参数,需手动执行并回传结果。
手动处理函数调用的示例:
ChatResponse response = chatClient.call(userMessage);
if (response.getMetadata().containsKey("function_call")) {
// 解析函数调用请求
FunctionCallRequest functionCall = parseFunctionCall(response.getMetadata());
// 执行函数
Object result = executeFunction(functionCall.getName(), functionCall.getArguments());
// 将结果回传给模型生成最终回答
ChatResponse finalResponse = chatClient.call(
new UserMessage(
"函数调用结果:" + result,
OpenAiChatOptions.builder().build()
)
);
return finalResponse.getResult().getContent();
}
4. 核心优势
- 动态数据整合:模型可实时获取外部数据(如天气、订单状态)。
- 业务逻辑触发:通过自然语言触发后端操作(如发送邮件、更新数据库)。
- 精准性提升:结合函数调用与 RAG,生成更准确、实时的回答。
5. 典型应用场景
- 客服机器人:查询用户订单、物流信息。
- 智能助手:控制智能家居设备(“打开客厅的灯”)。
- 数据分析:根据用户问题动态生成图表(调用图表生成服务)。
6. 注意事项
- 模型支持:确保使用的模型支持函数调用(如 GPT-3.5-turbo、GPT-4)。
- 参数验证:严格校验模型传入的参数,避免注入攻击。
- 权限控制:限制敏感函数的访问权限(如仅允许管理员触发删除操作)。
7. 完整示例:天气查询
用户输入:"北京现在天气怎么样?"
流程分解:
- 模型识别需要调用
getCurrentWeather
,参数location: 北京
。 - Spring AI 触发
WeatherService.getWeather("北京")
。 - 函数返回 JSON 数据:
{"temperature": 25, "condition": "晴"}
。 - 模型将结果转换为自然语言:
"北京当前天气晴朗,气温 25 摄氏度。"