尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Java企业级Agent实战:Spring AI 2.0 + Langchain4j构建航空智能助手

Java企业级Agent实战:Spring AI 2.0 + Langchain4j构建航空智能助手 如果你是一个 Java 后端工程师最近一年大概没少听到这样的需求“咱们这个系统要不要也接一个大模型”可当你真正动手做的时候会发现中文技术社区里AI 应用教程的主角不是 Python 就是 JavaScriptJava 往往只在“Java 是不是没落了”的争论帖里出现。这种感觉很容易让人误判Java 团队是不是做不了 AI 应用这篇文章想说的第一个判断是Java 团队做 AI 应用真正的优势从来不在模型而在业务系统。LLM 只是一个推理引擎它没有你的航班数据库不了解你的行李托运规定文档更不能直接操作你的值机接口。Spring AI 2.0 和 Langchain4j 要做的事情本质上是把这三样东西标准化地交到模型手里让模型变成一个会调用业务系统的“代理”。因此本文用一个非常典型的场景——航空领域智能助手来拆解一套完整的企业级 Agent 实现路线。这个场景的好处是它同时包含实时航班查询这种强业务操作、行李托运和延误补偿这种强知识文档以及多轮对话、工具组合、任务拆解这些 Agent 典型诉求。技术选型上主线采用 Spring AI 2.0同时结合 Langchain4j 的工具调用与 AiServices 思想最终把 Tools、RAG、Agent 串成一条从零到生产可用的演进路径。读完这篇文章你至少能搞清楚三件事Spring AI 2.0 和 Langchain4j 到底是什么关系在 Java 项目里RAG、工具调用、Agent 编排各自解决什么问题以及怎么从零跑通一个“能查航班、能答政策、能处理多轮对话”的航空智能助手。常见问题章节里还集中整理了 DeepSeek 不输出 content、Java 内存溢出、向量库检索不相关等高频坑位。1. 这篇文章真正要解决的问题先说说为什么这类项目值得关注。过去两年Java 团队接入大模型的典型做法要么是把一个 Python 写的 AI 服务单独部署在外围Java 通过 HTTP 调用要么是只做最简单的“大模型聊天接口”把用户的问题丢给模型再把模型的回答返回给前端。第一种做法的问题是系统割裂AI 服务拿不到业务上下文运维和权限控制都要多维护一套体系第二种做法的问题是太浅模型是“没有手”的它查不了实时航班也回答不了你企业内部的知识。企业级 Agent 要解决的正是这两层问题。它要求模型不仅能“说话”还能“做事”回答问题之前先去检索企业内部知识库需要实时数据时主动去调用业务 API多轮对话中记得住上下文最后把结果用用户能理解的方式组织出来。这才是 Spring AI 2.0、Langchain4j 这类框架真正关心的能力。再来看当前 Java AI 应用开发的现状。Spring AI 是 Spring 官方推出的 AI 应用框架它的核心价值是把模型接入、Prompt 模板、输出解析、向量存储这些能力做成 Spring Boot 的自动配置让 Java 开发者用最熟悉的依赖注入方式接入 AI。Langchain4j 则是 Java 社区中发展较早的 LLM 应用框架它提供了 AiServices 这种接口式编程模型以及比较成熟的 Tool 注解、ChatMemory、RAG 组件。两者不是简单的二选一甚至可以互相借鉴。对于已经深度使用 Spring Boot 的团队推荐以 Spring AI 作为主线对于更看重 Agent 高层封装、想少写样板代码的团队Langchain4j 是很好的参考方案。所以这篇文章真正要解决的问题可以概括成一句话在 Java/Spring Boot 技术栈下如何把大模型、业务工具、企业内部知识库三者整合成一个可落地的 Agent 应用。我们会用航空智能助手这个场景把每一步的关键设计和技术选型讲清楚。2. 核心概念从 LLM 到 Agent 的五个层次在写代码之前先建立一套统一的概念框架。很多教程一上来就讲 RAG 或 Agent但读者往往连“为什么要用 RAG”“工具调用和 Agent 有什么区别”都没想明白。这里用一个五层模型来理解一个完整的 LLM 应用。第一层是 LLM 本身也就是你选用的模型服务比如 DeepSeek、通义千问、智谱或者本地部署的 Qwen 系列。这一层只负责“根据输入生成文本”它没有企业数据也没有执行能力。第二层是 Embedding也就是文本向量化。它的作用是把一段文字转换成一串浮点数让语义相近的文本在向量空间中距离更近。RAG 的检索环节依赖这个能力。第三层是 RAG全称 Retrieval-Augmented Generation检索增强生成。它的标准流程是先从知识库中检索与用户问题相关的文档片段再把片段作为上下文拼进 Prompt最后让模型基于这些片段生成回答。RAG 解决的是“模型不知道企业内部知识”的问题让回答有依据、可追溯。第四层是 Tools也就是工具调用或者叫 Function Calling。它做的事情是把 Java 方法的能力描述给模型模型在回答过程中判断“要查实时航班数据了”于是返回一个调用请求Java 端执行方法再把结果交给模型继续生成。Tools 解决了“模型没有手”的问题。第五层是 Agent。Agent 不是一个具体 API而是一种编排策略。它让模型在对话中自主决定“要不要调用工具、调用哪个工具、检索完之后怎么回答”甚至可以连续多轮地规划工具调用步骤。严格来说RAG 和 Tools 都是 Agent 的“能力组件”Agent 是更高层的控制器。这里值得特别强调一个概念Agentic RAG。它是 RAG 和 Agent 的结合形态。传统 RAG 是不管用户问什么都强制去知识库里检索一遍Agentic RAG 则让模型先判断“这个问题是否需要检索”再决定检索策略。如果用户问的是“CA1234 航班几点起飞”模型应该去查实时航班接口而不是翻知识库如果用户问的是“宠物托运需要什么手续”模型才应该去检索行李政策文档。这种“先分流、再执行”的方式更接近真实业务场景。下面用一张表对比 Spring AI 和 Langchain4j 在这一整套能力上的侧重点能力维度Spring AI 2.0Langchain4j模型接入官方抽象支持 OpenAI 兼容接口、Ollama、通义等同样支持 OpenAI 兼容接口、Ollama 等Spring Boot 集成官方自动配置体验最顺需要手动创建 Bean也提供 Spring Boot Starter工具调用支持 Tool 注解和 FunctionCallback支持 Tool 注解提炼较早RAG提供文档读取、切分、向量存储、Advisor提供完整 RAG 组件可插拔性较好Agent 高层封装偏向组件组合开发者自行编排AiServices 接口式编程使用门槛较低适合场景Spring Boot 深度用户希望快速实现 Agent 原型或偏好接口封装需要说明的是两者的能力重叠度很高很多项目用其中任意一个都能完成。本文以 Spring AI 2.0 为主线实现航空助手同时用 Langchain4j 的写法做一个对照帮助你在选型时建立体感。3. 智能航空助手项目需求与整体架构航空场景很适合作为 Agent 项目的教学载体。它不像纯问答系统那样只需要 RAG也不像内部工单系统那样只需要工具调用它要求 RAG、Tools、Agent 三者协同工作。3.1 核心功能需求我们定义四个主要能力点第一航班实时查询。用户问“CA1234 航班现在准点吗”Agent 需要调用实时航班状态接口返回起飞到达时间、登机口、延误状态等信息。这是典型的 Tools 场景因为数据是实时变化的不能预先写入知识库。第二航空政策知识问答。用户问“托运宠物需要什么手续”“锂电池可以随身携带吗”“航班延误多久可以申请补偿”。这些内容来自民航规定和航司政策文档答案相对稳定适合用 RAG 实现并且回答时要能给出政策依据。第三多轮对话与记忆。用户先说“我想从北京去上海”接着问“明天有哪些航班”。Agent 要在第二轮中理解“明天”和“北京到上海”来自前文上下文这就是 ChatMemory 或对话管理器要解决的问题。第四组合任务编排。用户问“帮我查一下明天的 CA1234 航班如果延误了我能申请什么补偿”。这个问题同时涉及工具调用和知识检索Agent 需要先查航班状态再基于状态结果决定是否检索延误补偿政策。这是 Agent 编排能力的核心体现。3.2 技术架构整体架构可以理解为五个层次浏览器或小程序发起请求进入 Spring Boot 网关或 Controller向下是 Agent 编排层它负责接收用户提问、维护上下文、调用模型再向下是能力层包含工具调用器和 RAG 检索器工具调用器连接航班接口、值机接口等业务系统RAG 检索器连接文档解析服务和向量数据库最底层是模型层通过 OpenAI 兼容接口连接 DeepSeek、通义千问等模型服务。从部署视角看Spring Boot 应用是整个系统的核心。向量数据库在生产环境可以选用 Milvus开发阶段也可以先用内存向量库快速验证。知识文档可以放在对象存储或文件目录中通过定时任务或事件触发更新向量库。模型 API 的 Key 放在配置中心或环境变量中不建议硬编码在代码里。这种架构的好处是每一层职责清晰后续替换模型厂商、更换向量数据库、接入更多业务 API 时都不需要改动 Agent 编排层的核心逻辑。4. 环境准备与前置条件动手之前先把环境准备好。下面这些依赖不是死板的清单而是为了让项目能跑通的最小组件。4.1 基础运行环境组件版本建议说明JDK17 或 21Spring Boot 3.x 需要 JDK 17 起Spring Boot3.3.x 或更高与 Spring AI 2.0 匹配Maven3.9依赖管理模型 APIDeepSeek / 通义千问等需准备 API Key或本地部署 Ollama向量数据库Milvus 或开发期内存向量库存储知识文档向量文档解析PDFBox / Tika读取知识文档版本这一块要特别说明Spring AI 2.0 仍处于迭代期不同小版本的类名和配置项可能调整。本文示例采用官方 BOM 管理版本实际开发时建议先到 Spring AI 官方文档确认当前稳定版本不要照抄一个固定版本号。4.2 大模型服务选择最省事的做法是使用云端模型 API。DeepSeek 提供 OpenAI 兼容接口base-url 为https://api.deepseek.com/v1模型名常用deepseek-chat。通义千问也提供 OpenAI 兼容端点。如果你希望本地部署可以使用 Ollama 加载 Qwen2.5 系列模型Spring AI 原生支持 Ollama。这里有一个要注意的坑不同模型的“工具调用”能力不完全一致。Agent 项目非常依赖 Function Calling建议选择明确支持工具调用的模型。如果你在测试时发现模型始终不调用工具先检查模型名是否正确。4.3 向量数据库选择航空项目的知识库文档量通常不会特别大开发阶段完全可以用 Spring AI 内置的内存向量库跑通流程生产环境再切换到 Milvus。Milvus 是当前 Java 生态中集成比较成熟的向量数据库之一支持集合管理、混合检索和标量过滤适合企业级 RAG。如果你在本地没有 Milvus可以用 Docker 快速启动一个实例。Milvus 对内存有一定要求启动前建议给 Docker 分配足够的内存避免出现OutOfMemoryError。5. 核心流程拆解四步走完 Agent 项目很多教程只给你最终代码但不知道每一步为什么这么写。这里把航空助手的实现拆成四个步骤每一层都能独立运行、独立验证。5.1 第一步接通大模型这一步的目标是让 Spring Boot 项目里能发起一次模型对话。Spring AI 的做法很简单引入依赖、配置模型地址和 Key、注入 ChatClient 然后调用。这一步最容易出现的问题就是“连接 DeepSeek 不输出 content”。原因是部分推理模型在 OpenAI 兼容接口中返回了reasoning_content字段而标准 OpenAI 客户端只读取content字段于是你把接口调通了对吧但返回的 content 是空的。解决思路是优先使用对话模型如deepseek-chat或者升级 Spring AI 版本以支持 reasoning 内容解析。5.2 第二步构建 RAG 知识问答当用户问“宠物托运需要什么手续”时模型不可能凭空知道答案。RAG 的做法是提前把航空政策文档加载、切分、向量化存入向量库。用户提问时先从向量库检索相关片段把片段拼进 Prompt再让模型生成回答。这一步的难点不在调用 API而在“文档切分策略”。如果切分粒度过大检索结果可能噪音太多粒度过小又会丢失上下文。常用的做法是设置 chunk size 在 300 到 800 个字符之间并让相邻 chunk 保留少量重叠。更进阶的做法是在文档片段中加入元数据比如文档标题、条款编号、更新时间检索时可以利用元数据过滤。5.3 第三步暴露业务工具模型不能直接查询航班数据库但可以让模型“调用”一个 Java 方法。Spring AI 的 Tool 注解可以把一个类方法注册成工具方法名、参数描述、返回值都会作为元信息传给模型。这一步容易出现“模型不调用工具”或“调用参数错误”的问题。常见的解决办法是在 Tool 的 description 里面写清楚方法的用途、参数格式、返回值含义。模型其实是按描述来决定调用时机的描述越模糊调用越不准确。5.4 第四步Agent 编排最后一步是把前面的能力组合起来。Agent 不是一个新的框架而是一套“如何决定下一步做什么”的机制。Spring AI 的 ChatClient 可以同时配置默认工具和 RAG Advisor模型会在需要时自动选择工具调用或知识检索。这个阶段建议从简单场景开始验证先测“今天从北京到上海有哪些航班”再测“托运宠物需要注意什么”最后测组合问题“查一下明天的 CA1234 航班如果延误了能申请什么补偿”。每通过一个测试再增加新的能力和 new 工具。这样逐步扩展比一次性写一个大 Agent 更容易控制质量。6. 完整示例与代码实现下面进入代码实现环节。这个项目以 Spring AI 2.0 为主线完整演示模型接入、工具调用和 RAG 知识库三个核心模块。6.1 pom.xml 依赖配置创建一个 Spring Boot 项目加入 Web、Spring AI OpenAI 兼容客户端、Milvus 向量库和 PDFBox 解析依赖。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.3.5/version relativePath/ /parent dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version2.0.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring AI OpenAI 兼容接口支持 DeepSeek、通义千问等 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency !-- Spring AI Milvus 向量库支持 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-milvus/artifactId /dependency !-- PDF 文档解析 -- dependency groupIdorg.apache.pdfbox/groupId artifactIdpdfbox/artifactId version3.0.3/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies代码里强调一点spring-ai-bom的版本号应根据官方发布情况调整。在实际项目中更推荐用 Maven BOM 管理版本避免每个依赖单独写版本号导致冲突。6.2 application.yml 关键配置接下来配置模型接入和向量库连接。这里使用 DeepSeek 的 OpenAI 兼容端点作为示例。spring: application: name: aviation-agent ai: openai: base-url: https://api.deepseek.com/v1 api-key: ${AI_API_KEY} chat: options: model: deepseek-chat temperature: 0.7 vectorstore: milvus: client: host: localhost port: 19530 database-name: default collection-name: aviation_kb server: port: 8080API Key通过环境变量AI_API_KEY注入避免硬编码在配置文件中。Milvus 的 collection 需要提前定义好向量维度维度必须和 Embedding 模型输出的维度保持一致。例如使用通义千问的text-embedding-v3向量维度通常是 1024具体维度以你使用的模型为准。6.3 航班查询工具实现这是整个项目中最体现“Tools”价值的部分。我们定义两个工具方法查询航班状态和搜索航班列表。实际项目中这里应该调用航司 API 或者查询数据库在示例里先用返回固定文本的方式演示流程。package com.example.aviation.tool; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Component; Component public class FlightTools { Tool(description 根据航班号查询航班实时状态返回起飞时间、到达时间、登机口、延误状态) public String queryFlightStatus( ToolParam(description 航班号例如 CA1234) String flightNo, ToolParam(description 日期格式 yyyy-MM-dd) String date) { // 实际项目中改为调用航司接口或查询数据库 return 航班 flightNo 在 date 计划起飞 08:30计划到达 10:45当前状态准点 登机口B23行李转盘12。; } Tool(description 根据出发城市、到达城市和日期查询当日可用航班列表) public String searchFlights( ToolParam(description 出发城市例如北京) String departure, ToolParam(description 到达城市例如上海) String arrival, ToolParam(description 日期格式 yyyy-MM-dd) String date) { return 以下为 departure 到 arrival 在 date 的可用航班\n CA1234 08:00-10:15\n MU5678 10:30-12:45\n HU9012 14:20-16:35; } }这段代码的关键在于Tool注解。Spring AI 会把方法名、参数描述、注解描述一起传给模型模型根据这些描述决定“用户问航班状态时应该调用 queryFlightStatus并填充参数”。所以工具描述写得越清楚模型调用就越准确。6.4 RAG 文档加载与知识库初始化现在实现 RAG 部分。这里演示一个KnowledgeBaseInitializer在应用启动时读取 classpath 下的 PDF 文档切分后写入向量库。package com.example.aviation.rag; import org.springframework.ai.document.Document; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; Component public class KnowledgeBaseInitializer implements ApplicationRunner { private final VectorStore vectorStore; public KnowledgeBaseInitializer(VectorStore vectorStore) { this.vectorStore vectorStore; } Override public void run(ApplicationArguments args) throws Exception { // 读取知识文档真实项目中可以读取 PDF、Word、Markdown Path policyFile Path.of(data/aviation_policy.txt); if (!Files.exists(policyFile)) { return; } String content Files.readString(policyFile); // 这里是最简切分按段落切分。生产环境建议使用 TokenTextSplitter 等组件按语义切分。 String[] paragraphs content.split(\\n\\n); ListDocument documents new ArrayList(); for (int i 0; i paragraphs.length; i) { documents.add(new Document(paragraphs[i], java.util.Map.of(source, aviation_policy.txt, chunk, i))); } vectorStore.add(documents); System.out.println(Knowledge base initialized, chunks documents.size()); } public String searchKnowledge(String question) { ListDocument results vectorStore.similaritySearch( SearchRequest.builder() .query(question) .topK(5) .build()); StringBuilder sb new StringBuilder(); for (Document doc : results) { sb.append(doc.getText()).append(\n---\n); } return sb.toString(); } }这个类实现了一个常见的启动初始化流程文档加载、切分、向量入库。searchKnowledge方法供后续 Agent 层调用。生产项目中知识文档的更新频率一般高于应用启动频率通常配合定时任务或消息监听在运行时更新向量库。6.5 Agent 服务与 Controller最后是 Agent 的核心服务类。这里使用 Spring AI 的 ChatClient同时配置FlightTools和QuestionAnswerAdvisor让模型既会调用工具也能参考知识库回答。package com.example.aviation.agent; import com.example.aviation.rag.KnowledgeBaseInitializer; import com.example.aviation.tool.FlightTools; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.stereotype.Service; Service public class AviationAgentService { private final ChatClient chatClient; public AviationAgentService(ChatClient.Builder builder, FlightTools flightTools, VectorStore vectorStore) { this.chatClient builder .defaultSystem( 你是航空智能助手负责帮助旅客查询航班、了解航空政策。 如果需要查实时航班信息请使用航班查询工具。 如果问题涉及行李托运、宠物运输、延误补偿等政策请优先参考知识库内容。 回答要简洁准确并说明信息来源。 ) .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore)) .defaultTools(flightTools) .build(); } public String chat(String userMessage) { return chatClient.prompt() .user(userMessage) .call() .content(); } }注意QuestionAnswerAdvisor是 Spring AI 提供的 RAG Advisor它在用户问题进入模型前会自动从 VectorStore 检索相关文档片段并拼入 Prompt。这样我们就实现了“工具 知识库”双层能力。再写一个简单的 Controller 对外暴露接口。package com.example.aviation.controller; import com.example.aviation.agent.AviationAgentService; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/agent) public class AviationController { private final AviationAgentService agentService; public AviationController(AviationAgentService agentService) { this.agentService agentService; } PostMapping(/chat) public String chat(RequestBody ChatRequest request) { return agentService.chat(request.message()); } public record ChatRequest(String message) { } }到这里一个可运行的航空智能助手已经具备雏形。下面再看看另一种实现方式用 Langchain4j 如何实现同样的功能。6.6 对照参考Langchain4j 的 AiServices 实现Langchain4j 的典型写法是先定义一个接口再用 AiServices 自动生成实现。这种“接口即服务”的方式非常符合 Java 开发者的直觉。import dev.langchain4j.agent.tool.Tool; import dev.langchain4j.memory.chat.MessageWindowChatMemory; import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.service.AiServices; import org.springframework.stereotype.Component; interface AviationAssistant { String chat(String userMessage); } class Langchain4jFlightTools { Tool(根据航班号查询航班实时状态) String queryFlightStatus(String flightNo, String date) { return 航班 flightNo 当前状态准点起飞时间 08:30。; } } Component public class Langchain4jAgent { private final AviationAssistant assistant; public Langchain4jAgent() { OpenAiChatModel model OpenAiChatModel.builder() .baseUrl(https://api.deepseek.com/v1) .apiKey(System.getenv(AI_API_KEY)) .modelName(deepseek-chat) .build(); this.assistant AiServices.builder(AviationAssistant.class) .chatLanguageModel(model) .tools(new Langchain4jFlightTools()) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .build(); } public String chat(String message) { return assistant.chat(message); } }从这段代码可以看出Langchain4j 在“定义 Agent”这件事上更简洁。你只需要声明接口框架会根据方法签名自动处理模型调用、工具注册和记忆管理。如果你的项目不依赖 Spring AI用这种方式快速搭一个 Agent 原型是非常高效的。7. 运行结果与效果验证代码写完接下来要验证它真的能工作。首先启动 Milvus如果使用 Dockerdocker run -d --name milvus \ -p 19530:19530 \ -p 9091:9091 \ milvusdb/milvus:latest然后启动 Spring Boot 应用export AI_API_KEY你的DeepSeekApiKey mvn spring-boot:run启动成功后用 curl 发起一次请求测试航班查询工具curl -X POST http://localhost:8080/api/agent/chat \ -H Content-Type: application/json \ -d {message:从北京到上海明天有哪些航班}如果工具调用配置正确模型会返回类似下面的内容明天从北京到上海有以下航班可选 - CA1234 08:00-10:15 - MU5678 10:30-12:45 - HU9012 14:20-16:35再测试一个 RAG 问题curl -X POST http://localhost:8080/api/agent/chat \ -H Content-Type: application/json \ -d {message:托运宠物需要什么手续}预期返回应包含知识库中的行李托运政策比如检疫证明、航空箱要求等。如果返回内容没有任何相关依据说明 RAG 检索没有命中或者向量库中没有正确写入文档。在验证时更重要的是检查“Agent 是否真的调用了工具”。你可以在应用日志中搜索“Tool”相关记录。Spring AI 默认会记录工具调用过程中的模型响应。如果你发现模型直接编造了一个航班列表而没有调用searchFlights方法说明工具描述不够清晰或者当前模型版本不支持工具调用。最后一个测试是组合问题curl -X POST http://localhost:8080/api/agent/chat \ -H Content-Type: application/json \ -d {message:帮我查明天CA1234的航班状态如果延误了能申请什么补偿}这个请求会触发两条链路先调用queryFlightStatus工具再根据返回状态决定是否检索延误补偿政策。如果 Agent 编排正常回答会先说明航班状态再给出延误补偿政策并且政策内容来自知识库。8. 常见问题与排查思路这类项目在开发期踩坑非常正常。下面把最常见的几个问题整理成表方便你按图索骥。问题现象可能原因排查方式解决方案Spring AI 连接 DeepSeek 不输出 content模型返回了 reasoning_content但客户端只读取 content 字段查看模型原始响应 JSON改用 deepseek-chat 对话模型或升级 Spring AI 版本Agent 始终不调用工具模型版本不支持工具调用或工具描述不够清晰在日志中查看模型响应是否包含 tool_calls更换支持 Function Calling 的模型补充工具描述RAG 回答完全无关文档切分不合理或 Embedding 模型与领域不匹配打印检索到的文档内容检查相关度排名调整 chunk size 和 overlap更换 Embedding 模型增加重排序向量库检索结果为空集合维度与 Embedding 维度不一致检查 Milvus 集合配置和写入日志统一集合维度删掉集合后重新创建java.lang.OutOfMemoryError: insufficient memory文档解析或向量化过程中内存不足查看堆栈信息检查启动参数和 Docker 内存增加 JVM 堆内存分批处理文档避免一次性加载大文件Lombok 报错not supported by lombokJDK 版本与 Lombok 版本不兼容查看 javac 报错信息升级 Lombok 版本或降低 JDK 版本多轮对话没有上下文没有配置 ChatMemory 或 Advisor 记忆策略检查模型请求是否携带历史消息在 ChatClient 中加入 MessageChatMemoryAdvisor或参考 Langchain4j 的 ChatMemory这里特别说明一下“Spring AI 连接 DeepSeek 不输出 content”这个问题。它出现的概率不低因为 DeepSeek 的推理模型接口返回格式与标准 OpenAI 不完全一致。如果你使用的是deepseek-reasoner这类推理模型响应里经常有reasoning_content字段而标准 OpenAI 客户端的content字段可能为空。最简单的规避办法是使用deepseek-chat这类模型返回更稳定对工具调用支持也更好。9. 最佳实践与工程建议代码能跑通只是第一步。把项目真正推向生产环境还需要以下几个层面的建设。第一模型与业务解耦。在 Service 层之上定义自己的接口不直接依赖 ChatClient 的返回值结构。这样以后换模型厂商、改 Prompt 策略时不会影响 Controller 和前端。第二Prompt 管理。System Prompt 和工具描述不要散落在代码里。建议放在配置中心或独立的资源文件中通过配置动态加载。Prompt 的一次修改可能要经过多轮测试版本化管理非常重要。第三RAG 文档工程化。知识库的核心不只是“存了多少文档”而是“回答是否可靠”。生产环境建议实现“解析→切分→清洗→向量化→人工校验”的完整流程。文档更新后要重建向量数据并保留文档来源和版本号。回答中可以要求模型标明“根据哪份政策文件的哪一条”。第四工具调用的安全边界。航班查询这类只读操作相对安全如果 Agent 要执行改签、退票、值机等敏感操作必须增加权限校验、确认机制和审计日志。更稳妥的做法是让 Agent 先生成操作意图再由用户确认后才真正执行。这个设计原则在 AI Agent 项目中尤其重要。第五多轮记忆的成本控制。消息记忆越长Token 消耗越大响应越慢。建议限制单次对话的最大消息数或者在长时间对话后做摘要压缩。对生产环境可以做会话维度的过期清理。第六成本和延迟优化。大模型调用存在明显的成本和延迟差异。可以配置两层模型策略简单问题走轻量模型复杂推理或工具调用走强模型。同时对热点问题的回答做缓存减少重复调用。第七评估体系。Agent 项目上线前准备一组评测问题集包括“工具调用准确率”“RAG 命中率”“回答正确率”“多轮一致性”几个维度。每次修改 Prompt 或模型后都跑一遍评测集防止回归。第八灰度发布。AI Agent 的回复具有不确定性直接全量上线存在风险。建议先在“AI 辅助”模式下运行比如客服建议先给人工客服做参考确认稳定后再开放给旅客自助使用。10. 总结与后续学习方向这篇文章从一个比较贴近真实业务的视角梳理了 Java 技术栈构建企业级 Agent 项目的完整路径。我们讲了 Spring AI 2.0 和 Langchain4j 在模型接入、工具调用、RAG、Agent 编排上的不同侧重点用航空智能助手这个场景从 ChatClient 基础对话出发一步步加入航班查询工具、政策知识库和 Agent 编排最后整理了工具调用失败、向量库检索不相关、DeepSeek 返回空 content 等高频问题的排查思路。下一步实践可以从三个方向继续。第一把代码跑通以后结合你自己的业务系统写一个真实业务工具接入到 Agent 中第二完善 RAG 部分把文档解析从 txt 换成 PDF、Word加入更合理的切分策略和重排序第三研究 Agentic RAG 和多 Agent 协作模式。比如把“航班客服助手”“延误补偿助手”“会员权益助手”拆成多个子 Agent再由一个主 Agent 做路由编排这是企业级应用的常见形态。最后想提醒一点Java 做 AI 应用不需要等“某个完美框架”出现。Spring AI 和 Langchain4j 的成熟度足够支撑商业项目落地关键是你是否愿意把业务能力标准化地暴露给模型并建立一整套验证、安全和评估机制。这比追新模型、调 Prompt 模板更值得投入精力。
返回列表