什么是 LLM Agent:从 LLM 到自主智能体的范式转变
什么是 LLM Agent:从 LLM 到自主智能体的范式转变
一、从一个很具体的困惑说起
设想你对着一个通用大模型说:
帮我查一下北京今天的天气,如果下雨就提醒我带伞,然后把结论发到我的待办清单里。
模型可以立刻给你一段漂亮的回答:它会解释"应该先调用天气接口,判断是否有雨,再写入待办"。步骤条理清晰,甚至能写出对应的代码。但你会发现,它什么都没做——没有查询、没有判断、没有写入。它只是把"该怎么做"用文字描述了一遍。
这正是本文要回答的核心问题:一个能写出完美行动方案的模型,为什么还不是一个 Agent(智能体)?
答案不在模型能力上,而在结构上。从"会说话"到"会做事",中间隔着三个工程增量:工具、循环、状态。把这三者补齐,LLM 才从"推理引擎"变成"行动实体"。下面我们一步步拆开看。
二、LLM 的本质:一个无状态的条件概率生成器
先把 LLM(Large Language Model,大语言模型)的本质说清楚,否则后面所有讨论都会漂浮。
从计算角度看,LLM 做的是自回归(autoregressive)生成:给定一段已有文本,预测下一个 token(词元)的概率分布,采样出一个 token,把它接到文本末尾,再预测下一个,如此往复。形式化地:
[
P(t_1, t_2, \dots, t_n) = \prod_{i=1}^{n} P(t_i \mid t_1, t_2, \dots, t_{i-1})
]
这个定义带来三个对 Agent 至关重要的性质:
- 输入输出都是文本。模型的世界边界就是 token 序列,它无法直接读写文件、无法发起网络请求、无法操作数据库——除非有人替它把动作翻译成真实的函数调用,再把结果翻译回文本。
- 单次调用是无状态的(stateless)。模型本身不记得你上一次说了什么。所谓"多轮对话",是外部程序把历史消息重新拼接进 prompt 再发一次。记忆从来不在模型里,而在调用方。
- 输出止于 token。模型生成完就结束了,它不会"等一会儿再看看结果怎么样"。
把这三点合起来看,可以得到一个关键判断:
LLM 是一个推理引擎,不是一个行动主体。它擅长"想",不擅长"做",也不会自己决定"何时再做一次"。
所以,构建 Agent 的工作,本质上是在 LLM 外面搭一套工程结构,补上它缺失的能力。
三、Agent 的三个增量:工具、循环、状态
从普通 LLM 调用到 Agent,需要补三个增量。它们各自解决一个明确的缺失。
增量一:工具(Tool / Function)——把"说"变成"做"
工具是 Agent 可以调用的外部能力,通常表现为一个有名字、有参数、有返回值的函数。天气查询、数据库读写、代码执行、网页检索,都是工具。
工具的作用是把模型的文本输出转化为对真实世界的操作。模型不再输出"建议你查询天气",而是输出一个结构化的调用请求,比如"调用 get_weather,参数 city=北京",由外部程序真正执行。
这里的关键设计点是:模型只负责"决定调用什么",不负责"怎么执行"。执行权、权限、超时、重试,都留在外部程序手里。这条边界是 Agent 安全与可控性的基石,后文还会反复回到它。
增量二:循环(Loop / Control Flow)——把"一次"变成"多次"
一次 LLM 调用是线性的:输入 → 输出,结束。但真实任务往往需要多步:查天气 → 根据结果判断 → 查日历 → 写入待办。每一步的输入都依赖上一步的输出。
Agent 的解法是引入一个控制循环:反复执行"思考 → 行动 → 观察",直到任务完成或触发终止条件。这个循环让 Agent 具备了两件普通调用没有的能力:
- 根据反馈调整:观察到"今天下雨"之后,才会决定"提醒带伞";
- 条件终止:不是固定跑 N 步,而是"目标达成即停"。
增量三:状态(State)与记忆(Memory)——把"孤立"变成"连续"
循环一旦多步,就必须有人记住"我已经做了什么、拿到了什么、还差什么"。这就是状态。状态可以是简单的一个消息列表,也可以是结构化的任务进度、待办清单、已访问过的网页集合。
状态的作用有两个:
- 让每一步决策都基于完整历史,避免重复劳动或自相矛盾;
- 支持跨会话的长期记忆,比如记住用户的偏好、上次任务的进展。
把这三个增量合起来,就能给出一个工作定义:
LLM Agent 是一个以 LLM 为推理核心,能够感知环境、规划步骤、调用工具采取行动、依据观察结果调整策略,直至达成目标的系统。
注意这个定义里的每个动词都对应一个工程模块:"推理"对应模型,"行动"对应工具层,"观察"对应环境与返回值处理,"调整"对应循环控制,"记住"对应状态与记忆。
四、形式化:Agent 循环长什么样
把上面的定义落成一个循环结构,几乎是所有 Agent 框架的共同骨架:
state ← 初始化(目标, 初始上下文)
while 未满足终止条件:
thought ← LLM.推理(state) # 想:现在该做什么
action ← LLM.决策(state) # 定:选择哪个工具、什么参数
if action 为空: # 模型认为任务已完成
break
observation ← 环境.执行(action) # 做:真正调用工具,拿到结果
state ← 更新(state, thought, action, observation)
return 汇总(state)
这个"思考—行动—观察"的往复,最广为人知的命名是 ReAct(Reasoning + Acting,推理与行动)。它并不是某个特定框架的专利,而是一种架构范式:让模型在每一步都显式地交替产出推理文本与工具调用。
需要澄清一个常见类比:Agent 的决策过程在数学上常被拿来与 POMDP(Partially Observable Markov Decision Process,部分可观测马尔可夫决策过程) 对照——环境状态不可完全观测,Agent 依据观测做决策。这个类比在理解"为什么需要记忆和信念状态"时很有帮助,但它是建模视角,不等于 Agent 真的在做 POMDP 求解。不要据此推断"用 RL 求解 Agent 就能得到最优策略",那是另一个话题。
五、一个最小 Agent 循环(示意代码)
理论说再多,不如看一段能跑起来的骨架。下面这段 Python 不依赖任何在线模型,用一个规则化的"假模型"代替 LLM,让你在没有 API Key 的情况下也能看清循环的每一步。
环境与依赖
- Python 3.9 及以上(仅用到标准库
dataclasses) - 无第三方依赖
运行方式:保存为 minimal_agent.py,执行 python minimal_agent.py。
"""一个最小 Agent 循环的示意实现,不依赖任何在线模型。
说明:
- 本示例用规则化的 mock_model 代替真实 LLM,便于离线运行、观察循环结构;
- 真实系统中,mock_model 应替换为对 LLM 的调用,并由模型返回结构化的
{thought, action},其中 action 描述要调用的工具与参数;
- 这是一段"示意代码",用于说明结构,不代表生产实现。
"""
from dataclasses import dataclass, field
# ---------- 1) 工具层:Agent 能"做"的事 ----------
def get_weather(city: str) -> str:
# 真实系统会调用天气 API;此处返回固定值,保证示例可离线运行
fake = {"北京": "晴,18℃", "上海": "多云,22℃"}
return fake.get(city, "未知城市")
TOOLS = {"get_weather": get_weather}
# ---------- 2) "模型"层:把目标翻译成一个 action ----------
def mock_model(state: "State") -> dict:
# 真实 LLM 在此处的工作:读目标与历史 -> 输出 {thought, action}
if state.step == 0:
return {
"thought": "要回答天气问题,需要先调用天气工具",
"action": {"name": "get_weather", "args": {"city": "北京"}},
}
return {"thought": "已获得信息,可以结束", "action": None} # None = 终止
# ---------- 3) 状态层:跨步骤保持上下文 ----------
@dataclass
class State:
goal: str
step: int = 0
history: list = field(default_factory=list)
def run_agent(goal: str, max_steps: int = 5) -> str:
state = State(goal=goal)
while state.step < max_steps: # 循环控制 + 步数上限
decision = mock_model(state)
state.history.append(("thought", decision["thought"]))
action = decision["action"]
if action is None: # 终止条件:模型判定完成
break
observation = TOOLS[action["name"]](**action["args"]) # 执行工具
state.history.append(("observation", observation))
state.step += 1
return summarize(state)
def summarize(state: State) -> str:
obs = [v for _, v in state.history if _ == "observation"]
return f"目标:{state.goal};结果:{obs[-1] if obs else '无可用信息'}"
if __name__ == "__main__":
print(run_agent("北京今天天气怎么样?"))
一次运行的输出:
目标:北京今天天气怎么样?;结果:晴,18℃
请特别注意代码里的三处结构,它们对应前文的三个增量:
TOOLS字典 —— 工具层。模型给出的只是一个字符串名字加参数字典,真正执行发生在这里。while循环加max_steps—— 循环层。max_steps是防止死循环的保险丝,生产系统里这一步不可或缺。State.history—— 状态层。把每步的思考与观察记下来,后续决策才能基于完整历史。
把 mock_model 换成真实 LLM 调用后,结构完全不变——变的只是"谁来产生那个 decision"。这正是理解 Agent 的关键:框架再花哨,骨架就是这个循环。
六、Agent 的五个核心构件
把上面的讨论系统化,一个 Agent 系统通常由五个构件组成。理解每个构件的职责和它最容易出问题的地方,比记住某个框架的 API 更有价值。
| 构件 | 职责 | 常见失败点 |
|---|---|---|
| 模型(Model) | 推理、决策、生成 | 幻觉、指令遵循不稳、长上下文退化 |
| 工具(Tools) | 与外部世界交互 | 描述不清导致选错工具、参数错误、返回超长 |
| 记忆 / 状态(Memory / State) | 保持上下文与长期信息 | 上下文溢出、记忆污染、检索不准 |
| 编排 / 控制(Orchestration) | 循环、终止、分支、重试 | 死循环、错误累积、过早终止 |
| 环境 / 沙箱(Environment) | 工具运行的真实世界 | 权限越界、副作用不可逆、环境不一致 |
一个值得记住的经验判断:Agent 上线后的大部分事故,出在模型之外的四个构件上,而不是模型本身。 模型能力会随版本提升,但工具描述、循环控制、状态管理和权限边界,永远需要工程师亲手设计。
七、自主性的谱系:不是非黑即白
"是不是 Agent"其实不是一个二元问题,而是一条自主性(autonomy)谱系。自主性越高,灵活度越高,但可预测性和可控性越低。
| 层级 | 形态 | 决策权 | 典型场景 |
|---|---|---|---|
| L0 | 固定工作流 | 全在代码里,模型只填内容 | 格式固定的批处理 |
| L1 | 路由 | 模型选择走哪条预设分支 | 意图分类、客服分流 |
| L2 | 工具调用 | 模型选工具,路径由代码定 | 单步查询 + 生成 |
| L3 | 多步 Agent | 模型决定步骤与工具序列 | 研究、排障、数据分析 |
| L4 | 自治 Agent | 模型设定子目标、自主循环 | 开放式任务、长时程作业 |
一个成熟的工程判断是:在能满足需求的前提下,尽量选低自主性。L3 能解决的事,不要用 L4;固定流程能做的事,不要交给模型自由发挥。原因很直接——每提升一级自主性,延迟、成本、调试难度和不可预测性都会同步上升。
八、常见误区
误区一:用了 Function Calling 就是 Agent。
函数调用只是"工具"这一个增量。如果调用是单次的、没有循环、没有基于结果的再决策,那它只是一个"带参数的 LLM 调用",不是 Agent。
误区二:Agent 一定比 Workflow 好。
恰恰相反。当任务步骤固定、边界清晰时,工作流(workflow)更便宜、更快、更可靠、更好调试。Agent 的价值只在"步骤无法预先穷举、需要根据中间结果动态决策"时才体现。把确定性任务做成 Agent,是典型的过度工程。
误区三:Agent 等于多智能体。
单 Agent 是最常见、也最容易上线的形态。多智能体(multi-agent)是在单 Agent 遇到明确瓶颈时才引入的架构升级,它带来通信开销、协调复杂度和新的失败模式。不要默认从多智能体起步。
误区四:模型越强,Agent 就越好。
模型是五个构件之一。一个工具描述含糊、循环没有终止条件、状态无限增长的 Agent,换个更强的模型只会"更快地犯错"。
九、适用边界与局限
Agent 并非万能,它有明确的适用条件和固有代价。
适合的场景:任务可被拆成若干步;每步有可观测的反馈(工具返回值、执行结果);步骤顺序无法在编码时完全穷举。
不适用的场景:步骤完全固定(用工作流);要求严格确定性(用规则引擎);单步即可完成(直接调模型);对延迟极其敏感(Agent 的多轮往返天然更慢)。
固有代价,必须提前认知:
- 延迟与成本被放大。每一步都要一次模型调用加一次工具往返,多步任务的耗时与费用是单次调用的数倍甚至数十倍。
- 错误会累积。第 2 步的幻觉会成为第 3 步的错误前提。步数越多,误差放大越明显。
- 行为不完全可预测。同一输入不保证同一轨迹,这给测试和复现带来困难。
- 攻击面变大。工具带来了权限与数据外泄风险,外部内容可能携带提示注入(prompt injection,通过污染输入内容来劫持模型行为)攻击。
因此,一个负责任的 Agent 工程实践,一定包含:明确的终止条件、工具权限最小化、关键步骤的人机确认、完整的轨迹日志。这些不是可选项,而是把 Agent 从演示推进到生产的前提。
十、小结
用一句话回答标题里的问题:
LLM Agent = LLM(推理)+ 工具(行动)+ 循环(调整)+ 状态(记忆)。
LLM 提供了通用的推理与语言能力,但它天生无状态、无行动力、不会自我循环。Agent 的全部工程价值,就在于围绕这个推理核心,补上行动、反馈与记忆的结构,让它从"会说话"走向"会做事"。
理解了这条主线,后面所有内容——工具协议怎么设计、循环如何终止、记忆如何检索、多步任务如何规划、系统如何评估和加固——都能挂到这条主线上,而不是零散的知识点。
动手练习:把上面示例中的 get_weather 换成两个工具(比如"查天气"和"写待办"),让 mock_model 在第二步根据天气结果决定是否写入待办。你会立刻遇到两个真实问题:如何让"模型"知道第一步的结果(状态设计),以及如何判断任务真的结束了(终止条件设计)。这两个问题,正是构建任何 Agent 都绕不开的起点。
- 点赞
- 收藏
- 关注作者
评论(0)