当前位置: 首页 > news >正文

Spring+LangChain4j工程搭建

Spring+LangChain4j工程搭建

文章目录

  • Spring+LangChain4j工程搭建
  • 环境准备
  • SpringAI & LangChain4j
      • Spring AI 与 LangChain4j 的区别、优缺点及适用场景
  • 工程搭建
    • 项目结构
    • 后端架构
    • pom 依赖
  • API KEY 申请
    • DeepSeek
    • Qwen-Max
  • 配置文件
  • 配置读取
  • 配置注入
  • 定义模型对话接口
  • 模型Service
  • Controller层
  • 测试

环境准备

JDK 21

SpringBoot 3.4.2
Maven 3.6.9

模型API_KEY : DeepSeek / Qwen

Postman

Idea

SpringAI & LangChain4j

Spring AI 与 LangChain4j 的区别、优缺点及适用场景

在 Java 生态中集成大语言模型 (LLM) 已成为企业智能化转型的关键路径。 目前, Spring AILangChain4j 是两个最受关注的 Java AI 开发框架,它们分别代表了 企业级集成模块化灵活构建 两种不同的技术理念。

一、核心定位与设计理念

维度Spring AILangChain4j
定位Spring 官方推出的 企业级 AI 集成框架(2025 年 5 月发布 1.0)LangChain 的 Java 实现,轻量级、模块化的 LLM 应用构建工具
设计理念“约定大于配置”,深度融入 Spring Boot/Cloud 生态,强调 标准化、可观测性与安全性“链式组合、按需集成”,强调 灵活性、可扩展性与快速原型开发
抽象层级提供统一高层抽象(如 ChatClientTextGenerator),屏蔽底层模型差异提供细粒度组件(如 PromptTemplateChainToolProvider),支持自由编排

二、功能特性对比

  1. 模型支持与切换能力
  • Spring AI
    通过 ModelProvider 接口统一接入 OpenAI、Hugging Face、阿里云百炼等模型,支持 运行时无感切换。开发者只需修改配置即可更换底层模型,无需修改业务代码,适合多模型灰度发布或灾备场景。
  • LangChain4j
    支持更广泛的模型生态(包括 OpenAI、Anthropic、Azure、LLaMA、Falcon、通义千问等),并允许通过 ModelExecutor 在代码中 动态选择主备模型,适用于对模型控制粒度要求更高的场景(如成本敏感型应用)。
  1. 提示工程与上下文管理
  • Spring AI
    提供 PromptTemplate 实现参数化提示,但链式提示编排能力较弱。上下文管理依赖 ChatMemoryAdvisor 机制,需显式配置。
  • LangChain4j
    内置强大的 Chain 机制,可将多个提示、工具调用、解析器串联为可视化工作流,天然支持复杂推理流程(如“需求分析 → 代码生成 → 单元测试”)。对话历史管理自动集成,开箱即用。
  1. 工具调用(Function Calling)
  • Spring AI
    通过 @Tool 注解与 FunctionCallHandler 实现函数注册,与 Spring 依赖注入无缝集成,支持结构化参数校验与安全控制。
  • LangChain4j
    使用 ToolProvider 机制,支持同时注册多个工具,并可结合 OutputParser 对模型返回结果进行后处理,灵活性更高,但需手动处理异常与权限。
  1. RAG(检索增强生成)支持
  • Spring AI
    开箱即用的 RAG 管道:内置 DocumentReaderTextSplitterVectorStore(如 PgVector)、QuestionAnswerAdvisor 等组件,通过 Spring 配置即可构建完整 RAG 应用。
  • LangChain4j
    需手动组合 DocumentLoaderEmbeddingModelVectorStore 等模块,虽灵活但集成成本较高,适合需要定制检索逻辑的场景。
  1. 企业级能力
  • Spring AI
    原生集成 Spring Security、Micrometer 监控、Actuator 健康检查,提供 /actuator/ai 端点实时追踪 AI 调用指标,符合企业生产环境要求。
  • LangChain4j
    本身不包含企业级中间件支持,需依赖 Spring Boot 或第三方库实现监控、认证等功能,更适合轻量级或实验性项目。

三、优缺点总结

框架优点缺点
Spring AI✅ 企业级特性完备 ✅ 与 Spring 生态无缝集成 ✅ 结构化输出(POJO 映射) ✅ 内置 RAG 与工具调用 ✅ 可观测性强❌ 学习曲线较陡 ❌ 灵活性较低,定制成本高 ❌ 社区生态尚在成长
LangChain4j✅ 上手简单,注解驱动(@AiService) ✅ 模块化设计,组合自由 ✅ 支持复杂链式工作流 ✅ 多模型兼容性极强❌ 企业级能力需自行补充 ❌ RAG 需手动搭建 ❌ 缺乏统一监控方案

