原文地址【带图片】:Workflow 与 Agent 的区别:从原理到实践的完整指南

从一场争论说起

最近一年,“AI Agent” 成了技术圈最热门的话题之一。但伴随热度的,是越来越多的困惑——到底什么是 Agent?它和我们一直在用的 Workflow(工作流)有什么区别?为什么 Anthropic 在《Building Effective Agents》博文中强调"大多数场景根本不需要 Agent"?

这篇文章将从控制流归属这一本质区别出发,用图解、代码和实践决策框架,帮你在 Workflow 和 Agent 之间做出正确的选择。

本质区别:谁在控制流程?

Workflow 和 Agent 的根本不同,不在于是否使用了 LLM,而在于**"下一步做什么"这个决策由谁做出**:

  • Workflow:流程由代码预先定义。开发者在写代码时就决定好了每一步干什么、什么时候执行。LLM 只负责生成内容,不做流程决策。
  • Agent:流程由LLM 在运行时动态决定。LLM 自己选择调用哪个工具、要不要重试、什么时候结束。开发者只设置边界和约束。

这个区别看似简单,但它决定了系统的可预测性、成本和适用范围。

AI 系统自主性光谱

上面这张图展示了从简单 LLM 调用到 Agent 的渐进过程。这不是非黑即白的选择,而是一个连续的光谱

不要一上来就造 Agent

Anthropic 的工程实践有一条核心原则:从最简单的方案开始,只在确实需要时才增加复杂度。

很多场景用一次 LLM 调用就能完美解决——总结文档、分类邮件、翻译文本。给 LLM 加上检索(RAG)和上下文示例,效果往往已经足够好。

什么时候才需要升级到 Workflow 和 Agent?简单来说:

  • 一次调用不够,需要多步处理 → 考虑 Workflow
  • 步骤无法预先确定,LLM 必须自己决定做什么 → 考虑 Agent

下面我们通过代码来具体理解两种模式。

Workflow 模式:预定义的确定性流程

Workflow 的思路是:把复杂任务拆解成一系列确定的步骤,每一步由 LLM 或传统代码完成。LLM 参与内容生成,但流程编排由开发者完全控制。

Workflow 确定性流程

Python 代码示例

下面是一个基于 LangGraph 的 Workflow 实现:它按固定顺序执行"分类意图 → 改写查询 → 检索 → 生成答案"四个步骤。

from langgraph.graph import StateGraph, START, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from pydantic import BaseModel
from typing import TypedDict

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

# 定义结构化状态
class WorkflowState(TypedDict):
    question: str
    intent: str
    rewritten_query: str
    retrieval_results: list[str]
    final_answer: str

# 步骤 1:分类用户意图
class IntentClassification(BaseModel):
    intent: str  # "math" | "general_knowledge" | "weather"

def classify_intent(state: WorkflowState) -> dict:
    response = llm.with_structured_output(IntentClassification).invoke([
        SystemMessage(content="将意图分类为: math, general_knowledge, weather。"),
        HumanMessage(content=state["question"])
    ])
    return {"intent": response.intent}

# 步骤 2:改写查询
class RewrittenQuery(BaseModel):
    query: str

def rewrite_query(state: WorkflowState) -> dict:
    response = llm.with_structured_output(RewrittenQuery).invoke([
        SystemMessage(content="改写问题,使其更适合搜索引擎检索。"),
        HumanMessage(content=state["question"])
    ])
    return {"rewritten_query": response.query}

# 步骤 3:向量检索(确定性步骤,不使用 LLM)
def retrieve(state: WorkflowState) -> dict:
    knowledge_base = {
        "weather": "今日天气:晴,22°C。",
        "general": "法国的首都是巴黎。"
    }
    key = "weather" if "weather" in state["intent"] else "general"
    return {"retrieval_results": [knowledge_base.get(key, "无结果")]}

# 步骤 4:基于检索结果生成答案
def generate_answer(state: WorkflowState) -> dict:
    context = "\n".join(state["retrieval_results"])
    response = llm.invoke([
        SystemMessage(content=f"使用以下上下文回答问题:\n{context}"),
        HumanMessage(content=state["question"])
    ])
    return {"final_answer": response.content}

