SpringAI 2.0与Langchain4j构建Java智能航空Agent实战
之前帮团队落地一个 Java 后端智能问答项目时最头疼的不是模型接口接入而是把 RAG、Tools 调用、Agent 编排这些概念真正落到 Spring Boot 工程里。网上资料大多以 Python 为主Java 生态里的完整案例少之又少尤其是一套能直接跑起来的企业级 Agent 项目翻遍社区也找不到几个。本文基于 SpringAI 2.0 与 Langchain4j 整理出一套智能航空项目全流程教程覆盖 Tools、RAG、Agent 三大核心模块附带完整代码与高频问题排查方案适合有 Java 基础、正在做 AI 应用落地的开发者参考。1. 智能航空项目背景与核心概念1.1 为什么 Java 项目也要做 Agent过去一年大模型应用爆发Python 生态的 LangChain、LlamaIndex 等框架确实丰富但企业级后端系统里 Java 仍然占据主导地位。很多航空、金融、政务类项目不能简单地用 Python 重写也不能在 Java 服务里直接拉起一个 Python 进程去跑 AI 链路最合理的方案是在 Java 技术栈内实现大模型接入、知识库检索、工具调用和智能体编排。SpringAI 2.0 和 Langchain4j 的出现让这件事变得可行。SpringAI 是 Spring 官方推出的 AI 框架负责统一对接大模型、向量数据库、Embedding 模型等底层能力Langchain4j 则是社区中非常成熟的 Java LLM 编排框架提供了类似 LangChain 的链式调用、AiServices、RAG、Tools 等高级能力。把这两个框架结合起来可以在 Spring Boot 工程中构建真正的企业级 Agent用户问一句“帮我查一下明天北京到上海的航班”Agent 能自动调用航班查询工具返回结构化结果同时结合航空政策知识库给出退改签建议。整个过程是 Java 代码在大模型帮助下自主完成任务而不是简单地一问一答。1.2 四个关键词必须分清SpringAI、Langchain4j、RAG、Agent先理清概念后面写代码才不容易混乱。Langchain4j 是一个 Java 版本的 LLM 应用框架它的设计目标是把大模型接入、提示词模板、输出解析、记忆管理、RAG 检索、工具调用等功能封装成可组合的组件。如果你用过 Python LangChainLangchain4j 的很多概念是类似的比如 ChatLanguageModel、EmbeddingModel、ContentRetriever、Tool 等。SpringAI 是 Spring 官方推出的 AI 支持库它更强调与 Spring Boot 生态的整合提供了类似 Spring Data 的抽象层。SpringAI 2.0 版本开始支持更完整的 ChatModel、EmbeddingModel、VectorStore 抽象并且内置了 OpenAI、Ollama、Qwen、DeepSeek 等多种模型的适配。对于已经使用 Spring Boot 的团队来说SpringAI 的学习成本更低但它在 Agent 编排方面相比 Langchain4j 轻量一些。实际项目中两者可以协同使用SpringAI 负责模型与向量库的标准接入Langchain4j 负责 Agent 编排和工具调用。RAGRetrieval-Augmented Generation是指检索增强生成。大模型的知识截止时间有限也无法知道企业内部数据。RAG 的思路是先把文档切分成片段经过 Embedding 模型转换成向量存入向量数据库用户提问时先从向量库中检索相似的文档片段再把这些片段和用户问题一起交给大模型让模型基于检索到的内容生成答案。这样回答就有依据而不是凭空编造。Agent 可以理解为一种能够自主调用工具、规划任务的智能体。Agent 不满足于“问答”它可以判断当前问题需要调用哪个工具比如查航班、查政策、查天气它也可以根据用户意图拆分任务然后循环执行“思考—调用—观察结果—再思考”的过程直到完成任务。在 Langchain4j 中AiServices 提供了便捷的 Agent 构建方式。1.3 航空场景为什么适合用 Agent RAG Tools航空业务天然适合演示这一整套技术栈因为它的核心痛点很典型。第一政策文档多。航空公司有大量旅客须知、行李政策、退改签规则、会员权益文档这些内容更新频繁用户咨询量大。这类知识非常适合做 RAG 知识库问答。第二实时数据查询需求强。航班时刻、余票、价格、延误状态都是实时数据大模型不能凭空生成必须通过工具调用查询接口。Tools 机制正好解决这个问题。第三用户问题往往涉及多步操作。用户说“帮我订明天早上从北京出发去上海的最早航班顺便问一下能带多少行李”。这句话既需要查航班又需要查行李政策还可能需要判断是否适合下单。Agent 可以拆分这些意图分别调用不同工具最后汇总回复。所以本文的智能航空项目会包含三个核心能力航班查询工具通过 Tools 机制让大模型调用 Java 方法查询航班。航空政策知识库问答通过 RAG 流程让大模型基于文档回答行李、退改签等问题。Agent 编排通过 Langchain4j 把工具调用 知识库检索统一编排实现多轮对话和自主决策。2. 技术选型与环境准备2.1 环境依赖清单在开始写代码之前先确认环境。下面的版本是当前示例使用的实际项目请根据你的环境调整重点演示的是思路与完整链路。组件版本建议说明JDK17Spring Boot 3.x 要求 JDK 17 起Maven3.8构建工具Spring Boot3.3.x 或 3.4.x以 Spring AI 2.0 兼容版本为准Spring AI2.0.x官方 AI 框架Langchain4j1.0.x 或最新稳定版Java LLM 编排框架大模型 APIDeepSeek / Qwen / OpenAI 兼容可以使用 OpenAI 兼容协议接入Embedding 模型Qwen Embedding 或 OpenAI Embedding用于 RAG 向量化向量数据库Milvus / Redis / Elasticsearch生产推荐 Milvus版本说明Spring AI 与 Langchain4j 版本迭代很快不同版本之间的 API 可能有差异。本文代码以较新的稳定版本写法为例如果编译报错优先检查依赖版本并参考官方迁移文档。2.2 Maven 依赖配置如果使用 Spring Boot SpringAI核心依赖如下。这里保留一个相对通用的配置实际版本号请以 Maven 中央仓库和官方 BOM 为准。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.3.5/version relativePath/ /parent properties java.version17/java.version spring-ai.version2.0.0/spring-ai.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- SpringAI 核心 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency !-- 如果使用 DeepSeek 等 OpenAI 兼容接口同样走 openai starter -- !-- 向量数据库 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-milvus/artifactId /dependency !-- Langchain4j 核心 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version1.0.0/version /dependency !-- Langchain4j OpenAI 兼容模块 -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai/artifactId version1.0.0/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies这里有一个容易踩坑的点SpringAI 与 Langchain4j 都会引入部分相同语义的包比如 ChatModel、EmbeddingModel使用时要避免把两者的 API 混用。建议团队内明确一个原则模型接入以 SpringAI 为主Agent 编排与 RAG 链路以 Langchain4j 为主不要在同一个类里混用两套 API。2.3 配置文件示例配置文件里需要包含模型接入、向量库连接等关键信息。spring: application: name: airline-agent ai: openai: base-url: https://api.deepseek.com/v1 api-key: ${DEEPSEEK_API_KEY} chat: options: model: deepseek-chat temperature: 0.7 embedding: options: model: text-embedding-v2 milvus: client: host: localhost port: 19530 database: airline_db collection: policy_docs embedding-dimension: 1024 index-type: IVF_FLAT metric-type: COSINE langchain4j: open-ai: chat-model: base-url: ${spring.ai.openai.base-url} api-key: ${spring.ai.openai.api-key} model-name: ${spring.ai.openai.chat.options.model} temperature: 0.7配置项中比较关键的是embedding-dimension它必须与 Embedding 模型输出向量的维度一致。不同 Embedding 模型输出维度不同OpenAI 的 text-embedding-3-small 是 1536 维Qwen 的 text-embedding-v2 通常是 1024 维。如果向量维度不一致写入 Milvus 时会直接报错。3. Agent、Tools、RAG 核心原理拆解3.1 RAG 的完整处理链路RAG 不是单一功能而是一整条数据处理流水线。完整的 RAG 流程包含以下步骤第一步文档加载。把 PDF、Word、TXT、Markdown 等格式的文档读入系统。Java 中常见方案是使用 Tika 或 PdfBox 解析Langchain4j 也内置了多种 DocumentLoader。第二步文档切分。大模型上下文窗口有限不可能把整本手册塞进去需要把文档按固定长度或语义边界切成片段。常见切分参数是 chunkSize每个片段的大小和 chunkOverlap相邻片段重叠长度一般 chunkSize 取 500 到 1000 个 token 比较合适重叠 50 到 100 个 token 用于保持上下文衔接。第三步Embedding 向量化。把每个文本片段通过 Embedding 模型转成向量。Embedding 模型的作用是让语义相近的文本在向量空间中的距离更近。第四步向量存储。将文本片段和对应向量写入向量数据库。Milvus 是当前企业级项目常用的向量库支持百万级向量检索Redis 也可以作为轻量级向量存储方案适合数据量较小的场景。第五步检索召回。用户提问时先把用户问题转成向量然后在向量库中执行相似度检索返回最相关的 topK 个片段。第六步重排与增强。检索出来的片段不一定按相关性排序最优可以接入 Rerank 模型做二次排序。将排序后的片段拼入提示词形成增强后的上下文。第七步生成回答。把增强后的提示词交给大模型模型基于检索内容生成答案并在回答中注明信息来源。对于航空政策问答RAG 链路最关键的优化点在于文档切分和检索结果排序。如果切分不合理一段完整政策被拦腰截断检索召回就会出现信息缺失如果检索结果排序不准大模型可能会引用不相关内容。3.2 Tools 机制的本质Tools 机制的本质是让大模型在对话过程中调用你预先定义好的 Java 方法。大模型本身不直接执行代码而是根据用户问题和工具描述生成一个 JSON 格式的调用请求框架把这个请求转换成 Java 方法调用再把方法返回值交回给大模型让模型基于真实数据继续回答。Langchain4j 中实现一个 Tool 非常简单核心思路是把工具类注册成一个 Bean然后在工具类上使用Tool注解描述每个方法。Component public class FlightTools { Tool(根据出发城市、到达城市和日期查询航班列表) public ListFlightInfo searchFlights(String departureCity, String arrivalCity, String date) { // 调用真实的航班查询接口或查询数据库 return flightService.search(departureCity, arrivalCity, date); } }写工具时要注意描述准确。大模型是根据方法名和方法描述来判断何时调用这个工具的描述写得模糊会导致模型误调用。例如searchFlights方法如果只写“查询航班”模型可能不知道该传什么参数明确写出“根据出发城市、到达城市和日期查询航班列表”之后模型就能准确抽取参数。3.3 Agent 是如何编排任务和调用工具的Agent 的核心不是单次问答而是多轮推理。Langchain4j 中 Agent 底层采用 ReAct 模式Reason Act模型先根据用户问题推理下一步应该做什么决定调用哪个工具工具返回结果后模型继续观察结果并决定下一步动作直到模型认为已获得足够信息才生成最终回复。在一个智能航空 Agent 中典型执行流程如下用户提问“明天从北京去上海出差能带多少行李帮我查一下航班”时Agent 会先拆解用户意图需要查询航班也需要了解行李政策。Agent 先调用航班查询工具拿到北京到上海明天的航班列表再从 RAG 知识库中检索行李政策相关文档最后把航班信息与行李政策整合到回答中给出“推荐乘坐 MU5101经济舱可免费托运 20kg 行李”这类结果。Agent 与普通问答的最大区别在于它具备“主动性”。普通问答只能做单轮生成Agent 可以循环调用工具直到任务完成。3.4 Spring AI 2.0 与 Langchain4j 的定位差异在实际项目中经常有团队纠结到底选 SpringAI 还是 Langchain4j。这里给出一个比较实际的分工建议。SpringAI 2.0 的优势在于官方生态和 Spring Boot 原生整合尤其是对 OpenAI 协议、向量数据库、Advisor 等模块的抽象比较优雅。如果项目希望尽量减少第三方依赖优先选 SpringAI。Langchain4j 的优势在于 Agent 编排的完整度更高AiServices 可以直接声明一个接口让框架自动生成实现Tool 注解更成熟RAG 相关的 DocumentSplitter、EmbeddingStoreIngestor 等组件开箱即用。本文采用“SpringAI 做模型底座Langchain4j 做 Agent 编排”的组合方案这也是目前 Java AI 项目里比较流行的架构。4. 智能航空 Agent 项目实战4.1 项目需求与功能拆分为了让项目完整可落地我们设定一个智能航空助手需要支持以下功能用户询问某条航线的航班时刻、航班号、起降时间。用户询问行李托运政策、退改签规则。用户组合提问例如“明天从北京到深圳最早的一班航班是什么能带登机箱吗”。Agent 需要根据用户问题自动选择调用工具或知识库或两者结合。项目结构设计如下airline-agent/ ├── pom.xml ├── src/main/java/com/example/airline/ │ ├── AirlineAgentApplication.java │ ├── config/ │ │ ├── LLMConfig.java │ │ └── RAGConfig.java │ ├── controller/ │ │ └── AgentController.java │ ├── service/ │ │ ├── FlightService.java │ │ ├── PolicyRagService.java │ │ └── AirlineAgentService.java │ ├── tools/ │ │ └── FlightTools.java │ ├── model/ │ │ ├── FlightInfo.java │ │ └── AgentRequest.java │ └── repository/ │ └── FlightRepository.java4.2 航班数据模型与航班查询服务航班查询是 Agent 的工具能力之一。为了演示方便我们使用内存数据模拟航班查询服务实际项目中可以替换为数据库或第三方接口。// 文件路径src/main/java/com/example/airline/model/FlightInfo.java Data Builder NoArgsConstructor AllArgsConstructor public class FlightInfo { private String flightNo; private String airline; private String departureCity; private String arrivalCity; private String departureTime; private String arrivalTime; private String status; }// 文件路径src/main/java/com/example/airline/service/FlightService.java Service public class FlightService { private final ListFlightInfo flights new ArrayList(); public FlightService() { flights.add(FlightInfo.builder() .flightNo(MU5101) .airline(东方航空) .departureCity(北京) .arrivalCity(上海) .departureTime(08:00) .arrivalTime(10:15) .status(准点) .build()); flights.add(FlightInfo.builder() .flightNo(CA1831) .airline(中国国航) .departureCity(北京) .arrivalCity(上海) .departureTime(09:30) .arrivalTime(11:45) .status(准点) .build()); flights.add(FlightInfo.builder() .flightNo(CZ3151) .airline(南方航空) .departureCity(北京) .arrivalCity(深圳) .departureTime(07:30) .arrivalTime(11:00) .status(延误) .build()); } public ListFlightInfo searchFlights(String departureCity, String arrivalCity) { return flights.stream() .filter(f - f.getDepartureCity().contains(departureCity)) .filter(f - f.getArrivalCity().contains(arrivalCity)) .collect(Collectors.toList()); } public OptionalFlightInfo findEarliestFlight(String departureCity, String arrivalCity) { return searchFlights(departureCity, arrivalCity) .stream() .min(Comparator.comparing(FlightInfo::getDepartureTime)); } }FlightService 提供两个方法查询航班列表和查询最早航班。这两个方法会作为 Agent 的工具能力暴露给大模型。4.3 航班查询工具注册// 文件路径src/main/java/com/example/airline/tools/FlightTools.java Component RequiredArgsConstructor public class FlightTools { private final FlightService flightService; Tool(根据出发城市和到达城市查询可用航班列表) public ListFlightInfo queryFlights(String departureCity, String arrivalCity) { return flightService.searchFlights(departureCity, arrivalCity); } Tool(根据出发城市和到达城市查询最早的一班航班) public FlightInfo queryEarliestFlight(String departureCity, String arrivalCity) { return flightService.findEarliestFlight(departureCity, arrivalCity) .orElse(null); } }queryFlights和queryEarliestFlight分别对应航班查询和最早航班查询场景。通过Tool注解Langchain4j 会在构建 Agent 时自动扫描这两个方法并把方法描述注册到模型的工具列表中。4.4 RAG 知识库服务航空政策知识库需要先把文档写入向量库。这里以简化方式演示 RAG 服务的构建过程。// 文件路径src/main/java/com/example/airline/service/PolicyRagService.java Service RequiredArgsConstructor public class PolicyRagService { private final EmbeddingModel embeddingModel; private final VectorStore vectorStore; public void ingestPolicyDocument(String documentId, String content) { Document document Document.builder() .id(documentId) .text(content) .build(); // 切分文档 DocumentSplitter splitter DocumentSplitters.recursive(600, 100); ListTextSegment segments splitter.split(document); // 向量化并存储 embeddingModel.embed(segments); vectorStore.add(segments); } public ListTextSegment searchPolicy(String query, int topK) { return vectorStore.search(query, topK); } }这里解释一下几个核心组件的作用。Document是文档对象text是文档内容DocumentSplitter负责文档切分recursive(600, 100)表示每个片段约 600 字符重叠 100 字符EmbeddingModel将每个片段转成向量VectorStore把向量和原文写入 Milvus。实际航空项目中政策文档通常来自 PDF 或 Word可以通过 Tika 解析后传入。4.5 知识库文档初始化为了让项目启动后能够直接测试 RAG 效果需要在应用启动时初始化一部分政策文档。这里使用ApplicationRunner在服务启动时向向量库写入演示数据。// 文件路径src/main/java/com/example/airline/config/RAGDataInitializer.java Component RequiredArgsConstructor public class RAGDataInitializer implements ApplicationRunner { private final PolicyRagService policyRagService; Override public void run(ApplicationArguments args) { policyRagService.ingestPolicyDocument( policy_001, 国内航班经济舱旅客免费托运额度为20公斤公务舱为30公斤头等舱为40公斤。超出部分按每公斤经济舱全价票的1.5%计算。 ); policyRagService.ingestPolicyDocument( policy_002, 退票规则航班起飞前2小时以上申请退票收取票面价格10%退票手续费起飞前2小时以内申请退票收取票面价格30%退票手续费。 ); policyRagService.ingestPolicyDocument( policy_003, 登机行李尺寸不得超过20*40*55厘米重量不得超过7公斤。超出规定的行李必须办理托运。 ); } }在实际项目中这批文档应该由运维或运营团队定期更新而不是写死在代码里。这里只是演示链路。4.6 Agent 编排核心代码Agent 编排是整个项目最核心的部分。Langchain4j 的AiServices提供了一种声明式的 Agent 构建方式你定义一个接口框架自动生成实现。// 文件路径src/main/java/com/example/airline/service/AirlineAssistant.java public interface AirlineAssistant { SystemMessage( 你是一个专业的航空智能助手。你可以查询航班信息也可以通过知识库回答航空政策问题。 回答时请使用中文语言风格专业、简洁。如果用户询问的是实时航班信息必须调用工具获取不要编造航班数据。 如果用户询问的是行李政策、退改签规则等知识库内容请基于检索到的知识回答并注明该内容根据航空公司政策整理。 ) String chat(String userMessage); }// 文件路径src/main/java/com/example/airline/service/AirlineAgentService.java Service RequiredArgsConstructor public class AirlineAgentService { private final ChatLanguageModel chatLanguageModel; private final FlightTools flightTools; private final PolicyRagService policyRagService; public String chat(String message) { // 构建 Agent AirlineAssistant assistant AiServices.builder(AirlineAssistant.class) .chatLanguageModel(chatLanguageModel) .tools(flightTools) .retriever(policyRagService::searchPolicy) .build(); // 执行对话 return assistant.chat(message); } }这段代码有三个关键点第一AirlineAssistant接口上使用SystemMessage定义了系统提示词。系统提示词的作用是约束 Agent 的角色和回答规则。这里特别强调了“不要编造航班数据”实际项目中这句约束非常重要因为大模型没有实时航班数据不约束就会出现幻觉。第二AiServices.builder()是 Langchain4j 的核心 API。通过.tools(flightTools)注册工具通过.retriever()注册 RAG 检索器。这样 Agent 在回答时既可以使用工具也可以检索知识库。第三assistant.chat(message)是 Agent 的入口。整个 ReAct 循环发生在内部业务代码不需要关心模型到底调了几次工具。4.7 Controller 控制器最后写一个简单的 REST 接口用于测试。// 文件路径src/main/java/com/example/airline/controller/AgentController.java RestController RequestMapping(/agent) RequiredArgsConstructor public class AgentController { private final AirlineAgentService airlineAgentService; PostMapping(/chat) public ResponseEntityMapString, String chat(RequestBody AgentRequest request) { String answer airlineAgentService.chat(request.getMessage()); return ResponseEntity.ok(Map.of(answer, answer)); } }// 文件路径src/main/java/com/example/airline/model/AgentRequest.java Data public class AgentRequest { private String message; }4.8 运行与验证启动 Spring Boot 应用后使用 curl 测试curl -X POST http://localhost:8080/agent/chat \ -H Content-Type: application/json \ -d {message: 明天从北京去上海出差最早的一班航班是什么}预期返回结果中会包含 Agent 调用工具的痕迹最终回答类似为您查询到明天北京到上海最早的航班是 MU510108:00 起飞10:15 到达由东方航空执飞当前状态为准点。再测试 RAG 链路curl -X POST http://localhost:8080/agent/chat \ -H Content-Type: application/json \ -d {message: 经济舱可以免费托运多少公斤行李}预期回答会基于向量库中的 policy_001 文档生成根据航空公司政策国内航班经济舱旅客免费托运额度为 20 公斤。超出部分按每公斤经济舱全价票的 1.5% 计算。如果 Agent 回答正确说明 Tools 调用和 RAG 检索链路都已打通。5. 常见问题与排查思路5.1 SpringAI 连接 DeepSeek 不输出 content很多开发者在用 SpringAI 接入 DeepSeek 时遇到请求成功但 content 为空的问题。这个问题的常见原因有三个第一DeepSeek 采用了 OpenAI 兼容协议但部分参数不完全兼容。比如stream默认行为和max_tokens参数。遇到 content 为空时建议先关闭流式输出测试确认是非流式场景是否正常。第二模型名称配置错误。Spring AI 中配置的是model-nameDeepSeek 可用模型是deepseek-chat和deepseek-reasoner。如果配置了不存在的模型名接口虽然可能返回成功但 content 为空或报错。第三API Key 或 base-url 配置有误。检查base-url是否包含/v1路径。通常需要配置为https://api.deepseek.com/v1漏掉会导致 404 或空响应。排查建议先用 curl 直接调 DeepSeek API确认模型正常返回再检查 SpringAI 配置映射是否正确最后再排查代码中是否对输出做了错误处理。5.2 Langchain4j 向量维度不一致导致写入 Milvus 失败如果使用 Qwen Embedding 生成向量并存储到 Milvus出现维度不一致的报错通常是embedding-dimension配置错误。Qwen 的 text-embedding-v2 默认输出 1024 维OpenAI 的 text-embedding-3-small 输出 1536 维。Milvus 创建 Collection 时指定的维度必须与 Embedding 模型的实际维度一致。修改方式是在配置文件中调整embedding-dimension并注意如果 Collection 已经存在Milvus 不允许直接修改维度需要删除重建或新建 Collection。5.3 Agent 执行超时或 no responseLangchain4j Agent 调用工具后超时通常出现在工具方法执行时间过长或者模型推理次数过多。排查思路先确认工具方法内部是否有网络请求超时再确认 Agent 的 maxIterations 是否设置过小导致模型在几次工具调用后还没有生成最终回答最后检查模型服务是否本身过慢比如 DeepSeek 在高负载时推理时间较长可以适当增加 HTTP 客户端超时时间。示例配置调整spring: ai: openai: client: connect-timeout: 30s read-timeout: 60s5.4 Lombok 编译报错报错信息类似java: You arent using a compiler supported by lombok, so lombok will not work通常是因为 JDK 版本过高或 Lombok 版本过旧。解决方案是先升级 Lombok 到最新版本再确认 Maven 编译器插件版本与 JDK 匹配。Spring Boot 3.x 项目建议使用 Lombok 1.18.30 以上版本。如果项目中使用 Java 21需要特别注意 Lombok 对 JDK 21 的支持情况必要时升级到最新版。5.5 RAG 检索结果不准确RAG 回答质量差多数不是模型问题而是检索链路问题。可以从以下几个方面排查文档切分是否合理。切分过大导致上下文不聚焦切分过小导致信息不完整。Embedding 模型是否适合当前领域。通用 Embedding 模型对航空专业术语的理解能力有限可以考虑垂直领域微调模型。是否使用重排。只依赖向量相似度排序前几个结果可能不是最相关的建议接入 Rerank 模型。检索 topK 数量。topK 太小可能漏掉关键内容topK 太大可能引入噪声。一般建议取 3 到 5。5.6 常见问题速查表问题现象常见原因解决思路SpringAI 请求 DeepSeek 返回空 content流式/非流式配置不一致、模型名错误先 curl 验证模型再检查配置Milvus 写入报维度错误Embedding 模型维度与 Collection 维度不一致统一下游模型与配置维度Agent 调用工具后不返回工具方法耗时过长或 maxIterations 太小检查工具网络耗时调整迭代次数Lombok 编译失败JDK 与 Lombok 版本不匹配升级 LombokRAG 回答答非所问切分不合理、缺少重排优化切分参数、接入 Rerank内存溢出JVM 堆内存不足调整 JVM 参数并检查大文档加载逻辑内存溢出问题在 RAG 项目中比较常见。如果你在加载大 PDF 时遇到java.lang.OutOfMemoryError: Insufficient memory通常是文档解析时一次性把整个文件读入内存。建议分批读取文档并适当增加 JVM 堆内存例如java -Xms512m -Xmx2g -jar airline-agent.jar6. 最佳实践与工程建议6.1 配置隔离与环境管理AI 项目最容易出问题的是配置管理。API Key、模型名称、底座地址在不同环境通常不同建议区分本地、测试、生产环境配置避免把真实 API Key 提交到代码仓库。推荐使用环境变量或配置中心管理敏感配置spring: ai: openai: api-key: ${DEEPSEEK_API_KEY}实际生产环境建议使用 Apollo、Nacos 等配置中心统一管理模型参数支持动态调整 temperature、topK 等参数无需重启服务。6.2 工具方法的防御式编程Tools 暴露给大模型后模型可能传入不存在的城市名、非法日期等参数。工具方法必须对参数做校验和兜底不能因为一个脏参数导致整个 Agent 崩溃。Tool(根据出发城市和到达城市查询可用航班列表) public ListFlightInfo queryFlights(String departureCity, String arrivalCity) { if (departureCity null || arrivalCity null) { return Collections.emptyList(); } return flightService.searchFlights(departureCity.trim(), arrivalCity.trim()); }这里对空参数做了防御避免后续代码出现空指针。生产项目中还可以加参数长度限制、城市名校验等逻辑。6.3 日志与链路追踪Agent 项目比普通 CRUD 项目复杂得多一次用户请求背后可能有多轮模型调用和工具调用。如果没有日志追踪定位问题会非常困难。建议至少记录以下信息用户原始问题。模型每次推理的输入输出。工具方法名和入参出参。RAG 检索到的文档片段 ID。Agent 最终回答。Langchain4j 中可以通过监听器或拦截器实现日志记录。示例代码如下// 伪代码演示监听器思路 ChatModelListener listener new ChatModelListener() { Override public void onRequest(ChatModelRequestContext context) { log.info(Model request: {}, context.request()); } Override public void onResponse(ChatModelResponseContext context) { log.info(Model response: {}, context.response()); } };6.4 生产环境安全边界在真实企业项目中Agent 可能会调用查询订单、改签、退票等敏感操作工具。这时必须增加权限校验和人工确认环节。安全建议只读操作可以自动执行例如查航班、查政策。写操作必须经过二次确认例如退票、改签Agent 只能生成操作建议不能直接调用工单系统。工具方法内部要做身份校验从登录上下文获取用户信息不要相信模型传入的用户 ID。对模型输出做敏感信息过滤防止提示词注入导致的信息泄露。6.5 性能优化建议Agent 项目性能瓶颈通常不在模型本身而在工具调用和向量检索。工具调用层面建议给外部接口设置超时时间和缓存。同一航线的查询结果在几分钟内基本不变可以加本地缓存减少对外部系统的压力。向量检索层面Milvus 索引类型会影响查询速度和召回精度。数据量较小时使用 FLAT 暴力检索精度最高数据量达到百万级时切换 IVF_FLAT 或 HNSW提升查询性能。实际项目中可以在建索引时做性能压测选择最合适的索引类型。RAG 链路还可以增加多路召回机制既走向量检索也走全文检索如 Elasticsearch 的 BM25最后用 Rerank 模型融合排序。混合检索的效果通常优于单路向量检索这也是 Langchain4j 中支持的做法。7. 总结与下一步学习建议这篇教程从零到一构建了一个完整的智能航空 Agent 项目覆盖了 SpringAI 2.0 模型接入、Langchain4j 工具调用、RAG 知识库问答、Agent 自动编排四大核心模块。对照项目可以直观地看到Tools 让大模型具备了实时查询航班的能力RAG 让大模型能够回答企业内部政策文档中的问题Agent 则把两者统一编排起来实现复杂任务的自主完成。对于刚接触 Java AI 项目的开发者建议先动手把本文的项目跑通再逐步替换成自己的业务场景。替换时重点关注三个地方一是模型的接入方式和配置参数二是工具方法的设计和描述三是知识库文档的切分与检索策略。这三块质量决定了 Agent 在真实业务中的表现上限。下一步可以继续深入的方向有RAG 混合检索与重排优化、Agent 多工具复杂任务规划、SpringAI 官方 Advisor 机制、生产环境模型调用链路监控以及 Agent 结果评估体系建设。建议在实际项目中使用小流量灰度上线持续积累 Agent 回答失败案例再反向优化提示词、工具描述和检索链路。如果你在搭建过程中遇到问题欢迎把报错信息发在评论区一起讨论。

