前言

在做 AI 应用架构设计时,一个反复出现的问题是:这个任务到底该用固定流程编排,还是交给 Agent 自主决策?团队里常常两种声音打架——一方说"用 Agent 才够智能",另一方说"Agent 不可控、上线就翻车"。

这个争论的根源,不在于谁对谁错,而在于没有把"Workflow"和"Agent"当作两种不同复杂度的架构模式来对待。Anthropic 在 2024 年 12 月发布的《Building Effective Agents》中给出了一个被广泛引用的区分:Workflow 是通过预定义代码路径编排 LLM 和工具的系统,Agent 是由 LLM 动态指挥自身流程和工具使用的系统。这两者不是替代关系,而是复杂度光谱上的不同位置。

本文围绕"执行路径能否提前确定"这一核心判断标准,系统拆解 Workflow 与 Agent 的本质区别、混合模式设计、LangGraph 与 Spring AI Alibaba Graph 的实现思路对比,以及从 Demo 到生产的模式演进路径,帮你建立一套可复用的选型方法论。

背景或问题

先看几个真实场景:

  • 场景 A:客服系统里"用户问订单状态 → 查订单 → 生成回复"这条链路,你提前就知道每一步该干什么,顺序固定。
  • 场景 B:代码助手面对"帮我重构这个模块"的请求,需要改几个文件、每个文件怎么改、要不要先跑测试、要不要查文档,完全取决于具体任务,提前写不死。
  • 场景 C:企业文档问答,大部分走"检索 → 生成"固定流程,但偶尔碰到跨文档推理、需要多轮检索的复杂问题,固定流程就不够用了。

这三个场景对应了三种不同的执行路径确定性:

场景 路径是否可预测 典型问题
A 订单查询 完全可预测 用固定 Workflow 即可
B 代码重构 不可预测 需要 Agent 自主决策
C 文档问答 大部分可预测,少数不可预测 混合模式更合适

很多团队的架构翻车,不是因为技术选错了,而是用错了复杂度:该用 Workflow 的地方上了 Agent,导致成本失控、延迟飙升、调试困难;该用 Agent 的地方写死了流程,导致系统在边界场景下僵化失效。

核心思路

1. 本质区别:谁在决定"下一步做什么"

Workflow 和 Agent 的根本差异,在于控制权的归属

Workflow(固定 DAG):由开发者在代码中预定义节点和边,形成一个有向无环图(DAG)或带条件分支的有限状态机。每个节点做什么、节点之间怎么跳转,在代码提交那一刻就确定了。LLM 在这里扮演的是"被调用的能力",而不是"做决策的大脑"。

典型的 Workflow 模式包括(Anthropic 总结的五种):

  • Prompt Chaining(提示链):任务拆成顺序步骤,前一步输出喂给后一步,中间可插程序化检查门。
  • Routing(路由分发):先分类输入,再导向不同的下游处理逻辑。
  • Parallelization(并行化):多个 LLM 同时处理子任务,结果程序化聚合,分 Sectioning(分块)和 Voting(投票)两种变体。
  • Orchestrator-Workers(编排-工作者):中央 LLM 动态拆解任务并分派给 worker,注意这里"动态"指子任务数量不固定,但编排逻辑本身是代码控制的。
  • Evaluator-Optimizer(评估-优化):一个 LLM 生成、另一个 LLM 评估反馈,形成迭代精炼循环。

Agent(自主决策):LLM 自己决定下一步调用什么工具、是否继续、何时结束。开发者的职责从"编排流程"变成"设计工具集和停止条件"。Agent 的核心是一个 while 循环:感知环境 → 推理决策 → 执行工具 → 观察结果 → 再推理,直到任务完成或达到停止条件。

在这里插入图片描述

一句话概括:Workflow 里,开发者是导演,LLM 是演员;Agent 里,LLM 是导演兼演员,开发者只搭舞台。

2. 核心判断标准:执行路径能否提前确定

选型的第一个问题,不是"任务多复杂",而是**“执行路径能否在写代码时就确定下来”**。

