Java+AI技术栈选型实战:基于Spring AI与LangChain4j构建智能航空客服系统
2026/8/25 7:35:48 网站建设 项目流程

大家好,我是专注于Java后端与AI应用落地的技术博主。最近在规划一个智能航空客服项目时,面对琳琅满目的AI技术栈,从Spring AI、LangChain4j到各种Agent框架,着实经历了一番选型纠结。网上资料要么是概念科普,要么是单一框架的“Hello World”,缺乏一个从Java开发者视角出发、贯穿业务场景的完整技术选型与实战指南。

本文正是为了解决这个问题。我将以“智能航空客服”为业务背景,系统性地拆解Java+AI技术栈的选型逻辑,并手把手带你完成一个融合了RAG、AI Agent和Spring AI Alibaba的核心模块实战。无论你是想将AI能力集成到现有Java系统,还是从零开始构建AI应用,这篇文章都能为你提供清晰的路径和可复用的代码。

1. 背景与核心概念:为什么Java开发者需要关注AI技术栈?

在传统的Java开发领域,我们擅长处理高并发、复杂业务逻辑和稳定的事务。然而,当业务需求扩展到智能问答、内容生成、意图理解时,传统的规则引擎和模板匹配就显得力不从心。大语言模型(LLM)的出现,为这些场景提供了新的解决方案。

对于Java团队而言,直接调用OpenAI等云端API是最快的方式,但会带来数据安全、网络延迟、成本不可控和模型能力固化等问题。因此,一套能够灵活集成、支持本地模型、且符合Java工程化规范的技术栈变得至关重要。

核心概念解析:

  • Spring AI: Spring官方推出的AI应用开发框架。它抽象了不同AI提供商(如OpenAI、Azure OpenAI、Ollama)的接口,让开发者通过统一的ChatClientEmbeddingClient等与AI模型交互,极大地简化了集成工作。其核心理念是“为AI工程带来Spring生态的便利性”。
  • LangChain4j: Java版的LangChain。它提供了一套更高层次的抽象,用于构建由LLM驱动的应用程序。其核心价值在于“链”(Chain)和“工具”(Tool)的概念,能轻松编排多个LLM调用、工具执行和记忆管理,是构建复杂AI Agent的理想选择。
  • AI Agent(智能体): 一个能够感知环境、进行决策并执行动作以完成目标的系统。在本文语境下,它指的是一个能调用工具(如查询数据库、执行代码)、拥有记忆和规划能力的LLM增强程序。例如,一个航空客服Agent可以理解用户问题,自动查询航班信息、政策,并组织语言回复。
  • RAG(检索增强生成): 解决LLM“幻觉”(生成虚假信息)和知识滞后问题的关键技术。其原理是:先将外部知识库(如航空手册、政策文档)向量化存储;当用户提问时,先从向量库中检索出最相关的文档片段;然后将这些片段作为上下文,连同问题一起提交给LLM生成答案。这能确保答案基于事实且实时。
  • Spring AI Alibaba: 阿里巴巴基于Spring AI生态的扩展,提供了与阿里云百炼、灵积等平台模型服务的深度集成,同时也包含了一些针对国内开发环境的优化和额外组件。

为什么是“Java + AI”?Java拥有庞大的企业级应用存量,其稳定性、可维护性和丰富的中间件生态是企业核心系统的基石。将AI能力无缝融入现有Java体系,而不是推倒重来或用Python另起炉灶,是成本最低、效益最高的技术演进路径。上述技术栈正是为此而生。

2. 环境准备与版本说明

在开始实战前,我们需要搭建好开发环境。本文将使用最通用的Spring Boot 3.x架构进行演示。

基础环境:

  • JDK: 17 或 21(推荐17,长期支持版本)
  • Maven: 3.6+
  • IDE: IntelliJ IDEA 或 VS Code
  • 模型服务:
    • 选项A(云端,快速上手):OpenAI API Key 或 阿里云通义千问API Key。
    • 选项B(本地,数据安全):使用Ollama在本地运行开源模型(如qwen2.5:7b,llama3.2:3b)。需要安装Docker或直接下载Ollama。

