摘要:基于 Spring Boot + LangChain4j 实现支持多轮对话的 AI 助手,让仓库任务查询变得像聊天一样简单。
引言
在仓库管理系统中,我们经常需要查询任务状态、运行情况等信息。传统的做法是打开后台系统,找到对应的查询页面,输入任务 ID,然后等待结果。
但如果这一切可以通过聊天完成呢?
"帮我查一下任务 ID 是 85090,运行情况"
"任务 ID 85090,运行完成没有?"
就像和同事聊天一样自然。这正是我们基于 LangChain4j 实现的 AI 聊天机器人所做的。
技术架构
核心组件
| 组件 | 说明 |
|---|---|
| LangChain4j | Java 生态的 LLM 应用框架 |
| Spring Boot | 后端框架,提供 REST API |
| Reactor (Flux) | 响应式流,支持 SSE 流式输出 |
| InMemoryChatMemoryStore | 内存级聊天记录存储 |
整体流程
用户请求 → Spring Controller → @AiService → LLM API (流式)
↑ ↓
ChatMemoryProvider ← InMemoryChatMemoryStore
关键实现
1. 聊天记录存储
@Slf4j
public class InMemoryChatMemoryStore implements ChatMemoryStore {
private final Map<Object, List<ChatMessage>> store = new ConcurrentHashMap<>();
@Override
public List<ChatMessage> getMessages(Object memoryId) {
return store.getOrDefault(memoryId, List.of());
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
store.put(memoryId, messages);
}
@Override
public void deleteMessages(Object memoryId) {
store.remove(memoryId);
}
}
设计要点:
- 使用
ConcurrentHashMap保证线程安全 - 通过
memoryId(即 sessionId)隔离不同会话 - 应用重启后历史会丢失(生产环境可替换为 Redis/数据库)
2. AI 配置与流式模型
@Configuration
@RequiredArgsConstructor
public class AiConfig {
final AiProperties aiProperties;
@Bean
public OpenAiStreamingChatModel openAiStreamingChatModel() {
return OpenAiStreamingChatModel.builder()
.apiKey(aiProperties.getApiKey())
.baseUrl(aiProperties.getBaseUrl())
.sendThinking(true) // 发送思考内容
.returnThinking(true) // 接收思考内容
.modelName(aiProperties.getModelName())
.build();
}
@Bean("chatMemoryProvider")
public ChatMemoryProvider chatMemoryProvider(InMemoryChatMemoryStore store) {
return memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.chatMemoryStore(store)
.maxMessages(50) // 保留最近50条消息
.build();
}
}
亮点:
-
sendThinking/returnThinking支持模型的推理内容往返 -
MessageWindowChatMemory控制消息窗口大小,避免上下文过长
3. AI 服务接口
@AiService(
streamingChatModel = "openAiStreamingChatModel",
tools = {"tasksFileReadTool"},
chatMemoryProvider = "chatMemoryProvider"
)
public interface IChatService {
Flux<String> chat(@MemoryId String sessionId, @UserMessage String message);
}
核心特性:
-
@AiService注解自动实现接口,无需手写实现类 -
tools参数注入自定义工具(如文件读取、数据库查询) - 返回
Flux<String>实现 SSE 流式输出
4. Controller 层
@RestController
@RequiredArgsConstructor
public class ChatController {
final IChatService chatService;
@GetMapping(value = "chat", produces = "text/plain;charset=utf-8")
public Flux<String> chat(String sessionId, String question) {
return chatService.chat(sessionId, question);
}
}
实际效果
第一轮对话
用户提问:
帮我查一下任务id是85090,运行情况
AI 回复:
好的,我来查询任务ID为85090的相关信息。
任务ID 85090 运行情况报告
项目 内容 任务ID 85090 箱号 CDKJLX013566 任务类型 入库任务(type=1, smallType=3) 最终状态 ✅ 已完成(status=3) 时间线:
- 10:23:18 — 任务创建
- 10:23:19 — 任务下发
- 10:24:21~24 — RGV小车(03号)在6层执行任务
- 10:24:30 — 任务状态上报为完成
结论: 任务85090是一个入库任务,将箱号CDKJLX013566从2层搬运至6层储位,整个过程耗时约1分12秒,成功完成。
第二轮对话(带历史记忆)
用户提问:
任务id85090,运行完成没有?
AI 回复:
根据查询到的日志信息,任务ID 85090 已经运行完成了 ✅
关键信息如下:
- 任务状态 → 已完成(status=3)
- 入库完成时间:2026-05-13 10:24:30
- 任务删除回调成功:success=true, errorCode=0
- 数据已迁移至历史表归档
总结: 任务85090已于 10:24:30 顺利执行完成,整个过程无异常。
注意: 第二轮对话中,AI 不需要用户再次提供任务详情,直接基于历史上下文给出了精准回答。
技术亮点总结
1. 多轮对话记忆
通过 ChatMemoryProvider + InMemoryChatMemoryStore,每个 sessionId 拥有独立的对话历史,AI 能理解上下文。
2. 流式输出体验
使用 Flux<String> 实现 SSE 流式返回,用户可以看到 AI 逐字输出的效果,体验更接近真实对话。
3. 工具扩展能力
@AiService 的 tools 参数支持注入任意 Bean,可以轻松扩展:
- 数据库查询工具
- 文件读取工具
- API 调用工具
- 自定义业务逻辑
4. 思考内容往返
sendThinking(true) + returnThinking(true) 让模型的推理过程也能在对话中传递,适合需要展示推理链的场景。
生产环境优化建议
| 优化项 | 当前方案 | 生产建议 |
|---|---|---|
| 记忆存储 | 内存 Map | Redis / PostgreSQL |
| 消息窗口 | 固定50条 | 动态窗口 + Token 限制 |
| 流式输出 | SSE | WebSocket / SSE |
| 鉴权 | 无 | JWT / OAuth2 |
| 限流 | 无 | Redis 滑动窗口 |
| 监控 | 日志 | Prometheus + Grafana |
结语
通过 LangChain4j + Spring Boot,我们用不到 100 行核心代码就实现了一个带历史记忆的 AI 聊天机器人。仓库管理人员只需要像聊天一样提问,就能获取任务状态、运行情况等信息。
代码即文档,对话即交互。 这,就是 AI 原生应用的魅力。
本文代码基于 LangChain4j 1.x + Spring Boot 3.x 实现,适用于 Java 17+ 环境。
标签: #LangChain4j #SpringBoot #AI聊天机器人 #仓库管理 #Java #大模型应用