Spring Boot 无缝集成SpringAI的函数调用模块

这是一个 完整的 Spring AI 函数调用实例,涵盖从函数定义、注册到实际调用的全流程,以「天气查询」功能为例,结合代码详细说明:


1. 环境准备

1.1 添加依赖
xml 复制代码
<!-- Spring AI OpenAI -->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
1.2 配置 OpenAI 密钥
properties 复制代码
# application.properties
spring.ai.openai.api-key=YOUR_API_KEY
spring.ai.openai.chat.options.model=gpt-3.5-turbo-0125

2. 定义函数逻辑

2.1 天气服务接口
java 复制代码
@Service
public class WeatherService {

    // 模拟天气数据存储
    private Map<String, String> weatherData = Map.of(
        "北京", "晴,气温 25°C",
        "上海", "多云,气温 28°C",
        "广州", "阵雨,气温 30°C"
    );

    /**
     * 定义函数:获取当前天气
     * @Function 注解描述函数元数据
     */
    @Function(
        name = "getCurrentWeather",
        description = "获取指定城市的当前天气信息",
        inputType = @Function.Parameter(
            type = "object",
            properties = @Function.ParameterProperty(
                name = "location", 
                type = "string", 
                description = "城市名称,如 '北京'"
            )
        )
    )
    public String getWeather(@RequestParam String location) {
        return weatherData.getOrDefault(location, "暂无该城市天气数据");
    }
}

3. 注册函数到 Spring AI

3.1 函数回调配置
java 复制代码
@Configuration
public class FunctionConfig {

    @Bean
    public FunctionCallback weatherFunction(WeatherService weatherService) {
        return new FunctionCallbackWrapper<>(
            "getCurrentWeather", // 函数名称(必须与 @Function 注解一致)
            "获取天气信息",        // 函数描述(可选)
            weatherService::getWeather, // 函数实现方法引用
            new WeatherRequestConverter() // 参数转换器(见下一步)
        );
    }

    // 参数转换器:将模型传入的 JSON 参数转换为 Java 对象
    private static class WeatherRequestConverter implements Converter<String, String> {
        @Override
        public String convert(String source) {
            // 解析 JSON 参数(示例简化,实际可使用 Jackson)
            return source.replaceAll("\"", "").split(":")[1].trim();
        }
    }
}
3.2 启用函数调用
java 复制代码
@Configuration
public class ChatConfig {

    @Bean
    public ChatClient chatClient(
        OpenAiChatClient chatClient,
        List<FunctionCallback> functionCallbacks
    ) {
        // 将函数回调注册到 ChatClient
        chatClient.setFunctionCallbacks(functionCallbacks);
        return chatClient;
    }
}

4. 实现对话接口

java 复制代码
@RestController
public class ChatController {

    @Autowired
    private ChatClient chatClient;

    @PostMapping("/chat")
    public String chat(@RequestBody String userMessage) {
        // 构造对话请求
        UserMessage message = new UserMessage(
            userMessage,
            OpenAiChatOptions.builder()
                .withFunctionCallbacks(List.of("getCurrentWeather")) // 允许调用的函数
                .build()
        );

        // 发送请求并获取响应
        ChatResponse response = chatClient.call(message);
        
        // 处理可能的函数调用结果
        if (response.getMetadata().containsKey("function_call")) {
            return handleFunctionCall(response);
        }
        
        return response.getResult().getOutput().getContent();
    }

    private String handleFunctionCall(ChatResponse response) {
        // 解析函数调用请求
        String functionName = response.getMetadata().get("function_call.name").toString();
        String functionArgs = response.getMetadata().get("function_call.arguments").toString();

        // 执行函数(此处实际由 Spring AI 自动处理,此处仅为演示)
        String result = "执行函数 " + functionName + " 参数: " + functionArgs;
        
        // 将结果回传模型生成最终回答
        ChatResponse finalResponse = chatClient.call(
            new UserMessage("函数执行结果:" + result)
        );
        return finalResponse.getResult().getOutput().getContent();
    }
}

