Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)

最近在学习 Java AI 应用开发,先用 Spring Boot 搭了一个最小项目,完成了大模型调用,然后在这个基础上继续接入 AI Service 和 Tool Calling。

这篇文章记录整个实现过程,也把中间遇到的几个配置问题整理出来。

本文最终实现的效果是:

复制代码
用户发送自然语言请求
        ↓
Spring Boot 接收请求
        ↓
大模型判断是否需要调用工具
        ↓
LangChain4j 执行指定的 Java 方法
        ↓
工具返回业务数据
        ↓
大模型整理后回复用户

目前使用固定数据模拟查询,后续可以把 Tool 接到 Service、MyBatis 和 MySQL。


一、项目环境

本文使用的环境如下:

复制代码
JDK 17
Spring Boot 3.5.x
Maven
LangChain4j 1.18.0-beta28

一开始使用的是:

复制代码
JDK 8
Spring Boot 2.6.13

项目可以正常启动,但无法正常使用当前版本的 LangChain4j Spring Boot Starter,自动配置也没有生效。因此学习项目建议直接使用 JDK 17 和 Spring Boot 3。


二、创建 Spring Boot 项目

创建一个 Maven 类型的 Spring Boot 项目,依赖先选择:

复制代码
Spring Web

项目创建后,确认 pom.xml 中的 Java 版本为 17:

复制代码
<properties>
    <java.version>17</java.version>
</properties>

完整的核心依赖如下:

复制代码
<dependencies>

    <!-- Spring MVC、Controller、内置 Tomcat -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- OpenAI 兼容模型支持 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
        <version>1.18.0-beta28</version>
    </dependency>

    <!-- AI Service、Tool Calling 等 Spring 集成能力 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-spring-boot-starter</artifactId>
        <version>1.18.0-beta28</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

</dependencies>

这两个 LangChain4j 依赖的作用不同。

复制代码
langchain4j-open-ai-spring-boot-starter

负责读取模型配置并创建 ChatModel

复制代码
langchain4j-spring-boot-starter

负责支持 @AiService、Tool Calling 等更高层能力。

添加完成后,刷新 Maven 依赖。


三、配置大模型

在下面位置创建配置文件:

复制代码
src/main/resources/application.yml

配置内容如下:

复制代码
server:
  port: 8080

langchain4j:
  open-ai:
    chat-model:
      base-url: http://langchain4j.dev/demo/openai/v1
      api-key: demo
      model-name: gpt-4o-mini
      temperature: 0.3
      log-requests: true
      log-responses: true

几个配置项需要分开理解。

base-url

复制代码
base-url: http://langchain4j.dev/demo/openai/v1

这是模型服务的接口地址,不是具体模型。

api-key

复制代码
api-key: demo

这是接口调用凭证。当前使用的是演示配置,只适合本地学习。

model-name

复制代码
model-name: gpt-4o-mini

这一项才是具体使用的模型名称。

整体关系可以理解为:

复制代码
base-url:请求发到哪个模型服务
api-key:用什么凭证调用
model-name:具体调用哪个模型

四、先完成最简单的模型调用

创建 Controller:

复制代码
package com.hsw.langchain4jdemo.controller;

import dev.langchain4j.model.chat.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/ai")
public class AiController {

    private final ChatModel chatModel;

    public AiController(ChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return chatModel.chat(message);
    }
}

启动项目后访问:

复制代码
http://localhost:8080/api/ai/chat?message=请介绍一下Java

如果可以正常返回内容,说明下面这条链路已经打通:

复制代码
Controller
    ↓
ChatModel
    ↓
LangChain4j
    ↓
大模型接口
    ↓
返回文本

ChatModel 是什么

ChatModel 并不是大模型本身,而是 LangChain4j 对聊天模型能力定义的统一接口。

代码中注入的是:

复制代码
ChatModel chatModel

Spring 容器中实际创建的对象一般是对应模型的具体实现,例如:

复制代码
OpenAiChatModel

可以类比:

复制代码
List<String> list = new ArrayList<>();

List 是接口,ArrayList 是具体实现。

ChatModel 的作用就是屏蔽不同模型服务之间的请求细节,让业务代码统一使用:

复制代码
chatModel.chat(message);

五、使用 AI Service

直接调用 ChatModel 适合验证模型连接,但后面要做系统提示词、对话记忆、Tool Calling 和 RAG,通常会使用 AI Service。

创建接口:

复制代码
com.hsw.langchain4jdemo.assistant.Assistant

代码如下:

复制代码
package com.hsw.langchain4jdemo.assistant;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.spring.AiService;