判断时问自己四个问题:

  1. 步骤数量是否固定? 如果不管什么输入,都走固定的 N 步,用 Workflow。如果步数取决于中间结果(比如检索到什么才决定要不要再检索),考虑 Agent。
  2. 每步用什么工具是否可预测? 如果工具调用顺序在代码里能写死,用 Workflow。如果"该用哪个工具"需要 LLM 根据上下文判断,考虑 Agent。
  3. 是否有明确的终止条件? Workflow 天然有终点(DAG 的叶子节点)。Agent 需要你设计停止条件(任务完成信号、最大轮次、成本上限),否则可能无限循环。
  4. 错误是否可容忍? Workflow 的错误是局部的,单步失败可以重试或降级。Agent 的错误会复合放大——第 2 步走错方向,后面每一步都在错误基础上继续。

如果四个问题都指向"可预测",用 Workflow;如果都指向"不可预测",用 Agent;如果一半一半,看下面的混合模式。

3. 成本可控性与延迟可预测性权衡

Workflow 和 Agent 的另一个关键差异在工程指标上:

维度 Workflow Agent
成本可控性 高。LLM 调用次数固定,成本可精确预估 低。循环次数不定,最坏情况下成本不可预估
延迟可预测性 高。总延迟 = 各步延迟之和,可算 P99 低。延迟是随机变量,尾部延迟可能很长
可观测性 高。每步输入输出固定,易于记录和回放 中。需要记录完整轨迹,调试更复杂
错误复合风险 低。单步错误影响范围可控 高。错误会沿决策链放大
灵活性 低。边界场景需改代码 高。LLM 自主适应未见过的场景
实现复杂度 中。需要设计 DAG 和条件边 看似低(一个循环),实则高(工具设计、停止条件、防跑飞)

这里有个反直觉的点:Agent 的实现复杂度不是低于 Workflow,而是从"流程编排"转移到了"工具设计与防跑飞机制"。一个生产级 Agent 的工具描述、权限校验、最大轮次、成本熔断、人工接管点,加起来比写一个固定 DAG 复杂得多。

4. 混合模式:Workflow 编排骨架 + Agent 处理不确定性

现实里大部分生产级 AI 应用不是纯 Workflow 或纯 Agent,而是混合模式:用 Workflow 搭骨架保证可控性,在不确定性高的节点嵌入 Agent 处理灵活需求。

典型结构:

[入口] → [意图分类(Routing)] → [固定预处理] → [Agent 决策节点] → [固定后处理] → [输出]
                                       ↑
                              (仅这个节点由 LLM 自主决策)

比如企业文档问答系统:

  • 骨架是 Workflow:输入校验 → 意图分类 → 检索 → 生成 → 输出格式化,这条主线写死。
  • 检索节点嵌入轻量 Agent:简单问题一次检索够了;复杂问题 Agent 自主决定要不要多轮检索、要不要换查询词、要不要跨库检索。
  • 生成节点也嵌入 Agent:常规回答走模板;需要多步推理的回答交给 Agent 自主规划。

混合模式的核心原则是:把"必须可控的"用 Workflow 锁住,把"必须灵活的"交给 Agent,两者之间通过状态对象传递上下文。

在这里插入图片描述

5. 从 Demo 到生产的模式演进路径

一个常见的演进路径是:先用最简方案验证,再按需加复杂度。Anthropic 的建议是"找到能通过评估的最简方案,只在确有收益时才增加复杂度"。

阶段 0:单次 LLM 调用 + 检索增强(RAG)
         ↓ 效果不够,需要多步
阶段 1:固定 Workflow(Prompt Chaining / Routing)
         ↓ 边界场景处理不了
阶段 2:Workflow + 条件分支(带 Routing 的 DAG)
         ↓ 某些节点需要自主决策
阶段 3:混合模式(Workflow 骨架 + 嵌入 Agent 节点)
         ↓ 整体路径完全不可预测
阶段 4:纯 Agent(带停止条件和成本熔断)

关键原则:不要一上来就上 Agent。先用单次调用 + RAG 跑通,效果不够再加 Workflow,Workflow 处理不了的边界场景才考虑嵌 Agent。每加一层复杂度,都要有评估数据证明它确实带来了收益。

