在上一篇文章中,我们通过LangChain框架介绍了AI Agent,也提到了对LLM的调用,那么对LLM的调用和AI Agent之间究竟有什么区别?本文则继续基于LangChain详细介绍两者的本质区别以及相应的使用场景。

一、普通大模型调用解决的是一次推理任务

先看最简单的大模型程序。

代码片段Text
用户输入

构造 Prompt / Messages

调用 LLM

获得 Response

程序继续执行

例如:

代码片段Python
from langchain.chat_models import init_chat_model
 
model = init_chat_model("openai:gpt-5.4")
 
response = model.invoke(
    "请解释 Python 中 list 和 tuple 的主要区别。"
)
 
print(response.content)

运行结果

模型生成内容具有随机性,下面展示一次典型结果:

代码片段Text
list 和 tuple 都用于保存有序数据。

主要区别是 list 可以修改,而 tuple 通常作为不可变序列使用。
list 使用 [],tuple 通常使用 ()。

这里有两个角色。

LLM 负责:

代码片段Text
输入 → 推理 → 输出

应用程序负责:

代码片段Text
什么时候调用 LLM

给 LLM 什么数据

拿到结果之后做什么

也就是说,模型拥有内容生成权,但没有程序流程的控制权。

它完成的是一次推理任务。

翻译、摘要、分类、信息抽取、文本改写、生成 SQL 等大量场景,本质上都可以采用这种模式。LangChain 当前也把 Model 作为可以独立调用的基础组件,同时说明模型也可以作为 Agent 的推理引擎。

二、Tool Calling 仍然不等于 Agent

这里有一个特别容易混淆的问题:

模型可以自己选择工具,是不是就已经成为 Agent 了?

不一定。

现代模型普遍支持工具调用(Tool Calling / Function Calling)。开发者先告诉模型有哪些工具以及每个工具的参数结构,模型可以返回一个结构化的工具调用请求。

例如:

代码片段Python
from langchain.chat_models import init_chat_model
from langchain.tools import tool
 
@tool
def get_order_status(order_id: str) -> str:
    """查询订单当前状态。"""
    return f"订单 {order_id} 已发货"
 
model = init_chat_model("openai:gpt-5.4")
model_with_tools = model.bind_tools([get_order_status])
 
response = model_with_tools.invoke(
    "查询订单 A1024 的状态"
)
 
print(response.tool_calls)

示例输出

代码片段Text
[
    {
        "name": "get_order_status",
        "args": {"order_id": "A1024"},
        ...
    }
]

模型确实已经做出了一个决定:

代码片段Text
应该调用 get_order_status
参数是 A1024

但这里需要注意,模型只是提出了调用请求,并没有真正执行 Python 函数。

在独立使用 Model 时,LangChain 官方文档明确说明:模型返回 Tool Call 之后,需要应用程序执行工具,再把 Tool Result 放回消息历史,然后再次调用模型。

完整过程实际上是:

代码片段Text
LLM

我要调用 get_order_status

你的 Python 程序执行工具

得到工具结果

你的程序重新调用 LLM

LLM 生成最终答案

因此:

Tool Calling 是模型的一种能力,而 Agent 是围绕这种能力构建出来的一种执行系统。

这是理解 Agent 非常重要的一层边界。

三、Agent改变的是程序的控制方式

普通 LLM 调用与 Agent 最根本的区别,可以从“控制流”来理解。

传统程序通常是:

代码片段Python
result_a = step_a()
 
if result_a:
    result_b = step_b()
 
result_c = model.invoke(...)

下一步做什么,由开发者提前写进代码。

即使中间使用了 LLM,程序整体仍然是:

代码片段Text
开发者定义流程

程序按照流程执行

LLM只是其中一个节点

Agent 则引入了一种不同的运行方式:

代码片段Text
目标

LLM判断

选择Action

环境执行

获得Observation

重新判断

选择下一步Action

……

完成任务

LangChain 当前的 create_agent 正是围绕这个循环运行:调用模型,让模型选择工具,执行工具,然后把结果重新送入模型;当模型不再请求工具时结束。

所以,更准确地说:

普通 LLM 调用把模型放在流程里面;Agent 则让模型参与决定流程本身。

变化的不是“调用次数”,而是决策权的位置

四、从一次调用到 Agent Loop

假设用户提出一个稍微复杂的任务:

查询订单 A1024。如果已经发货,查询物流状态;如果物流异常,再查询售后处理规则,然后告诉我应该怎么办。

传统 Workflow 可以直接写:

代码片段Text
查询订单

判断是否发货

查询物流

判断是否异常

查询售后规则

调用 LLM 生成回答

这个方案没有任何问题。

甚至从工程角度看,这种流程往往更加可靠。

因为每一步都是开发者预先确定的:

代码片段Text
条件 A → 执行 B
条件 C → 执行 D

但如果任务变成:

帮我调查为什么订单 A1024 还没有收到,并给出处理建议。

事情就变得不同。

完成这个目标可能需要:

代码片段Text
查订单?
查物流?
查仓库?
查天气?
查客服记录?
查退款政策?

