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

相关推荐
乌旭1 小时前
量子计算与GPU的异构加速:基于CUDA Quantum的混合编程实践
人工智能·pytorch·分布式·深度学习·ai·gpu算力·量子计算
deephub3 小时前
CLIMB自举框架:基于语义聚类的迭代数据混合优化及其在LLM预训练中的应用
人工智能·深度学习·大语言模型·聚类
他҈姓҈林҈4 小时前
使用 Spring Boot 进行开发
spring boot
思通数科AI全行业智能NLP系统4 小时前
AI视频技术赋能幼儿园安全——教师离岗报警系统的智慧守护
大数据·人工智能·安全·目标检测·目标跟踪·自然语言处理·ocr
struggle20255 小时前
deepseek-cli开源的强大命令行界面,用于与 DeepSeek 的 AI 模型进行交互
人工智能·开源·自动化·交互·deepseek
ocr_sinosecu15 小时前
OCR定制识别:解锁文字识别的无限可能
人工智能·机器学习·ocr
奋斗者1号6 小时前
分类数据处理全解析:从独热编码到高维特征优化
人工智能·机器学习·分类
Java&Develop6 小时前
onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
前端·spring boot·编辑器
契合qht53_shine6 小时前
深度学习 视觉处理(CNN) day_02
人工智能·深度学习·cnn
就叫飞六吧6 小时前
如何判断你的PyTorch是GPU版还是CPU版?
人工智能·pytorch·python