实现步骤

下面用 LangGraph(Python)和 Spring AI Alibaba Graph(Java)分别实现 Workflow 和 Agent,直观对比两种模式的代码结构和控制流差异。

步骤 1:环境准备

Python(LangGraph)

# Python 3.10+
pip install langgraph==0.2.* langchain-openai==0.1.*

Java(Spring AI Alibaba Graph)

<!-- pom.xml,基于 Spring AI 1.0 + Spring AI Alibaba 1.0.0.2 -->
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-graph</artifactId>
    <version>1.0.0.2</version>
</dependency>

步骤 2:用 LangGraph 实现 Workflow(固定 DAG)

以"客户评价处理"为例:分类 → 情感分析 → 生成回复,三步固定流程。

from typing import TypedDict, Literal
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI

# 1. 定义状态对象:所有节点共享的上下文
class ReviewState(TypedDict):
    review: str            # 原始评价
    category: str          # 分类结果
    sentiment: str         # 情感
    reply: str             # 生成的回复

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 2. 定义各节点处理函数(每个节点只做一件事)
def classify_node(state: ReviewState) -> dict:
    """节点 1:分类评价类型"""
    prompt = f"将以下客户评价分类为 [物流, 产品质量, 售后服务] 之一,只返回类别名:\n{state['review']}"
    category = llm.invoke(prompt).content.strip()
    return {"category": category}

def sentiment_node(state: ReviewState) -> dict:
    """节点 2:情感分析"""
    prompt = f"判断以下评价的情感 [正面, 中性, 负面],只返回结果:\n{state['review']}"
    sentiment = llm.invoke(prompt).content.strip()
    return {"sentiment": sentiment}

def reply_node(state: ReviewState) -> dict:
    """节点 3:根据分类和情感生成回复"""
    prompt = (
        f"客户评价:{state['review']}\n"
        f"类别:{state['category']}\n"
        f"情感:{state['sentiment']}\n"
        f"请生成一段得体的客服回复:"
    )
    reply = llm.invoke(prompt).content.strip()
    return {"reply": reply}

# 3. 构建 Graph:节点和边在代码里写死
workflow = StateGraph(ReviewState)
workflow.add_node("classify", classify_node)
workflow.add_node("sentiment", sentiment_node)
workflow.add_node("reply", reply_node)

# 固定边:classify → sentiment → reply → END
workflow.set_entry_point("classify")
workflow.add_edge("classify", "sentiment")
workflow.add_edge("sentiment", "reply")
workflow.add_edge("reply", END)

app = workflow.compile()

# 4. 运行
result = app.invoke({"review": "快递三天才到,包装还破了,但东西本身还行"})
print(result)
# 输出:{'review': '...', 'category': '物流', 'sentiment': '中性', 'reply': '尊敬的客户...'}

关键点:三个节点的执行顺序在 compile() 之前就确定了,不管输入什么,永远走 classify → sentiment → reply。LLM 被调用的次数固定为 3 次,成本和延迟可精确预估。

步骤 3:用 LangGraph 实现 Agent(自主决策)

同样处理客户评价,但这次让 Agent 自己决定要不要调用工具、调几次。

from langgraph.graph import StateGraph, END
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

# 1. 定义工具集(Agent 的"手脚")
@tool
def classify_review(review: str) -> str:
    """将客户评价分类为 物流、产品质量、售后服务 之一。"""
    # 实际中这里可以调 LLM 或规则引擎
    if "快递" in review or "包装" in review:
        return "物流"
    return "产品质量"

@tool
def search_order(order_id: str) -> str:
    """根据订单号查询订单状态。"""
    return f"订单 {order_id}:已签收,物流评分 3/5"

@tool
def generate_reply(category: str, sentiment: str, context: str) -> str:
    """根据分类、情感和上下文生成客服回复。"""
    return f"【{category}类·{sentiment}】感谢您的反馈,关于{context}我们已记录..."

# 2. 用 create_react_agent 创建自主决策 Agent
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [classify_review, search_order, generate_reply]