@AiService
public interface Assistant {

    @SystemMessage("""
            你是一名Java学习助手。
            回答尽量准确、清晰。
            遇到不确定的数据时不要编造。
            """)
    String chat(String message);
}

这里没有编写 AssistantImpl

LangChain4j 会在项目启动时为这个接口创建代理对象,并把它注册到 Spring 容器中。

调用过程类似:

复制代码
Assistant 接口
      ↓
LangChain4j 动态代理
      ↓
ChatModel
      ↓
大模型

Controller 可以改成:

复制代码
package com.hsw.langchain4jdemo.controller;

import com.hsw.langchain4jdemo.assistant.Assistant;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/ai")
public class AiController {

    private final Assistant assistant;

    public AiController(Assistant assistant) {
        this.assistant = assistant;
    }

    @GetMapping("/assistant")
    public String assistant(@RequestParam String message) {
        return assistant.chat(message);
    }
}

测试地址:

复制代码
http://localhost:8080/api/ai/assistant?message=线程池是什么

六、添加第一个 Tool

普通模型只能根据已有知识生成内容,无法直接查询项目中的数据库或业务接口。

例如用户输入:

复制代码
帮我查询用户1001的信息

模型并不知道项目里的用户数据。如果直接回答,很可能会编造。

Tool Calling 的作用就是让模型在需要真实数据时,调用后端提供的 Java 方法。

创建工具类:

复制代码
com.hsw.langchain4jdemo.tool.UserTool

代码如下:

复制代码
package com.hsw.langchain4jdemo.tool;

import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;

@Component
public class UserTool {

    @Tool("根据用户ID查询用户信息")
    public String queryUser(Long userId) {

        // 暂时使用固定数据模拟数据库查询
        if (Long.valueOf(1001L).equals(userId)) {
            return """
                    用户ID:1001
                    用户名:张三
                    年龄:25
                    会员等级:黄金会员
                    """;
        }

        return "没有找到对应的用户";
    }
}

这里的 @Tool 不是 Controller 接口,也不要求它是 HTTP 接口。

它就是一个普通 Java 方法,只不过通过 @Tool 告诉大模型:

复制代码
系统拥有一个根据用户ID查询用户信息的能力

真实项目中一般会写成:

复制代码
UserTool
   ↓
UserService
   ↓
UserMapper
   ↓
MySQL

例如:

复制代码
@Component
public class UserTool {

    private final UserService userService;

    public UserTool(UserService userService) {
        this.userService = userService;
    }

    @Tool("根据用户ID查询用户信息")
    public UserDTO queryUser(Long userId) {
        return userService.getById(userId);
    }
}

七、把 Tool 注册到 AI Service

修改 Assistant

复制代码
package com.hsw.langchain4jdemo.assistant;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.spring.AiService;

@AiService(
        tools = "userTool"
)
public interface Assistant {

    @SystemMessage("""
            你是一个用户信息查询助手。

            查询用户信息时必须调用工具,
            不允许自行编造用户数据。
            """)
    String chat(String message);
}

这里写的是:

复制代码
tools = "userTool"

而不是:

复制代码
tools = UserTool.class

因为当前版本中,tools 属性接收的是 Spring Bean 名称。

工具类是:

复制代码
@Component
public class UserTool

Spring 默认会把它注册成:

复制代码
userTool

所以 AI Service 中填写:

复制代码
tools = "userTool"

如果手动指定 Bean 名称:

复制代码
@Component("userQueryTool")
public class UserTool {
}

对应配置也需要改成:

复制代码
@AiService(
        tools = "userQueryTool"
)

八、测试 Tool Calling

启动项目后访问:

复制代码
http://localhost:8080/api/ai/assistant?message=帮我查询用户1001的信息

完整流程如下:

复制代码
用户输入:
帮我查询用户1001的信息
        ↓
Assistant 接收消息
        ↓
大模型分析用户意图
        ↓
模型决定调用 queryUser
        ↓
LangChain4j 执行 UserTool.queryUser(1001)
        ↓
Java 方法返回用户数据
        ↓
工具结果再次交给大模型
        ↓
大模型整理后返回最终答案

需要注意,大模型并没有直接执行 Java 方法。

实际分工是:

复制代码
大模型:决定调用哪个工具以及传递什么参数
LangChain4j:解析调用请求并执行 Java 方法
Java 业务代码:真正查询数据库或调用业务服务

九、wiringMode 是什么

在配置 AI Service 时,可能会看到下面这种写法:

