Agent(智能体)比较权威的定义出自 Stuart Russell 与 Peter Norvig 的《Artificial Intelligence: A Modern Approach》(1995, 《人工智能:一种现代方法》)。
An agent is anything that can be viewed as perceiving its environment through sensors and acting upon that environment through actuators.
通常指一个能够自主感知环境、决策并执行动作以完成特定目标的智能系统 。
简单来说,它就像是一个智能代理,可以接受我们的指令,在一定程度上自己想办法去完成任务,而不仅仅是被动响应。
举个日常类比:可以把 Agent 想象成自己的 AI 助手或员工,给出任务,它会自己想如何去做,必要时查资料、调用工具,最后给出结果。
发展历史
人工智能领域的「Agent」概念经历了漫长的发展演变:
规则驱动的系统与专家系统(1950 - 1990年):
早期的 AI 系统多是基于手工编写规则的。这类系统按照预设的 if-then 规则集工作,缺乏灵活性但在特定领域表现不错。
典型代表是专家系统,例如 1970s 的医学诊断专家系统 MYCIN 和更早的 DENDRAL 。专家系统通过将人类专家的知识转化为规则库,能在狭窄领域模拟出专家级推理 。
比如 MYCIN 系统包含数百条治疗传染病的规则,可以根据患者症状给出诊断和治疗建议。它甚至能用一定的自然语言与用户交互并解释自己的推理过程 。
然而,这类系统的局限在于:知识获取成本高(需要专家手工编码大量规则),不具备自我学习,遇到规则覆盖不到的情况就束手无策。
强化学习 Agent(1990 - 2020年)
随着机器学习兴起,Agent 的智能决策开始由学习而非死板规则产生。
强化学习(Reinforcement Learning, RL)提供了一种让 Agent 通过试错与环境交互、自主学习策略的框架。
经典的 RL 设定中,Agent 不断感知环境状态,采取动作,根据环境给的奖励/惩罚调整策略。经过无数轮训练,Agent 学会在环境中达到奖励最大化的行动序列。
1990 - 2000 年代,RL 被用于机器人控制、游戏等领域,但真正让大众震撼的是 2010 年代的深度强化学习:例如 2016 年 DeepMind 的 AlphaGo 通过深度神经网络结合强化学习,在围棋上击败了人类世界冠军,展示了 Agent 在复杂环境下惊人的决策能力。
这一时期的 Agent 多数是在模拟/游戏环境里训练出的「智能体」(如学会玩雅达利游戏、下棋等),它们能自行探索出有效策略。
然而,RL Agent 通常需要明确的奖励函数和大量训练样本,在现实开放任务上应用受限。此外,训练得到的策略往往专门针对某一任务,缺乏通用性。
大语言模型时代的 Agent(2020年代)
进入 2020 年,AI 出现了一个新拐点:大型语言模型(LLM)的崛起。
像 GPT-3、GPT-4 这样的模型在海量文本上预训练,掌握了丰富的世界知识和推理能力。
研究者们很快意识到,可以把 LLM 当作通用「大脑」来赋予 Agent 智慧,而不必像过去那样为每个任务单独训练模型。
2022年,提出了链式思考(Chain-of-Thought, CoT)提示方法,让语言模型学会在输出最终答案前先生成逐步的思考过程。这使模型在复杂推理题上表现大幅提升 。
紧接着,研究者开始探索如何让 LLM 不仅会「想」也会「做」,于是出现了将推理和行动交织的架构(后面详述的 ReAct 等),赋予模型调用工具、与外界交互的能力 。
Autonomous Agent(自主代理)的概念在 2023 年引爆开源社区:比如 AutoGPT 和 BabyAGI 等项目火遍全网 。这些系统基于 GPT-4 等强大 LLM,围绕「让AI自主完成复杂任务」展开实验。
例如 AutoGPT 可以在给定一个高阶目标后,自己拆解子任务、通过互联网搜索信息、执行代码等,一系列操作循环,直到完成目标。
虽然早期的 AutoGPT 暂未表现出可靠实用的效果,但它标志着一种全新的 Agent 形态:完全由 LLM 驱动的自治智能体。
同时,LangChain 等开发框架崛起,为构建此类 LLM Agent 提供了便利工具库。
总的来说,LLM时代的 Agent 相比以往有几个显著特点:无需专项训练即可通用(依赖预训练知识),以自然语言为接口(决策过程和人类可读的计划融为一体),以及能够调用开放工具和知识源(如网络、数据库),从而显著拓展了 AI 解决现实任务的能力。
LLM agent
回到目前爆火的大语言模型(LLM) agent。业界逐渐探索出多种架构范式,其中有两种典型模式:一种是 ReAct (Reason + Act) 推理-行动交替模式,另一种是 Plan-and-Execute 先规划再执行的模式。
ReAct
ReAct 是 Reasoning and Acting 的缩写,顾名思义,它的核心思想是在 Agent 内部将「思考(Reason)」和「行动(Act)」交替进行 。这一范式最早由 2022 年谷歌大脑团队的论文「ReAct: Synergizing Reasoning and Acting in Language Models」提出 。
简单来说,ReAct 让 LLM 在解决任务时模拟人类的思考过程:想一步,做一步,再根据结果调整思考,再行动……如此循环,直到得出最终答案。
ReAct Agent 的典型工作流程如下:
Thought(思考):Agent(LLM)对当前问题或状态进行分析,在内部生成一段思考/推理。这一步类似人脑的自言自语,可能涉及分解问题、制定子目标、假设下一步需要的信息等。
例如面对一个复杂提问,Agent 可能产生内部思考:「要回答这个问题,我需要先查找相关统计数据」。
Action(行动):基于上一步的思考结论,Agent 决定采取一个具体行动 。在LLM Agent中,这通常体现为模型输出一个特殊格式的指令,如调用某个工具。举例:“Action: Search[关于X的统计数据]”。
这里的工具可以是预先注入 Agent 的函数,比如网络搜索、计算器、数据库查询等。ReAct 提示模板通常要求模型按照「Thought: … \n Action: … \n Action Input: …」格式输出 ,以明确指示要用的工具及输入 。
Observation(观察):一旦 Agent 发出了 Action 指令,外部环境(或我们预先设置的执行器)就会执行这个动作,并将结果返回给 Agent 。
比如当 Action 是搜索查询时,Observation 可能是一段搜索结果摘要。当 Action 是调用计算器,Observation 则是计算结果的值。这个观察结果相当于 Agent 在环境中获取到的新信息。
循环迭代:Agent 将 Observation 纳入自己的上下文,再次进入 Thought 阶段进行推理,总结新获取的信息,与之前的目标对比,决定下一步怎么做 。它可能修正原先思路或提出新的子任务。
如果任务还没完成就继续 Thought → Action → Observation 循环。如此反复,Agent 不断交替“思考-行动”,逐步推进任务。
Final Answer(最终答案):当 Agent 判断已经收集了足够信息或完成了目标,就会在最后一次 Thought 后输出最终答案而不是新行动指令 。这标志着 ReAct 流程的终止,Agent 向用户给出结果。
用一个具体例子说明:假设用户问题是“中国的人口是多少的两倍?”。一个 ReAct Agent 可能这样运作:
- 初始 Thought:“用户在问中国人口的两倍,这需要先查中国人口是多少”。
- Action:“Search[中国人口]”。
- Observation:“搜索结果显示:中国 2023 年人口约 14.1 亿”。
- Thought:“好的,中国人口约 14.1 亿,问题要两倍,那计算一下 2×14.1 亿”。
- Action:“Calculator[ 2 * 14.1 亿]”。(注:Agent可能将14.1亿转成数字再计算)
- Observation:“结果=28.2 亿”。
- Thought:“已经得到答案,可以作答”。
- Final Answer:“约 28.2 亿”。
ReAct 模式以其直观明了的循环成为LLM Agent的基础范式之一。
它通过交替的「思想」和「行动」赋予 Agent 如同人类一般的解题风格,能逐步推理、调用工具获取实时信息以降低幻觉,并通过思维外显便于调试,通用性强。
但它效率较低、缺乏全局规划且依赖工具,因而更适合交互性强、步骤较少、需要实时查询或轻量推理的任务场景。
Plan-and-Execute 模式:先计划后执行
当任务变得更加复杂、步骤繁多时,另一种「规划-执行」架构开始展现威力。
这种模式将 Agent 的流程明确分为两个阶段:先规划(Plan),再执行(Execute) 先让 Agent 想出一整套方案,然后按照方案逐步落实。
与 ReAct 不同,Plan-and-Execute 会强制 LLM 做全局思考。它通常涉及两个子 Agent 或子模块:一个 Planner(规划者)和一个Executor(执行者)。两者分工如下:
Planner:由一个 LLM 来承担,它的任务是分析目标,产出详细的执行计划。Planner 会接收用户的最终任务描述,然后以列表形式生成需要完成的子任务序列。
Planner 在这一步可以充分利用 LLM 的链式思考能力,将模糊的目标细化为可执行的步骤,并考虑步骤间的依赖、先后顺序等 。
Executor(s):执行者负责按照 Planner 给出的每个子任务,逐条执行 。Executor 本质上也是一个 Agent,可以针对不同子任务切换工具或 API,也可以调用一个内部 ReAct Agent 来完成。
Executor 会读取任务清单的某一条,比如「第1步:搜索 X 信息」,然后实际调用对应的工具完成它,将结果记录下来,再执行下一步。
Plan-and-Execute 模式的运行过程可以概括如下:
任务规划(Planning):接收用户请求后,首先调用 Planner (LLM) 来生成完整计划。Planner 输出的计划通常是有序列表形式的步骤1、步骤2… 。
例如用户让 Agent 「写一份关于某课题的调研报告」,Planner 可能输出:1. 搜集背景资料;2. 分析资料;3. 撰写报告初稿;4. 定稿并输出报告。
Planner 提示词通常会明示模型:「先理解问题并制定计划,然后我们再逐步执行」。这一阶段,LLM 会尽量细化步骤直到每一步可以由工具或简单操作完成。
任务执行(Execution):拿到 Planner 给出的任务清单后,进入执行环节。Executor 会逐步读取每条子任务并执行之 。执行时可能再次用到LLM,尤其当需要处理任务中的自然语言逻辑时。
例如 LangChain 实现中,每一步的执行其实可以调用一个内部 ReAct Agent 来完成 (因为子任务本身也许需要检索或计算,多步才能得出结果)。
但重要的是,Executor 聚焦于当前子任务的完成,不用操心全局流程。执行一个步骤后,把结果保存到共享状态中(相当于黑板或内存,记录目前有哪些信息、子任务完成情况) 。
计划调整(Replan,可选):理想情况下,按照初始计划顺利执行完所有步骤,就可以结束了。然而现实中,有时初始计划并不完美:可能遗漏了一些步骤,或者某步结果出乎意料、需要增加新的步骤。
Plan-and-Execute 架构因此通常允许一个反馈回路:当执行到一定阶段后,Agent 可以启动 Planner 进行重新规划 (Replan) 。此时 Planner 会参考当前已完成的任务状态,增补或修改后续计划。这个规划-执行循环可以进行多轮,直到 Agent 确信任务完成。
生成最终答案:所有必要的子任务都执行完毕,Agent 最后汇总状态中的信息,由 LLM 编写最终交付结果,并返回给用户 (比如完整的报告文本) 。
Plan-and-Execute 的核心优势在于结构化地解决复杂任务,但也带来额外成本。
相比 ReAct,它通过 Planner 和 Executor 分工来保证任务分解、执行更有条理,适合多步骤、长程、高精度和跨工具的任务。
但缺点在于:实现复杂、误差传递、上下文管理压力大、执行耗时。
因此,它更适合在复杂问题分解、长程规划、精度要求高或需要跨工具协调的场景下使用,而在简单任务或即时反应的场合,ReAct 往往更高效。
代码实战
零框架实现 ReAct
核心是两点:
- 通过 prompt 控制大模型的输出格式
- 解析大模型的输出,手动调用工具
直接 Cursor 生成代码就好:
忘了让 AI 用 ollama,再让它改一下:
核心就是一个不停的调用大模型的循环,期间拆解动作,执行动作,循环往复:
1 | def solve(self, question: str, verbose: bool = True) -> str: |
拆解一下:
一个循环的框架:
1 | def solve(self, question: str, verbose: bool = True) -> str: |
_get_system_prompt
返回提示词:
1 | def _get_system_prompt(self) -> str: |
其中的可用工具,需要提前实现:
1 | 可用工具: |
接着是循环里边,将用户问题和提示词传给大模型:
1 | def solve(self, question: str, verbose: bool = True) -> str: |
因为 prompt 中要求了大模型用 「Final Answer:」给出最终答案,因此循环终点就是判断是否有 「Final Answer」。
接着再解析 大模型返回的Action ,来手动调用提前实现好的工具:
1 | def solve(self, question: str, verbose: bool = True) -> str: |
其中 _parse_action 就是解析 prompt 中说的 用 "Action:" 开始行动,格式为 Action: tool_name(parameters)
1 | def _parse_action(self, text: str) -> Optional[tuple]: |
先正则解析出 Action 的内容 r"Action:\s*(\w+)\((.*?)\)"
,接着拿到 tool_name(工具名)和 params_str(入参)返回。
拿到之后去调用函数:
1 | action_result = self._parse_action(assistant_message) |
拿到对应的函数,然后将参数传入即可。
最后将工具返回的结果追加到对话列表中下一次循环即可:
1 | observation = self._execute_tool(tool_name, params) |
看下运行效果:
直接调用一次 Action: calculator(9 * 8 - 2)
调用两次 Action,web_search("中国当前人口数")
和 calculator(1400000000 * 2)
。
LangChain 实现 Plan-and-Execute
用 LangChain 的话,我们只需要提供 Tools,提示词、agent、记忆管理全部内置了,代码会简单很多:
1 | from langchain_community.llms import Ollama |
调用 load_agent_executor 就可以得到一个 ReAct 的 Agent,调用 load_chat_planner 就得到了可以 planner 的 Agent。
问一个相对复杂的问题 「调查气候变化对北极熊种群的影响,并给出一份总结报告。」,最开始是生成了步骤,然后一步一步得出了结论:
1 | Entering new PlanAndExecute chain... |
总
大模型是一个聪明的大脑,但它不会主动做什么,需要我们通过 prompt 指挥,然后它需要干什么我们帮它去做,循环往复,结合起来就变成了一个 agent。
Prompt 控制 / 模块化设计、规划策略、工具调度 / 使用、记忆机制、控制流与反馈、Agent 协同架构、以及工具库可扩展性 / 安全性,这些共同决定了一个 agent 表现的好坏,也诞生了现在各种各样的 agent 应用。