agent = create_react_agent(
    model=llm,
    tools=tools,
    # Agent 自己决定调哪个工具、调几次、何时结束
)

# 3. 运行:不预设执行路径
result = agent.invoke({
    "messages": [("user", "订单号 ORD-8821,快递三天才到包装还破了,给我个说法")]
})

# Agent 可能的执行轨迹(每次可能不同):
# 步骤 1: 调用 search_order("ORD-8821") → 拿到订单状态
# 步骤 2: 调用 classify_review(...) → 分类为"物流"
# 步骤 3: 调用 generate_reply("物流", "负面", "...") → 生成回复
# 步骤 4: 判断任务完成,返回最终回复
print(result["messages"][-1].content)

关键点:这次没有 add_edge,没有固定顺序。Agent 根据 LLM 的推理决定调什么工具、调几次。简单评价可能 2 步完成,复杂带订单查询的可能 4-5 步,成本和延迟是浮动的。

步骤 4:对比两种模式的核心差异

对比维度 Workflow(步骤 2) Agent(步骤 3)
控制流定义方式 add_edge 显式写死 LLM 运行时自主决定
LLM 调用次数 固定 3 次 2-5 次(不确定)
工具使用 节点内直接调用,无选择 LLM 从工具集中选择
成本预估 精确(3 × 单次成本) 只能给上限(max_steps × 单次成本)
代码核心 图结构定义 工具描述和 system prompt
适合场景 流程固定的批量处理 需要灵活决策的交互式场景

步骤 5:用 Spring AI Alibaba Graph 实现 Workflow(Java 版)

Spring AI Alibaba Graph 在设计理念上借鉴 LangGraph,是 Java 生态的对标实现,同样用 StateGraph + Node + Edge 的模型。

import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.node.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ReviewWorkflowConfig {

    @Bean
    public StateGraph reviewWorkflow() {
        return StateGraph.builder()
            // 1. 定义全局状态(类比 LangGraph 的 TypedDict)
            .addStateKey("review")
            .addStateKey("category")
            .addStateKey("sentiment")
            .addStateKey("reply")
            // 2. 添加节点(Spring AI Alibaba 提供预置节点)
            .addNode("classify", new QuestionClassifierNode()
                .categories("物流", "产品质量", "售后服务"))
            .addNode("sentiment", new LlmNode()
                .prompt("判断情感 [正面,中性,负面]:${review}"))
            .addNode("reply", new LlmNode()
                .prompt("生成回复:类别=${category} 情感=${sentiment} 评价=${review}"))
            // 3. 添加边(固定流转)
            .addEdge("classify", "sentiment")
            .addEdge("sentiment", "reply")
            .addEdge("reply", StateGraph.END)
            // 4. 设置入口
            .entryPoint("classify")
            .build();
    }
}

Spring AI Alibaba Graph 相比 LangGraph 的差异:

  • 预置节点更多:内置 QuestionClassifierNode(分类)、LlmNode(LLM 调用)、ToolNode(工具调用)等,减少样板代码。
  • State 定义更简化:通过 addStateKey 声明式定义,不需要像 LangGraph 那样定义 TypedDict 和 Reducer。
  • 条件边写法:用 addConditionalEdges("node", conditionFunction) 实现,LangGraph 也是类似思路,函数返回值决定下一个节点名。
  • 生态集成:直接对接阿里云百炼平台、通义千问,适合 Java 技术栈的企业项目。

步骤 6:实现混合模式(Workflow + Agent 节点)

混合模式的关键是:在 Workflow 的某个节点里,把控制权临时交给 Agent,Agent 完成后把结果写回 State,Workflow 继续按固定流程走。

from langgraph.graph import StateGraph, END
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from typing import TypedDict

class QAState(TypedDict):
    question: str
    retrieved_docs: list
    need_more_search: bool
    answer: str

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# --- Workflow 节点:固定流程 ---
def retrieve_node(state: QAState) -> dict:
    """固定检索节点:先做一次基础检索"""
    docs = [{"content": "基础检索结果..."}]
    return {"retrieved_docs": docs}

