前言
很多技术文章会直接说:Agent就是用工作流编排大模型。不少开发者会产生误解:工作流是AI Agent独有的技术。
但实际上,工作流、状态机、流程引擎在传统业务系统早已大规模落地:OA审批、订单流转、售后工单都是典型工作流。LangGraph这类Agent框架底层本质依旧是状态机,技术同源,但解决的核心矛盾、风险点、设计目标完全不一样。
大量资料把普通业务工作流和LLM Agent工作流混为一谈,导致开发者对Agent特有的State状态污染、提示注入绕过流程、死循环风险理解不到位。本文对比传统业务工作流与Agent工作流,厘清拓扑结构、运行时路径、条件分支的本质差异,同时给出生产环境安全最佳实践。
一、普通业务系统工作流(OA/订单状态机)
代表场景:订单状态流转、企业审批流。
核心特点
1. 输入、规则全部由开发者预先写死
流转逻辑、分支条件全部硬编码,每一步去往哪个节点,由程序赋值的结构化状态字段驱动。
示例流转:
待付款 → 已付款 → 已发货 → 已完成
提交申请 → 经理审批 → 总监审批 → 通过/驳回
分支判断示例:if(status == PAID){...},全部为业务代码。状态字段由程序赋值,外部输入无法直接修改状态控制流程跳转。
2. 不确定性极少
异常来源大多是网络异常、数据库异常等系统层面故障,业务流转路径是可穷举的。
3. 核心目标
编排已经写好的业务步骤,负责状态持久化、事务回滚、任务重试,执行人类预先定义完备的业务逻辑。
简单概括:规则人写死,引擎只负责执行。
二、LLM Agent工作流(LangGraph StateGraph)
底层依旧是状态机+工作流引擎,但是引入了一个不可控的参与者:LLM大模型黑盒。
AI工作流的本质:给不可控的大模型行为套上笼子,实现动态决策、自我修正、强制收敛。
Agent工作流独有的痛点(传统业务几乎遇不到)
1. LLM输出不稳定,需要运行时循环自我修正
大模型会幻觉、回答不全、输出错误。业务期望:调用工具补全信息 → 重新生成内容 → 审核校验 → 不合格就修订,循环迭代直到输出合格结果。
传统业务代码出错属于Bug,需要修改代码修复,不会在运行时自动循环修正自身输出。
2. 部分决策逻辑交给LLM,不再全部硬编码
传统工作流所有if分支全部写死在代码;Agent工作流支持把分支判断交给大模型输出结果驱动。
风险随之而来:State状态不再只有业务代码可以写入,LLM也可以写入状态字段,由此诞生Agent特有漏洞:状态污染,提示注入绕过流程节点。传统业务工作流不会把状态写权限交给黑盒外部组件,几乎不存在这类安全问题。
3. 运行路径无法预先完全枚举,循环次数未知
OA审批流程路径固定可数;但是用户提问千变万化:有的问题直接回答,有的需要搜索,有的需要多轮修订。编码阶段无法预知会循环多少次,框架必须提供最大轮次保护,防止LLM逻辑异常造成死循环。
4. 混合编排:代码节点 + LLM节点共存
- 代码节点:Java实现工具调用、数据库读写、业务计算;
- LLM节点:大模型生成、模型判断;
工作流统一处理两类节点:异常捕获、退避重试、状态持久化、断点恢复。
三、误区澄清:为什么AI Agent需要工作流?
❌错误观点:工作流是AI专属技术。
✅正确观点:普通业务系统早已广泛使用工作流/状态机。但是LLM输出不确定、存在幻觉、部分决策由模型输出驱动,给AI系统带来额外刚需:循环迭代修正、动态条件分支、最大轮次防死循环、状态隔离校验、失败重试、断点续跑。
仅靠普通顺序代码 +if‑else+ 手写循环,很难妥善处理LLM带来的不确定性。
反例:不使用LangGraph,手写Java实现修订循环
// 伪代码:手写Agent revise‑review循环
String answer = llm.generate(query);
for(int i = 0; i < MAX_ROUND; i++){
boolean pass = llm.review(answer);
if(pass) break;
answer = llm.revise(answer);
}
return answer;看起来实现了修订循环,但工程上坑非常多:
- 需要自行实现中间状态持久化,服务中断之后无法断点恢复;
- LLM调用的超时、限流退避、异常重试全部自己封装;
- 业务复杂之后多层嵌套循环,代码迅速臃肿难以维护;
- 安全风险:循环判断flag由LLM输出控制,极易被Prompt注入直接break跳过审核逻辑;手写很难实现每一条分支出口的白名单校验。
LangGraph这类框架就是标准化解决上述通用问题:状态持久化、条件边、分支校验、最大轮次限制、节点重试、断点续跑。
四、关键概念区分:图拓扑结构 VS 运行时执行路径
很多开发者混淆这两个概念,这是理解Agent不确定性的核心。
| 对象 | 是否确定 | 说明 |
|---|---|---|
| 工作流图拓扑(节点、边、跳转目标) | ✅完全确定 | 代码定义死:有哪些节点、循环跳转到哪个目标节点,运行时不会新增节点 |
| 运行时行为:是否走循环、循环多少次、选择哪条分支 | ❌不确定 | 由LLM运行时输出决定 |
举个例子定义拓扑:
generate → review;review条件边:不通过跳回revise修订节点;通过直接结束。
拓扑是写死的:不通过就必须回到revise,跳转目标固定。
但是运行时:
- 用户问题简单:review一次直接结束;
- 模型幻觉严重:revise‑review来回循环3次;
- 问题极难:循环触达最大轮次阈值强制退出。
Agent不是无约束自由跳转,流转被锁死在预先定义好的图拓扑之内;不确定性体现在:在允许的路径集合里,由LLM动态选择走哪条分支、循环多少轮。
和普通while循环本质区别
普通Java while/for循环也可以做到不确定循环次数。核心差异不在于循环语法本身,而在于条件判断的数据来源。
1. 普通业务循环:条件来源于业务代码计算
boolean ok = codeCheck(answer); // 纯业务代码逻辑,不受黑盒输入污染
while(!ok){ ... }判断逻辑完全可控,不存在幻觉、提示注入风险。
2. Agent典型循环:条件判断来自LLM黑盒输出
boolean ok = llmJudgeReview(answer); // 判断结果来自大模型输出
while(!ok){ ... }LLM是不可控黑盒,会幻觉、会被提示注入篡改判断结果,甚至篡改State路由字段绕过关键节点。因此框架必须配套:最大轮次防死循环、状态路由白名单校验、LLM调用重试。
五、LangGraph条件边两种模式:LLM判断 vs 纯代码判断
addConditionalEdges是LangGraph实现分支跳转的核心API,框架本身不强制使用LLM做判断,两种模式可以独立使用,也可以混合。
模式1:交给LLM做条件判断(典型Agent场景,带来安全风险)
条件边内部调用大模型,由模型输出决定下一个节点。
workflow.addConditionalEdges("review",
edge_async(state -> {
// 条件判断交给LLM黑盒
String llmJudge = llm.call(state.get("answer"));
if ("不通过".equals(llmJudge)){
return "revise";
}else{
return "end";
}
}),
Map.of("revise","revise", "end", END)
);风险点:
- LLM幻觉输出错误判断;
- Prompt注入场景,模型输出伪造结果,跳过审核直接结束流程;
- 若设计为LLM直接把
next_node写入State,风险会进一步放大。
模式2:纯Java代码做条件判断(等价传统业务状态机)
条件边完全不调用大模型,全部逻辑手写代码,没有Agent特有安全漏洞。
workflow.addConditionalEdges("review",
edge_async(state -> {
// 纯Java业务逻辑,无任何LLM调用
int errorCount = state.value("error_count").orElse(0);
if(errorCount >=3){
return "end";
}else{
return "revise";
}
}),
Map.of("revise","revise", "end", END)
);模式3:生产常用混合模式:LLM做业务判断,代码做安全兜底
LLM负责业务语义层面判断;Java代码负责强制约束、安全兜底,这是生产环境推荐写法。
workflow.addConditionalEdges("review",
edge_async(state -> {
// 1. LLM输出业务标记
Boolean llmNeedRevise = llm.judge(state);
// 2. Java强制兜底:最大循环轮次,防止死循环
int round = state.value("round").orElse(0);
if(round >=5){
return "end";
}
if(llmNeedRevise){
return "revise";
}else {
return "end";
}
}),
Map.of("revise","revise", "end", END)
);六、生产安全最佳实践,规避State状态污染风险
根源:LangGraph本身框架不带安全漏洞;风险来自我们把路由判断权力交给LLM黑盒。
- ❌禁止:让LLM直接输出节点ID(
next_node)写入State状态,条件边读取该字段直接跳转。 - ✅推荐:LLM只输出业务语义标记,例如
need_revise:true/false;路由跳转决策逻辑保留在Java代码层。 - ✅Java层增加多重防护:
- 最大循环轮次强制限制,杜绝LLM异常导致死循环;
- 对读取到的路由标记做白名单校验,只允许配置内的节点跳转;
- State字段做权限隔离,区分「LLM可写入字段」和「代码独占的路由控制字段」,敏感路由字段不开放给LLM写入。
- 条件分支优先代码兜底,LLM输出仅作为业务参考依据,不要作为唯一判断依据。
七、总结
- 普通业务工作流:规则全部由人编码定义,工作流只负责执行;风险来自系统故障。
- LLM Agent工作流:底层依旧是状态机,图拓扑结构确定,运行时路径不确定;工作流核心作用是约束、驯化、收敛大模型带来的不确定性。
- Agent独有的
State污染、提示注入绕过流程漏洞根源不是LangGraph框架本身,而是将分支判断能力交给不可控的LLM黑盒。 - 生产实践:LLM输出业务信号,代码掌握最终路由决策权,做好兜底校验,是规避Agent流程安全问题的核心方案。