项目初始化:使用 Spring Initializr 创建一个Spring Boot项目。

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.2.x (建议选择当前稳定版)
  • Dependencies: 先选择Spring Web

生成项目后,用IDE打开。接下来的依赖我们将手动添加到pom.xml

3. 技术栈选型深度解析与对比

面对众多选择,如何决策?下图清晰地展示了各组件在智能航空客服系统中的角色与协作关系:

flowchart TD A[用户提问<br>“明天北京飞上海的航班有哪些?”] --> B(航空客服AI Agent) subgraph B[智能体决策与执行] B1{Agent分析用户意图} -->|需查询实时信息| B2[调用“航班查询工具”] B1 -->|需依据政策回答| B3[调用“RAG知识库检索工具”] B1 -->|简单对话| B4[直接调用LLM生成回复] B2 --> B5[获取结构化航班数据] B3 --> B6[获取相关政策文档片段] end B5 & B6 --> C{Agent合成最终答案} C --> D[回复用户<br>“明天共有X班航班,最早一班是...”] subgraph E[支撑技术栈] E1[Spring AI<br>统一模型接口] E2[LangChain4j<br>Agent与链编排] E3[向量数据库<br>存储知识库] E4[本地/云端LLM<br>大语言模型] end E1 & E2 & E3 & E4 -- 为智能体提供能力 --> B

3.1 Spring AI vs. LangChain4j:定位与选择

这是选型中最常见的困惑。两者并非互斥,而是互补。

  • Spring AI模型交互层的抽象。它解决的是“如何用统一的方式调用不同模型”的问题。如果你的应用核心是简单地发送Prompt、获取Completion或生成Embedding,那么引入Spring AI就足够了。它轻量、与Spring生态无缝集成。
  • LangChain4j应用编排层的框架。它解决的是“如何构建复杂的、多步骤的AI应用”问题。当你需要构建一个能自动选择工具、管理对话历史、进行条件判断的Agent时,LangChain4j提供了更强大的抽象。

选型建议:

  • 简单集成场景: 仅需调用模型API ->首选Spring AI
  • 复杂Agent场景: 需要工具调用、记忆、复杂链式逻辑 ->使用LangChain4j,它底层可以集成Spring AI的客户端。
  • 组合使用最佳实践是使用Spring AI 作为模型访问层,同时使用LangChain4j 作为应用编排层。这样既能享受Spring的配置管理、依赖注入,又能利用LangChain4j强大的Agent能力。

3.2 RAG技术栈选型

构建RAG系统需要三个核心组件:

  1. 文本嵌入模型(Embedding Model): 将文本转换为向量。可选Spring AI的EmbeddingClient或LangChain4j的嵌入接口。
  2. 向量数据库(Vector Database): 存储和检索向量。Java生态中,Redis(通过RediSearch模块)、PostgreSQL(通过pgvector扩展)、MilvusWeaviate都是常见选择。
  3. 检索器(Retriever): 执行相似性搜索。

选型建议(针对Java项目):

  • 轻量级/快速验证: 使用Redis。很多项目已在使用Redis,增加RediSearch模块成本低,且Spring Data Redis支持良好。
  • 已有PostgreSQL: 使用pgvector。无需引入新组件,利用现有数据库,管理简单。
  • 大规模、高并发向量检索: 考虑MilvusWeaviate等专业向量数据库。

本文为简化演示,将使用内存向量存储,但这仅适用于演示,生产环境务必替换为上述持久化方案。

3.3 AI Agent框架选型

除了LangChain4j,还有agentscope-java等框架。LangChain4j社区活跃,文档相对完善,且与LangChain(Python)概念对齐,学习成本较低,是目前Java生态中构建Agent的主流选择。Spring AI Alibaba也提供了Agent相关的初步支持,但成熟度和生态丰富度仍在发展中。