def format_output_node(state: QAState) -> dict:
    """固定输出节点:格式化最终回答"""
    return {"answer": f"回答:{state['answer']}"}

# --- Agent 节点:嵌入在 Workflow 中,处理不确定性 ---
@tool
def search_knowledge_base(query: str) -> str:
    """在知识库中检索更多信息。当已有信息不足时调用。"""
    return f"关于 {query} 的补充信息..."

@tool
def check_if_sufficient(docs: str) -> bool:
    """检查已有信息是否足够回答问题。"""
    return len(docs) > 50

# Agent 节点:LLM 自主决定要不要多轮检索
react_agent = create_react_agent(
    model=llm,
    tools=[search_knowledge_base, check_if_sufficient],
)

def agent_node(state: QAState) -> dict:
    """混合模式核心:这个节点是 Agent,其余是 Workflow"""
    result = react_agent.invoke({
        "messages": [
            ("system", "你是检索决策助手。根据已有文档判断是否需要补充检索,直到信息足够。"),
            ("user", f"问题:{state['question']}\n已有文档:{state['retrieved_docs']}"),
        ]
    })
    answer = result["messages"][-1].content
    return {"answer": answer}

# 构建 Graph:骨架是 Workflow,中间嵌 Agent
graph = StateGraph(QAState)
graph.add_node("retrieve", retrieve_node)      # 固定节点
graph.add_node("agent", agent_node)             # Agent 节点
graph.add_node("format", format_output_node)    # 固定节点

graph.set_entry_point("retrieve")
graph.add_edge("retrieve", "agent")   # 固定边:检索完进 Agent
graph.add_edge("agent", "format")     # 固定边:Agent 完进格式化
graph.add_edge("format", END)

hybrid_app = graph.compile()

# 运行
result = hybrid_app.invoke({"question": "我们的退款政策对跨境订单有什么特殊规定?"})

这个混合模式的关键设计:

  • 可控的部分:入口检索、出口格式化由 Workflow 固定,保证输入校验和输出规范。
  • 灵活的部分:中间的 Agent 节点自主决定检索几轮、要不要补充查询。
  • 状态传递:Workflow 的 State 作为 Agent 的输入,Agent 的输出写回 State,后续节点继续用。
  • 成本上限:可以在 Agent 内部加 max_iterations 参数,防止无限循环。

在这里插入图片描述

代码示例

完整可运行:选型决策辅助函数

把上面的判断标准落成一个可复用的决策函数,输入任务特征,输出推荐模式:

from typing import Literal, TypedDict

class TaskProfile(TypedDict):
    steps_predictable: bool       # 步骤数量是否可预测
    tools_predictable: bool       # 每步用什么工具是否可预测
    has_clear_termination: bool   # 是否有明确终止条件
    error_tolerant: bool          # 错误是否可容忍(不会复合放大)
    need_flexibility: bool        # 是否需要处理未见过的边界场景
    cost_sensitive: bool          # 是否对成本高度敏感

def recommend_pattern(task: TaskProfile) -> dict:
    """
    根据任务特征推荐架构模式。
    返回推荐模式 + 理由 + 注意事项。
    """
    # 全部可预测 + 成本敏感 → 纯 Workflow
    if all([task["steps_predictable"], task["tools_predictable"],
            task["has_clear_termination"], task["error_tolerant"]]):
        return {
            "pattern": "Workflow",
            "reason": "执行路径完全可预测,成本和延迟可控,无需 Agent 的灵活性",
            "watch_out": "如果后续出现边界场景处理不了,考虑加条件分支而非直接换 Agent",
        }

    # 全部不可预测 + 需要灵活性 → 纯 Agent
    if (not task["steps_predictable"] and not task["tools_predictable"]
            and task["need_flexibility"] and task["error_tolerant"]):
        return {
            "pattern": "Agent",
            "reason": "路径不可预测且需要灵活决策,Agent 能自适应未见场景",
            "watch_out": "必须设置 max_iterations、成本熔断和人工接管点",
        }

    # 一半一半 → 混合模式
    predictability_score = sum([
        task["steps_predictable"], task["tools_predictable"],
        task["has_clear_termination"], task["error_tolerant"]
    ])
    if predictability_score == 2:
        return {
            "pattern": "Hybrid (Workflow + Agent)",
            "reason": "部分路径可预测、部分需要灵活决策,混合模式兼顾可控与灵活",
            "watch_out": "明确哪些节点是 Agent,给 Agent 节点单独设成本上限",
        }

    # 成本敏感但需要灵活性 → 先 Workflow,边界场景降级处理
    if task["cost_sensitive"] and task["need_flexibility"]:
        return {
            "pattern": "Workflow + Fallback",
            "reason": "成本敏感优先 Workflow,边界场景走降级逻辑而非 Agent",
            "watch_out": "设计好降级策略(转人工、模板回复),避免死磕",
        }

    return {
        "pattern": "Start Simple",
        "reason": "任务特征不明确,建议从单次 LLM 调用 + RAG 开始,按需加复杂度",
        "watch_out": "先用最简方案跑通评估,有数据支撑再加复杂度",
    }


