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 或消息队列扩展。

相关推荐
蟑螂恶霸15 分钟前
Windows安装OpenCV 4.8
人工智能·windows·opencv
枫叶林FYL16 分钟前
【自然语言处理 NLP】第二章 经典NLP算法与特征工程(Classical NLP Algorithms)
人工智能·深度学习·机器学习
非著名程序员23 分钟前
阿里云重磅上线 Qoder 专家团模式,AI 编程进入组团作战时代
人工智能
cjy0001111 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
AEIC学术交流中心1 小时前
【快速EI检索 | IEEE出版】2026年人工智能、智能系统与信息安全国际学术会议(AISIS 2026)
人工智能
火山引擎开发者社区2 小时前
李诞、何同学、小Lin说同台直播,解锁养虾新玩法!
人工智能
sheji34162 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
剑穗挂着新流苏3122 小时前
117_PyTorch 实战:利用训练好的模型进行单张图片验证
人工智能·python·深度学习
程序员cxuan2 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
数据皮皮侠2 小时前
中国城市间地理距离矩阵(2024)
大数据·数据库·人工智能·算法·制造