四、适用场景建议

  • 选择 Spring AI,如果:
    • 你正在构建 生产级、高可靠性的企业 AI 应用(如智能客服、风控决策、文档分析系统);
    • 项目已基于 Spring Boot/Spring Cloud 构建,希望最小化技术栈变更;
    • 需要 结构化输出、审计日志、性能监控 等企业级保障;
    • 希望通过配置而非代码实现 模型切换与灰度发布
  • 选择 LangChain4j,如果:
    • 你需要 快速验证 AI 想法(MVP 开发),30 行代码即可接入 LLM;
    • 应用涉及 复杂多步骤推理(如代码生成、多工具协同);
    • 需要 同时调用多个模型或本地开源模型
    • 提示工程、工作流编排 有高度定制需求。

工程搭建

  • 后端技术栈: Spring Boot 3 + LangChain4j + WebFlux
  • 前端技术栈: React 18 + TypeScript + Vite
  • AI 模型: DeepSeek、Qwen(可扩展)
  • 核心特性: 流式对话、对话记忆、工具调用、动态模型加载

项目结构

LangChain4jAgent/
├── doc/                        # 项目文档目录
├── front/                      # 前端项目目录
├── model-provider/             # 后端项目目录
├── pom.xml                     # Maven 父项目配置
├── README.md                   # 项目说明文档          

后端架构

org.xjl.model.provider/
├── common/                     # 公共模块
│   ├── constants/             # 常量定义
│   │   ├── ModelBuildParamConstant.java    # 模型构建参数常量
│   │   └── ModelTypeConstant.java          # 模型类型常量
│   └── utils/                 # 工具类(预留)
│
├── config/                     # 配置模块
│   ├── ModelConfig.java       # 模型 Bean 动态注册配置
│   └── ModelProperties.java   # 模型配置属性绑定类
│
├── controller/                 # 控制器层
│   └── ChatClient.java        # AI 对话 REST 接口控制器
│
├── core/                       # 核心业务模块
│   ├── dao/                   # 数据访问层(预留)
│   ├── facade/                # 门面层(预留)
│   ├── handler/               # 处理器
│   │   └── SseEmitterStreamingResponseHandler.java  # SSE 流式响应处理器
│   ├── memory/                # 记忆管理
│   │   └── Assistant.java     # AI 助手接口定义
│   ├── model/                 # 数据模型(预留)
│   ├── service/               # 业务服务层
│   │   ├── ChatClientService.java              # 对话服务接口
│   │   └── impl/
│   │       └── ChatClientServiceImpl.java      # 对话服务实现
│   └── tools/                 # AI 工具集
│       ├── CalculatorTool.java     # 计算器工具
│       ├── DateTimeTool.java       # 日期时间工具
│       ├── StringUtilTool.java     # 字符串处理工具
│       ├── SystemInfoTool.java     # 系统信息工具
│       └── WeatherTool.java        # 天气查询工具
│
└── ModelProviderApplication.java   # Spring Boot 启动类
model-provider/
├── src/
│   ├── main/
│   │   ├── java/org/xjl/model/provider/     # Java 源代码
│   │   └── resources/                        # 配置文件和静态资源
│   └── test/                                 # 测试代码(未使用)
├── pom.xml                                   # Maven 项目配置

pom 依赖

  1. 父项
  <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.2</version><relativePath/></parent>
  1. 版本管理
   <properties><maven.compiler.source>21</maven.compiler.source><maven.compiler.target>21</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!-- 版本由 BOM 管理 --><dependencyManagement><dependencies><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-bom</artifactId><version>1.8.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
  1. 依赖项
        <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.52</version></dependency><!-- Web + Controller 必备 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- LangChain4j 核心能力 --><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId></dependency><!-- Streaming 支持(用于 SSE 流式返回) --><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId></dependency><!-- JAX-RS SSE 所需(含 SseEventSink) --><dependency><groupId>org.glassfish.jersey.core</groupId><artifactId>jersey-server</artifactId></dependency><dependency><groupId>org.glassfish.jersey.media</groupId><artifactId>jersey-media-sse</artifactId></dependency><!-- 监控 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- 链路追踪 --><dependency><groupId>io.micrometer</groupId><artifactId>micrometer-tracing-bridge-otel</artifactId></dependency><dependency><groupId>io.opentelemetry</groupId><artifactId>opentelemetry-exporter-zipkin</artifactId></dependency><!-- AOP --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- MapDB --><dependency><groupId>org.mapdb</groupId><artifactId>mapdb</artifactId><version>3.0.9</version></dependency><!-- for Flux<String> support --><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-reactor</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
  1. 编译
    <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