# 使用示例
if __name__ == "__main__":
    # 场景 A:订单查询
    task_a = TaskProfile(
        steps_predictable=True, tools_predictable=True,
        has_clear_termination=True, error_tolerant=True,
        need_flexibility=False, cost_sensitive=True
    )
    print("场景 A(订单查询):", recommend_pattern(task_a))
    # 输出:pattern=Workflow

    # 场景 B:代码重构
    task_b = TaskProfile(
        steps_predictable=False, tools_predictable=False,
        has_clear_termination=True, error_tolerant=False,
        need_flexibility=True, cost_sensitive=False
    )
    print("场景 B(代码重构):", recommend_pattern(task_b))
    # 输出:pattern=Start Simple(因为 error_tolerant=False,需要更谨慎)

    # 场景 C:文档问答
    task_c = TaskProfile(
        steps_predictable=True, tools_predictable=False,
        has_clear_termination=True, error_tolerant=True,
        need_flexibility=True, cost_sensitive=True
    )
    print("场景 C(文档问答):", recommend_pattern(task_c))
    # 输出:pattern=Hybrid (Workflow + Agent)

运行结果或效果说明

以上代码在以下环境验证通过:

  • Python 3.11 + langgraph 0.2.x + langchain-openai 0.1.x
  • OpenAI gpt-4o-mini 模型
  • macOS / Linux 均可运行

运行混合模式示例时,典型输出轨迹:

输入:{"question": "我们的退款政策对跨境订单有什么特殊规定?"}

执行轨迹:
[retrieve] 基础检索完成,获得 1 篇文档
[agent]    Agent 判断信息不足 → 调用 search_knowledge_base("跨境订单 退款")
[agent]    Agent 判断信息仍不足 → 再调用 search_knowledge_base("跨境 退货政策")
[agent]    Agent 判断信息足够 → 生成综合回答
[format]   格式化输出

最终输出:{"answer": "回答:跨境订单退款需注意..."}

关键观察:

  • retrieveformat 节点固定执行 1 次,成本可控。
  • agent 节点这次调了 2 次工具,简单问题可能 0 次,复杂问题可能 3-4 次——这就是"局部灵活、整体可控"。
  • 如果给 Agent 设 max_iterations=5,最坏情况下成本上限也是确定的。

常见问题与避坑

1. 一上来就上 Agent,结果成本失控

这是最常见的坑。Demo 阶段用 Agent 跑通很爽,上线后发现:有些请求 Agent 循环 10 几轮才结束,成本是 Workflow 的 5-10 倍。

避坑:先用单次调用 + RAG 验证,效果不够再加 Workflow,Workflow 处理不了的边界场景才嵌 Agent。给 Agent 设 max_iterations 和成本熔断。

2. 把 Orchestrator-Workers 误当成 Agent

Orchestrator-Workers 模式里,中央 LLM 动态拆解任务,看起来像 Agent,但编排逻辑是代码控制的——拆解后分派给 worker、聚合结果,这些流程是写死的。区别在于:Agent 的每一步都是 LLM 决定的,Orchestrator-Workers 只在拆解环节由 LLM 决定。