# 构建固定流程
workflow = StateGraph(WorkflowState)
workflow.add_node("classify_intent", classify_intent)
workflow.add_node("rewrite_query", rewrite_query)
workflow.add_node("retrieve", retrieve)
workflow.add_node("generate_answer", generate_answer)

workflow.add_edge(START, "classify_intent")

# 条件分支:数学问题跳过检索
workflow.add_conditional_edges("classify_intent",
    lambda s: "generate_answer" if s["intent"] == "math" else "rewrite_query",
    {"rewrite_query": "rewrite_query", "generate_answer": "generate_answer"}
)
workflow.add_edge("rewrite_query", "retrieve")
workflow.add_edge("retrieve", "generate_answer")
workflow.add_edge("generate_answer", END)

pipeline = workflow.compile()

# 运行
result = pipeline.invoke({"question": "今天天气怎么样?"})
print(result["final_answer"])

上面的代码有几个关键特征:

  • 每个节点做什么,预先定义得清清楚楚
  • 条件分支(数学问题跳过检索)是开发者写死的规则
  • LLM 只负责"分类"“改写”"生成"这些内容任务,不做流程决策

这就是 Workflow 的核心特征:控制流在代码里,不在模型里

Agent 模式:LLM 自主决策的循环推理

Agent 的架构完全不同。它把"下一步做什么"的决定权交给了 LLM。典型的 Agent 采用 ReAct(Reasoning + Acting)循环:LLM 观察当前状态 → 推理需要什么 → 选择工具并执行 → 观察结果 → 继续推理,直到认为任务完成。

Agent ReAct 循环

Python 代码示例

下面是一个基于 LangGraph 的 ReAct Agent 实现。注意代码量反而比 Workflow 更少,因为 LLM 接管了流程编排。

from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import MemorySaver
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from typing import Annotated
from typing_extensions import TypedDict
import operator

# 定义工具
@tool
def multiply(a: int, b: int) -> int:
    """两个整数相乘。"""
    return a * b

@tool
def add(a: int, b: int) -> int:
    """两个整数相加。"""
    return a + b

@tool
def subtract(a: int, b: int) -> int:
    """两个整数相减,返回 a - b。"""
    return a - b

@tool
def web_search(query: str, max_results: int = 3) -> str:
    """搜索网络获取最新信息。"""
    from duckduckgo_search import DDGS
    with DDGS() as ddgs:
        results = [f"{r['title']}" for r in ddgs.text(query, max_results=max_results)]
    return "\n".join(results)

tools = [add, multiply, subtract, web_search]

# 将工具绑定到 LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0).bind_tools(tools)

# 定义状态
class AgentState(TypedDict):
    messages: Annotated[list, operator.add]

# Agent 节点:LLM 决定调用工具还是直接回复
def agent_node(state: AgentState) -> dict:
    ai_msg = llm.invoke(state["messages"])
    return {"messages": [ai_msg]}

# 构建 Agent 图
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent_node)
workflow.add_node("tools", ToolNode(tools))

workflow.add_edge(START, "agent")
# 关键:根据 LLM 输出决定下一步
workflow.add_conditional_edges(
    "agent",
    tools_condition,  # 有 tool_calls → tools,否则 → END
    {"tools": "tools", END: END}
)
workflow.add_edge("tools", "agent")  # 工具结果返回 Agent 继续推理

agent = workflow.compile(checkpointer=MemorySaver())

# 运行——LLM 自己决定调用哪些工具、调用几次
result = agent.invoke(
    {"messages": [{"role": "user", "content": "计算 (15 * 7 + 22) / 11,顺便搜一下今天的科技新闻"}]},
    config={"configurable": {"thread_id": "user-1"}}
)
print(result["messages"][-1].content)

注意上面这段代码和 Workflow 的本质区别:

  • 没有预定义步骤顺序——LLM 自己决定先算乘法还是先搜索
  • tools_condition 是实现自主性的关键——它检查 LLM 的响应中是否包含 tool_calls,有则进入工具节点,没有则结束
  • 工具执行完会自动回到 Agent 节点——形成"推理-行动-观察-推理"的循环
  • 开发者只定义了能力和边界(有哪些工具可用),不定义执行路径

Workflow vs Agent 对比一览