5. 完整流程测试

测试请求 1:直接提问
bash 复制代码
curl -X POST http://localhost:8080/chat -H "Content-Type: text/plain" -d "北京现在的天气怎么样?"

模型响应流程

  1. 模型识别需要调用 getCurrentWeather(location="北京")
  2. Spring AI 自动触发 WeatherService.getWeather("北京")
  3. 函数返回 "晴,气温 25°C"
  4. 模型生成最终回答:"北京当前的天气是晴,气温 25°C。"
测试请求 2:需要澄清参数
bash 复制代码
curl -X POST http://localhost:8080/chat -d "帮我查一下天气"

模型响应

请问您要查询哪个城市的天气?

6. 关键代码解析

6.1 函数元数据的重要性
  • @Function 注解:提供模型理解函数用途的关键信息,影响模型是否决定调用。
  • 参数描述 :清晰的参数描述(如 location 类型为城市名称)提升模型参数提取准确性。
6.2 函数执行流程
  1. 模型决策:根据用户输入,模型决定是否调用函数。
  2. 参数解析WeatherRequestConverter 将模型传入的 JSON 参数转为 Java 类型。
  3. 自动执行 :Spring AI 自动调用注册的 WeatherService.getWeather() 方法。
  4. 结果回传:函数返回结果自动注入后续对话上下文,模型生成最终回答。

7. 扩展场景

7.1 多函数协同

定义更多函数并注册:

java 复制代码
// 股票查询函数
@Function(name = "getStockPrice", description = "查询股票实时价格")
public String getStockPrice(@RequestParam String symbol) { ... }

// 注册
@Bean
public FunctionCallback stockFunction(StockService stockService) { ... }
7.2 动态函数调用列表

根据用户身份动态启用不同函数:

java 复制代码
UserMessage message = new UserMessage(
    input,
    OpenAiChatOptions.builder()
        .withFunctionCallbacks(getAllowedFunctions(userRole)) // 根据角色返回允许的函数列表
        .build()
);

8. 调试技巧

  1. 查看元数据 :检查 response.getMetadata() 中的 function_call.* 字段。
  2. 日志拦截 :添加 Advisor 记录函数调用请求和响应。
  3. 模拟测试:使用 Mock 替换真实函数实现,验证参数传递逻辑。

将函数调用无缝集成到 Spring Boot 应用以后,即可实现动态数据获取与业务逻辑触发。如需进一步优化(如异步执行函数),可结合 @Async 或消息队列扩展。

相关推荐
珊珊而川11 分钟前
传统机器学习和深度学习
人工智能·深度学习·机器学习
小蒜学长38 分钟前
校园网上店铺的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·美食
摸鱼仙人~1 小时前
An Attention Free Transformer论文参考文献
人工智能·深度学习·transformer
Future_yzx1 小时前
Spring Boot应用中实现基于JWT的登录拦截器,以保证未登录用户无法访问指定的页面
hive·spring boot·后端
你爱写程序吗(新H)1 小时前
基于微信小程序游泳馆管理系统 游泳馆管理系统小程序 (设计与实现)
java·spring boot·微信小程序·小程序
大叔_爱编程1 小时前
wx043基于springboot+vue+uniapp的智慧物流小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
码农小灰1 小时前
Spring MVC中HandlerInterceptor的作用及应用场景
java·spring boot·后端·spring·mvc
火星数据-Tina2 小时前
板球背后的数据魔法:如何用数据分析提升印度板球比赛策略
大数据·人工智能·数据分析
背水3 小时前
梯度下降优化算法-指数加权平均
人工智能·算法·机器学习
计算机-秋大田3 小时前
基于微信小程序的4S店客户管理系统设计与实现(LW+源码+讲解)
java·spring boot·后端·微信小程序·小程序·课程设计