API KEY 申请

DeepSeek

https://platform.deepseek.com/api_keys

点击这里创建API KEY,然后需要充值额度。

Qwen-Max

https://bailian.console.aliyun.com/?tab=model#/model-market

阿里云百炼平台每天有2000Token额度可以免费使用

配置文件

注意将自己的API_KEY保存至项目环境变量中,以保证数据安全。

langchain4j:models:- name: deepseekapi-key: ${LANGCHAIN4J_OPEN_AI_DEEPSEEK_API_KEY}model-name: deepseek-chatendpoint: "https://api.deepseek.com/v1"log-requests: falselog-responses: truemaxTokens: 500temperature: 0.7timeOut: 60- name: qwenapi-key: ${LANGCHAIN4J_OPEN_AI_QWEN_API_KEY}model-name: qwen3-maxendpoint: "https://dashscope.aliyuncs.com/compatible-mode/v1"log-requests: falselog-responses: truemaxTokens: 500temperature: 0.7timeOut: 60

配置读取

package org.xjl.model.provider.config;import jakarta.annotation.PostConstruct;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;@Data
@Configuration
@ConfigurationProperties(prefix = "langchain4j")
public class ModelProperties {private List<ModelConfig> models;public Set<String> modelName;@Datapublic static class ModelConfig {private String name;private String apiKey;private String modelName;private String endpoint;private Boolean logRequests;private Boolean logResponses;private Integer maxTokens;private Double temperature;private Integer timeOut;}@PostConstructpublic void init() {if(models != null){modelName = models.stream().map(ModelConfig::getName).collect(Collectors.toSet());}}}

配置注入