结论:对于智能航空客服这类需要工具调用(查航班、查政策)的复杂场景,LangChain4j是更成熟和强大的选择

4. 完整实战:构建智能航空客服核心模块

我们将构建一个具备以下能力的客服Agent原型:

  1. RAG知识库问答: 回答关于行李规定、退改签政策的问题。
  2. 工具调用: 查询“模拟”的航班信息。
  3. 意图识别与路由: 自动判断用户问题属于哪一类,并调用相应能力。

4.1 项目结构与依赖引入

首先,在pom.xml中添加关键依赖。

<!-- Spring Boot 基础 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring AI - 核心抽象,支持OpenAI/Ollama等 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <!-- 请查看Spring AI官方文档获取最新版本 --> <version>0.8.1</version> </dependency> <!-- LangChain4j - 核心库 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>0.31.0</version> </dependency> <!-- LangChain4j 与 Spring AI 集成 --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-spring-ai</artifactId> <version>0.31.0</version> </dependency> <!-- LangChain4j 内存向量库(仅用于演示) --> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId> <!-- 内置的轻量级嵌入模型 --> <version>0.31.0</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-store-embedding-in-memory</artifactId> <version>0.31.0</version> </dependency>

4.2 配置模型连接

application.yml中配置Spring AI。这里以本地Ollama(运行qwen2.5:7b模型)为例,确保数据安全。

spring: ai: openai: # 如果使用本地Ollama,base-url指向本地服务 base-url: http://localhost:11434/v1 api-key: ollama # Ollama不需要真实的key,但属性需要存在 chat: options: model: qwen2.5:7b # 指定Ollama中已拉取的模型名称 temperature: 0.7

4.3 实现RAG知识库

第一步,创建知识库服务,用于加载政策文档并支持检索。

// 文件路径:src/main/java/com/example/ai航空客服/service/KnowledgeBaseService.java package com.example.ai航空客服.service; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import jakarta.annotation.PostConstruct; import org.springframework.ai.embedding.EmbeddingClient; import org.springframework.stereotype.Service; import dev.langchain4j.store.embedding.EmbeddingMatch; import java.util.List; import java.util.stream.Collectors; @Service public class KnowledgeBaseService { private final EmbeddingClient embeddingClient; // Spring AI的嵌入客户端 private final EmbeddingStore<TextSegment> embeddingStore; public KnowledgeBaseService(EmbeddingClient embeddingClient) { this.embeddingClient = embeddingClient; // 生产环境请替换为 RedisEmbeddingStore 或 PgVectorEmbeddingStore this.embeddingStore = new InMemoryEmbeddingStore<>(); } @PostConstruct public void init() { // 模拟加载航空公司的政策文档 List<String> policyDocuments = List.of( "经济舱旅客的免费托运行李额为20公斤,尺寸三边之和不超过158厘米。", "商务舱旅客的免费托运行李额为30公斤,尺寸三边之和不超过158厘米。", "航班起飞前2小时以上可以免费办理退票,起飞前2小时内退票收取20%手续费。", "随身携带的液体物品每件容器容积不得超过100毫升,并需放入透明塑料袋中。", "婴儿票(2周岁以下)不占座,票价为成人全价票的10%。" ); // 使用LangChain4j的Ingestor来分割文本、生成向量并存储 EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder() .embeddingModel(new SpringAiEmbeddingModel(embeddingClient)) // 适配Spring AI客户端 .embeddingStore(embeddingStore) .textSegmenter(/* 使用默认分割器 */) .build(); // 将文档转换为TextSegment并摄入向量库 List<TextSegment> segments = policyDocuments.stream() .map(TextSegment::from) .collect(Collectors.toList()); ingestor.ingest(segments); System.out.println("知识库初始化完成,已加载 " + policyDocuments.size() + " 条政策。"); } /** * 根据用户问题检索最相关的政策片段 */ public String retrieveRelevantPolicy(String userQuestion) { // 1. 将问题转换为向量 float[] queryEmbedding = embeddingClient.embed(userQuestion).getOutput(); // 2. 在向量库中搜索最相似的3个片段 List<EmbeddingMatch<TextSegment>> relevantMatches = embeddingStore.findRelevant( dev.langchain4j.data.embedding.Embedding.from(queryEmbedding), 3, 0.6 // 相似度阈值 ); // 3. 合并检索结果作为上下文 if (relevantMatches.isEmpty()) { return "未找到相关政策信息。"; } return relevantMatches.stream() .map(match -> match.embedded().text()) .collect(Collectors.joining("\n\n")); } }