而且查询物流之后得到的信息,可能决定下一步是否还需要查询其他系统。

这时很难提前写出一棵完整的 if/else 决策树。

Agent 更适合处理这种情况。

它可能第一次执行:

代码片段Text
get_order_status("A1024")

得到:

代码片段Text
已发货

然后决定:

代码片段Text
继续查询物流

得到:

代码片段Text
包裹停留在上海中转站 3 天

模型发现仍然不能解释原因,于是继续:

代码片段Text
get_logistics_exception(...)

最后才生成回答。

这就是 Agent Loop 的意义:

下一步不是只由最初的问题决定,也由前一步执行结果决定。

LangChain 官方把 Agent 描述为动态定义自身过程和工具使用方式的系统,而 Workflow 则具有预先确定的代码路径。

五、Agent不是“LLM + Tools”,而是一个闭环系统

如果继续向下拆,Agent 至少包含几个相互配合的部分。

Model:判断下一步

Model 是推理引擎。

它读取当前上下文,然后决定:

代码片段Text
直接回答
还是
调用工具

如果调用工具,还要决定:

代码片段Text
调用哪个工具
使用什么参数

工具返回以后,模型还要再次判断:

代码片段Text
信息够了吗?
还需要做什么?
是否应该结束?

因此 Model 提供的是决策能力,但 Model 本身并不是 Agent。LangChain 官方也明确把模型描述为 Agent 的 reasoning engine。

Tool:改变或观察外部世界

LLM 本身主要处理上下文中的信息。

Tool 则把模型连接到外部系统,例如:

代码片段Text
数据库
搜索引擎
文件系统
浏览器
Python
GitHub
企业 API
邮件系统
日历

工具既可以读取信息,也可能产生真实副作用,例如:

代码片段Text
发送邮件
创建订单
修改数据库
提交代码

因此工具不是“给模型补充知识”这么简单,它实际上提供了 Agent 观察环境和作用于环境的接口。LangChain 的 Tool 也是具有明确输入、输出和描述的可调用函数。

State:保存当前执行现场

一次普通 LLM 调用通常只关心:

代码片段Text
Input → Output

但 Agent 需要知道自己已经执行到了哪里。

例如:

代码片段Text
用户原始任务
历史消息
已经调用过哪些工具
工具返回了什么
当前有哪些中间结果
任务是否已经完成

这些信息共同形成执行过程中的状态(State)

如果没有状态,每次模型调用都会像重新开始一样,它无法根据之前的工具结果继续工作。

LangGraph 的 Graph API 将 State 定义为应用当前状态的共享数据结构;LangChain 的 Agent 又运行在 LangGraph Runtime 之上,因此状态和执行过程不是附加功能,而是 Agent 编排的重要基础。

Runtime:真正执行这个循环

Model 只负责产生决策。

Tool 只负责执行某个动作。

还需要一个 Runtime 把它们连接起来:

代码片段Text
调用模型

读取 Tool Call

执行 Tool

更新 State

再次调用模型

检查是否结束

LangChain 当前的 create_agent 底层运行在 LangGraph Runtime 上。这个 Runtime 还可以承载上下文、Store、执行信息以及流式输出等能力。

因此一个更完整的 Agent 可以理解为:

代码片段Text
Agent
=
Model
+
Tools
+
State
+
Agent Loop
+
Runtime
+
控制规则

而不是简单的:

代码片段Text
Agent = LLM + Tools

后者适合作为入门记忆,前者才更接近工程实现。

六、Agent与Workflow的边界尤其重要

理解 Agent 时,最容易犯的另一个错误,是把所有多步骤 LLM 程序都叫作 Agent。

例如:

代码片段Text
用户问题

分类器

搜索

RAG

LLM总结

返回

这可能是一个非常完整的 AI 应用,但它并不一定是 Agent。

判断标准不是:

代码片段Text
有没有 LLM?
有没有 Tool?
步骤多不多?

而是:

执行路径主要由谁决定?

LangGraph 官方给出的区分非常直接:Workflow 的代码路径是预先确定的,而 Agent 的过程和工具使用是动态的。

因此可以形成三个层级。

普通 LLM 调用

代码片段Text
开发者决定:什么时候调用模型
模型决定:生成什么

Workflow

代码片段Text
开发者决定:整个执行路径
模型负责:某些节点中的推理

Agent

代码片段Text
开发者决定:目标、工具、规则和边界
模型决定:运行过程中下一步采取什么行动

这个区别比“Agent 可以调用工具”更加准确。

七、Agent获得自主性的同时,也失去了一部分确定性

把控制权交给模型之后,会产生一个很直接的结果:

系统的执行路径变得不完全确定。

对于传统 Workflow:

代码片段Text
A → B → C → D

开发者通常知道下一步一定是什么。

对于 Agent:

代码片段Text
A

LLM
├─→ B
├─→ C
└─→ D

进入 B 以后,模型还可能继续选择:

代码片段Text
B
├─→ E
└─→ F

于是一次任务可能执行:

代码片段Text
A → B → E → Response

另一次相似任务可能执行:

