SpringCloud+原生LangChain双栈改造Vol.3 AI订单查询功能落地
前言
前文已经完成了Java+Python的基础设施构建,接下来进入核心业务:构建AI模块逻辑
阶段新目标
基于当前家政项目的特点,决定从性价比最高的方案入手:
- 聊天界面询问订单状况
- 评价总结(像电商平台那种在评论区顶上的AI评论总结)
- 智能客服(基于RAG构建知识库)
本文先搭建聊天界面询问订单功能
开始设计
一、需求澄清与领域建模
1.1 核心需求
用AI查询用户的订单相关信息,返回结果
1.2 列出核心实体名词
- 订单:
用户、服务人员/企业、订单状态、服务项目、数量、价格、地址、联系电话
1.3 梳理主要流程
正常流程: 收到查询意向→llm分析意向→llm调用tool→返回查询数据→llm整理→返回结果
异常流程:
输入意向不包含查询→llm正常回答
模型超时→返回友好提示
数据库没对应数据→llm返回友好提示
ai应用层宕机→返回友好提示
1.4 确定模块边界
Python端不做:
- 查询数据库
- 用户鉴权
Java端不做:
- 决策执行
二、架构选型与模块划分
2.1 当前已有功能
- 基于OpenAI SDK实现聊天功能
- Java↔Python websocket双向通信
- Java⇢前端 SSE;前端→Java HTTP
- 前端支持AI消息渲染
2.2 基于已有功能升级
- Python端(ai-engine模块)引入LangChain,配合本地tool(Python端)和远程tool(调用Java端),复用之前的websocket,方便后续扩展更多实时交互功能
- Java端复用查询接口,定义工具类调用接口
2.3 技术选型
- Python端:LangChain , LangGraph
- Java端和前端无需新增技术栈
2.4 新增模块分层
jzo2o-ai-engine/
├── app/
│ ├── agent/
│ │ ├── graph.py #StateGraph 编排 LLM 调用和工具执行
│ │ ├── state.py #Agent 状态定义
│ │ ├── tool_context.py #远程工具执行的异步桥接
│ │ └── tool.py #本地工具(Python直接执行)和远程工具(Java通过WebSocket执行)
│ ├── api/
│ │ └── ws_chat.py #LangGraph Agent 集成架构
│ ├── core/
│ │ └── config.py # 工具配置
│ ├── schemas/
│ └── ws_message.py # 远程工具调用消息模型
├── requirements.txt
├── .env
三、详细设计
1. 外部接口设计(WebSocket 协议)
1.1 WebSocket 路径
/ws/chat/{session_id}
一个 session_id 对应单独一条通道(支持多用户并发)
1.2 消息类型
Java → Python:
"type": "user_message"- 含
messages: [{role, content}, ...],触发新一轮会话/推理。
- 含
"type": "cancel"- 立即中断当前推理/工具调用。
"type": "tool_result"- Java 端 business tool 执行结果,随 tool_call_id 注入。
Python → Java:
"type": "token"- LLM 逐 token 输出(支持流式推理)。
"type": "agent_finish"- 当前 Agent/LLM 一轮推理全部完成。
"type": "error"- 当前轮异常信息。
"type": "tool_call"- (新增) 触发 Java 端特定工具执行。含 tool_call_id。
"type": "tool_start"- (新增) 工具开始执行,供前端进度反馈。
"type": "tool_end"- (新增) 工具结束。
1.3 典型流程举例
- Java 发送 user_message,Python Agent 开始推理流式回 token。
- Agent 需要调用外部工具时,发送 tool_call,Java 响应 tool_result。
- 推理被用户中止时,cancel 收到后 agent 立刻终止。
- 所有信令均为
{"type": ..., ...}结构化 JSON 帧。
2. 数据模型(app/schemas/ws_message.py)
新旧消息格式详细对照,并且为每一类 JSON 帧定义强类型 Pydantic 数据模型,便于 IDE 类型提示和后续协议扩展。
2.1 Java → Python
class WsClientMessage(BaseModel):
type: Literal["user_message", "cancel"]
messages: Optional[List[dict]]
class WsToolResultPayload(BaseModel):
type: Literal["tool_result"]
tool_call_id: str
content: str
2.2 Python → Java
class WsTokenPayload(BaseModel):
type: Literal["token"]
content: str
class WsToolCallPayload(BaseModel):
type: Literal["tool_call"]
tool_call_id: str
tool_name: str
args: dict[str, Any]
class WsToolStartPayload(BaseModel):
type: Literal["tool_start"]
tool_call_id: str
tool_name: str
class WsToolEndPayload(BaseModel):
type: Literal["tool_end"]
tool_call_id: str
class WsErrorPayload(BaseModel):
type: Literal["error"]
message: str
3. 新增/重构核心模块
3.1 Agent相关(jzo2o-ai-engine/app/agent/*)
3.1.1 agent/state.py
定义 Agent 运行状态(会话上下文),主要包含 messages:
class AgentState(TypedDict):
messages: Annotated[Sequence[AnyMessage], add_messages]
3.1.2 agent/tool_context.py
管理 Agent 与 Java 之间远程工具调用的生命周期,实现:
- 调用工具时,通过 send_callback 把 tool_call 发给 Java
- 等待 Java 结果,异步回调
- 工具调用支持超时、取消
核心接口:
class ToolExecutionContext:
async def execute(self, tool_call_id, tool_name, args): ...
async def on_tool_result(self, msg): ...
def cancel_all(self): ...
def set_send_callback(self, cb): ...
3.1.3 agent/graph.py
用 StateGraph/LangGraph 封装 Agent 推理主流程,抽象成 call_model、tool_executor 两类节点并可扩展:
- call_model:单步推理,确定是否有工具调用
- tool_executor:本地工具直接执行,远程工具异步发给 Java
- 多轮对话/工具调用通过 StateGraph condition 分支与循环实现
3.1.4 agent/tool.py
新增远程工具
@tool
async def customer_order_query(order_id: str) -> str:
"""查询客户订单详情。根据订单ID查询完整订单信息,包括订单状态、金额、服务类型、服务人员、地址等。"""
raise NotImplementedError("Remote tool executed via Java WebSocket")
3.2 LLM 相关(jzo2o-ai-engine/app/core/llm_client.py)
3.2.1 支持原始 OpenAI、ChatDeepSeek
- OpenAI SDK 用于传统 HTTP 单向流兼容
- LangChain-DeepSeek 支持多步推理/工具调用
- 配置项(model/key/base、温度、最大token),新增环境变量支持
3.2.2 关键补丁
- Monkey-patch ChatDeepSeek 的 message 序列化,额外透传 reasoning_content 字段,保证工具链场景简单切换。
3.3 WebSocket端点(jzo2o-ai-engine/app/api/ws_chat.py)
完全重构,采用三任务并发模型:
reader_task:循环从 WebSocket 收消息(解析类型后分发)- user_message 入自身队列
- cancel 事件、断连事件分别处理
- tool_result 传入 ToolExecutionContext
sender_task:主动从 send_queue 推送信令到 WebSocketagent_task(动态):处理一次 user_message 触发的 Agent 任务- 运行 LangGraph Agent,流式将 LLM token、工具信令推到 send_queue
- 能被 cancel_event、会话断开安全中断
代码核心片段
@router.websocket("/ws/chat/{session_id}")
async def ws_chat(...):
...
# reader_task, sender_task, agent_task 并发协作
...
while True:
msg = await incoming_queue.get()
if msg["type"] == "user_message":
# 启动新的 agent_task,结束此前对话
elif msg["type"] == "cancel":
# cancel 当前 agent_task
elif ...
3.4 Java端
WebSocket客户端
handleWsMessage方法新增:
case "tool_call":
// Python Agent 请求执行远程工具 → 调用业务服务 → WS 回传 tool_result
handleToolCall(frame, sessionId);
break;
case "tool_start":
// 透传工具开始事件给前端 (展示进度)
emitter.send(SseEmitter.event().name("tool_start").data(payload));
break;
case "tool_end":
// 透传工具完成事件给前端
emitter.send(SseEmitter.event().name("tool_end").data(payload));
break;
新增支持tool_call/tool_start/tool_end帧处理
/**
* 处理 tool_call 帧 — 异步执行远程工具, 结果通过 WebSocket 回传给 Python
*/
private void handleToolCall(Map<String, Object> frame, String sessionId) {
String toolName = (String) frame.get("tool_name");
String toolCallId = (String) frame.get("tool_call_id");
@SuppressWarnings("unchecked")
Map<String, Object> args = (Map<String, Object>) frame.getOrDefault("args", Map.of());
CompletableFuture.supplyAsync(() -> toolExecutor.execute(toolName, toolCallId, args))
.thenAccept(result -> sendToolResult(sessionId, toolCallId, result))
.exceptionally(e -> {
log.error("远程工具执行失败, sessionId={}, toolName={}: {}",
sessionId, toolName, e.getMessage());
// 失败时也回传 tool_result, 避免 Python 侧干等超时
sendToolResult(sessionId, toolCallId,
"{\"error\": \"" + e.getMessage().replace("\"", "'") + "\"}");
return null;
});
}
/** 通过 WebSocket session 向 Python 发送 tool_result 帧 */
private void sendToolResult(String sessionId, String toolCallId, String content) {
WebSocketSession wsSession = activeWsSessions.get(sessionId);
if (wsSession != null && wsSession.isOpen()) {
try {
String resultJson = objectMapper.writeValueAsString(
Map.of("type", "tool_result",
"tool_call_id", toolCallId,
"content", content));
wsSession.send(Mono.just(wsSession.textMessage(resultJson)))
.subscribe(
null,
e -> log.error("发送 tool_result 失败, sessionId={}: {}",
sessionId, e.getMessage()));
} catch (Exception e) {
log.error("序列化 tool_result 失败, sessionId={}: {}",
sessionId, e.getMessage());
}
} else {
log.warn("WebSocket 会话已关闭, 无法发送 tool_result, sessionId={}", sessionId);
}
}
验收
验收指标:
- 程序运行正常
- 核心业务:AI查询订单能跑通
开始验收
所有服务启动启动启动启动
还有这个
工具调用:
完整回答:
好的,我来查询您的订单信息。以下是您查询的订单 2605200000000000129 的详细信息:
📋 订单基本信息
项目 内容
订单编号 2605200000000000129
服务类型 🧹 保洁清
服务项目 日常保洁
数量 1 份
订单金额 ¥58.00(实付)
订单状态 已下单(待处理)
支付状态 已支付
评价状态 未评价
👤 客户信息
项目 内容
联系人 哈喽哈喽
联系电话 18999665522
服务地址 重庆市重庆市11街11号
🕐 时间信息
项目 时间
创建时间 2026年5月20日
| 服务开始时间 | 2026年5月21日 |
订单目前已支付成功,服务安排在了 2026年5月21日,请您按时到达服务地址。如果您还需要其他帮助,请随时告诉我!😊
悬浮窗窗口界面:
注:本篇省去了前端的开发流程,主要就是新增了侧边栏独立聊天界面,状态可在悬浮窗和侧边栏之间转换,升级了下TDesign版本和做点适配
验证其有的工具:
注:这里把这篇文章没涉及到的功能也列出来了,后面的文章会提一下
验收通过
总结
本文基于家政项目,使用 Java + Python 混合架构 成功实现了 AI 查询订单功能。核心成果如下:
- Python 端:引入 LangChain + LangGraph 编排 Agent 推理流程,通过 WebSocket 与 Java 端双向通信,实现了远程工具调用的完整生命周期管理。
- Java 端:复用现有查询接口,新增
tool_call/tool_start/tool_end帧处理,异步执行业务工具并通过 WebSocket 回传结果。 - 通信协议:设计了结构化的 JSON 帧协议,覆盖
user_message、cancel、token、tool_call、tool_result等全链路信令。
验收环节已跑通完整链路,AI 能够准确查询订单详情并以结构化表格形式返回结果,悬浮窗和侧边栏界面运行正常。
下一个功能:评价总结
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)