4.4 定义Agent工具(Tool)

工具是Agent扩展能力的关键。这里定义两个工具:航班查询工具和知识库查询工具。

// 文件路径:src/main/java/com/example/ai航空客服/tool/FlightQueryTool.java package com.example.ai航空客服.tool; import dev.langchain4j.agent.tool.Tool; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.util.List; import java.util.stream.Collectors; @Component public class FlightQueryTool { // 模拟一个航班数据库 private static final List<Flight> mockFlights = List.of( new Flight("CA1501", "北京", "上海", LocalDate.now().plusDays(1), "08:00", "10:20", 1200, 50), new Flight("MU5102", "北京", "上海", LocalDate.now().plusDays(1), "10:30", "12:45", 1100, 120), new Flight("CZ6166", "广州", "上海", LocalDate.now().plusDays(1), "14:00", "16:10", 900, 30) ); /** * 根据条件查询航班信息 * @Tool 注解让LangChain4j能识别这是一个可供Agent调用的工具 */ @Tool("根据出发地、目的地和日期查询可用的航班信息。") public String queryFlights(String departureCity, String arrivalCity, String date) { LocalDate queryDate = LocalDate.parse(date); List<Flight> result = mockFlights.stream() .filter(f -> f.departureCity.equals(departureCity)) .filter(f -> f.arrivalCity.equals(arrivalCity)) .filter(f -> f.date.equals(queryDate)) .collect(Collectors.toList()); if (result.isEmpty()) { return String.format("未找到%s从%s飞往%s的航班。", date, departureCity, arrivalCity); } return result.stream() .map(f -> String.format("航班号:%s, 时间:%s-%s, 价格:¥%d, 余票:%d", f.flightNumber, f.departureTime, f.arrivalTime, f.price, f.seatsAvailable)) .collect(Collectors.joining("\n")); } // 内部航班数据类 static class Flight { String flightNumber; String departureCity; String arrivalCity; LocalDate date; String departureTime; String arrivalTime; int price; int seatsAvailable; // 构造函数、getter/setter 省略... } }
// 文件路径:src/main/java/com/example/ai航空客服/tool/PolicyQueryTool.java package com.example.ai航空客服.tool; import com.example.ai航空客服.service.KnowledgeBaseService; import dev.langchain4j.agent.tool.Tool; import org.springframework.stereotype.Component; @Component public class PolicyQueryTool { private final KnowledgeBaseService knowledgeBaseService; public PolicyQueryTool(KnowledgeBaseService knowledgeBaseService) { this.knowledgeBaseService = knowledgeBaseService; } @Tool("查询航空公司的行李、退改签、乘机等政策规定。") public String queryPolicy(String question) { // 调用RAG知识库服务获取相关信息 String context = knowledgeBaseService.retrieveRelevantPolicy(question); return "根据相关政策,信息如下:\n" + context; } }

4.5 构建并运行AI Agent

这是最核心的部分,我们将使用LangChain4j创建一个具备工具调用能力的AI Agent。

