什么是 LLM Agent:从 LLM 到自主智能体的范式转变

举报
柠檬🍋 发表于 2026/10/15 21:57:11 2026/10/15
【摘要】 什么是 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 至关重要的性质:

  1. 输入输出都是文本。模型的世界边界就是 token 序列,它无法直接读写文件、无法发起网络请求、无法操作数据库——除非有人替它把动作翻译成真实的函数调用,再把结果翻译回文本。
  2. 单次调用是无状态的(stateless)。模型本身不记得你上一次说了什么。所谓"多轮对话",是外部程序把历史消息重新拼接进 prompt 再发一次。记忆从来不在模型里,而在调用方。
  3. 输出止于 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 都绕不开的起点。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。