尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

springboot+langchain4j 实战 Day15——打造一个“生产“级 Agent 服务:单个 Agent 同时持有多个 Tool,LLM 自主判断调用哪个

springboot+langchain4j 实战 Day15——打造一个“生产“级 Agent 服务:单个 Agent 同时持有多个 Tool,LLM 自主判断调用哪个
📅 发布时间:2026/6/26 4:11:26

Day 15 — 单 Agent 多 Tool + MySQL 数据源 + Redis 缓存 + AOP 追踪 + SSE 流式输出

一、目标

融合 Day 1-14 全部能力,打造一个生产级 Agent 服务:单个 Agent 同时持有多个 Tool,LLM 自主判断调用哪个;数据落 MySQL、Tool 结果走 Redis 缓存、每次调用被 AOP 追踪。

二、架构

浏览器 (static/index.html) ├── GET /agent/chat?message=... → JSON 同步响应 └── GET /stream/chat?message=... → SSE 逐 token 流式推送 ↓ UnifiedAgentController ↓ UnifiedAgentService(单 Agent) ├── OrderTool ← MyBatis-Plus → MySQL t_order ├── RefundTool ← MyBatis-Plus → MySQL t_refund ├── KnowledgeBaseTool ← MyBatis-Plus → MySQL t_knowledge └── LLM (DeepSeek-V3 via 硅基流动) ↓ ToolTraceAspect(AOP 环绕通知,记录每次 @Tool 调用) ↓ Redis(@Cacheable,TTL 10min)

与 Day 13/14 的关键区别:

维度Day 13/14Day 15
路由方式Router LLM 先分类,再分发到子 Agent无需 Router— 单 Agent 挂多个 Tool,LLM 自己判断
数据来源Mock 硬编码MySQL 真实数据库(Druid 连接池 + MyBatis-Plus)
缓存层无Redis@Cacheable缓存 Tool 查询结果
调用追踪无(仅 log.info)AOP 切面记录入参 / 耗时 / 结果
前端无SSE 打字机效果HTML 页面(static/index.html)
流式对话Day 12 独立项目集成在统一项目中(双端点)

三、技术栈

组件版本用途
Spring Boot2.7.18应用框架
Tomcat9.0.83(内嵌)Web 容器
Java17运行语言
LangChain4j0.36.2Agent 框架(AiServices+@Tool)
DeepSeek-V3via 硅基流动LLM 模型
MyBatis-Plus3.5.3.1ORM + Lambda 查询
Druid1.2.20数据库连接池(含监控页/druid)
MySQL8.0(Docker 3307)业务数据库
Redis7(Docker 6379)Tool 结果缓存
Lombok1.18.30减少样板代码
Jackson2.13.x(Spring Boot 内置)JSON 序列化

四、项目结构

day15/ ├── pom.xml ├── README.md └── src/main/ ├── java/com/day15/demo/ │ ├── Day15Application.java # 启动类 │ ├── aop/ │ │ └── ToolTraceAspect.java # AOP 切面:环绕所有 @Tool 方法 │ ├── config/ │ │ ├── CacheConfig.java # Redis 缓存配置(TTL 10min) │ │ └── ChatModelConfig.java # LLM 模型 Bean(Chat + Streaming 双实例) │ ├── controller/ │ │ └── UnifiedAgentController.java # 双端点:/agent/chat + /stream/chat │ ├── dto/ │ │ └── Result.java # 统一响应体 {code, message, data} │ ├── entity/ │ │ ├── Order.java # t_order 映射(@TableId + @JsonIgnore + @JsonFormat) │ │ ├── Refund.java # t_refund 映射 │ │ └── Knowledge.java # t_knowledge 映射 │ ├── mapper/ │ │ ├── OrderMapper.java # MyBatis-Plus BaseMapper │ │ ├── RefundMapper.java │ │ └── KnowledgeMapper.java │ ├── service/ │ │ └── UnifiedAgentService.java # 单 Agent 注入 3 个 Tool │ └── tool/ │ ├── OrderTool.java # 订单查询 / 列表(@Cacheable + MySQL) │ ├── RefundTool.java # 退款创建 / 政策(写入 MySQL) │ ├── KnowledgeBaseTool.java # 知识库检索 / 目录(@Cacheable + MySQL) │ └── WeatherTool.java # 天气(备用,暂未挂载) └── resources/ ├── application.yml # MySQL + Druid + Redis 配置 ├── schema.sql # DDL 建表(LONGTEXT 兼容 MySQL) ├── data.sql # 种子数据(INSERT IGNORE,4 订单 + 1 退款 + 5 知识库) └── static/ └── index.html # 前端聊天页面(SSE 打字机效果)