// 文件路径:src/main/java/com/example/ai航空客服/service/AirlineCustomerServiceAgent.java package com.example.ai航空客服.service; import dev.langchain4j.agent.tool.ToolSpecification; import dev.langchain4j.memory.ChatMemory; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.service.AiServices; import dev.langchain4j.service.TokenStream; import com.example.ai航空客服.tool.FlightQueryTool; import com.example.ai航空客服.tool.PolicyQueryTool; import org.springframework.ai.chat.client.ChatClient; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import java.util.List; @Service public class AirlineCustomerServiceAgent { private final Assistant assistant; // 定义Agent的交互接口 interface Assistant { String chat(String userMessage); Flux<String> chatStream(String userMessage); // 流式响应(可选) } public AirlineCustomerServiceAgent(ChatClient.Builder chatClientBuilder, FlightQueryTool flightTool, PolicyQueryTool policyTool) { // 1. 通过Spring AI创建LangChain4j可用的模型 ChatLanguageModel model = new SpringAiChatModel(chatClientBuilder.build()); // 2. 创建聊天记忆,保留最近10轮对话 ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10); // 3. 使用AiServices.builder()构建Agent this.assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .chatMemory(chatMemory) .tools(flightTool, policyTool) // 注入工具 .build(); } /** * 与客服Agent交互 */ public String chat(String userMessage) { return assistant.chat(userMessage); } }

4.6 创建REST API控制器

最后,暴露一个HTTP接口供前端或测试调用。

// 文件路径:src/main/java/com/example/ai航空客服/controller/ChatController.java package com.example.ai航空客服.controller; import com.example.ai航空客服.service.AirlineCustomerServiceAgent; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/chat") public class ChatController { private final AirlineCustomerServiceAgent agent; public ChatController(AirlineCustomerServiceAgent agent) { this.agent = agent; } @PostMapping public String chat(@RequestBody ChatRequest request) { if (request == null || request.getMessage() == null || request.getMessage().trim().isEmpty()) { return "请输入您的问题。"; } return agent.chat(request.getMessage()); } // 简单的请求体 public static class ChatRequest { private String message; // getter/setter 省略... } }

4.7 运行与验证

  1. 启动你的Spring Boot应用。
  2. 使用curl、Postman或任何HTTP客户端测试。
    curl -X POST http://localhost:8080/api/chat \ -H "Content-Type: application/json" \ -d '{"message": "我明天从北京飞上海,有什么航班?"}'
    预期输出(示例)
    为您查询到明天从北京飞往上海的航班如下: 航班号:CA1501, 时间:08:00-10:20, 价格:¥1200, 余票:50 航班号:MU5102, 时间:10:30-12:45, 价格:¥1100, 余票:120
  3. 测试政策查询:
    curl -X POST http://localhost:8080/api/chat \ -H "Content-Type: application/json" \ -d '{"message": "经济舱的行李额是多少?"}'
    预期输出(示例)
    根据相关政策,信息如下: 经济舱旅客的免费托运行李额为20公斤,尺寸三边之和不超过158厘米。
  4. 测试复杂意图(Agent自动判断并组合工具):
    curl -X POST http://localhost:8080/api/chat \ -H "Content-Type: application/json" \ -d '{"message": "我想订明天北京到上海的航班,另外想问下退票政策"}'
    Agent可能会先调用FlightQueryTool查询航班,再调用PolicyQueryTool查询退票政策,最后将两者信息整合成一段连贯的回答。

5. 常见问题与排查思路

在集成过程中,你可能会遇到以下典型问题:

