2249 字
约 7 分钟
2
LangGraph4j 多 Agent 工作流:把 AI 放进确定性的业务流水线

大模型负责它擅长的不确定性任务,工作流负责确定性的流程控制。

LangGraph4j 多 Agent 工作流:把 AI 放进确定性的业务流水线

Spring AI 的 ChatClient 很适合解决:

用户输入
   ↓
LLM
   ↓
Tool Calling
   ↓
最终回答

这类“一进一出”的对话任务。

但有些任务不是一次模型调用就结束,而是:

步骤 A
 ↓
判断
 ↓
步骤 B
 ↓
判断
 ↓
步骤 C
 ↓
步骤 D

例如岗位数据采集:

判断输入类型
   ↓
AI 提取岗位
   ↓
业务规则清洗
   ↓
发布岗位

这种 多步骤 + 条件分支 + 状态传递 的任务,更适合工作流引擎。

LangGraph4j 就是用来解决这类问题的。


1. ChatClient 和 LangGraph4j 的区别

ChatClient 关注的是:

怎么完成一次 LLM 调用。

LangGraph4j 关注的是:

多个处理步骤应该按照什么顺序执行。

可以简单理解成:

ChatClient
= 一个节点里的 AI 能力

LangGraph4j
= 把很多节点组织成流程

所以两者不是替代关系。

反而经常是:

LangGraph4j
    ↓
Node A
    ↓
Node B → ChatClient → LLM
    ↓
Node C
    ↓
Node D

AI 只是整个工作流中的某一个环节。


2. LangGraph4j 的三个核心概念

理解 LangGraph4j,只需要抓住:

Node
Edge
State

Node:节点

一个节点就是一个独立处理步骤。

例如:

task_classify
任务分类

task_gather
数据采集

draft_washer
数据清洗

draft_publish
数据发布

代码类似:

.addNode(
    "task_gather",
    node_async(taskGatherAgent::apply)
)

节点只负责自己的事情,不需要知道整个流程怎么走。


Edge:边

边决定:

当前节点执行完成以后去哪。

固定边:

A → B

表示 A 执行完成一定进入 B。

条件边:

        → B
A
        → C

根据当前状态决定下一步。

例如:

.addConditionalEdges(
    "task_classify",
    edge_async(state ->
        state.getTask() == null
            ? END
            : "gather"
    ),
    ...
)

也就是:

分类成功
→ 继续采集

分类失败
→ END

条件边是工作流非常重要的能力。


3. State:节点之间怎么传数据?

节点之间不应该:

nodeA.callNodeB();

而是通过一个共享状态传递数据。

例如:

INPUT
→ 原始输入

TASK
→ 分类后的任务

GATHER
→ AI 提取结果

WASHER
→ 清洗后的记录

PUBLISH
→ 最终发布结果

整个执行过程就是不断丰富 State:

开始

State
{
  input
}

分类完成

State
{
  input,
  task
}

采集完成

State
{
  input,
  task,
  gather
}

清洗完成

State
{
  input,
  task,
  gather,
  washer
}

发布完成

State
{
  input,
  task,
  gather,
  washer,
  publish
}

所以可以把 State 理解成:

整条工作流共享的数据总线。


4. 一个完整的岗位采集工作流

整个流程可以画成:

START
  ↓
Task Classify
  │
  ├── 无效 → END
  │
  ↓
Task Gather
  │
  ├── 无数据 → END
  │
  ↓
Draft Washer
  │
  ├── 无有效数据 → END
  │
  ↓
Draft Publish
  ↓
END

这里非常重要的一点是:

流程怎么走,不是让 LLM 决定,而是业务代码决定。

例如:

task == null
gatherList.isEmpty()
validIds.isEmpty()

全部是确定性判断。

这和让大模型回答:

“你觉得下一步应该执行哪个节点?”

完全不同。


5. AI 应该放在哪?

这个设计里,大模型只负责:

非结构化内容
↓
LLM
↓
结构化岗位数据

比如:

网页
图片
招聘公告
Excel 内容

交给大模型提取:

List<Job>

后面的:

公司类型标准化
招聘类型转换
年份校验
数据发布

全部使用 Java 业务代码。

这体现了一个非常重要的 Agent 设计原则:

确定性的事情,不要交给 LLM。

例如:

if (list.isEmpty())

Java 可以 100% 确定。

就没必要问模型:

“请判断这些数据是否为空。”

否则只会增加:

Token
延迟
成本
不确定性

6. LangGraph4j 真正解决的是编排

你可以把整个系统理解为:

             LangGraph4j
                  │
       ┌──────────┼──────────┐
       ↓          ↓          ↓
   Java Node   AI Node    Java Node
       │          │          │
       │     ChatClient      │
       │          ↓          │
       │         LLM         │
       │                     │
       └──────── State ──────┘