代码片段Text
A → C → F → B → Response

这就是 Agent 可以处理开放问题的原因,也是 Agent 更难工程化的原因。

两者实际上是在做一种交换:

维度普通调用 / WorkflowAgent
控制流开发者预先定义运行时动态决定
模型角色内容生成或局部判断持续参与决策
执行路径相对固定可能变化
工具使用程序决定模型可动态选择
中间状态通常较简单通常更重要
可预测性相对低
测试难度较低较高
Token / API 成本较容易估计与实际路径相关
适合问题已知流程开放式、多步骤任务

因此 Agent 并不是免费获得“自主性”。

它实际上完成了一次交换:

代码片段Text
降低部分确定性

换取更强的运行时适应能力

这也是为什么 Agent 系统往往需要更多的可观测、重试、限流、权限、终止条件和人工介入机制。LangChain 当前通过 Middleware 提供日志、工具选择控制、重试、提前终止、Guardrails 和 Human-in-the-loop 等控制能力。

八、Agent的“自主”实际上是受约束的自主

Agent 经常被描述成“自主执行任务的 AI”。

这个说法容易产生另一个误解,好像模型获得了完全自由的执行能力。

实际上,工程中的 Agent 更接近:

在开发者规定的行动空间中,由模型动态选择下一步动作。

开发者仍然决定:

代码片段Text
给它什么模型
给它哪些工具
工具具有什么权限
能够访问什么上下文
最多执行多少步
什么操作需要人工确认
发生错误如何处理
什么时候强制停止

例如一个 Agent 只有:

代码片段Text
search_web
read_file

两个工具,那么无论模型如何推理,它都不能发送邮件。

如果再增加:

代码片段Text
send_email

它才拥有发送邮件的行动能力。

因此 Agent 的能力边界,并不只是由模型决定,而是由:

代码片段Text
Model 能力
×
Tool 能力
×
Context
×
Runtime
×
Policy

共同决定。

这也是为什么 Agent 工程中经常会出现 Middleware、Guardrails、权限控制以及 Human-in-the-loop。它们并不是额外装饰,而是在动态执行过程中重新建立可控性。

九、什么时候用普通调用,什么时候用 Agent

实际开发中,不应该从“Agent 更先进”这个角度做选择。

更实用的判断方式,是看任务路径是否可以提前确定。

例如:

代码片段Text
文本 → 摘要
文本 → 分类
数据 → JSON
中文 → 英文

直接调用 LLM 即可。

如果任务是:

代码片段Text
读取用户问题
→ 查询知识库
→ 把资料交给模型
→ 生成答案

流程已经非常明确,更适合 Workflow。

即使其中调用了向量数据库、搜索 API 和 LLM,也没有必要强行做成 Agent。

但如果需求是:

调查这个项目为什么部署失败,并尽可能找到原因。

模型可能需要:

代码片段Text
读日志

判断问题

查配置

发现依赖异常

查 package.json

搜索文档

再次检查日志

给出结论

开发者很难提前知道需要执行哪些步骤。

这种目标明确,但解决路径不明确的问题,更适合 Agent。

可以用一句简单的判断来区分:

代码片段Text
步骤已知 → 优先 Workflow

目标已知、步骤未知 → 考虑 Agent

当然,两者并不是互斥关系。

实际生产系统经常采用混合方式:

代码片段Text
确定性 Workflow

某个开放问题

Agent

返回 Workflow

继续确定性处理

LangChain 的 Middleware 文档也明确支持把完整 Agent 作为节点或子图放入更大的 LangGraph 工作流中,用确定性步骤包围 Agent。

这通常比“所有事情全部交给 Agent”更加容易控制。

十、真正需要理解的是控制权的变化

回到最开始的问题。

普通大模型调用、Tool Calling、Workflow 和 Agent,并不是四个完全独立的技术。

它们更像是逐步增加模型决策范围的几种系统形态:

代码片段Text
普通 LLM
模型决定:说什么



Tool Calling
模型还可以决定:想调用什么工具



Workflow
模型参与多个步骤
但整体路径仍由代码决定



Agent
模型持续根据当前状态决定:
下一步做什么、用什么工具、是否继续

所以,AI Agent 与普通大模型调用之间最值得理解的差异,并不是“Agent 调用了更多次 LLM”,也不是“Agent 能联网、能搜索、能调用 API”。

它改变的是应用程序中的控制权分配。

普通调用中,模型是被程序调用的一个能力;Agent 中,模型进一步成为运行时的决策组件,而 Runtime 负责不断把模型决策、工具执行和状态更新组织成反馈循环。

本文可以最终把这个关系总结成一句话:

LLM 负责推理,Tool 负责行动,State 记录现场,Runtime 负责执行循环,而 Agent 让模型在这些能力之上持续决定“下一步做什么”。

这也是为什么学习 Agent 时,不必急着进入多 Agent、长期记忆或复杂规划。先真正理解一次 Model Call、一次 Tool Call 和一个 Agent Loop 之间发生了什么,后面的 LangChain、LangGraph 和 Deep Agents 才会自然衔接起来。