问题现象常见原因解决思路
启动报错:No qualifying bean of type 'EmbeddingClient'未正确引入Spring AI starter或配置有误。1. 检查pom.xmlspring-ai-openai-spring-boot-starter依赖是否正确。
2. 检查application.ymlspring.ai.openai.*配置,特别是base-urlapi-key
Agent不调用工具,直接回答“我不知道”1. 工具描述不清晰。
2. 模型能力不足(特别是小参数本地模型)。
3. Prompt未引导模型使用工具。
1. 优化@Tool注解中的描述,确保清晰、具体。
2. 尝试使用能力更强的模型(如GPT-4、DeepSeek-V3)。
3. 在构建AiServices时,可以通过.promptTemplate()自定义系统提示词,明确要求其使用工具。
RAG检索结果不相关1. 嵌入模型不适合中文。
2. 文本分割(Chunk)策略不合理。
3. 相似度阈值设置不当。
1. 更换为针对中文优化的嵌入模型,如BAAI/bge-small-zh
2. 调整文本分割的大小和重叠度。
3. 调整findRelevant方法中的相似度阈值和返回数量。
调用本地Ollama模型超时或失败1. Ollama服务未启动。
2. 模型未正确拉取。
3. 网络端口被占用。
1. 运行ollama serve启动服务。
2. 运行ollama pull qwen2.5:7b拉取模型。
3. 确认application.yml中的base-url(默认http://localhost:11434)是否正确。
OutOfMemoryError: Insufficient memory本地模型(特别是7B以上)或向量操作消耗内存过大。1. 为JVM增加堆内存:-Xmx8g -Xms4g
2. 考虑使用量化版本模型(如qwen2.5:7b-q4_K_M)。
3. 生产环境使用云端API或专用推理服务器。

6. 最佳实践与工程建议

将AI能力投入生产环境,远不止让代码跑通那么简单。以下是一些关键的工程化考量:

6.1 配置与安全

  • 密钥管理: 绝对不要将API Key硬编码在代码或配置文件中。使用Spring Cloud Config、Apollo、环境变量或云厂商的密钥管理服务。
  • 配置分离: 将模型配置(如base-url, model-name)放在application-{profile}.yml中,便于不同环境(dev/test/prod)切换。
  • 网络与代理: 国内访问OpenAI等可能需要配置网络代理,可在RestTemplateWebClient层面统一处理。

6.2 性能与稳定性

  • 超时与重试: 为AI模型调用配置合理的连接超时、读取超时,并实现重试机制(可使用Spring Retry或Resilience4j)。
  • 限流与熔断: AI服务可能不稳定或昂贵。使用Sentinel或Resilience4j对模型调用进行限流和熔断,防止雪崩。
  • 异步与非阻塞: 对于耗时的AI生成或RAG检索,考虑使用@Async或WebFlux进行异步处理,避免阻塞主线程。

6.3 RAG优化

  • 高质量知识库: RAG的效果严重依赖原始文档质量。需对文档进行清洗、去重、结构化。
  • 智能分块(Chunking): 不要简单按固定字数分割。尝试按段落、标题或使用语义分割算法,保证块的完整性。
  • 元数据过滤: 在检索时,除了向量相似度,还可结合文档类型、更新时间等元数据进行过滤,提升精度。
  • 重排序(Re-ranking): 在初步向量检索后,使用一个更精细的交叉编码器模型对结果进行重排序,进一步提升Top1答案的相关性。

6.4 Agent设计

  • 工具设计原则: 工具应职责单一、接口明确。工具的描述(@Tool注解)要足够详细,让LLM能准确理解其用途。
  • 验证与回退: Agent调用的工具(如航班查询)返回的结果,在展示给用户前应进行基本的逻辑或格式验证。对于工具调用失败,要有明确的回退话术。
  • 可控性与审计: 记录Agent的完整思考过程(Chain-of-Thought)和工具调用日志,这对于调试、优化和满足合规性要求至关重要。

6.5 监控与可观测性

  • 关键指标: 监控AI调用的延迟、成功率、Token消耗量、费用。
  • 链路追踪: 集成Micrometer、SkyWalking等,将一次用户问答背后的RAG检索、LLM调用、工具执行串联起来,便于排查问题。
  • 效果评估: 建立人工评估或自动化评估机制,定期检查问答准确率、相关性,持续迭代模型、提示词和知识库。

通过本文的梳理,你应该对Java生态下的AI技术栈选型有了清晰的认识,并成功搭建了一个具备RAG和工具调用能力的智能航空客服原型。从简单的模型调用到复杂的Agent编排,Java开发者完全有能力在熟悉的生态内构建强大的AI应用。接下来的方向可以是接入真实的航班API、丰富知识库、优化提示词工程,并将向量存储和模型服务部署到生产环境。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询