维度 Workflow Agent
控制流归属 代码(开发者预定义) LLM(运行时动态决策)
执行路径 固定或有限分支(DAG) 动态循环,直到目标达成
可预测性 高——相同输入走相同路径 较低——相同输入可能走不同路径
LLM 调用次数 可预估(通常固定) 不可预估(取决于任务复杂度)
延迟 低且稳定 波动较大
Token 成本 可控、预算明确 上限难预估
工具调用 开发者在特定节点预设 LLM 运行时自主选择
错误处理 显式分支或终止 LLM 可尝试自修复
代码复杂度 节点和边多,路由逻辑多 架构简洁,但调试困难
适用场景 结构化、可重复、需审计 开放、探索性、需判断

混合架构:生产环境的务实选择

现实世界中,纯粹的 Agent 很少单独存在。大多数成功的生产系统采用混合架构:外层是确定性的 Workflow,只在需要动态推理的环节嵌入 Agent。

混合架构模式

典型场景

客服系统:Workflow 负责意图分类、权限校验、会话管理;Agent 负责在知识库中动态搜索、调用业务接口、根据客户情绪调整回复策略。

代码审查工具:Workflow 负责拉取 PR、解析 diff、按文件拆分;Agent 负责分析代码逻辑、提出改进建议(因为每个 PR 的问题各不相同)。

数据分析助手:Workflow 负责查询生成、SQL 校验、结果格式化;Agent 负责理解用户的分析意图、决定从哪个角度切入、发现异常时动态调整分析方向。

混合模式的代码结构

# 混合架构示意
from langgraph.graph import StateGraph, START, END

# 外层 Workflow
workflow = StateGraph(HybridState)

# 确定性节点
workflow.add_node("validate_input", validate_input)    # 参数校验
workflow.add_node("fetch_context", fetch_context)      # 拉取上下文

# Agent 节点(嵌入在 Workflow 中)
workflow.add_node("agent_推理", agent_node)             # LLM 自主推理

workflow.add_node("format_output", format_output)      # 格式化输出
workflow.add_node("audit_log", audit_log)              # 审计日志

# 固定流程
workflow.add_edge(START, "validate_input")
workflow.add_edge("validate_input", "fetch_context")
workflow.add_edge("fetch_context", "agent_推理")
workflow.add_edge("agent_推理", "format_output")
workflow.add_edge("format_output", "audit_log")
workflow.add_edge("audit_log", END)

# Agent 节点内部是自主循环,但输入/输出接口是确定的

混合架构的优势:

  • 可靠性:输入校验、输出格式化、审计日志这些环节保持确定性
  • 灵活性:Agent 环节可以动态处理多变的任务
  • 可观测性:每个节点的输入输出都是确定的数据结构,便于监控和调试
  • 安全性:在 Agent 节点的入口和出口设置校验和权限检查

如何选择:一个实用的决策框架

面对具体需求时,可以按下面的流程来判断:

决策流程图

实践建议

优先使用单次 LLM 调用。大多数"AI 功能"用简单的 prompt + RAG 就能做好。先上线,再根据实际效果判断是否需要升级。

需要多步时才考虑 Workflow。写清楚每一步做什么,LLM 只承担内容任务。这样成本可控,出了问题也好排查。

仅当步骤不可预知时才引入 Agent。如果你在写代码时无法确定"做完这一步之后该做什么",那才是 Agent 发挥价值的地方。典型的信号包括:

  • 需要根据中间结果动态选择工具
  • 任务路径随输入变化很大
  • 需要探索性推理(比如调试、研究、复杂分析)

警惕落地风险。Gartner 预测 2027 年超过 40% 的 Agent 项目会因成本失控或价值不明确而被取消。在引入 Agent 之前,先确保:

  1. 核心子任务模型能可靠执行(不存在致命瓶颈)
  2. 错误可以被检测且代价可接受
  3. 任务的业务价值值得付出额外的 token 成本

总结

Workflow 和 Agent 不是"谁更好"的问题,而是"谁更适合当前场景"的问题。如果用一句话总结:

能预先列出所有步骤的,用 Workflow;必须让 LLM 自己想办法的,用 Agent。

从技术演进的角度看,大部分团队的建议路径是:单次 LLM 调用 → Prompt Chaining → Workflow → 混合架构(仅当需要时引入 Agent)。每一步升级都应该由实际需求驱动,而不是技术热情。

希望这篇文章帮你在下一次架构讨论中,能清晰地回答:“我们真的需要 Agent,还是 Workflow 就够了?”

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