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

相关推荐
大龄程序员狗哥5 小时前
第25篇:Q-Learning算法解析——强化学习中的经典“价值”学习(原理解析)
人工智能·学习·算法
陶陶然Yay5 小时前
神经网络常见层Numpy封装参考(5):其他层
人工智能·神经网络·numpy
极客老王说Agent5 小时前
2026实战指南:如何用智能体实现药品不良反应报告的自动录入?
人工智能·ai·chatgpt
imbackneverdie5 小时前
本科毕业论文怎么写?需要用到什么工具?
人工智能·考研·aigc·ai写作·学术·毕业论文·ai工具
lulu12165440785 小时前
Claude Code项目大了响应慢怎么办?Subagents、Agent Teams、Git Worktree、工作流编排四种方案深度解析
java·人工智能·python·ai编程
riNt PTIP5 小时前
SpringBoot创建动态定时任务的几种方式
java·spring boot·spring
大橙子打游戏5 小时前
talkcozy像聊微信一样多项目同时开发
人工智能·vibecoding
deephub5 小时前
LangChain 还是 LangGraph?一个是编排一个是工具包
人工智能·langchain·大语言模型·langgraph
OidEncoder6 小时前
编码器分辨率与机械精度的关系
人工智能·算法·机器人·自动化
Championship.23.246 小时前
Harness工程深度解析:从理论到实践的完整指南
人工智能·harness