1. Spring AI与Function Call深度整合实战
作为一名长期从事AI应用开发的工程师,我一直在寻找能够简化大语言模型集成过程的工具。Spring AI的出现彻底改变了Java生态中AI应用的开发方式,特别是其Function Call功能的引入,让我们能够以更灵活的方式扩展模型能力。本文将分享如何基于Spring AI实现Function Call的完整实践过程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目搭建
2.1 基础环境配置
开发环境需要满足以下要求:
- JDK 17或更高版本(推荐使用Oracle JDK或OpenJDK)
- Maven 3.6+
- Spring Boot 3.2.3
提示:使用SDKMAN可以方便地管理多个JDK版本,命令
sdk install java 17.0.10-tem安装指定版本
2.2 项目初始化
创建Maven项目时,pom.xml中需要包含以下关键依赖:
xml复制<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
</parent>
<dependencies>
<!-- Spring AI OpenAI Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>0.8.0</version>
</dependency>
<!-- 其他工具类依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.24</version>
</dependency>
</dependencies>
3. Function Call核心实现
3.1 功能服务类设计
我们以实现天气查询功能为例,创建WeatherService类:
java复制@Slf4j
public class WeatherService implements Function<WeatherService.Request, WeatherService.Response> {
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonClassDescription("Weather API request")
public record Request(
@JsonProperty(required = true, value = "location")
@JsonPropertyDescription("The city and state e.g. 广州")
String location
) {}
public record Response(String weather) {}
@Override
public Response apply(Request request) {
log.info("查询天气位置: {}", request.location);
// 实际项目中这里可以调用第三方天气API
String weather = switch(request.location()) {
case "广州" -> "小雨转阴 13~19°C";
case "深圳" -> "阴 15~26°C";
default -> "晴 20~30°C";
};
return new Response(weather);
}
}
3.2 Function配置注册
创建配置类将功能注册到Spring上下文:
java复制@Configuration
public class FunctionConfig {
@Bean
@Description("获取指定位置的天气信息")
public FunctionCallback weatherFunction() {
return FunctionCallbackWrapper.builder(new WeatherService())
.withName("currentWeather")
.withDescription("Get the weather in location")
.build();
}
}
4. 控制器与API集成
4.1 控制器实现
java复制@RestController
@RequestMapping("/api/weather")
public class WeatherController {
@Autowired
private OpenAiChatClient chatClient;
@GetMapping
public String getWeather(@RequestParam String city) {
String systemPrompt = "你是一个智能天气助手";
SystemPromptTemplate promptTemplate = new SystemPromptTemplate(systemPrompt);
Message systemMessage = promptTemplate.createMessage();
Message userMessage = new UserMessage(city + "的天气如何?");
OpenAiChatOptions options = OpenAiChatOptions.builder()
.withFunction("currentWeather")
.withTemperature(0.3)
.build();
Prompt prompt = new Prompt(List.of(userMessage, systemMessage), options);
return chatClient.call(prompt)
.getResults()
.stream()
.map(Generation::getOutput)
.map(AssistantMessage::getContent)
.collect(Collectors.joining());
}
}
4.2 交互流程解析
- 用户提问:"广州的天气如何?"
- 模型识别需要调用weather函数
- Spring AI自动调用本地WeatherService
- 服务返回实际天气数据
- 模型整合结果返回给用户
5. 高级配置与优化
5.1 模型参数调优
application.yml中可配置的OpenAI参数:
yaml复制spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-3.5-turbo
temperature: 0.4 # 控制创造性(0-2)
max_tokens: 1000 # 最大输出长度
top-p: 0.9 # 核采样阈值
presence-penalty: 0.5 # 避免重复内容
5.2 多函数组合调用
可以注册多个FunctionCallback实现复杂场景:
java复制@Configuration
public class MultiFunctionConfig {
@Bean
public FunctionCallback weatherFunction() {
// 天气功能配置
}
@Bean
public FunctionCallback stockFunction() {
// 股票查询功能
}
@Bean
public FunctionCallback calculatorFunction() {
// 计算器功能
}
}
6. 生产环境注意事项
6.1 性能优化建议
- 为频繁调用的函数添加缓存
- 设置合理的API超时时间(默认5秒可能不够)
- 监控函数调用耗时和成功率
6.2 错误处理机制
增强鲁棒性的处理方式:
java复制try {
ChatResponse response = chatClient.call(prompt);
// 处理正常响应
} catch (OpenAiApiException e) {
if (e.getStatusCode().value() == 429) {
// 处理速率限制
} else {
// 其他错误处理
}
}
7. 扩展应用场景
7.1 企业级应用集成
将Function Call与企业现有系统对接:
- CRM系统客户数据查询
- ERP系统库存检查
- BI系统报表生成
7.2 自定义知识库增强
结合RAG(检索增强生成)技术:
- 函数调用向量数据库
- 检索相关文档片段
- 注入到提示词中
java复制FunctionCallback knowledgeSearch = FunctionCallbackWrapper.builder(query -> {
// 调用向量数据库
List<Document> docs = vectorStore.similaritySearch(query);
return docs.stream().map(Document::getContent).collect(Collectors.joining("\n"));
})
.withName("knowledgeSearch")
.build();
8. 常见问题解决方案
8.1 函数不被识别问题
排查步骤:
- 确认函数名称拼写一致
- 检查函数描述是否清晰
- 验证模型是否支持function calling
- 检查温度参数是否过高(建议0.3-0.7)
8.2 响应格式异常处理
添加格式校验逻辑:
java复制public Response apply(Request request) {
if (StringUtils.isBlank(request.location())) {
throw new IllegalArgumentException("位置参数不能为空");
}
// 正常处理逻辑
}
在实际项目中使用Spring AI的Function Call功能时,最大的体会是一定要做好错误边界处理。模型有时会以意想不到的方式调用函数,我们的实现需要足够健壮。另外,为每个函数编写清晰的描述非常重要,这直接影响模型是否以及如何调用它们。