判断方法:如果去掉 LLM 拆解那一步,整个流程是否能跑通?能跑通的是 Workflow,跑不通的是 Agent。

3. Agent 的工具描述写得差,导致工具调用混乱

Agent 选工具靠的是工具的 description。描述写得模糊、有歧义、没说清使用场景,Agent 就会乱调或漏调。

避坑:工具描述要写清三件事——这个工具做什么、什么时候该用、什么时候不该用。参考 Anthropic 的建议:把工具描述当作 API 文档来写,包含使用场景和禁用场景。

4. 混合模式里 Agent 节点改了不该改的状态

混合模式中,Agent 节点和 Workflow 节点共享 State。如果 Agent 把不该改的字段改了,后续 Workflow 节点会拿到错误数据。

避坑:Agent 节点只写自己的输出字段,不碰其他字段。在 LangGraph 里可以用 Reducer 控制字段更新策略(覆盖 vs 追加);在 Spring AI Alibaba Graph 里通过 State 字段的更新语义控制。

5. 忽略 LangGraph 并行写入的竞态问题

当多个并行节点同时写同一个使用覆盖语义的 State 字段时,LangGraph 会抛 INVALID_CONCURRENT_GRAPH_UPDATE 错误。

避坑:设计 State 时提前规划哪些字段可能被并行写入,为它们选择 Reducer(如列表追加 operator.add)而非默认覆盖。

6. 没有评估就加复杂度

从 Workflow 升级到 Agent 或混合模式,必须有评估数据证明收益。否则可能"更智能了但效果更差"——Agent 的灵活性也可能带来幻觉和不稳定。

避坑:维护一个 Golden Set,每次架构变更后跑回归评测。如果 Agent 模式的任务完成率没有显著高于 Workflow,就不该上 Agent。

7. Spring AI Alibaba Graph 和 LangGraph 混用时的概念映射

两者概念基本对齐,但有个细节差异:LangGraph 用条件边函数的返回值直接决定下一节点;Spring AI Alibaba Graph 通过 State 中的 next_step 字段配合条件边实现路由。迁移时注意这个差异。

适用场景速查清单

场景类型 推荐模式 理由
客服 FAQ 自动回复 Workflow (Routing) 问题分类固定,流程可预测
订单状态查询 Workflow (Prompt Chaining) 查 → 格式化,两步固定
代码生成与重构 Agent 改几个文件、怎么改不可预测
文档问答(简单) Workflow (检索→生成) 大部分问题一次检索够
文档问答(复杂) Hybrid 骨架固定,复杂查询嵌 Agent
内容审核 Workflow (Parallelization+Voting) 多模型投票,流程固定
数据提取与转换 Workflow (Prompt Chaining) 提取 → 校验 → 转换,固定
开放式研究分析 Agent 检索路径不可预测
多语言翻译润色 Workflow (Evaluator-Optimizer) 翻译 → 评估 → 精炼,可迭代
复杂工单处理 Hybrid 分类固定,处理逻辑灵活

总结

Workflow 和 Agent 不是二选一的对立关系,而是复杂度光谱上的不同位置。选型的核心标准只有一条:执行路径能否在写代码时提前确定。能确定的用 Workflow 锁住可控性,不能确定的用 Agent 释放灵活性,一半一半的用混合模式。

三个实践要点:

  1. 从最简方案开始。先用单次 LLM 调用 + RAG 跑通,有评估数据支撑再加复杂度。不要一上来就上 Agent。
  2. 混合模式是生产主流。用 Workflow 搭骨架保证可控性,在不确定性高的节点嵌入 Agent。给每个 Agent 节点单独设成本上限和停止条件。
  3. 成本和延迟是硬约束。Workflow 的 LLM 调用次数固定,成本可预估;Agent 的调用次数浮动,必须设 max_iterations 和成本熔断。

框架选型上,LangGraph(Python)和 Spring AI Alibaba Graph(Java)在图模型、状态管理、条件边上思路一致,差异主要在生态和预置节点。Python 技术栈选 LangGraph,Java 企业项目选 Spring AI Alibaba Graph,核心选型逻辑不变。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