所以:

LangGraph4j 不是让所有步骤都变成 AI,而是把 AI 节点和普通业务节点组织在一张图里。

这才是最值得沉淀的理解。


7. Java 使用 LangGraph4j 要注意 State 序列化

LangGraph4j 的状态底层可以理解成:

Map<String, Object>

如果里面只放:

String
Integer
Boolean

通常没什么问题。

但实际项目经常需要:

GatherTaskEntity
GatherVo
List<Job>

这种复杂对象。

因此需要给这些类型注册序列化器:

serializer.mapper().register(
    GatherTaskEntity.class,
    new JsonSerializer<>(
        GatherTaskEntity.class
    )
);

否则跨节点传递时可能出现:

类型丢失
反序列化失败
状态恢复失败

所以 Java 场景下要特别记住:

State 中放复杂 POJO 时,要提前设计好序列化。


8. 为什么工作流还需要 SSE?

工作流和普通请求不一样。

一次执行可能持续:

10 秒
30 秒
甚至几分钟

如果前端只发送:

POST /workflow/run

然后一直等结果,用户根本不知道执行到哪了。

因此可以通过 SSE 推送:

任务分类开始
↓
任务分类完成

数据采集开始
↓
已提取 23 条岗位

数据清洗开始
↓
18 条通过

发布开始
↓
发布完成

于是:

LangGraph4j Node
      ↓
Workflow Event
      ↓
SSE
      ↓
Web 管理后台

管理员就能实时看到整个流程。

这属于工作流非常重要的:

Observability / 可观测性。


9. 对话 Agent 和工作流 Agent 怎么选?

这个地方最值得以后做项目时直接套用。

对话型 Agent

例如:

用户:
帮我找武汉 Java 岗位

Agent:
好的……

用户:
25K 以上

Agent:
……

重点是:

自然语言理解
多轮上下文
Tool Calling
用户交互

适合:

Spring AI
ChatClient
ChatMemory
ReAct

工作流型 Agent

例如:

上传招聘文件
↓
识别
↓
采集
↓
清洗
↓
发布

重点是:

步骤明确
输入输出明确
有条件分支
需要状态传递
需要失败终止

适合:

LangGraph4j

可以直接记一个判断方法:

任务核心是“和人交流”,优先 ChatClient;任务核心是“把事情按步骤做完”,优先 Workflow。


10. 两套 Agent 可以同时存在

真实项目通常不是二选一。

完全可以:

                AI Application
                       │
           ┌───────────┴───────────┐
           ↓                       ↓
      Conversational            Workflow
         Agent                   Agent
           │                       │
       ChatClient              LangGraph4j
           │                       │
    用户岗位推荐              岗位数据采集
           │                       │
           └──────────┬────────────┘
                      ↓
                   Database

工作流负责:

把岗位数据采集进来

对话 Agent 负责:

把这些岗位推荐给用户

两个系统职责不同,但可以共享底层数据。


11. 最值得沉淀的架构原则

这一篇真正重要的不是:

addNode()
addEdge()
addConditionalEdges()

而是这几个原则:

确定性流程
→ Workflow 控制

不确定性理解
→ LLM 处理

节点之间
→ State 传递

流程分支
→ Conditional Edge

复杂 POJO
→ Serializer

长任务进度
→ SSE

核心思想可以概括为:

不要让 LLM 控制所有事情,让工作流控制流程,让 LLM 只处理真正需要智能判断的部分。


最后总结

LangGraph4j 最适合解决:

多步骤
+
条件分支
+
共享状态
+
流程可观测

它和 Spring AI 的关系可以理解成:

Spring AI
→ 提供 AI 能力

LangGraph4j
→ 编排 AI 能力和业务能力

最终:

Workflow
   ↓
确定性 Java
   ↓
LLM
   ↓
确定性 Java
   ↓
最终结果

最值得记住的一句话是:

工作流引擎的价值,不是让 AI 参与更多步骤,而是把 AI 限制在它真正擅长的不确定性环节,把流程控制、校验、清洗、发布这些确定性任务交还给业务代码。

把你前面学的内容继续串起来,现在整个体系已经越来越完整:

ChatClient
→ 单次 AI 调用编排

Advisor
→ 增强调用过程

ReAct
→ 控制模型与工具循环

MCP
→ 扩展工具能力

LangGraph4j
→ 编排多个业务 / AI 节点

State
→ 在节点之间传递数据

Conditional Edge
→ 控制工作流分支
LangGraph4j 多 Agent 工作流:把 AI 放进确定性的业务流水线
http://www.clxhxhhr.top/posts/663/
作者
clxstart
发布于
2026-09-17
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。