【Spring AI & LangChain4j 进阶篇】大模型“牵手”Java工具:Function Calling核心原理+Spring AI/LangChain4j双框架实现
摘要:本文探讨了如何让ChatGPT等大模型调用Java方法、Spring Bean及第三方API,对比了Spring AI和LangChain4j的工具调用实现。核心流程包括:注册工具(通过注解或配置)、模型解析用户需求、框架执行工具并返回结果。文章详细介绍了两种框架的具体用法,涵盖参数绑定、多工具调度和异常处理等高级特性,旨在帮助Java开发者突破大模型的知识限制,实现更复杂的应用场景落地。
引言
大模型再强,脱离工具调用也只是“纸上谈兵”!作为Java开发者,你是否曾困惑:如何让ChatGPT、通义千问等大模型调用自定义Java方法、Spring Bean,甚至第三方API?Spring AI和LangChain4j两大热门框架,谁的工具调用更高效、更易落地?本文从核心原理到实战案例,手把手教你搞定工具调用全流程,解决参数绑定、多工具调度、异常兜底等核心痛点,让大模型真正成为开发助手~
文章目录
一、TOOL CALLING核心原理:大模型如何“调用工具”?
大模型的工具调用(Function/Tool Calling),本质是让模型根据用户需求,自主判断是否需要调用工具、调用哪个工具,再将工具返回结果整合后,生成最终回答的过程。简单来说,就是给大模型“配工具包”,让它从“只会说”变成“会做事”。
💡 核心逻辑:用户提问 → 大模型分析需求 → 生成工具调用指令 → 执行工具并获取结果 → 大模型整合结果 → 输出回答
1.1 工具调用的完整执行流程(以Java生态为例)
- 开发者提前封装工具(Java方法、Spring Bean、第三方API等),并定义工具的名称、参数、描述(让大模型“认识”工具);
- 用户输入自然语言提问(如“查询今天北京的天气”“统计近7天的订单总数”);
- 大模型接收提问,结合工具描述,判断需要调用的工具及所需参数;
- 框架(Spring AI/LangChain4j)解析大模型生成的调用指令,执行对应工具,获取返回结果;
- 框架将工具返回结果回传给大模型,大模型对结果进行整理、优化,生成自然语言回答;
- 若工具调用失败(如参数错误、接口超时),执行异常兜底逻辑,重新调用或返回友好提示。
1.2 工具调用的核心价值
- 突破大模型“知识上限”:解决大模型无法实时获取数据(如实时天气、最新订单)、无法执行计算逻辑的问题;
- 降低开发成本:无需手动编写大模型与工具的交互逻辑,框架已封装好核心能力;
- 提升回答准确性:通过工具获取真实数据,避免大模型“胡编乱造”(幻觉问题);
- 拓展应用场景:实现智能查询、自动化办公、第三方API集成等复杂场景落地。
二、Java方法快速封装:让大模型“调用”你的Spring Bean
无论是Spring AI还是LangChain4j,都支持将Java方法、Spring Bean快速注册为可调用工具,核心是通过注解或配置,让框架识别工具的元信息(名称、参数、描述)。这部分是实战的基础,建议点赞收藏,反复查看~
2.1 Spring AI:Spring Bean一键注册为工具
Spring AI对Spring生态的适配性极强,只需通过@Function注解,即可将Spring Bean的方法注册为大模型可调用工具,无需额外编写适配代码。
代码示例:Spring Bean工具封装(天气查询工具)
import org.springframework.ai.function.annotation.Function;
import org.springframework.stereotype.Component;
// 天气查询工具Bean
@Component
public class WeatherQueryTool {
/**
* 天气查询方法
* @param city 城市名称(必填)
* @param type 查询类型(可选:today-今日天气,7days-7天预报)
* @return 天气信息字符串
*/
@Function(name = "weather_query", description = "用于查询指定城市的天气信息,type参数默认值为today")
public String queryWeather(String city, String type) {
// 模拟调用第三方天气API(实际开发中替换为真实接口)
if (type == null || type.isEmpty()) {
type = "today";
}
return String.format("【%s天气】%s:晴,气温10-22℃,微风", city,
type.equals("today") ? "今日" : "未来7天");
}
}
核心说明
@Function注解:标记该方法为可调用工具,name是工具唯一标识(大模型通过该名称调用),description是工具描述(让大模型理解工具的用途和参数含义);- 参数说明:方法参数需明确含义,大模型会根据用户提问,自动填充对应参数;
- 注册方式:Spring Boot项目中,只需将该Bean注入容器,Spring AI会自动扫描并注册工具。
2.2 LangChain4j:自定义Java方法注册为工具
LangChain4j的工具注册更灵活,支持通过Tool接口或@Tool注解封装工具,同时支持非Spring项目使用,兼容性更强。
代码示例:LangChain4j工具封装(订单查询工具)
import dev.langchain4j.agent.tool.Tool;
// 订单查询工具(非Spring Bean也可使用)
public class OrderQueryTool {
/**
* 订单总数查询
* @param days 近N天的订单(必填,如7表示近7天)
* @return 订单总数
*/
@Tool(description = "用于查询近N天的系统订单总数,days参数为正整数,不可为空")
public Integer queryOrderCount(Integer days) {
// 模拟查询数据库(实际开发中替换为MyBatis/MyBatis-Plus查询逻辑)
if (days <= 0) {
throw new IllegalArgumentException("days参数必须为正整数");
}
return 1286; // 模拟返回订单总数
}
}
核心说明
@Tool注解:LangChain4j的工具标记注解,description需详细说明参数要求和工具用途,帮助大模型精准调用;- 注册方式:通过
Tools类的create方法,将工具实例注册到LangChain4j的代理中,示例如下:// LangChain4j工具注册 OrderQueryTool orderTool = new OrderQueryTool(); WeatherQueryTool weatherTool = new WeatherQueryTool(); Tools tools = Tools.create(orderTool, weatherTool);
三、高级特性:让工具调用更稳定、更智能
仅仅实现基础的工具调用还不够,实际开发中,我们需要处理参数绑定、多工具调度、错误重试、异常兜底等问题,Spring AI和LangChain4j都提供了对应的高级特性,帮我们解决这些痛点。
3.1 函数参数结构化绑定
大模型返回的工具调用参数是JSON格式,框架会自动将JSON参数绑定到Java方法的参数中,无需手动解析。同时,支持参数校验、默认值设置,避免参数错误。
示例:参数结构化绑定(Spring AI)
@Function(name = "user_info_query", description = "查询用户信息")
public UserDTO queryUserInfo(
@Parameter(description = "用户ID,必填,正整数") Integer userId,
@Parameter(description = "是否查询详细信息,默认false") Boolean detail) {
// 自动绑定参数,detail有默认值,无需担心空值
detail = detail == null ? false : detail;
// 模拟查询用户信息
return new UserDTO(userId, "张三", 25, detail ? "详细信息:XXX" : "基础信息");
}
3.2 多工具自动调度
当用户的提问需要调用多个工具时,框架会自动分析需求,按顺序调用多个工具,整合所有结果后返回给大模型。
📌 示例场景:用户提问“查询北京今日天气,并统计近7天的订单总数”,框架会自动调用「天气查询工具」和「订单查询工具」,分别获取结果后,由大模型整合为自然语言回答。
Spring AI多工具调度实现
// 注入所有工具Bean
@Autowired
private WeatherQueryTool weatherTool;
@Autowired
private OrderQueryTool orderTool;
// 构建工具列表
List<FunctionCallback> tools = Arrays.asList(
FunctionCallback.from(weatherTool),
FunctionCallback.from(orderTool)
);
// 大模型调用时传入工具列表,自动调度
ChatResponse response = chatClient.call(
Message.of("查询北京今日天气,并统计近7天的订单总数"),
ChatOptions.builder().functions(tools).build()
);
3.3 错误重试与异常兜底
工具调用过程中,可能出现参数错误、接口超时、第三方服务不可用等问题,框架支持配置错误重试策略和异常兜底逻辑,提升工具调用的稳定性。
LangChain4j异常兜底实现
// 配置工具调用的异常处理器
ToolExecutionErrorHandler errorHandler = (tool, arguments, exception) -> {
// 异常兜底逻辑:返回友好提示,避免程序崩溃
log.error("工具调用失败:{},参数:{}", tool.name(), arguments, exception);
return "工具调用暂时失败,请稍后再试~";
};
// 注册工具时设置异常处理器
Tools tools = Tools.create(errorHandler, orderTool, weatherTool);
核心技巧
- 重试策略:可配置重试次数、重试间隔,针对临时网络问题有效;
- 异常分类:区分参数错误、超时错误、服务错误,分别设置兜底逻辑;
- 日志记录:记录工具调用的详细日志,便于排查问题。
四、实战案例:大模型+工具调用,实现多场景落地
结合前面的知识点,我们通过3个实战案例,完整实现大模型与工具的深度整合,涵盖天气查询、数据库订单查询、第三方API调用,直接复制代码即可上手!
4.1 案例1:天气查询(Spring AI + 第三方天气API)
1. 工具封装(同上2.1节,略作修改,调用真实API)
@Component
public class WeatherQueryTool {
@Value("${weather.api.key}")
private String apiKey;
@Function(name = "weather_query", description = "查询指定城市的天气,type可选today/7days,默认today")
public String queryWeather(String city, String type) {
try {
// 调用第三方天气API(示例:高德天气API)
String url = String.format("https://restapi.amap.com/v3/weather/weatherInfo?city=%s&key=%s&extensions=%s",
city, apiKey, type == null ? "base" : "all");
// 发送HTTP请求获取结果(使用RestTemplate/OkHttp)
String response = restTemplate.getForObject(url, String.class);
// 解析JSON结果,返回简洁信息(实际开发中需完善解析逻辑)
return parseWeatherResponse(response);
} catch (Exception e) {
throw new RuntimeException("天气查询失败:" + e.getMessage());
}
}
// 解析天气API返回结果(简化版)
private String parseWeatherResponse(String response) {
// 实际开发中使用Jackson/Gson解析JSON
return "北京今日天气:晴,气温10-22℃,微风,空气质量优";
}
}
2. 大模型调用工具(Spring Boot完整示例)
@RestController
@RequestMapping("/ai")
public class AIController {
@Autowired
private ChatClient chatClient;
@Autowired
private WeatherQueryTool weatherTool;
@GetMapping("/queryWeather")
public String queryWeather(@RequestParam String question) {
// 注册工具
List<FunctionCallback> tools = Collections.singletonList(FunctionCallback.from(weatherTool));
// 调用大模型,传入工具
ChatResponse response = chatClient.call(
Message.of(question),
ChatOptions.builder().functions(tools).functionCall(FunctionCall.AUTO).build()
);
return response.getResult().getOutput().getContent();
}
}
4.2 案例2:数据库订单查询(LangChain4j + MyBatis)
1. 工具封装(查询近N天订单总数、订单详情)
@Service
public class OrderQueryTool {
@Autowired
private OrderMapper orderMapper;
@Tool(description = "查询近N天的订单总数,days为正整数,必填")
public Integer queryOrderCount(Integer days) {
if (days <= 0) {
throw new IllegalArgumentException("days必须为正整数");
}
// 计算N天前的日期
LocalDate startDate = LocalDate.now().minusDays(days);
return orderMapper.countByDate(startDate, LocalDate.now());
}
@Tool(description = "查询指定订单号的详情,orderNo为订单编号,必填")
public OrderDTO queryOrderDetail(String orderNo) {
if (orderNo == null || orderNo.isEmpty()) {
throw new IllegalArgumentException("订单号不能为空");
}
OrderDO orderDO = orderMapper.selectByOrderNo(orderNo);
if (orderDO == null) {
return new OrderDTO(null, "订单不存在", null, null);
}
// DO转DTO
return new OrderDTO(orderDO.getOrderNo(), orderDO.getUserName(),
orderDO.getAmount(), orderDO.getCreateTime());
}
}
2. LangChain4j整合大模型与工具
@Service
public class AIAgentService {
// 初始化大模型(以通义千问为例)
private final ChatLanguageModel model = TongyiQianwenChatModel.builder()
.apiKey("你的通义千问APIKey")
.temperature(0.7)
.build();
@Autowired
private OrderQueryTool orderQueryTool;
// 构建智能代理,整合大模型与工具
public String processQuestion(String question) {
// 注册工具并设置异常兜底
ToolExecutionErrorHandler errorHandler = (tool, arguments, exception) ->
"工具调用失败:" + exception.getMessage();
Tools tools = Tools.create(errorHandler, orderQueryTool);
// 构建代理,自动调度工具
Agent agent = Agent.builder()
.chatLanguageModel(model)
.tools(tools)
.build();
// 执行提问,返回结果
return agent.execute(question);
}
}
4.3 案例3:多工具协同(天气+订单+第三方短信API)
场景需求
用户提问:“查询上海今日天气,统计近3天的订单总数,然后给管理员发送一条包含这两个信息的短信”。
实现思路
- 封装3个工具:天气查询、订单查询、短信发送;
- 框架自动调度3个工具,按顺序执行;
- 短信发送工具接收前两个工具的结果,生成短信内容并发送。
核心代码(LangChain4j)
// 短信发送工具
public class SmsSendTool {
@Tool(description = "给管理员发送短信,content为短信内容,必填")
public String sendSms(String content) {
// 模拟调用第三方短信API
log.info("给管理员发送短信:{}", content);
return "短信发送成功";
}
}
// 多工具协同调用
public String multiToolTest() {
// 注册所有工具
Tools tools = Tools.create(
new WeatherQueryTool(),
new OrderQueryTool(),
new SmsSendTool()
);
// 构建代理,执行多工具调度
Agent agent = Agent.builder()
.chatLanguageModel(model)
.tools(tools)
.build();
// 用户提问
String question = "查询上海今日天气,统计近3天的订单总数,然后给管理员发送一条包含这两个信息的短信";
return agent.execute(question);
}
🌟 小贴士:实战中,建议给每个工具添加详细的描述,让大模型更准确地判断是否调用工具、如何传递参数,这是工具调用成功的关键!记得点赞收藏,后续实战直接复用~
五、两大框架的工具调用实现差异与最佳实践
Spring AI和LangChain4j都能实现工具调用,但在生态适配、功能侧重、使用场景上有明显差异,选择对的框架能大幅提升开发效率。
5.1 核心差异对比(表格清晰呈现)
| 对比维度 | Spring AI | LangChain4j |
|---|---|---|
| 生态适配 | 强依赖Spring生态,Spring Boot项目无缝集成 | 无框架依赖,支持Spring/非Spring项目,兼容性更强 |
| 工具注册 | 基于@Function注解,自动扫描Spring Bean,配置简单 |
基于@Tool注解或Tool接口,手动注册,灵活度高 |
| 多工具调度 | 需手动配置工具列表,调度逻辑较简单 | 内置Agent代理,自动调度多工具,智能性更强 |
| 异常处理 | 需自定义异常处理器,配置较繁琐 | 内置异常处理机制,支持自定义兜底逻辑,更易用 |
| 适用场景 | Spring Boot项目、快速集成、轻量级工具调用 | 复杂多工具调度、非Spring项目、高灵活性需求 |
5.2 最佳实践建议
- 若你是Spring Boot开发者,且需求是简单的工具调用(如单个API调用、数据库查询),优先选择Spring AI,开发效率更高,无需额外适配;
- 若你需要实现复杂的多工具调度、异常兜底,或项目是非Spring架构,优先选择LangChain4j,灵活性和智能性更优;
- 工具描述要“精准详细”,明确参数类型、必填项、默认值,避免大模型传递错误参数;
- 对核心工具添加错误重试和异常兜底,提升系统稳定性,避免因工具调用失败导致整体服务崩溃;
- 尽量将工具拆分为“单一职责”,避免一个工具实现多个功能,便于大模型精准调用和后期维护。
六、结尾总结
本文从Tool Calling核心原理出发,详细讲解了Spring AI和LangChain4j两大框架的工具封装方法、高级特性,通过3个实战案例,实现了天气查询、数据库订单查询、多工具协同等场景的落地,最后对比了两大框架的差异并给出最佳实践建议。
工具调用是大模型落地的核心能力之一,掌握Spring AI和LangChain4j的工具调用技巧,能让你快速实现大模型与Java生态的深度整合,解决实际开发中的复杂需求。
我是予枫,专注Java、AI、大模型相关技术分享,关注我,下期带你解锁更多大模型落地实战技巧~
若本文对你有帮助,麻烦点赞+收藏,你的支持是我更新的动力!
更多推荐



所有评论(0)