在这里插入图片描述

🍃 予枫个人主页

📚 个人专栏: 《Java 从入门到起飞》《读研码农的干货日常

💻 Debug 这个世界,Return 更好的自己!

引言

大模型再强,脱离工具调用也只是“纸上谈兵”!作为Java开发者,你是否曾困惑:如何让ChatGPT、通义千问等大模型调用自定义Java方法、Spring Bean,甚至第三方API?Spring AI和LangChain4j两大热门框架,谁的工具调用更高效、更易落地?本文从核心原理到实战案例,手把手教你搞定工具调用全流程,解决参数绑定、多工具调度、异常兜底等核心痛点,让大模型真正成为开发助手~

一、TOOL CALLING核心原理:大模型如何“调用工具”?

大模型的工具调用(Function/Tool Calling),本质是让模型根据用户需求,自主判断是否需要调用工具、调用哪个工具,再将工具返回结果整合后,生成最终回答的过程。简单来说,就是给大模型“配工具包”,让它从“只会说”变成“会做事”。

💡 核心逻辑:用户提问 → 大模型分析需求 → 生成工具调用指令 → 执行工具并获取结果 → 大模型整合结果 → 输出回答

1.1 工具调用的完整执行流程(以Java生态为例)

  1. 开发者提前封装工具(Java方法、Spring Bean、第三方API等),并定义工具的名称、参数、描述(让大模型“认识”工具);
  2. 用户输入自然语言提问(如“查询今天北京的天气”“统计近7天的订单总数”);
  3. 大模型接收提问,结合工具描述,判断需要调用的工具及所需参数;
  4. 框架(Spring AI/LangChain4j)解析大模型生成的调用指令,执行对应工具,获取返回结果;
  5. 框架将工具返回结果回传给大模型,大模型对结果进行整理、优化,生成自然语言回答;
  6. 若工具调用失败(如参数错误、接口超时),执行异常兜底逻辑,重新调用或返回友好提示。

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天的订单总数,然后给管理员发送一条包含这两个信息的短信”。

实现思路

  1. 封装3个工具:天气查询、订单查询、短信发送;
  2. 框架自动调度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 最佳实践建议

  1. 若你是Spring Boot开发者,且需求是简单的工具调用(如单个API调用、数据库查询),优先选择Spring AI,开发效率更高,无需额外适配;
  2. 若你需要实现复杂的多工具调度、异常兜底,或项目是非Spring架构,优先选择LangChain4j,灵活性和智能性更优;
  3. 工具描述要“精准详细”,明确参数类型、必填项、默认值,避免大模型传递错误参数;
  4. 对核心工具添加错误重试和异常兜底,提升系统稳定性,避免因工具调用失败导致整体服务崩溃;
  5. 尽量将工具拆分为“单一职责”,避免一个工具实现多个功能,便于大模型精准调用和后期维护。

六、结尾总结

本文从Tool Calling核心原理出发,详细讲解了Spring AI和LangChain4j两大框架的工具封装方法、高级特性,通过3个实战案例,实现了天气查询、数据库订单查询、多工具协同等场景的落地,最后对比了两大框架的差异并给出最佳实践建议。

工具调用是大模型落地的核心能力之一,掌握Spring AI和LangChain4j的工具调用技巧,能让你快速实现大模型与Java生态的深度整合,解决实际开发中的复杂需求。


我是予枫,专注Java、AI、大模型相关技术分享,关注我,下期带你解锁更多大模型落地实战技巧~
若本文对你有帮助,麻烦点赞+收藏,你的支持是我更新的动力!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