相关新闻

AI写文献综述总编参考文献?我把这几款工具捋了一遍

AI写文献综述总编参考文献?我把这几款工具捋了一遍

每年开题季,我都会收到同一种求助:“文献综述写不出来,用 AI 吧,结果生成的参考文献一查全是假的,导师脸都绿了。” 这两年我前前后后用过二十多款 AI 学术工具,从通用大模型到智能体平台再到垂直学术产品&…

2026/8/30 3:14:08 阅读更多 →
Claude Code暗底风险:AI生成代码安全审查实战指南

Claude Code暗底风险:AI生成代码安全审查实战指南

最近开发圈有个挺扎心的说法——以后让 Claude 写的东西,可能要小心留暗底了。这个说法并不夸张。随着 Claude Code 这类智能编码工具进入日常开发流程,AI 不再只是给一段建议代码,而是会直接创建文件、修改配置、安装依赖、执行命令。速度提…

2026/8/30 3:13:07 阅读更多 →
AI编程工具的安全暗底:如何审查Claude Code留下的每一处改动

AI编程工具的安全暗底:如何审查Claude Code留下的每一处改动

最近一段时间,Claude Code 大概是开发者圈子里讨论度最高的 AI 编程工具之一。从安装教程到接入第三方模型,再到各种报错求助,热搜词几乎天天在变。但我今天想聊的,不是它有多强,而是一个更麻烦的问题:以后…

