从 Activiti 到 LangGraph:为什么说 AI Agent 的本质是“工作流引擎”?
引言
如果你是一名深耕 Java 领域、用过 Activiti 或 Flowable 的开发者,当你第一次接触到 LangChain 的最新框架 LangGraph 时,你可能会有一种强烈的既视感。
没错,你的直觉是对的。在“提示词工程”逐渐向“代理工作流”演进的今天,LangGraph 本质上就是一套适配 LLM 时代的轻量级、代码化、具备异步处理能力的 BPMN 引擎。
一、 核心概念:换个名字的“老朋友”
在 LangGraph 中,很多概念都能在 Activiti 中找到完美的映射。我们可以通过下表快速建立认知:
| 功能维度 | Activiti (BPMN 2.0) | LangGraph (Python) | 核心本质 |
|---|---|---|---|
| 流程定义 | Process Definition (XML) | StateGraph |
规定流程的“蓝图” |
| 执行单元 | Service Task / User Task | Node (Python Function) |
每一个具体干活的“步骤” |
| 数据传递 | Process Variables | State (TypedDict) |
贯穿始终的“全局变量池” |
| 逻辑网关 | Exclusive Gateway (XOR) | Conditional Edge |
决定下一步去哪里的“分叉口” |
| 持久化 | DB Persistence (ACT_RU_*) | Checkpointer (Saver) |
断点续传、状态保存的“记事本” |
| 人工干预 | User Task (Wait State) | interrupt() |
程序暂停,等待外部信号“唤醒” |
二、 为什么 LangGraph 选择了“图”而不是“链”?
早期的 LangChain 强调 Chain(链),就像是硬编码的脚本,一条路走到黑。但这无法应对 AI 的复杂性。
- 确定性 vs. 可能性:
- Activiti 的路由通常基于硬逻辑(如
金额 > 5000)。而 LangGraph 的节点往往是一个 LLM 思考步骤。它通过理解语义来决定路由,例如:“如果用户语气愤怒,则跳转到‘人工介入’节点”。 - 高频循环 (Agentic Loop):
- 在传统流程中,循环(Loop)往往意味着异常。但在 AI 领域,循环是常态。
- 示例:AI 写代码 -> 运行测试 -> 报错 -> 返回 AI 修复 -> 再次运行。
- LangGraph 原生支持这种**“思考-行动-观察”**的闭环,这是传统 BPMN 引擎难以优雅处理的。
三、 深度解析:LangGraph 的三大杀手锏
1. 状态管理 (The State)
在 Activiti 里,我们习惯用 Map<String, Object> 存变量。LangGraph 将其升级为 TypedDict + Reducers。
你可以精确定义:
messages字段是 Append(追加) 模式,保留对话全历史。current_status字段是 Replace(覆盖) 模式,只保留最新进度。
- 这种声明式的状态管理,比手动维护 Context 对象要安全得多。
2. “时间旅行”与持久化 (Time Travel)
Activiti 的执行记录存在数据库表里,LangGraph 的 Checkpointer 也是如此。
这意味着你可以实现 “时间旅行”:
- 发现 AI 在第 5 步回答错了?没关系。你可以回滚到第 4 步的状态,修改 Prompt,然后让它重新生成。这种调试能力是传统开发不敢想象的。
3. 人工参与 (Human-in-the-loop)
这是邮件代理等复杂场景的核心。
通过 interrupt(),LangGraph 模拟了 Activiti 的 Wait State。当程序执行到关键步骤(如:涉及金钱交易、回复敏感邮件),它会自动挂起。
- 保存状态 -> 退出线程 -> 等待人工审核 -> Resume 恢复执行。
- 这保证了 AI 的行为永远在人类的“安全围栏”之内。
四、 总结:开发者该如何选择?
如果你只是想写一个简单的 QA 机器人,用普通的 LCEL (LangChain Expression Language) 就够了。
但如果你要构建的是一个真正的生产级 Agent:
- 它需要调用多个工具。
- 它需要根据结果反复重试。
- 它需要人类在关键节点把关。 那么,请放下你手中的“链”,像设计 Activiti 流程图一样,去构建你的 LangGraph。
AI 开发的终点,终究会回归到对业务流程的精细化治理上。
💡 贴士:如果你已经熟悉
TypedDict和operator.add,你其实已经掌握了 LangGraph 的“流程变量声明”技巧。下一步,试着画出你的StateGraph吧!