五、核心代码

5.1 双模型注入(ChatModelConfig)

@Bean("openAiChatModel")publicOpenAiChatModelopenAiChatModel(){// 普通对话用returnOpenAiChatModel.builder().apiKey(apiKey).baseUrl(baseUrl).modelName(modelName).temperature(0.3).timeout(Duration.ofSeconds(60)).maxRetries(2).build();}@Bean("openAiStreamingChatModel")publicOpenAiStreamingChatModelopenAiStreamingChatModel(){// SSE 流式用returnOpenAiStreamingChatModel.builder().apiKey(apiKey).baseUrl(baseUrl).modelName(modelName).temperature(0.3).timeout(Duration.ofSeconds(60)).build();}

两种模式用同一个AiServices.Builder构建,AiServices自动根据接口方法返回值分发:

  • 返回String→ 走chatLanguageModel
  • 返回TokenStream→ 走streamingChatLanguageModel

5.2 单 Agent 多 Tool(UnifiedAgentService)

@PostConstructpublicvoidinit(){agent=AiServices.builder(UnifiedAgent.class).chatLanguageModel(chatModel).streamingChatLanguageModel(streamingChatModel).tools(orderTool,refundTool,knowledgeBaseTool)// 一次注入 3 个.chatMemory(MessageWindowChatMemory.withMaxMessages(10)).build();}

@SystemMessage引导 LLM 行为:

  • 订单/物流 → 优先用 Tool 查
  • 退款 → 主动创建工单
  • 技术问题 → 先搜知识库再回答
  • 不要凭自身知识猜测

5.3 MySQL 数据源(application.yml)

spring:datasource:type:com.alibaba.druid.pool.DruidDataSourceurl:jdbc:mysql://localhost:3307/ai_logs?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername:rootpassword:root123driver-class-name:com.mysql.cj.jdbc.Driverdruid:initial-size:5min-idle:5max-active:20max-wait:60000filter:stat:enabled:trueslow-sql-millis:2000log-slow-sql:truewall:enabled:false# MyBatis-Plus Lambda 查询不支持 wall 拦截

为什么wall: false:MyBatis-Plus LambdaWrapper 生成的 SQL 会触发 Druid WallFilter 误判,关闭后不影响安全(SQL 由框架生成,无拼接注入风险)。

5.4 Entity 注解规范

@Data@TableName("t_order")publicclassOrder{@JsonIgnore// 不暴露给前端(内部主键)@TableId(type=IdType.AUTO)// 数据库自增privateLongid;privateStringorderId;// 业务编号privateStringproduct;privateStringstatus;privateStringlogistics;privateBigDecimalamount;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="Asia/Shanghai")privateLocalDateTimecreatedAt;// 格式化输出,避免序列化为数组 [2025,6,1,...]}

5.5 AOP 链路追踪(ToolTraceAspect)

@Around("@annotation(dev.langchain4j.agent.tool.Tool)")publicObjecttrace(ProceedingJoinPointpjp)throwsThrowable{Stringmethod=pjp.getSignature().toShortString();Stringargs=/* 拼接参数 */;longstart=System.currentTimeMillis();log.info("[ToolTrace] ▶ {} | args=({})",method,args);Objectresult=pjp.proceed();longelapsed=System.currentTimeMillis()-start;log.info("[ToolTrace] ✔ {} | {}ms | result={}",method,elapsed,truncate(result,120));returnresult;}

输出示例:

[ToolTrace] ▶ OrderTool.queryOrder(..) | args=(20250615) [OrderTool] 查询订单(DB): 20250615 ==> Preparing: SELECT ... FROM t_order WHERE order_id = ? ==> Parameters: 20250615(String) <== Total: 1 [ToolTrace] ✔ OrderTool.queryOrder(..) | 45ms | result=订单 20250615 ...

5.6 Redis 缓存(CacheConfig+@Cacheable)

@Tool("Query order by orderId")@Cacheable(value="order",key="#orderId")// 同一订单号 10 分钟内走缓存publicStringqueryOrder(StringorderId){...}
  • Key 序列化:StringRedisSerializer
  • Value 序列化:GenericJackson2JsonRedisSerializer
  • TTL:10 分钟(spring.cache.redis.time-to-live: 600000)

5.7 SSE 流式推送

@GetMapping(value="/stream/chat",produces="text/event-stream;charset=UTF-8")publicSseEmitterstream(@RequestParamStringmessage){SseEmitteremitter=newSseEmitter(TimeUnit.MINUTES.toMillis(2));TokenStreamtokenStream=unifiedAgentService.stream(message);Executors.newSingleThreadExecutor().execute(()->{tokenStream.onNext(token->emitter.send(SseEmitter.event().data(token))).onComplete(resp->emitter.complete()).onError(emitter::completeWithError).start();});returnemitter;}

关键 API 匹配(LangChain4j 0.36.2):

  • onNext(Consumer<String>)— 每个 token 回调
  • onComplete(Consumer<Response<AiMessage>>)— 流结束
  • onError(Consumer<Throwable>)— 异常

六、双端点 API

GET /agent/chat— JSON 同步

curl"http://localhost:8088/agent/chat?message=查订单20250615"# → {"code":200,"message":"success","data":"订单 20250615\n商品: ..."}

GET /stream/chat— SSE 流式

curl-N"http://localhost:8088/stream/chat?message=hello"# → data:你好# → data:呀# → data:!

前端页面

浏览器打开http://localhost:8088/index.html:

  • 左侧:Agent 信息 + 快捷提问
  • 右侧:对话区(SSE 打字机逐字渲染)
  • 支持:回车发送、Tool 调用标记、超时提示

七、Druid 监控

http://localhost:8088/druid/→ 用户名admin/ 密码admin123

八、启动方式

前置条件

# MySQL(已运行)dockerps|grepai-mysql# → 0.0.0.0:3307->3306/tcp# Redis(已运行)dockerps|grepai-redis# → 0.0.0.0:6379->6379/tcp

启动

cdday15 mvn clean compile spring-boot:run-DskipTests

输出关键日志:

Tomcat started on port(s): 8088 (http) with context path '' Day15 UnifiedAgent 初始化完成: OrderTool + RefundTool + KnowledgeBaseTool (MySQL数据源 + Redis缓存 + AOP追踪) Started Day15Application in 3.3 seconds

九、演进路线

Day 1-2 基础环境 + LangChain4j Demo Day 3 RAG (InMemoryEmbeddingStore) 英文全称:Retrieval-Augmented Generation(检索增强生成)。意思就是:让 AI 在回答之前,先去「查资料」,再基于查到的资料来回答。就像考试时允许你翻书,而不是只靠脑子记忆答题。 Day 4 PGVector 向量库 Day 5 Redis 聊天记忆 Day 6-7 单元测试 + 统一响应体 Day 8-9 AOP 日志 + 降级Sringboot 2.7.18 Day 10 工具类完善,并且 MySQL + PGVector + Redis 一键docker-compose部署依赖的开发环境 Day 11 Agent 联网搜索,调用天气api Day 12 网页 + SSE 流式对话 Day 13 多 Agent 协作 (Router) Day 14 子 Agent 工具注入 Day 15 ← 融合全部能力:单 Agent 多 Tool + MySQL + Redis + AOP + SSE

Day 15 是项目集大成的里程碑 —— 不再需要 Router 分流,LLM 自己看懂意图并选择 Tool,数据落库、结果缓存、调用可追踪,同时支持 JSON 和 SSE 两种输出模式。

相关新闻

  • Web安全十大核心漏洞原理与防御实战指南
  • FPGA实战(32):多通道ADC数据打包模块设计
  • 大气层整合包系统:终极Nintendo Switch定制固件完全指南

最新新闻

  • 2026年常见文献管理工具优缺点横评:7款主流软件功能对比与客观选型参考
  • HarmonyOS技术精讲-UI开发调试调优:从零认识ArkUI调试体系
  • 如何用KeymouseGo实现自动化操作:鼠标键盘录制与重复执行的终极指南
  • 【C/C++】select、poll、epoll 实战对比:从 fd_set 到就绪事件列表
  • 云手机不只是挂机:ARM 虚拟化架构 + ADB 自动化实战,附完整代码
  • 从 0 到 1 搭建 NexusAgent

日新闻

  • Qwen2.5-Turbo百万上下文实战指南:百炼平台长文本处理全解析
  • 怎么监控对标账号更新,2026年作者监控工作流,5款深度对比
  • EdgeRemover:专业级Windows Edge浏览器管理工具,彻底解决顽固软件卸载难题

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号