2026/8/30 3:13:07 阅读更多 →

最新新闻

Python音游数据分析实战:从达成率到舞萌W5段位评估

Python音游数据分析实战:从达成率到舞萌W5段位评估

先说结论:很多时候,我们对“能不能上 W5”的判断并不是基于真实数据,而是基于打完几首歌之后的记忆印象。等我把机台成绩按歌曲、难度、达成率拆开分析之后,才发现体感和数据完全对不上。 这篇文章就用一个真实的“舞萌段位评估”…

2026/8/30 4:04:21 阅读更多 →
软考高级网络规划设计师备考攻略:真题与论文双线突击

软考高级网络规划设计师备考攻略:真题与论文双线突击

打算参加软考高级网络规划设计师,也就是大家常说的“网规”,可以直接开始看这篇。网规是软考高级里网络方向的对口科目,平时问的人不少。很多人会把它和“网络工程师”混在一起,实际上两者差别很大:网络工程师是中级&a…

2026/8/30 4:04:21 阅读更多 →
AI提示词优化失效?从结构化编写到自动批量生成的完整指南

AI提示词优化失效?从结构化编写到自动批量生成的完整指南

“不是,我的AI提示呢?这简直是一模一样。” 如果你也用AI工具优化过提示词,大概率遇到过这个场景:输入一句“一只猫在窗台上看夕阳”,让大模型帮你扩写,结果它只给出一句“一只猫在窗台上看夕阳”&#xf…

