尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用Spring Boot+DeepSeek+LangGraph4j打造能办事的AI Agent

用Spring Boot+DeepSeek+LangGraph4j打造能办事的AI Agent 本文介绍如何使用Spring Boot、DeepSeek大模型和LangGraph4j框架构建一个能实际解决问题的ReAct Agent。文章详细解析了六大工具的实现、增量Checkpoint机制、RAG混合检索、Text2SQL数据库查询以及SSE流式输出等技术要点并通过实际案例对比了纯LLM ChatBot和ReAct Agent在O2O业务场景中的表现差异。该项目代码已开源适合想要学习AI Agent开发的程序员和小白参考。背景你一定遇到过这种情况——接了一个 AI 智能客服需求老板说要能查订单、能排队、能退款你心想这不就是接个 LLM 的事吗。结果用户第一句话问帮我查一下昨天在火锅店的消费LLM 开始胡编订单号。你发现事情没那么简单LLM 不会查数据库、不知道你的业务规则、更没法真正帮用户办事。于是你开始搜Java AI Agent 实战出来的要么是 Python 的 LangChain 教程要么是抽象的 Agent 理论——思维链、多智能体协作、世界模型…看完只觉得更焦虑了。我只是想写个 Java 项目让 LLM 能调几个工具帮用户查个订单、排个队有那么难吗这就是本文要解决的问题用 Spring Boot LangGraph4j 构建一个真正能办事的 ReAct Agent打通从意图理解到工具执行到结果生成的完整闭环。不需要啃 LangGraph 论文不需要学 Python。你只需要三个东西Spring Boot — Java 人都熟DeepSeek — 便宜好用的国产大模型LangGraph4j — Java 版的状态机编排框架项目展示什么是能办事的 Agent在聊代码之前先对齐一个概念。很多人以为接个 LLM 就算有 AI 了。但实际上一个只会聊天的 ChatBot 和真正能办事的 Agent 之间差了三层能力普通 ChatBot 用户问 → LLM 答全靠记忆不知道你的数据库里有什么 ↓ 升级 带 RAG 的 ChatBot用户问 → 检索文档 → LLM 引用文档回答能看书了 ↓ 升级 ReAct Agent 用户问 → 理解意图 → 制定计划 → 调用工具 → 观察结果 → 判断是否够了 → 回答 能做事了——查数据库、调接口、执行操作ReAct Agent所谓的能办事就是 LLM 像一个实习生你给它一本操作手册和几个工具它能自己决定什么时候查手册、什么时候用哪个工具、看完结果后还需要什么信息。下面我以 O2O 生活服务平台为例一步步拆解怎么给 Java 项目装上这个能力。架构总览整个 AI 部分由三层组成和业务代码松耦合┌──────────────────────────────────────────────────┐ │ 前端 (Vue.js Element UI) │ │ 右下角 AI 悬浮窗 / 知识库管理后台 │ └──────────────────────┬───────────────────────────┘ │ HTTP SSE ┌──────────────────────▼───────────────────────────┐ │ Spring Boot 后端 │ │ ┌─────────────────┐ ┌────────────────────────┐ │ │ │ ReAct 状态机 │ │ RAG 引擎 │ │ │ │ 六节点编排 │ │ 摄入 混合检索 │ │ │ │ Context→Planner │ │ 切片→向量化→Qdrant │ │ │ └─────────────────┘ └────────────────────────┘ │ │ ┌────────────────────────┐ │ │ │ 工具集 (6 Tools) │ │ │ │ GeoSearch / Text2SQL │ │ │ │ 订单查询 / 排队取号 │ │ │ └────────────────────────┘ │ └──────┬───────────────────────┬───────────────────┘ │ │ ┌──────▼──────┐ ┌─────────────▼──────────────┐ │ DeepSeek │ │ Qdrant Ollama/PostgreSQL│ │ LLM API │ │ 向量库 / Checkpoint │ └─────────────┘ └────────────────────────────┘别被六节点状态机吓到核心代码其实很精简。下面我按 Agent 的五个关键能力来拆解——每个能力都是一块独立的拼图。能力一六大工具 — 让 Agent 能动手这是 Agent 区别于 ChatBot 的核心它不只是说话它能做事。工具怎么注册我们通过 LangGraph4j LangChain4j 的桥接层Tool注解的方法自动被提取为 JSON Schema注册到 Agent 的工具箱里// ToolRegistry.java — 6 个工具一行注册 LC4jToolMapBuilder? builder new LC4jToolMapBuilder() .toolsFromObject( knowledgeRetrievalTool, // RAG 知识检索 queueTicketTool, // 排队取号 text2SqlTool, // 动态 SQL 查询 geoSearchTool, // 地理位置搜索 historySearchTool // 对话历史回溯 );每个工具做什么工具触发场景背后做了什么geoSearchTool“附近有什么火锅店”Redis GEO 查询 → 返回店铺列表和距离queueTicketTool“帮我排个号”查询排队状态 → 确认 → 取号text2SqlTool“帮我看看xx店有没有优惠券”LLM 生成 SQL → 安全校验 → 执行knowledgeRetrievalTool“怎么退款”RAG 检索帮助文档historySearchTool“之前聊过的那家店”PostgreSQL ILIKE 关键词回溯历史对话关键设计决策LLM 自己决定何时调哪个工具。你不需要写 if-else 路由规则—— Agent 的 Planner 节点会根据用户意图自动制定计划并选择工具。这正是 ReAct 范式的价值不是预设路径而是推理出路径。能力二增量 Checkpoint — 给 Agent 装上记忆问题ReAct Agent 每轮对话要经过多个节点推理如果每次都从头跑一轮对话能跑十几秒。更致命的是用户说了帮我在海底捞排个号Agent 需要确认您确认在海底捞(朝阳店)排号吗——这时候 Agent 的工作状态推理到哪了、已获取了哪些信息必须被保存下来等用户回复后继续。传统的全量序列化方案每次存整个状态图初始化耗时 14 秒体感上是点一下 → 喝口水 → 还没反应。解决方案DeltaPostgresSaver核心思路一句话不存全量只存变化。完整状态messages[1..100] 所有标量字段 ↓ 对比上次快照 只存 delta ├── messages 差集新增的 5 条消息 ├── 变化的标量字段如 currentPlan 更新 └── 每隔 N 轮存一个全量快照做锚点// DeltaPostgresSaver.java — 增量序列化核心逻辑简化 public void put(Checkpoint checkpoint) { // 1. 加载最近一次全量快照 Checkpoint baseline loadLatestSnapshot(threadId); // 2. 计算 deltamessages 差集 变化的标量字段 MapString, Object delta computeDelta(baseline, checkpoint); // 3. 只序列化 delta 写入 PostgreSQL // 周期性如每 10 轮存一份全量快照 if (shouldCreateSnapshot()) { saveFullSnapshot(checkpoint); } else { saveDelta(delta); } }效果对比指标全量存储DeltaPostgresSaver图初始化耗时~14s 1s每次 checkpoint 写入量全量序列化仅变更部分跨实例恢复❌✅ 支持 checkpoint resume 这个思路和数据库的 WALWrite-Ahead Log如出一辙——找到最近的 checkpoint 锚点回放之后的增量操作重建完整状态。做后端的同学一看就懂。顺带解决了人机协同基于 Checkpoint 机制Agent 确认中断变得很自然Agent 需要用户确认 → 序列化当前 ReAct 上下文 → 挂起 用户回复 确认 → updateState 注入决策数据 → 恢复状态机执行 绕过 Planner 重跑避免上下文丢失能力三RAG 混合检索 — 让 Agent 能看书很多 RAG 系统的通病是搜不准。用户搜怎么退款返回的是退款政策的历史沿革——因为只做了关键词匹配。这个项目的检索链路是双路召回 重排序Step 1结构化切分文档普通的RecursiveCharacterTextSplitter不认识中文——它会把第一章、一、、1.1这些中文章节标记当作普通文本一刀切。我们实现了一个AdaptiveSplitter多层级降级切分// AdaptiveSplitter.java — 中文文档感知的切片策略简化 public ListChunk split(String markdown) { // 1. 保护特殊块代码块 表格占位符替换 MapString, String protectedBlocks protectCodeAndTable(markdown); // 2. 多层级切分逐级降级 // H2 标题 → H3 标题 → 中文标记(**一、 第一章) → 段落 → 句子 → 字符** ListSection sections splitByHeading(text, ##); // Level 1: H2 if (sections.size() 1) sections splitByChineseMarker(text); // Level 2: **一、第一章** if (sections.size() 1) sections splitByParagraph(text); // Level 3: 段落 // 3. 还原被保护的特殊块 return restoreBlocks(chunks, protectedBlocks); } 为什么不用现成的 LangChain 切分器因为RecursiveCharacterTextSplitter不认识文档结构。一篇 FAQ 被切在代码块中间检索出来的片段就废了。结构化文档必须用结构感知切分。Step 2双路召回 RRF 融合单独的语义检索容易漏掉精确关键词匹配单独的 BM25 又不理解语义。所以两路一起跑用 RRF 融合排序// RetrievalService.java — 混合检索核心简化 public ListSearchResult hybridSearch(String query, int topK) { // 1. LLM 改写查询扩展同义词、纠正口语化 String rewrittenQuery llmQueryRewriter.rewrite(query); // 2. 双路并行召回 ListSearchResult semanticResults qdrant.search(embed(rewrittenQuery), topK * 2); ListSearchResult keywordResults bm25Index.search(rewrittenQuery, topK * 2); // 3. RRF 融合排序 → LLM 精排 ListSearchResult fused rrfFusion(semanticResults, keywordResults); return llmReranker.rerank(query, fused); // 返回 Top-K }写入管线串联一条 API 调用文档就变成了知识库# POST /kb/ingest curl -X POST http://localhost:8080/kb/ingest / -H Content-Type: application/json / -d {source: faq, title: 帮助中心, content: # 退款政策/n/n## 申请条件/n...}背后发生了什么Markdown 文档 → AdaptiveSplitter 切片 → bge-m3 向量化 → Qdrant 存储能力四Text2SQL — 让 Agent 能查库这是让 Agent 从客服升级为管家的关键。用户问帮我看看xx店有没有优惠券——知识库没有答案必须查数据库。但让 LLM 直接写 SQL 执行是危险的。我们做了多层防护// Text2SqlTool.java — SQL 生成 安全校验链简化 public String executeQuery(String question, String userId) { // 1. LLM 选表从 Redis 缓存的 Schema 中匹配最相关的表 String tableName selectTable(question, getCachedSchemas()); // 2. LLM 生成 SQL String sql generateSql(question, getTableSchema(tableName)); // 3. 安全校验链 validate(sql); // 仅允许 SELECT / 禁止 DROP ALTER TRUNCATE / 强制 LIMIT // 4. COUNT(*) 预检 → 行数太多时提示缩小范围 long totalRows countCheck(sql); if (totalRows MAX_RESULT_ROWS) { return 查询结果约 totalRows 条建议缩小查询范围如指定日期区间; } // 5. 执行 格式化 return formatResult(execute(sql)); }还有一个容易被忽视的细节表名缓存。用户说xx店数据库里是tb_shop_type用户说优惠券数据库里是tb_voucher。我们在 Redis 里维护了表名和表的comment能够在用户查询时快速加载到所需要的表。采用渐进式披露的方式当用户具体查询某张表时才暴露表的全部字段名称。能力五SSE 流式 上下文管理 — 用户体验兜底打字机效果没人愿意盯着空白页面等 10 秒。LLM 每生成几个 token 就推到前端用户看到的是逐字出现的打字机效果// ReactStreamController.java — SSE 流式输出简化 PostMapping(value /chat/react/stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxServerSentEventString chat(RequestBody ChatRequest request) { return Flux.create(sink - { graph.compile().stream(request.getThreadId(), userMessage) .forEachRemaining(event - { sink.next(ServerSentEvent.Stringbuilder() .event(event.type()) .data(event.content()) .build()); }); sink.complete(); }); }⚠️ Nginx 代理 SSE 必须关 bufferingproxy_buffering off; proxy_cache off;——这是最常见的坑忘了改就看不到打字机效果。滑动窗口对话超过 3 轮后全塞进 Prompt 会爆 Token。我们用了近全量 远摘要的策略最近 3 轮完整保留用户刚说的内容最重要 超出部分 ├── LLM 摘要压缩提取关键信息丢掉废话 └── 硬上限裁剪Token 数超阈值时强制截断用户提到之前聊过的内容时通过 PostgreSQL ILIKE 关键词检索回捞历史片段——不是全量回放是按需检索。两个关键坑帮你填了坑一Spring Boot 2.7 LangGraph4j 的版本联调LangGraph4j 的版本更新节奏很快和 LangChain4j 的版本之间有耦合。项目目前稳定在组件版本选型理由LangGraph4j1.8.19稳定的图编排 APIStateGraph 语法成熟LangChain4j1.16.2ToolOpenAiStreamingChatModel完美支持 DeepSeekSpring Boot2.7.18生态最成熟大部分公司仍在使用版本组合建议不要追新这三个版本已在大批量对话中验证过稳定性。坑二Checkpoint 旧数据导致加载变慢如果从旧版本升级全量存储的旧数据会让 DeltaPostgresSaver 的优化失效。症状升级后图初始化反而更慢。解决方案-- 清空旧的全量 checkpoint 数据让 Delta 机制重新工作 DELETE FROM lg4jcheckpoint;应用重启后DeltaPostgresSaver 会重新建立增量存储——初始化耗时立刻降到 1 秒以内。效果实测用同一个 O2O 业务场景对比三种模式的实际表现对比维度纯 LLM ChatBot RAGReAct Agent本项目“帮我找附近的火锅店”编造店铺名引用文档里的店铺列表可能过时调用 GeoSearchTool 查 Redis返回实时数据“我昨天消费多少”编造金额无法回答文档里没有调用 Text2SqlTool 查数据库返回真实金额“帮我排个号”假装排了回复请联系人工调用 QueueTicketTool 实际取号返回排号单推理过程可见❌❌✅ 输出每个节点信息规划→执行→观察→判断→回答总结核心要点ReAct Agent ≠ ChatBot 加 Prompt。关键区别是Agent 有自己的推理循环规划→执行→观察→判断能自主决定调用哪个工具、什么时候需要更多信息六个节点里Observer 和 Judge 是两个最重要的角色——前者负责纠偏空结果重试、错误分类后者负责控制循环信息够了就答、不够就重规划。没有这两个节点Agent 要么停不下来要么停下来时说的是错的增量 Checkpoint 不是性能优化是必备基础设施——没有它人机协同中断恢复、跨实例状态迁移都无从谈起RAG 检索的效果 80% 取决于切片和召回策略——结构化文档用结构感知切分代码块和表格用占位符保护Text2SQL 的安全防护比 SQL 生成本身重要得多——强制 LIMIT、COUNT 预检、仅允许 SELECT 缺一不可适用场景O2O / 电商智能客服查店、排队、下单、售后企业内部数据查询助手订单、库存、报表——Text2SQL 直接查库任何既有文档库需要 RAG又有业务系统需要 Tool Calling的场景如何学习大模型 AI 由于新岗位的生产效率要优于被取代岗位的生产效率所以实际上整个社会的生产效率是提升的。但是具体到个人只能说是“最先掌握AI的人将会比较晚掌握AI的人有竞争优势”。这句话放在计算机、互联网、移动互联网的开局时期都是一样的道理。我在一线科技企业深耕十二载见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事早已在效率与薪资上形成代际优势我意识到有很多经验和知识值得分享给大家也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我们整理出这套AI 大模型突围资料包✅ 从零到一的 AI 学习路径图✅ 大模型调优实战手册附医疗/金融等大厂真实案例✅ 百度/阿里专家闭门录播课✅ 大模型当下最新行业报告✅ 真实大厂面试真题✅ 2026 最新岗位需求图谱所有资料 ⚡️ 朋友们如果有需要《AI大模型入门进阶学习资源包》下方扫码获取~① 全套AI大模型应用开发视频教程包含提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点② 大模型系统化学习路线作为学习AI大模型技术的新手方向至关重要。 正确的学习路线可以为你节省时间少走弯路方向不对努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划带你从零基础入门到精通③ 大模型学习书籍文档学习AI大模型离不开书籍文档我精选了一系列大模型技术的书籍和学习文档电子版它们由领域内的顶尖专家撰写内容全面、深入、详尽为你学习大模型提供坚实的理论基础。④ AI大模型最新行业报告2025最新行业报告针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估以了解哪些行业更适合引入大模型的技术和应用以及在哪些方面可以发挥大模型的优势。⑤ 大模型项目实战配套源码学以致用在项目实战中检验和巩固你所学到的知识同时为你找工作就业和职业发展打下坚实的基础。⑥ 大模型大厂面试真题面试不仅是技术的较量更需要充分的准备。在你已经掌握了大模型技术之后就需要开始准备面试我精心整理了一份大模型面试题库涵盖当前面试中可能遇到的各种技术问题让你在面试中游刃有余。以上资料如何领取为什么大家都在学大模型最近科技巨头英特尔宣布裁员2万人传统岗位不断缩减但AI相关技术岗疯狂扩招有3-5年经验大厂薪资就能给到50K*20薪不出1年“有AI项目经验”将成为投递简历的门槛。风口之下与其像“温水煮青蛙”一样坐等被行业淘汰不如先人一步掌握AI大模型原理应用技术项目实操经验“顺风”翻盘这些资料真的有用吗这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理现任上海殷泊信息科技CEO其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证服务航天科工、国家电网等1000企业以第一作者在IEEE Transactions发表论文50篇获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。资料内容涵盖了从入门到进阶的各类视频教程和实战项目无论你是小白还是有些技术基础的技术人员这份资料都绝对能帮助你提升薪资待遇转行大模型岗位。以上全套大模型资料如何领取
返回列表