package org.xjl.model.provider.config;import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;import java.time.Duration;@Slf4j
@Configuration
public class ModelConfig implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {private Environment environment;private static final String MODEL_CONFIG_PREFIX = "langchain4j";@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {log.info("Starting to register model beans...");try {// 使用 Binder API 手动绑定配置ModelProperties modelProperties = Binder.get(environment).bind(MODEL_CONFIG_PREFIX, ModelProperties.class).orElse(null);if (modelProperties == null || modelProperties.getModels() == null || modelProperties.getModels().isEmpty()) {log.warn("No models configured in langchain4j.models");return;}log.info("Found {} model configurations", modelProperties.getModels().size());modelProperties.getModels().forEach(modelConfig -> {log.info("Registering model bean: name={}, modelName={}", modelConfig.getName(), modelConfig.getModelName());GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(OpenAiStreamingChatModel.class);beanDefinition.setInstanceSupplier(() -> OpenAiStreamingChatModel.builder().apiKey(modelConfig.getApiKey()).modelName(modelConfig.getModelName()).baseUrl(modelConfig.getEndpoint()).logRequests(modelConfig.getLogRequests()).logResponses(modelConfig.getLogResponses()).maxTokens(modelConfig.getMaxTokens()).temperature(modelConfig.getTemperature()).timeout(Duration.ofSeconds(modelConfig.getTimeOut())).strictJsonSchema(true).build());// 使用 name 作为 Bean 名称(如 "qwen", "deepseek")registry.registerBeanDefinition(modelConfig.getName(), beanDefinition);log.info("Successfully registered bean: {}", modelConfig.getName());});log.info("Model bean registration completed");} catch (Exception e) {log.error("Failed to register model beans", e);throw new RuntimeException("Failed to register model beans", e);}}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 不需要实现}
}

定义模型对话接口

package org.xjl.model.provider.core.memory;import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.UserMessage;
import reactor.core.publisher.Flux;/*** AI助手接口 - 支持多会话对话*/
public interface Assistant {/*** 同步对话接口* @param memoryId 会话ID(用于区分不同用户/会话)* @param userMessage 用户消息* @return AI回复*/
//    @SystemMessage("你是一个复读机,接下来请你重复回答:{{memoryId}}.")String chat(@MemoryId int memoryId, @UserMessage String userMessage);/*** 流式对话接口* @param memoryId 会话ID(用于区分不同用户/会话)* @param userMessage 用户消息* @return AI回复*/Flux<String> chatStream(@MemoryId int memoryId, @UserMessage String userMessage);
}

模型Service

package org.xjl.model.provider.core.service;import reactor.core.publisher.Flux;public interface ChatClientService {Flux<String> chatStream(int sessionId, String message,String modelName);}
package org.xjl.model.provider.core.service.impl;import com.alibaba.fastjson2.JSON;
import dev.langchain4j.data.message.ToolExecutionResultMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.xjl.model.provider.core.memory.Assistant;
import org.xjl.model.provider.core.service.ChatClientService;
import org.xjl.model.provider.core.tools.*;
import reactor.core.publisher.Flux;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Slf4j
@Service
public class ChatClientServiceImpl implements ChatClientService {@Autowiredprivate ApplicationContext applicationContext;// 工具注入@Autowiredprivate CalculatorTool calculatorTool;@Autowiredprivate DateTimeTool dateTimeTool;@Autowiredprivate WeatherTool weatherTool;@Autowiredprivate StringUtilTool stringUtilTool;@Autowiredprivate SystemInfoTool systemInfoTool;public ConcurrentHashMap<String,Assistant> assistantMap = new ConcurrentHashMap<>();@PostConstructpublic void init() {Map<String,OpenAiStreamingChatModel> modelContext = applicationContext.getBeansOfType(OpenAiStreamingChatModel.class);log.info("Model Bean List = {}", JSON.toJSONString(modelContext));if(!modelContext.isEmpty()){modelContext.forEach((k,v)->{Assistant a = AiServices.builder(Assistant.class).streamingChatModel(v).chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10)).build();assistantMap.put(k,a);});}log.info("AI Assistants initialized successfully!!!");}@Overridepublic Flux<String> chatStream(int sessionId, String message, String modelName) {return assistantMap.get(modelName).chatStream(sessionId,message);}
}

Controller层

package org.xjl.model.provider.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.xjl.model.provider.config.ModelProperties;
import org.xjl.model.provider.core.service.ChatClientService;
import reactor.core.publisher.Flux;import java.util.Set;import static org.springframework.http.MediaType.TEXT_EVENT_STREAM_VALUE;@Slf4j
@RestController
@RequestMapping("/model/provider")
public class ChatClient {@Autowiredprivate ModelProperties modelProperties;@Autowiredprivate ChatClientService qwenClientService;/*** AiService 流式对话接口* @param message* @return*/@PostMapping(value = "/stream", produces = TEXT_EVENT_STREAM_VALUE)public Flux<String> streamingAssistant(@RequestBody String message, @RequestParam("sessionId") int sessionId,@RequestParam("modelName") String modelName) {Assert.isTrue(modelProperties.getModelName().contains(modelName), "model is not exists");return qwenClientService.chatStream(sessionId,message,modelName);}@GetMapping("/modelName")public Set<String> getModelName() {return modelProperties.getModelName();}}

测试

curl --location 'http://localhost:8080/model/provider/stream?sessionId=1&modelName=qwen' \
--header 'Content-Type: text/plain' \
--data '你好'
http://www.dtcms.com/a/561810.html

相关文章:

  • Raft协议
  • 快速建设网站视频教程网站内容质量
  • 建设银行网站登不上牛商网做网站的思路
  • C语言程序代码(四)
  • 仿射变换的图像配准技术
  • wordpress看文网站芜湖营销网站建设
  • 泰州企业建站程序做购物网站的图标从哪里来
  • 1. Linux C++ muduo 库学习——库的编译安装
  • C++中的多态
  • C++ 使用 SQLite3 数据库
  • 郑州做网站的专业公司有哪些导购网站自己做电商
  • 松江品划网站建设推广美食网站建设策划书范文
  • 网站建设 全包 模板安徽省建设干部学校网站关停
  • 从空间几何到地球重量——张祥前质量定义方程的实证推导
  • 做网站有什么注意事项新手怎样做网络营销推广
  • 网站账户上的余额分录怎么做做网站的目的是什么
  • Wan-AI/Wan2.2-Animate-14B
  • 杂记 17
  • 国际营销网站建设新型实体企业100强
  • 载带 东莞网站建设英文网站搜索
  • 【Java】关于mybatis动态拼接SQL实现动态查询时遇到的一些问题
  • 做电影网站会违法吗网站模块怎么恢复
  • 网站程上传服务商类型是什么意思
  • 3.基础--数据模型
  • 设计logo网站生成器个人电脑做网站服务器网站
  • 49.渗透-Yakit-基础模块应用(爆破与未授权检测)
  • Taro 开发快速入门手册
  • html5网络公司网站模板wordpress 左右翻页
  • Python GUI 编程(Tkinter)
  • 外贸商业网站建设重庆专业的网站建设公司