2026/8/30 4:04:21 阅读更多 →
MIT 6.00:用Python训练计算思维的经典编程入门课

MIT 6.00:用Python训练计算思维的经典编程入门课

一门 2008 年就录制的计算机入门课,为什么直到今天还在被反复搜索和讨论?如果你只是在搜索引擎里看到 MIT 6.00 这个名字,很可能会有一个疑问:Python 早已不是当年的写法,课程视频甚至带点年代感,学它还有什…

2026/8/30 4:04:21 阅读更多 →
SSM实验室设备预约系统设计实战:从源码剖析到并发冲突处理

SSM实验室设备预约系统设计实战:从源码剖析到并发冲突处理

简介:本资源是一套完整的基于SSM(SpringSpringMVCMyBatis)框架开发的实验室设备预约系统毕业设计项目,面向计算机类专业本科生及Java初学者,旨在解决高校实验室设备人工预约效率低、信息不同步、管理难等实际问题。压缩…

2026/8/30 4:04:21 阅读更多 →
DevOps工具链全景解析:从CI/CD到容器编排的实战指南

DevOps工具链全景解析:从CI/CD到容器编排的实战指南

这次我们直接把 DevOps 工具链摊开讲。不聊概念包装,不堆缩略词,而是按实际工程流转顺序,把每个环节用到的工具、解决的问题、选型逻辑和常见坑位讲清楚。 如果你正在搭建 CI/CD 流水线、梳理部署流程、准备团队规范,或者只是想搞…

2026/8/30 4:03:21 阅读更多 →

日新闻

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

2026/8/30 0:00:01 阅读更多 →
数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

2026/8/30 0:00:01 阅读更多 →
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

2026/8/30 0:00:01 阅读更多 →

周新闻

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

2026/8/30 0:00:01 阅读更多 →
数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

2026/8/30 0:00:01 阅读更多 →
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

2026/8/30 0:00:01 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/29 4:34:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/28 17:43:04 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/29 2:05:18 阅读更多 →