复制代码
@AiService(
        wiringMode = AiServiceWiringMode.EXPLICIT,
        tools = "userTool"
)

wiringMode 控制 AI Service 的依赖如何装配。

自动装配

默认情况下,LangChain4j 会从 Spring 容器中查找合适的模型和其他依赖。

复制代码
@AiService(
        tools = "userTool"
)

对于当前只有一个 ChatModel 的学习项目,使用自动装配比较简单。

显式装配

复制代码
wiringMode = AiServiceWiringMode.EXPLICIT

表示不再自动选择,而是要求开发人员明确指定所使用的模型、工具等 Bean。

它适合以下场景:

复制代码
项目中存在多个 ChatModel
不同 Agent 使用不同模型
不同 Agent 只能使用指定工具
需要严格控制依赖关系

如果写了:

复制代码
wiringMode = AiServiceWiringMode.EXPLICIT

却只指定了 Tool,没有指定 ChatModel,就可能出现:

复制代码
Please specify either chatModel or streamingChatModel

对于当前项目,直接删除 EXPLICIT,使用自动装配即可:

复制代码
@AiService(
        tools = "userTool"
)

十、常见问题

1. 找不到 ChatModel Bean

报错:

复制代码
required a bean of type 'dev.langchain4j.model.chat.ChatModel'
that could not be found

优先检查以下内容。

配置文件是否放在:

复制代码
src/main/resources/application.yml

配置前缀是否正确:

复制代码
langchain4j:
  open-ai:
    chat-model:

依赖是否使用了 Starter:

复制代码
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>

而不是只添加普通的模型依赖。

还需要检查 JDK、Spring Boot 和 LangChain4j 版本是否匹配。


2. tools 属性类型错误

错误写法:

复制代码
@AiService(
        tools = UserTool.class
)

IDEA 会提示需要 String[],实际提供的是 Class<UserTool>

正确写法:

复制代码
@AiService(
        tools = "userTool"
)

这里填写的是 Spring Bean 名称。


3. 提示必须指定 chatModel

报错:

复制代码
Please specify either chatModel or streamingChatModel

通常是因为使用了:

复制代码
wiringMode = AiServiceWiringMode.EXPLICIT

但没有明确指定模型。

初学阶段可以先使用自动装配:

复制代码
@AiService(
        tools = "userTool"
)

4. 找不到名为 chatModel 的 Bean

报错:

复制代码
required a bean named 'chatModel' that could not be found

通常是手动写了:

复制代码
chatModel = "chatModel"

这里要求 Spring 容器里必须存在一个名称正好为 chatModel 的 Bean。

但自动配置生成的模型 Bean 不一定叫这个名字。

如果当前只有一个模型,直接删除 Bean 名称配置,让 LangChain4j 按类型自动装配更合适。


十一、当前项目结构

完成后,项目结构大致如下:

复制代码
src/main/java/com/hsw/langchain4jdemo
├── LangChain4jDemoApplication.java
├── assistant
│   └── Assistant.java
├── controller
│   └── AiController.java
└── tool
    └── UserTool.java

src/main/resources
└── application.yml

当前调用关系:

复制代码
AiController
      ↓
Assistant
      ↓
ChatModel
      ↓
大模型
      ↓
判断是否调用 UserTool
      ↓
UserTool
      ↓
返回业务数据
      ↓
大模型生成最终回答

十二、这算不算 Agent

只调用:

复制代码
chatModel.chat(message);

属于普通的大模型接入,还不能算 Agent。

加入 Tool Calling 后,模型已经可以:

复制代码
理解用户需求
选择工具
生成工具参数
获取工具执行结果
根据结果继续回答

这已经具备了基础 Agent 能力。

不过距离完整业务 Agent 还有一些内容:

复制代码
多轮对话记忆
多个工具连续调用
数据库真实查询
RAG 知识库
权限校验
高风险操作二次确认
幂等控制
工具调用日志
异常重试和超时处理

下一步可以把当前的固定用户数据替换成:

复制代码
Spring Boot
+ MyBatis-Plus
+ MySQL
+ UserTool

让模型真正查询数据库中的用户信息。

相关推荐
大模型码小白2 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司3 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地4 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
莫逸风7 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
隔窗听雨眠7 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
z123456789867 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
yaoxin5211238 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python
做个文艺程序员8 小时前
Linux第24篇:Java应用监控体系搭建:Prometheus+Grafana可视化运维
java·grafana·prometheus
小钻风33669 小时前
Spring Boot 文件上传详解:深入理解 MultipartFile 的使用与原理
java·开发语言