欢迎来到智能体的世界!在人工智能浪潮席卷全球的今天,智能体(Agent)已成为驱动技术变革与应用创新的核心概念之一。无论你的志向是成为AI领域的研究者、工程师,还是希望深刻理解技术前沿的观察者,掌握智能体的本质,都将是你知识体系中不可或缺的一环。
因此,在本章,让我们回到原点,一起探讨几个问题:智能体是什么?它有哪些主要的类型?它又是如何与我们所处的世界进行交互的?通过这些讨论,希望能为你未来的学习和探索打下坚实的基础。
在探索任何一个复杂概念时,我们最好从一个简洁的定义开始。在人工智能领域,智能体被定义为任何能够通过传感器(Sensors)感知其所处环境(Environment),并自主地通过执行器(Actuators)采取行动(Action)以达成特定目标的实体。
这个定义包含了智能体存在的四个基本要素。环境是智能体所处的外部世界。对于自动驾驶汽车,环境是动态变化的道路交通;对于一个交易算法,环境则是瞬息万变的金融市场。智能体并非与环境隔离,它通过其传感器持续地感知环境状态。摄像头、麦克风、雷达或各类应用程序编程接口(Application Programming Interface, API)返回的数据流,都是其感知能力的延伸。
获取信息后,智能体需要采取行动来对环境施加影响,它通过执行器来改变环境的状态。,执行器可以是物理设备(如机械臂、方向盘)或虚拟工具(如执行一段代码、调用一个服务)。
然而,真正赋予智能体“智能”的,是其自主性(Autonomy)。智能体并非只是被动响应外部刺激或严格执行预设指令的程序,它能够基于其感知和内部状态进行独立决策,以达成其设计目标。这种从感知到行动的闭环,构成了所有智能体行为的基础,如图1.1所示。
图 1.1 智能体与环境的基本交互循环
在当前大语言模型(Large Language Model, LLM)的热潮出现之前,人工智能的先驱们已经对“智能体”这一概念进行了数十年的探索与构建。这些如今我们称之为“传统智能体”的范式,并非单一的静态概念,而是经历了一条从简单到复杂、从被动反应到主动学习的清晰演进路线。
这个演进的起点,是那些结构最简单的反射智能体(Simple Reflex Agent)。它们的决策核心由工程师明确设计的“条件-动作”规则构成,如图1.2所示。经典的自动恒温器便是如此:若传感器感知的室温高于设定值,则启动制冷系统。
这种智能体完全依赖于当前的感知输入,不具备记忆或预测能力。它像一种数字化的本能,可靠且高效,但也因此无法应对需要理解上下文的复杂任务。它的局限性引出了一个关键问题:如果环境的当前状态不足以作为决策的全部依据,智能体该怎么办?
图 1.2 简单反射智能体的决策逻辑示意图
为了回答这个问题,研究者们引入了“状态”的概念,发展出基于模型的反射智能体(Model-Based Reflex Agent)。这类智能体拥有一个内部的世界模型(World Model),用于追踪和理解环境中那些无法被直接感知的方面。它试图回答:“世界现在是什么样子的?”。例如,一辆在隧道中行驶的自动驾驶汽车,即便摄像头暂时无法感知到前方的车辆,它的内部模型依然会维持对那辆车存在、速度和预估位置的判断。这个内部模型让智能体拥有了初级的“记忆”,使其决策不再仅仅依赖于瞬时感知,而是基于一个更连贯、更完整的世界状态理解。
然而,仅仅理解世界还不够,智能体需要有明确的目标。这促进了基于目标的智能体(Goal-Based Agent)的发展。与前两者不同,它的行为不再是被动地对环境做出反应,而是主动地、有预见性地选择能够导向某个特定未来状态的行动。这类智能体需要回答的问题是:“我应该做什么才能达成目标?”。经典的例子是GPS导航系统:你的目标是到达公司,智能体会基于地图数据(世界模型),通过搜索算法(如A*算法)来规划(Planning)出一条最优路径。这类智能体的核心能力体现在了对未来的考量与规划上。
更进一步,现实世界的目标往往不是单一的。我们不仅希望到达公司,还希望时间最短、路程最省油并且避开拥堵。当多个目标需要权衡时,基于效用的智能体(Utility-Based Agent)便随之出现。它为每一个可能的世界状态都赋予一个效用值,这个值代表了满意度的高低。智能体的核心目标不再是简单地达成某个特定状态,而是最大化期望效用。它需要回答一个更复杂的问题:“哪种行为能为我带来最满意的结果?”。这种架构让智能体学会在相互冲突的目标之间进行权衡,使其决策更接近人类的理性选择。
至此,我们讨论的智能体虽然功能日益复杂,但其核心决策逻辑,无论是规则、模型还是效用函数,依然依赖于人类设计师的先验知识。如果智能体能不依赖预设,而是通过与环境的互动自主学习呢?
这便是学习型智能体(Learning Agent)的核心思想,而强化学习(Reinforcement Learning, RL)是实现这一思想最具代表性的路径。一个学习型智能体包含一个性能元件(即我们前面讨论的各类智能体)和一个学习元件。学习元件通过观察性能元件在环境中的行动所带来的结果来不断修正性能元件的决策策略。
想象一个学习下棋的AI。它开始时可能只是随机落子,当它最终赢下一局时,系统会给予它一个正向的奖励。通过大量的自我对弈,学习元件会逐渐发现哪些棋路更有可能导向最终的胜利。AlphaGo是这一理念的一个里程碑式的成就。它在围棋这一复杂博弈中,通过强化学习发现了许多超越人类既有知识的有效策略。
从简单的恒温器,到拥有内部模型的汽车,再到能够规划路线的导航、懂得权衡利弊的决策者,最终到可以通过经验自我进化的学习者。这条演进之路,展示了传统人工智能在构建机器智能的道路上所经历的发展脉络。它们为我们今天理解更前沿的智能体范式,打下了坚实而必要的基础。
以GPT(Generative Pre-trained Transformer)为代表的大语言模型的出现,正在显著改变智能体的构建方法与能力边界。由大语言模型驱动的智能体,其核心决策机制与传统智能体存在本质区别,从而赋予了其一系列全新的特性。
这种转变,可以从两者在核心引擎、知识来源、交互方式等多个维度的对比中清晰地看出,如表1.1所示。简而言之,传统智能体的能力源于工程师的显式编程与知识构建,其行为模式是确定且有边界的;而LLM智能体则通过在海量数据上的预训练,获得了隐式的世界模型与强大的涌现能力,使其能够以更灵活、更通用的方式应对复杂任务。
表 1.1 传统智能体与LLM驱动智能体的核心对比
这种差异使得LLM智能体可以直接处理高层级、模糊且充满上下文信息的自然语言指令。它不需要用户将需求拆解成机器可以理解的结构化输入,只需要输入人类的自然语言即可。
以“策划一场团队研讨会”为例,LLM智能体的一种工作方式是:
总而言之,我们正从开发专用自动化工具转向构建能自主解决问题的系统。核心不再是编写代码,而是引导一个通用的“大脑”去规划、行动和学习。
继上文回顾智能体的演进后,本节将从三个互补的维度对智能体进行分类。
(1)基于内部决策架构的分类
第一种分类维度是依据智能体内部决策架构的复杂程度,这个视角在《Artificial Intelligence: A Modern Approach》中系统性地提出[1]。正如 1.1.1 节所述,传统智能体的演进路径本身就构成了最经典的分类阶梯,它涵盖了从简单的反应式智能体,到引入内部模型的模型式智能体,再到更具前瞻性的基于目标和基于效用的智能体。此外,学习能力则是一种可赋予上述所有类型的元能力,使其能通过经验自我改进。
(2)基于时间与反应性的分类
除了内部架构的复杂性,还可以从智能体处理决策的时间维度进行分类。这个视角关注智能体是在接收到信息后立即行动,还是会经过深思熟虑的规划再行动。这揭示了智能体设计中一个核心权衡:追求速度的反应性(Reactivity)与追求最优解的规划性(Deliberation)之间的平衡,如图1.3所示。
图 1.3 智能体决策时间与质量关系图
这类智能体对环境刺激做出近乎即时的响应,决策延迟极低。它们通常遵循从感知到行动的直接映射,不进行或只进行极少的未来规划。上文的简单反应式和基于模型的智能体都属于此类别。
其核心优势在于速度快、计算开销低,这在需要快速决策的动态环境中至关重要。例如,车辆的安全气囊系统必须在碰撞发生的毫秒内做出反应,任何延迟都可能导致严重后果;同样,高频交易机器人也必须依赖反应式决策来捕捉稍纵即逝的市场机会。然而,这种速度的代价是“短视”,由于缺乏长远规划,反应式智能体容易陷入局部最优,难以完成需要多步骤协调的复杂任务。
与反应式智能体相对,规划式(或称审议式)智能体在行动前会进行复杂的思考和规划。它们不会立即对感知做出反应,而是会先利用其内部的世界模型,系统地探索未来的各种可能性,评估不同行动序列的后果,以期找到一条能够达成目标的最佳路径 。基于目标和基于效用的智能体是典型的规划式智能体。
可以将其决策过程类比为一位棋手。他不会只看眼前的一步,而是会预想对手可能的应对,并规划出后续几步甚至十几步的棋路。这种深思熟虑的能力使其能够处理复杂的、需要长远眼光的任务,例如制定一份商业计划或规划一次长途旅行。它们的优势在于决策的战略性和远见。然而,这种优势的另一面是高昂的时间和计算成本。在瞬息万变的环境中,当规划式智能体还在深思熟虑时,采取行动的最佳时机可能早已过去。
现实世界的复杂任务,往往既需要即时反应,也需要长远规划。例如,一个火星探测车既要能快速躲避滚落的岩石(反应性),又要能规划抵达下一个考察点的长期路径(规划性)。因此,混合式智能体应运而生,它旨在结合两者的优点,实现反应与规划的平衡。
一种经典的混合架构是分层设计:底层是一个快速的反应模块,处理紧急情况和基本动作;高层则是一个审慎的规划模块,负责制定长远目标。而现代的LLM智能体,则展现了一种更灵活的混合模式。它们通常在一个“思考-行动-观察”的循环中运作,巧妙地将两种模式融为一体:
通过这种方式,智能体将一个需要长远规划的宏大任务,分解为一系列“规划-反应”的微循环。这使其既能灵活应对环境的即时变化,又能通过连贯的步骤,最终完成复杂的长期目标。
(3)基于知识表示的分类
这是一个更根本的分类维度,它探究智能体用以决策的知识,究竟是以何种形式存于其“思想”之中。这个问题是人工智能领域一场持续半个多世纪的辩论核心,并塑造了两种截然不同的AI文化。
符号主义,常被称为传统人工智能,其核心信念是:智能源于对符号的逻辑操作。这里的符号是人类可读的实体(如词语、概念),操作则遵循严格的逻辑规则,如图1.4左侧所示。这好比一位一丝不苟的图书管理员,将世界知识整理为清晰的规则库和知识图谱。
其主要优势在于透明和可解释。由于推理步骤明确,其决策过程可以被完整追溯,这在金融、医疗等高风险领域至关重要。然而,其“阿喀琉斯之踵”在于脆弱性:它依赖于一个完备的规则体系,但在充满模糊和例外的现实世界中,任何未被覆盖的新情况都可能导致系统失灵,这就是所谓的“知识获取瓶颈”。
亚符号主义,或称连接主义,则提供了一幅截然不同的图景。在这里,知识并非显式的规则,而是内隐地分布在一个由大量神经元组成的复杂网络中,是从海量数据中学习到的统计模式。神经网络和深度学习是其代表。
如图1.4中间所示,如果说符号主义AI是图书管理员,那么亚符号主义AI就像一个牙牙学语的孩童 。他不是通过学习“猫有四条腿、毛茸茸、会喵喵叫”这样的规则来认识猫的,而是在看过成千上万张猫的图片后,大脑中的神经网络能辨识出“猫”这个概念的视觉模式 。这种方法的强大之处在于其模式识别能力和对噪声数据的鲁棒性 。它能够轻松处理图像、声音等非结构化数据,这在符号主义AI看来是极其困难的任务。
然而,这种强大的直觉能力也伴随着不透明性。亚符号主义系统通常被视为一个黑箱(Black Box)。它能以惊人的准确率识别出图片中的猫,但你若问它“为什么你认为这是猫?”,它很可能无法给出一个合乎逻辑的解释。此外,它在纯粹的逻辑推理任务上表现不佳,有时会产生看似合理却事实错误的幻觉 。
长久以来,符号主义和亚符号主义这两大阵营如同两条平行线,各自发展。为克服上述两种范式的局限,一种“大和解”的思想开始兴起,这就是神经符号主义AI,也称神经符号混合主义。它的目标,是融合两大范式的优点,创造出一个既能像神经网络一样从数据中学习,又能像符号系统一样进行逻辑推理的混合智能体。它试图弥合感知与认知、直觉与理性之间的鸿沟。诺贝尔经济学奖得主丹尼尔·卡尼曼(Daniel Kahneman)在其著作《思考,快与慢》(Thinking, Fast and Slow)中提出的双系统理论,为我们理解神经符号主义提供了一个绝佳的类比[2],如图1.4所示:
图 1.4 符号主义、亚符号主义与神经符号混合主义的知识表示范式
人类的智能,正源于这两个系统的协同工作。同样,一个真正鲁棒的AI,也需要兼具二者之长。大语言模型驱动的智能体是神经符号主义的一个极佳实践范例。其内核是一个巨大的神经网络,使其具备模式识别和语言生成能力。然而,当它工作时,它会生成一系列结构化的中间步骤,如思想、计划或API调用,这些都是明确的、可操作的符号。通过这种方式,它实现了感知与认知、直觉与理性的初步融合。
前一节我们讲解了智能体的不同类型。然而,仅有内部决策逻辑不足以实现目标,智能体必须通过与外部环境的持续互动来执行任务。其运作的核心是一个持续的智能体循环(Agent Loop),它将复杂的任务分解为一系列标准的交互步骤,通常包括:
这个循环构成了所有LLM智能体运作的基本模式,如图1.5所示。1.2.1节将从环境的构成入手,进一步探讨该交互机制的属性及其对智能体设计的影响。
图 1.5 智能体与环境交互的基本循环
要理解智能体的运作,我们必须先理解它所处的任务环境。在人工智能领域,通常使用 PEAS 模型来精确描述一个任务环境,即分析其性能度量 (Performance)、环境 (Environment)、执行器 (Actuators) 和 传感器 (Sensors)。以一个旅行规划智能体为例,下表1.2展示了如何运用PEAS模型对其任务环境进行规约。
表 1.2 旅行规划智能体的PEAS描述
在实践中,LLM智能体所处的数字环境展现出若干复杂特性,这些特性直接影响着智能体的设计。
首先,环境通常是部分可观察的。例如,一个购物智能体无法一次性看到所有商品信息,只能通过逐页访问来逐步构建对环境的认知,这就要求智能体必须具备记忆和状态追踪能力。
其次,行动的结果也并非总是确定的。根据结果的可预测性,环境可分为确定性和随机性。当智能体执行本地代码进行数学计算时,结果是确定的;但当它调用一个实时变化的搜索引擎API时,结果便带有随机性,这就要求智能体必须具备容错和处理不确定性的能力。
此外,环境中还可能存在其他行动者,从而形成多智能体** (Multi-agent) 环境。在这种情况下,智能体之间需要协作或竞争,一个智能体的行动会成为另一个智能体环境中的变量,这对智能体的沟通和协调能力提出了更高要求。
最后,几乎所有任务都发生在序贯且动态的环境中。“序贯”意味着当前动作会影响未来;而“动态”则意味着环境自身可能在智能体决策时发生变化。这就要求智能体的“感知-思考-行动-观察”循环必须能够快速、灵活地适应持续变化的世界。
LLM智能体与环境的互动需要一套明确的交互协议(Interaction Protocol)来规范信息的格式与流程。该协议的核心,体现在对智能体行动的结构化定义上。
在诸如ReAct(Reasoning and Acting)等现代框架中,智能体的每一次输出通常是一段特殊格式的文本。其中不仅包含了要执行的行动本身,还明确展示了该行动之前的思考过程。
这个“思考”部分是智能体内部决策的快照,它阐述了智能体如何分解任务、如何根据上一步的观察结果进行自我反思,以及最终决定下一步具体行动的策略规划。例如,一个正在规划旅行的智能体可能会生成如下格式化文本:
Thought: 用户想知道北京的天气。我需要调用天气查询工具。
Action: get_weather("北京")
这里的Action部分就是智能体对其执行器的指令。一个外部的解析器会捕捉到这个指令,并真正地去执行相应的get_weather函数。智能体的感知,即其传感
器的输入,则是上述行动执行后的结果。当外部工具执行完get_weather("北京")后,它可能得到一个包含温度、湿度、风力等信息的JSON对象。这个原始数据对于LLM来说过于冗长和非自然。因此,传感器的角色需要将这个JSON对象处理并封装成一段清晰、简洁的自然语言文本,例如:
Observation: 北京当前天气为晴,气温25摄氏度,微风。
这段Observation文本会被拼接在下一轮提供给LLM的输入中,成为其后续进行新一轮思考和行动的依据。
通过这个由Thought, Action, Observation构成的循环,LLM智能体得以将内部的语言推理能力,与外部环境的真实信息和工具操作能力结合起来,从而在一个明确的接口上,完成对复杂任务的逐步拆解和执行。因此,设计一个清晰、稳定且功能恰当的工具接口,是实现有效LLM智能体行为的工程学前提。
标准化接口组件定义
Perception-Thought-Action-Observation循环是通过一套标准化的接口组件来实现的。为确保系统的可扩展性与可维护性,这些接口遵循单一职责原则,分别对应循环中的一个关键环节。下面我们将对这四个核心组件进行定义。
接口1:感知器
感知器负责处理输入信息,将原始数据转化为智能体可理解的格式:
class PerceptionInterface:
"""感知器接口:处理输入信息,理解用户意图"""
def process_user_input(self, user_input: str, context: list) -> dict:
"""
处理用户输入,提取关键信息
参数: user_input - 用户原始输入, context - 历史上下文
返回: {"intent": "意图", "entities": "实体", "processed_text": "处理后文本"}
"""
pass
def update_context(self, new_info: str) -> None:
"""更新上下文信息"""
pass
```
接口2:思考器
思考器基于感知结果进行推理和规划:
class ThinkingInterface:
"""思考器接口:基于感知结果进行推理和规划"""
def analyze_situation(self, perception_result: dict) -> str:
"""
分析当前情况
参数: perception_result - 感知器的处理结果
返回: 情况分析文本
"""
pass
def generate_plan(self, analysis: str, available_tools: list) -> dict:
"""
生成执行计划
返回: {"thought": "思考过程", "action": "计划行动", "tool": "选择工具", "params": "参数"}
"""
pass
接口3:执行器
执行器负责将计划转化为具体的工具调用:
class ExecutionInterface:
"""执行器接口:执行具体的工具调用"""
def execute_tool(self, tool_name: str, parameters: dict) -> dict:
"""
执行指定工具
返回: {"success": bool, "data": "执行结果", "error": "错误信息(如有)"}
"""
pass
def register_tool(self, name: str, tool_function) -> None:
"""注册新工具"""
pass
接口4:观察器
观察器处理执行结果,生成反馈信息:
class ObservationInterface:
"""观察器接口:处理执行结果,生成观察反馈"""
def process_result(self, execution_result: dict, original_plan: dict) -> dict:
"""
处理执行结果
返回: {"observation": "观察文本", "success": bool, "next_action": "下一步建议"}
"""
pass
def format_response(self, observation: dict) -> str:
"""格式化最终用户回复"""
pass
统一的智能体接口
这四个组件通过一个统一的智能体接口进行协调:
class AgentInterface:
"""智能体统一接口:协调四个核心组件"""
def __init__(self):
self.perception = None # 感知器实例
self.thinking = None # 思考器实例
self.execution = None # 执行器实例
self.observation = None # 观察器实例
def process_request(self, user_input: str) -> str:
"""
处理用户请求的完整流程
返回: 最终回复给用户的文本
"""
# 1. 感知 -> 2. 思考 -> 3. 执行 -> 4. 观察
pass
这些接口定义为后续的具体实现提供了规范。每个接口都有明确的输入输出格式,确保了组件间的解耦和系统的可扩展性。在接下来的1.2.3节中,我们将逐步实现这些接口(分别为PerceptionImpl、ThinkingImpl、ExecutionImpl、ObservationImpl),并最终组装成一个完整的智能体的基本示例。
智能体的行动循环是其自主性的核心体现。它是一个从信息输入(感知),经过内部状态转换(思考),到行为输出(行动),再到结果反馈(观察)的完整闭环。这个持续运行的流程,确保了智能体能够响应外部世界,并根据结果动态调整其行为。
这里有必要澄清一个关键点:通常被描述为“思考-行动-观察”的循环,为何在这里以“感知”作为第一步。可以这样理解:思考-行动-观察是智能体内部的核心认知循环。然而,这个循环必须由一个外部刺激来启动。感知与理解阶段正是处理这种外部刺激的入口,它负责将外部数据转化为智能体内部可以处理的格式,从而触发核心认知循环的第一次迭代。
接下来,我们将把这个循环分解为四个逻辑阶段,并逐一探讨实现这些阶段所需的核心组件。
第一步:感知与理解
感知是整个信息处理流程的起点,是智能体接收外部输入的接口。其核心职责是将来自外部世界的原始、非结构化数据(如用户的自然语言查询、API的JSON响应等),转换为后续模块(尤其是思考模块)能够处理的结构化内部表述 (Internal Representation)。
此阶段的输出质量直接决定了智能体后续所有决策的上限。一个精确的感知模块能够准确地捕捉意图、提取关键参数,为高质量的规划奠定基础。
在 PerceptionImpl 类的实现中,process_user_input 方法承担了此项职能。它接收原始输入字符串,通过意图识别和实体提取等技术,将其转换为一个包含 intent 和 entities 键的字典。这个过程是自然语言理解的一个简化示例。
class PerceptionImpl:
"""感知器接口的简化实现,负责将外部输入结构化"""
def __init__(self):
self.context = [] # 存储历史交互信息
def process_user_input(self, user_input: str, context: list) -> dict:
"""处理用户输入,将其从自然语言转化为结构化的意图和实体。"""
# 模拟意图识别
intent = "unknown"
entities = {}
if "天气" in user_input:
intent = "weather_query"
# 模拟实体提取
if "北京" in user_input:
entities["city"] = "北京"
elif "上海" in user_input:
entities["city"] = "上海"
else:
entities["city"] = "未知城市"
return {
"intent": intent,
"entities": entities,
"processed_text": f"用户意图被解析为:{intent},相关实体:{entities}",
"original_input": user_input
}
def update_context(self, new_info: str) -> None:
"""更新上下文信息"""
self.context.append(new_info)
# 维持上下文队列的固定长度
if len(self.context) > 5:
self.context.pop(0)
第二步:思考与规划
思考与规划模块是智能体的决策单元。它接收来自感知模块的结构化信息,基于当前状态和可用资源(如工具集)进行推理、分析、任务分解,并最终制定出具体的行动计划。
此阶段的产出是一个明确的行动指令,它通常包含两部分:智能体进行决策的思考过程和具体的执行方案。Thought 提供了决策的可解释性,记录了智能体“为什么”这么做。Plan 则清晰地定义了“做什么”(例如,调用哪个工具)和“怎么做”(例如,需要哪些参数)。
ThinkingImpl 类演示了这一核心功能。analyze_situation 方法根据感知结果生成分析,即Thought。generate_plan 方法则基于该分析和可用的工具列表,生成一个包含目标工具和所需参数的结构化指令。
class ThinkingImpl:
"""思考器接口的简化实现,智能体的核心决策单元"""
def analyze_situation(self, perception_result: dict) -> str:
"""分析感知结果,形成内在的推理链(Thought)。"""
intent = perception_result["intent"]
entities = perception_result["entities"]
if intent == "weather_query":
city = entities.get("city", "未知城市")
return f"识别到用户意图为查询天气,目标城市为{city}。需要调用天气查询工具。"
else:
return "未能识别明确的用户意图,无法制定下一步计划。"
def generate_plan(self, analysis: str, available_tools: list) -> dict:
"""基于推理分析,生成结构化的执行计划(Action)。"""
if "天气查询工具" in analysis and "get_weather" in available_tools:
# 此处为简化处理,实际场景中需要更鲁棒的参数提取逻辑
city = "北京"
if "上海" in analysis:
city = "上海"
return {
"thought": analysis,
"action": "invoke_tool",
"tool": "get_weather",
"params": {"city": city}
}
else:
return {
"thought": analysis,
"action": "no_action",
"tool": None,
"params": {}
}
第三步:执行与操作
执行模块是连接智能体内部决策与外部世界的桥梁,是行动指令的实现层。它负责解析思考模块生成的行动计划,并调用相应的工具(如函数、API、数据库查询等)来完成具体任务。该模块使得智能体能够对外部环境产生实际影响或从中获取信息。执行结果的成功与否、返回的数据或错误信息,将成为下一阶段“观察”模块的关键输入。
ExecutionImpl 类扮演了执行器的角色。它通过一个工具注册表 (self.tools) 维护所有可用的工具。execute_tool 方法则充当调度器,根据指定的工具名称和参数,调用相应的函数,并以标准化的格式返回执行结果。
class ExecutionImpl:
"""执行器接口的简化实现,负责调用工具并与外部环境交互"""
def __init__(self):
self.tools = {}
# 注册一个默认工具
self.register_tool("get_weather", self._get_weather_tool)
def execute_tool(self, tool_name: str, parameters: dict) -> dict:
"""执行指定的工具,并返回标准化的结果对象。"""
if tool_name not in self.tools:
return {
"success": False,
"data": None,
"error": f"工具 '{tool_name}' 未注册。"
}
try:
result = self.tools[tool_name](**parameters)
return {
"success": True,
"data": result,
"error": None
}
except Exception as e:
return {
"success": False,
"data": None,
"error": f"执行工具 '{tool_name}' 时发生异常: {e}"
}
def register_tool(self, name: str, tool_function) -> None:
"""注册一个新工具,使其可被执行器调用。"""
self.tools[name] = tool_function
def _get_weather_tool(self, city: str) -> str:
"""一个模拟的天气查询工具API。"""
weather_data = {
"北京": "天气晴朗,温度25摄氏度,风力2级。",
"上海": "多云转阴,温度22摄氏度,风力3级。"
}
return weather_data.get(city, f"未能查询到 {city} 的天气信息。")
第四步:观察与学习
行动的完成并不意味着流程的结束,而是形成反馈闭环的关键一步。观察模块负责接收和评估执行阶段的输出,并将其转化为智能体内部可以理解的观察结果。
此阶段的核心功能是:
这个观察结果将作为新的信息输入,反馈给认知循环的下一个迭代,从而使智能体能够根据其行为的实际效果来调整后续策略。
在 ObservationImpl 的实现中,process_result 方法负责将执行结果转化为结构化的观察结论,而 format_response 则用于将最终结论格式化为面向用户的输出。
class ObservationImpl:
"""观察器接口的简化实现,负责评估执行结果并形成反馈"""
def process_result(self, execution_result: dict, original_plan: dict) -> dict:
"""处理执行结果,生成结构化的观察结论。"""
if execution_result["success"]:
observation_text = f"动作 '{original_plan['action']}' 执行成功,获取数据:{execution_result['data']}"
return {
"observation": observation_text,
"success": True,
"next_action": "respond_to_user"
}
else:
observation_text = f"动作 '{original_plan['action']}' 执行失败,错误信息:{execution_result['error']}"
return {
"observation": observation_text,
"success": False,
"next_action": "error_handling"
}
def format_response(self, observation: dict) -> str:
"""根据最终的观察结果,格式化对用户的回复。"""
if observation["success"]:
# 从观察文本中提取核心数据进行回复
return f"根据查询,{observation['observation'].split(':')[1]}"
else:
return f"处理请求时出错:{observation['observation'].split(':')[1]}"
完整的智能体行动循环演示
最后,我们将上述四个独立的模块化组件进行集成,构建一个完整的 AgentLoopDemo。这个类展示了四个阶段如何被依次调用和协同工作,形成一个从接收原始输入到生成最终响应的、端到端的处理流水线,具体流程如图1.6所示。
图 1.6 智能体行动循环的实现流程
每一次对 process_request 方法的调用,都代表了一次完整的“感知-思考-执行-观察”循环的执行过程。
class AgentLoopDemo:
"""智能体行动循环演示:集成四个核心组件的完整示例"""
def __init__(self):
self.perception = PerceptionImpl()
self.thinking = ThinkingImpl()
self.execution = ExecutionImpl()
self.observation = ObservationImpl()
def process_request(self, user_input: str) -> str:
"""处理用户请求的完整流程"""
print(f"\n[Input] 用户请求: {user_input}")
# 阶段 1: 感知与理解 (Perception)
perception_result = self.perception.process_user_input(user_input, self.perception.context)
print(f"[Perception] 解析结果: {perception_result['processed_text']}")
# 阶段 2: 思考与规划 (Thinking)
analysis = self.thinking.analyze_situation(perception_result)
available_tools = list(self.execution.tools.keys())
plan = self.thinking.generate_plan(analysis, available_tools)
print(f"[Thinking] 推理过程: {plan['thought']}")
print(f"[Planning] 行动计划: {plan['action']} -> Tool: {plan['tool']}, Params: {plan['params']}")
# 阶段 3: 执行与操作 (Execution)
if plan["tool"]:
execution_result = self.execution.execute_tool(plan["tool"], plan["params"])
print(f"[Execution] 执行结果: {'Success' if execution_result['success'] else 'Failure'}, Details: {execution_result['data'] or execution_result['error']}")
else:
execution_result = {"success": False, "data": None, "error": "无可用行动计划"}
print(f"[Execution] 执行结果: {execution_result['error']}")
# 阶段 4: 观察与学习 (Observation)
observation_result = self.observation.process_result(execution_result, plan)
print(f"[Observation] 观察结论: {observation_result['observation']}")
# 生成最终响应
final_response = self.observation.format_response(observation_result)
print(f"[Output] 最终回答: {final_response}")
# 更新上下文,用于潜在的后续交互
self.perception.update_context(f"User: '{user_input}', Agent: '{final_response}'")
return final_response
# 运行示例
if __name__ == "__main__":
agent = AgentLoopDemo()
test_cases = [
"我想知道北京今天的天气",
"查询上海的天气情况",
"今天心情不错" # 无法处理的请求
]
for test_input in test_cases:
result = agent.process_request(test_input)
print("-" * 60)
# 运行效果演示
当我们运行这个完整示例时,可以看到清晰的四步处理流程:
>>>
[Input] 用户请求: 我想知道北京今天的天气
[Perception] 解析结果: 用户意图被解析为:weather_query,相关实体:{'city': '北京'}
[Thinking] 推理过程: 识别到用户意图为查询天气,目标城市为北京。需要调用天气查询工具。
[Planning] 行动计划: invoke_tool -> Tool: get_weather, Params: {'city': '北京'}
[Execution] 执行结果: Success, Details: 天气晴朗,温度25摄氏度,风力2级。
[Observation] 观察结论: 动作 'invoke_tool' 执行成功,获取数据:天气晴朗,温度25摄氏度,风力2级。
[Output] 最终回答: 根据查询,天气晴朗,温度25摄氏度,风力2级。
------------------------------------------------------------
[Input] 用户请求: 查询上海的天气情况
[Perception] 解析结果: 用户意图被解析为:weather_query,相关实体:{'city': '上海'}
[Thinking] 推理过程: 识别到用户意图为查询天气,目标城市为上海。需要调用天气查询工具。
[Planning] 行动计划: invoke_tool -> Tool: get_weather, Params: {'city': '上海'}
[Execution] 执行结果: Success, Details: 多云转阴,温度22摄氏度,风力3级。
[Observation] 观察结论: 动作 'invoke_tool' 执行成功,获取数据:多云转阴,温度22摄氏度,风力3级。
[Output] 最终回答: 根据查询,多云转阴,温度22摄氏度,风力3级。
------------------------------------------------------------
[Input] 用户请求: 今天心情不错
[Perception] 解析结果: 用户意图被解析为:unknown,相关实体:{}
[Thinking] 推理过程: 未能识别明确的用户意图,无法制定下一步计划。
[Planning] 行动计划: no_action -> Tool: None, Params: {}
[Execution] 执行结果: 无可用行动计划
[Observation] 观察结论: 动作 'no_action' 执行失败,错误信息:无可用行动计划
[Output] 最终回答: 处理请求时出错:无可用行动计划
------------------------------------------------------------
在前述的 1.2.1 至 1.2.3 小节中,我们已经为智能体与环境的交互补充了理论基础:从任务环境的宏观介绍,到交互协议与接口的具体定义,再到一个基础智能体行动循环的实现。为了具体地了解智能体是如何在不同特性的环境中进行感知、规划与行动的,在本案例中,我们将构建一个实际的网络信息检索智能体。
准备工作:在开始编码之前,我们需要先安装几个Python库。
ddgs: 这是一个用于调用DuckDuckGo搜索引擎的客户端库,我们可以无需使用API来进行基本的搜索网页功能实现。openai: openai 提供了统一的 API 接口格式,简化了我们与多种大语言模型(LLM)交互的流程,可以选择自己所拥有的API进行适配。requests: 这是Python中处理网络请求的基础库,openai库依赖它来发送和接收数据。请打开你的终端(命令行工具),然后运行下面的命令来安装它们:
pip install ddgs openai requests
智能体需要一个核心组件来理解和生成语言,这个角色由LLM承担。考虑到LLM服务的多样性,为了保证代码的模块化与可扩展性,我们首先创建一个统一的客户端(Client)来封装与LLM的交互。首先,我们定义一个标准接口。在面向对象编程中,这通常通过抽象基类(Abstract Base Class)来实现。该基类定义了一个所有LLM客户端都必须遵守的规范,即它们都必须实现一个名为 generate 的方法。这种设计模式确保了主逻辑的稳定性:无论未来底层实现如何变更,主程序都依赖于统一的接口进行调用。
class BaseLLM:
"""
定义所有LLM客户端都应遵循的基本接口。
这是一个抽象基类,用于确保所有子类都有一个 generate 方法。
"""
def generate(self, prompt: str) -> str:
"""根据输入的提示生成文本。"""
raise NotImplementedError("子类必须实现这个方法")
接下来,我们继承 BaseLLM 接口,创建一个具体的、可以和任何兼容OpenAI接口的服务进行通信的客户端。
这个类主要负责以下三项任务:
init): 实例化时,接收API密钥、服务地址和模型名称作为参数,并使用这些信息配置底层的 openai 客户端。generate): 封装了调用LLM的核心逻辑。它接收一个提示(prompt),构建符合API规范的消息结构,发送请求,然后解析并返回模型生成的文本。错误处理: 使用 try...except 结构来捕获执行过程中可能出现的网络或API异常,以增强程序的鲁棒性。
from openai import OpenAI
class OpenAICompatibleClient(BaseLLM):
"""
用于调用任何兼容OpenAI接口的服务的具体实现类。
"""
def __init__(self, api_key: str, base_url: str, model: str):
# 初始化 OpenAI 客户端,指向目标服务地址
self.client = OpenAI(api_key=api_key, base_url=base_url)
self.model = model
def generate(self, prompt: str) -> str:
"""
调用兼容OpenAI的API来处理信息。
"""
print(f"🧠 正在调用 {self.model} 模型...")
try:
# 构建请求的消息体
messages = [
{'role': 'system', 'content': 'You are a helpful assistant.'},
{'role': 'user', 'content': prompt}
]
# 发起请求, 注意 stream=False 以便一次性获取完整回答
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
stream=False
)
# 提取并返回模型的回答
answer = response.choices[0].message.content
print("✅ 大语言模型响应成功。")
return answer
except Exception as e:
print(f"❌ 调用LLM API时发生错误: {e}")
return "抱歉,调用语言模型服务时出错。"
仅有语言能力不足以完成任务,智能体需要通过调用外部工具与环境进行交互。在本例中,行动即执行网络搜索。我们为此编写一个专用的函数。
search_web 函数的逻辑如下:
ddgs 库向DuckDuckGo搜索引擎发起查询。region='cn-zh' 参数,建议搜索引擎返回与中文区域更相关的结果。解析返回结果,提取每条内容的文本摘要(snippet),并将其组织成一个列表返回。
from ddgs import DDGS
def search_web(query: str, max_results: int = 5):
"""
执行行动 (Action): 调用搜索引擎API来检索信息。
"""
print(f"🤖 智能体正在使用关键词搜索: '{query}'...")
try:
# 使用 with 语句确保资源被正确管理
with DDGS() as ddgs:
# 添加 region='cn-zh' 参数以获取更相关的中文搜索结果
results = [r['body'] for r in ddgs.text(query, region='cn-zh', max_results=max_results)]
print(f"✅ 搜索完成,找到 {len(results)} 条相关信息。")
return results
except Exception as e:
print(f"❌ 搜索时发生错误: {e}")
return []
在定义了语言处理核心与外部工具之后,我们需要将它们整合,构建智能体的核心控制流。函数 information_retrieval_agent 扮演了主控流程的角色,负责协调各个模块。该流程遵循了经典的“思考-行动-观察”循环,这也是许多智能体系统的核心工作范式。
def information_retrieval_agent(user_question: str, llm_client: BaseLLM):
"""
网络信息检索智能体的完整工作流程。
"""
print(f"\n🚀 开始处理新任务: '{user_question}'")
# 1. 思考 (Thought): 查询重写/关键词提取
keyword_extraction_prompt = f"""
请从以下用户问题中,提取出最核心的、适合用于搜索引擎查询的关键词。
请只返回关键词,用空格隔开,不要添加任何解释或标点符号。
用户问题: "{user_question}"
关键词:
"""
print("📝 正在进行查询重写,提取核心关键词...")
search_keywords = llm_client.generate(keyword_extraction_prompt).strip()
# 2. 行动 (Action): 执行网络搜索
search_results = search_web(search_keywords)
if not search_results:
print("⏹️ 未找到任何信息,任务终止。")
return
# 3. 观察 (Observation) 与再次思考 (整合)
integration_prompt = f"""
你是一个信息整合助手。请根据下面提供的网络搜索结果,回答用户的原始问题。
请注意:
1. 你的回答必须完全基于以下提供的“搜索结果”,不能使用你自己的知识。
2. 如果搜索结果无法回答问题,请直接说明“根据现有信息,无法回答该问题”。
3. 将信息整合成一个流畅、连贯的段落。
---
原始问题: "{user_question}"
---
搜索结果:
- {"\n- ".join(search_results)}
---
你的回答:
"""
print("🧐 正在整合搜索结果并生成最终答案...")
final_answer = llm_client.generate(integration_prompt)
# 4. 输出最终结果
print("\n" + "="*20 + " 最终答案 " + "="*20)
print(final_answer)
print("="*50)
最后,程序的入口部分需要进行以下处理:
OpenAICompatibleClient 的实例。information_retrieval_agent 函数,传入一个示例问题以演示智能体的工作流程。交互: 提供一个命令行输入接口,允许用户提交自定义问题,与智能体进行交互。
if __name__ == "__main__":
# --- 模型服务配置 ---
# 请根据你使用的服务商,将这里替换成对应的凭证和地址
API_KEY = "YOUR-API-KEY"
BASE_URL = "YOUR-URL"
MODEL_ID = "YOUR-MODEL"
# 初始化我们想要使用的LLM客户端
llm = OpenAICompatibleClient(api_key=API_KEY, base_url=BASE_URL, model=MODEL_ID)
# 演示如何使用这个智能体
question = "什么是多智能体系统(Multi-Agent System)?它有哪些关键特征?"
information_retrieval_agent(question, llm_client=llm)
# 允许用户输入自己的问题
try:
custom_question = input("\n> 请输入你的问题 (或直接按回车退出): ")
if custom_question:
information_retrieval_agent(custom_question, llm_client=llm)
except KeyboardInterrupt:
print("\n程序已退出。")
>>>
🚀 开始处理新任务: '什么是多智能体系统(Multi-Agent System)?它有哪些关键特征?'
📝 正在进行查询重写,提取核心关键词...
🧠 正在调用 XXX 模型...
✅ 大语言模型响应成功。
🤖 智能体正在使用关键词搜索: '多智能体系统 Multi-Agent System 关键特征'...
✅ 搜索完成,找到 5 条相关信息。
🧐 正在整合搜索结果并生成最终答案...
🧠 正在调用 XXX 模型...
✅ 大语言模型响应成功。
==================== 最终答案 ====================
一个多智能体系统(Multi-Agent System,缩写为MAS),是由多个智能体组成的一个计算系统,这些智能体在一个共享环境中相互作用、通信、协作或竞争,以完成特定的任务或解决问题。这一概
念自20世纪70年代起逐渐发展,成为一种重要的分布式计算技术和复杂系统分析与模拟的方法。多智能体系统不仅在计算机科学和人工智能领域发挥着重要作用,还在解决分离的智能体和单层系统
难以处理的复杂问题上展现出显著优势。通过多个智能体之间的协作与协调,多智能体系统能够提升整体性能和鲁棒性。
==================================================
至此,一个功能完整的网络信息检索智能体就构建完成了。
上一节,我们通过亲手构建一个智能体,深入理解了其内部的运作循环。不过在更广泛的应用场景中,我们的角色正越来越多地转变为使用者与协作者。基于智能体在任务中的角色和自主性程度,其协作模式主要分为两种:一种是作为高效工具,深度融入我们的工作流;另一种则是作为自主的协作者,与其他智能体协作完成复杂目标。
本节将探讨这两种交互模式,通过具体案例,展示我们如何与LLM的智能体的构建者”,转变为其“用户”、“伙伴”乃至“管理者”。
(1)作为开发者工具的智能体
在这种模式下,智能体被深度集成到开发者的工作流中,作为一种强大的辅助工具。它增强而非取代开发者的角色,通过自动化处理繁琐、重复的任务,让开发者能更专注于创造性的核心工作。这种人机协同的方式,极大地提升了软件开发的效率与质量。
目前,市场上涌现了多款优秀的AI编程辅助工具,它们虽然均能提升开发效率,但在实现路径和功能侧重上各有千秋:
当然还有许多优秀的工具没有例举,为了更具体地展示此类工具如何与开发者进行日常协同,我们将选择 Cursor 作为使用案例。因为它编辑器即智能体的设计理念,能完整地体现AI作为开发者工具的交互模式。下面,我们将通过几个常见的开发场景,展示如何与Cursor这样的工具型智能体进行协作。
场景一:快速生成代码,从零到一创建一个“贪吃蛇”游戏。
本场景将演示如何利用 Cursor 从一个完全空白的项目开始,通过一次综合性的自然语言指令,生成一个包含多个文件的完整网页应用。我们的目标是创建一个经典的“贪吃蛇”游戏,以此展示 AI 在项目启动阶段快速生成原型代码的能力。
整个操作流程非常高效。首先,在 Cursor 编辑器中创建一个空项目,并预先建立三个核心文件:index.html 用于定义网页结构,style.css 用于控制界面样式,script.js 用于实现游戏逻辑。这一步是为了给 AI 提供一个明确的操作目标和上下文环境。
接下来是关键的指令下达环节。在聊天侧边栏中,我们首先使用 @ 符号将这三个文件全部引用,确保 AI 能够理解这是一个多文件协作的项目。随后,我们输入一段详细描述需求的指令,将任务清晰地分配给每个文件:
# Prompt
@index.html @style.css @script.js
你好,请帮我创建一个经典版的“贪吃蛇”网页游戏。
在 index.html 中,设置好基本的HTML结构,包含一个游戏画布(canvas)和一个显示分数的元素。
在 style.css 中,为游戏界面添加一些简单的样式,比如让画布居中,设置一个深色的背景。
在 script.js 中,实现游戏的全部逻辑: 绘制游戏区域、蛇和食物。 通过键盘的上下左右箭头控制蛇的移动方向。 实现蛇吃到食物后身体变长、分数增加的逻辑。 处理游戏结束的条件(撞到墙壁或自己)。 包含一个重新开始游戏的功能。
Cursor 接收到指令后,会立即分析需求,并同时为这三个文件生成对应的代码。它不会直接覆写文件,而是在聊天窗口中以代码差异的形式,清晰地展示将要应用的全部修改,如图 1.7 所示。这为开发者提供了一个审查和确认的环节。在确认 AI 的方案无误后,只需点击视为接受的按钮,所有代码就会被自动、准确地写入对应的文件中。
图 1.7 Cursor界面展示了AI为三个文件生成的代码
最终,我们得到了一个功能完备、可直接在浏览器中运行的“贪吃蛇”游戏,如图 1.8 所示。这个过程将传统开发中需要数小时的手动编码工作,压缩为一次与 AI 的自然语言交互,极大地提升了从概念到可运行原型的开发效率。
图 1.8 贪吃蛇游戏运行界面
场景二:理解与重构现有代码,优化一个复杂的函数。
软件开发不仅仅是创造新功能,更多的时候是在维护和优化已有的代码。随着项目迭代,我们经常会遇到一些“代码坏味道”,其中最常见的就是逻辑臃肿、职责不清的全能函数。本场景将演示如何利用 Cursor,将一个难以维护的复杂函数,优雅地重构为清晰、模块化的代码。
假设我们在一个电商项目的代码库中,遇到了一个名为 processOrder 的函数。这个函数最初可能很简单,但随着业务逻辑的增加(如添加优惠券、模拟支付、更新库存等),它逐渐膨胀到上百行,将订单处理的所有步骤都混合在一起。
这样的函数存在明显的问题:
以下是这个函数的原始代码 (order.js),它是一个典型的需要重构的对象:
// 一个难以维护的函数
function processOrder(order) {
// 步骤1: 验证订单数据
if (!order.id || !order.items || order.items.length === 0) {
console.error("订单数据无效");
return;
}
// 步骤2: 计算总价
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
if (order.coupon) {
// 优惠券逻辑
if (order.coupon === "SAVE10") {
total *= 0.9;
}
}
// 步骤3: 调用支付API
console.log(`正在为订单 ${order.id} 调用支付接口,金额: ${total.toFixed(2)}`);
const paymentSuccess = Math.random() > 0.1; // 模拟支付成功或失败
if (!paymentSuccess) {
console.error("支付失败");
return;
}
// 步骤4: 更新库存
for (const item of order.items) {
console.log(`正在更新商品 ${item.productId} 的库存...`);
}
// 步骤5: 发送确认邮件
console.log(`正在向用户 ${order.userId} 发送订单确认邮件...`);
console.log("订单处理完成!");
}
面对这样的函数,传统的手动重构既耗时又容易出错。但在 Cursor 中,这个过程可以被简化为一次与 AI 的对话。首先,在编辑器中选中整个 processOrder 函数体。然后,在选中的代码上方激活内联聊天框。在这里,我们输入一条重构指令:
# Prompt
“请将这个函数重构。把验证、计算总价、处理支付、更新库存和发送邮件这几个步骤,分别拆分成独立的、职责单一的私有函数。同时为每个新函数添加清晰的JSDoc注释。”
Cursor 的 AI 会立刻理解你的意图,分析函数内部的逻辑块,并生成重构方案。它不会直接修改你的代码,而是提供一个清晰的差异对比预览。如图1.9所示,你可以清楚地看到哪些代码被移除(红色),哪些是新增的(绿色),确保所有改动都在你的掌控之中。
图 1.9 Cursor界面展示函数代码重构过程
确认方案后,点击确认接受的按钮,重构便即刻完成。原来的函数被一个清晰的主流程函数和多个职责单一的辅助函数所取代。最终,我们没有手动修改一行代码。通过一条自然语言指令,一个臃肿的函数就被重构了。重构后的 processOrder 函数本身变得极为简洁,其代码几乎就像是业务流程的伪代码,清晰地描述了处理订单的每一个步骤。而每个具体的步骤则被封装在独立的、命名清晰的私有函数中,它们易于理解、易于独立测试,也更易于未来的维护和扩展。这充分展示了 AI 在代码理解和重构方面的强大能力,使其成为提升现有代码库质量的得力助手。
场景三:辅助调试,快速定位并修复运行时错误。
调试是软件开发中不可或缺的一环,但有时排查一个看似简单的运行时错误也可能耗费大量时间。本场景将展示当程序抛出错误时,如何利用 Cursor 快速理解错误原因、定位问题,并获得高质量的修复方案,从而显著提高调试效率。
假设我们正在开发一个简单的用户信息展示功能。代码逻辑很简单:获取一个 DOM 元素,然后将用户信息填充进去。然而,在浏览器中运行时,程序并未如期执行,反而在控制台抛出了一个常见的 TypeError。下面是存在问题的代码 (app.js):
function displayUserGreeting(user) {
// 尝试获取ID为 'greeting' 的元素
const greetingElement = document.getElementById('greeting');
// 如果用户存在,就显示欢迎信息
if (user) {
greetingElement.textContent = `你好, ${user.name}!`;
}
}
// 模拟获取用户信息
const currentUser = { name: "Alice" };
displayUserGreeting(currentUser);
在浏览器开发者工具的控制台中,我们看到了如下截图所示的错误信息,它明确指出了错误类型和发生位置:
Uncaught TypeError: Cannot set properties of null (setting 'textContent')
图 1.10 Cursor开发程序报错提示
如图1.10所示,程序试图为一个值为 null 的东西设置 textContent 属性,这在 JavaScript 中是不允许的。Cursor 提供了一种更直接的调试方式。我们只需将控制台的完整错误信息复制到剪贴板,然后在 Cursor 的聊天侧边栏中,@ 引用相关的代码文件并发起提问:
# prompt
@app.js 我的程序报了下面这个错误,请帮我分析一下原因,并告诉我如何修复它。 Uncaught TypeError: Cannot set properties of null (setting 'textContent')
Cursor 会结合错误信息和 app.js 的源代码进行综合分析,迅速给出诊断和解决方案。它不仅会解释发生了什么,还会深入说明为什么会发生,并提供一段可以直接应用的、更健壮的代码。
图 1.11 Cursor开发程序报错提示
如图1.11所示,通过一次简单的“复制-粘贴-提问”,我们完成了传统调试中多个步骤才能完成的工作。我们不仅立刻明白了错误的根本原因(HTML 结构与 JavaScript 脚本不匹配),还直接获得了一段经过优化的修复代码。这段新代码通过增加一个前置检查,提高了程序的容错性,能够有效避免未来同类错误的发生。
(2)作为自主协作者的智能体
与作为工具辅助人类不同,第二种交互模式将智能体的自动化程度提升到了一个全新的层次,自主协作者。在这种模式下,我们不再是手把手地指导AI完成每一步,而是将一个高层级的目标委托给它。智能体会像一个真正的项目成员一样,独立地进行规划、推理、执行和反思,直到最终交付成果。这种从助手到协作者的转变,使得LLM智能体更深的进入了大众的视野。它标志着我们与AI的关系从“命令-执行”演变为“目标-委托”。智能体不再是被动的工具,而是主动的目标追求者。
当前,实现这种自主协作的思路百花齐放,涌现了大量优秀的框架和产品,如BabyAGI、AutoGPT、CrewAI、AutoGen等。它们虽然在具体实现上各有侧重,但其核心思想都是赋予AI更大程度的自主权。为了清晰地展示这一领域的关键思想脉络,我们将选取三个具有里程碑意义的案例进行介绍。它们分别代表了三种截然不同的架构范式:
接下来,我们将通过具体的案例,逐一剖析这三种自主协作模式的技术特点。
案例一:AgentGPT
AgentGPT是最早引发大众对自主智能体广泛关注的开源项目之一。其核心机制在于一个强大的通用智能体,通过一个持续的“思考-规划-行动”闭环,不断地自我提示,以完成一个开放式的、高层级的目标。用户仅需提供一个最终目标,智能体便会自主地进行任务分解,然后利用各种工具(如网页搜索、文件读写、代码执行)去逐一完成子任务,并根据执行结果不断反思和调整后续计划。
本场景将深入探讨这个智能体项目。与前面案例中通过单次、详尽指令完成任务的模式不同,AgentGPT的核心魅力在于其自主规划和持续迭代的能力。它模拟了一个拥有独立思考能力的“研究员”,仅需一个高层级的开放式目标,便能自主地启动一个持续的“思考-规划-行动-观察”闭环,直至达成最终目的。我们将通过一个经典的商业研究任务,来具象化AgentGPT是如何像一个不知疲倦的个体主义者一样,独立完成复杂项目的。
假设我们将要在芝加哥市中心开设一家新的精品咖啡店并进行市场分析。项目成员就是AgentGPT。我们不需要为它制定详细的工作计划,只需要向AgentGPT下达一个不包含任何具体步骤的高层级指令。这比起“贪吃蛇”案例中需要明确告知每个文件具体做什么会简洁不少。
# Prompt
目标:为在芝加哥市中心开设一家新的精品咖啡店进行市场分析,并生成一份总结报告。
这句指令就是一次彻底的“委托”。提交之后,人类的角色便从“指挥官”转变为“观察者”。AgentGPT的内部循环被激活,一场自主的探索之旅就此展开。
接收到目标后,AgentGPT并不会立即执行单一动作,而是首先进行一次全面的任务规划。它会将“为精品咖啡店进行市场分析”这个高层级目标,分解成一个详尽的任务列表。正如真实操作界面所示,它会生成一系列具体的子任务,如图1.12所示。
图 1.12 AgentGPT运行过程
这个初始计划构成了它的行动蓝图。随后,AgentGPT会从列表的第一个任务开始,自主选择合适的工具(如网页搜索)来执行。这个发现并没有结束,反而成为了下一个行动的催化剂。这展现了AgentGPT作为自主智能体的核心优势:它无需人类提示下一步,便能根据已有信息自主规划并深化研究路径。它会继续这个循环,深挖竞争对手的优劣势、研究本地的消费趋势,并将所有收集到的信息,包括人口数据、竞争列表、消费热点等,自动写入一个文本文件中,作为它的工作笔记。整个过程就像一个不知疲倦的研究员,通过不断的自我对话和自我纠偏来逼近最终目标。当它判断信息足够支撑一份报告时,便会着手整合信息,最终生成一份结构化的分析文档。
AgentGPT的实操过程淋漓尽致地展现了单智能体范式的力量。它拥有极高的自主性,能够将一个模糊的开放式目标,层层分解为具体、可执行的步骤,这在处理探索性任务时效率惊人。然而,这种个体主义的工作模式也并非完美。作为一个通用的思考者,它缺乏特定领域的深度知识。它能找到关于咖啡市场的数据,但它并不真正懂咖啡。因此,它的分析可能广度有余,而深度不足。
更核心的缺陷在于其递归循环的脆弱性。这个不知疲倦的循环也可能使其陷入低效的自证陷阱,在某个不重要的细节上反复搜索,或因为一次错误的解读而导致后续所有步骤跑偏,消耗大量时间和计算资源。由于缺少一个批判者或是合作者的角色来审视其规划,它的策略完全依赖于自身的推理链。一旦最初的思路出现偏差,整个过程便可能走向错误的方向,而无人制止。
总而言之,AgentGPT作为一个单智能体循环项目的典范,证明了“目标-委托”模式的可行性。它像一个能力全面的独立顾问,能独自处理复杂的项目。但它的成功和其固有的单打独斗的局限性,也自然而然地引出了下一个问题:如果一个智能体容易犯错,那么引入另一个智能体进行监督和协作,是否会更有效?这便是我们下一个案例,CAMEL的角色扮演(Role-Playing)协作范式。
案例二:CAMEL
如果说AgentGPT是一个独自完成所有工作的个体主义者,那么CAMEL框架则探索了截然不同的协作路径。通过精心设计的初始提示(Inception Prompting)技术,CAMEL为两个AI智能体分配了不同的角色,一个扮演“任务规划者”(AI User),另一个扮演“任务执行者”(AI Assistant),让它们在一个高度结构化的对话中,通过相互启发和协作来完成任务。这种方案模拟真实世界中专家之间的合作。规划者负责提出想法、需求和高层级的方向,而执行者则负责提供技术方案、实现细节和可行性分析。在一定程度上,它解决了单智能体容易陷入自我逻辑闭环、缺乏外部视角纠偏的问题。
为了体验这种合作模式,我们设定一个需要金融领域知识和编程技术深度结合的任务:为股票市场开发一个交易机器人。在这个场景中,我们不再是向智能体下达一个开放式的目标,而是为其设定好分工明确的角色和初始任务,并观察这场自主的、结构化的设计讨论如何展开。
# Prompt
初始任务:为股票市场开发一个交易机器人。
角色分配:
- AI User (规划者): 股票交易员 (Stock Trader)
- AI Assistant (执行者): Python 程序员 (Python Programmer)
图 1.13 CAMEL框架执行任务过程
如图1.13所示,这场对话会持续进行下去,遵循“提出方案-确认实现”的节奏,不断深化交易机器人的功能,从风险管理、回测系统,到与其他API的集成。规划者(股票交易员)始终聚焦于交易策略,而执行者(Python程序员)则专注于技术实现。当股票交易员认为机器人的核心功能已经足够完善时,它会发出一个特殊的终止指令<CAMEL_TASK_DONE>,整个协作过程便随之结束。最终的产出是一套功能明确的交易机器人原型代码。
CAMEL的协作模式通过角色分工,它有效地避免了单智能体在专业深度上的不足。规划者和执行者各自专注于自己擅长的领域,使得最终方案在交易策略和技术可行性上都得到了保障。然而,这种模式的成功高度依赖于初始角色的设定。如果角色定义不清晰或不恰当,整个对话可能会变得低效甚至无效。此外,但它在处理极其开放、模糊的任务方面可能存在局限。不过总的来说,CAMEL为我们展示了一种通过分工与合作来提升AI能力的有效途径。这自然也引出了更进一步的思考:如果两个智能体的合作就能如此高效,那么一个模拟真实团队、拥有多个不同角色的多智能体系统,又将释放出怎样的潜力呢?Manus AI为我们提供了一种可行途径。
案例三:Manus AI
如果说AgentGPT是一个个体工作者,CAMEL是一个两人小组,那么Manus AI则代表了更高层次的组织形式:一个集成的、产品化的虚拟团队。它不再仅仅是一个开源框架或实验性项目,而是一个旨在交付完整、可用最终产品的自主系统。通过编排一个由多个各司职职的专业子智能体(如规划、研究、执行、验证)组成的团队,来处理复杂的端到端任务。用户只需提出一个高层级的需求,Manus AI就能像一个项目团队一样,在云端异步执行所有步骤,并最终交付一个成品,而非仅仅是文本或代码。
为了充分展现其团队协作和项目交付能力,我们设定一个比单一网页更复杂的任务:创建一个名为“Pixel Demo”的在线迷你游戏网站。这个任务需要并行开发多个独立的游戏模块,并将其整合到一个统一的门户页面中。
# Prompt
创建一个名为“Pixel Demo”的在线迷你游戏网站。要求:
- 风格:复古像素风。
- 门户页面 (index.html): 包含网站标题和一个用于展示所有游戏的网格布局。
- 游戏模块:
1. 井字棋 (Tic-Tac-Toe)
2. 贪吃蛇 (Snake)
- 交付物:一个包含所有HTML, CSS, 和JavaScript文件的可运行项目压缩包。
图 1.14 Manus AI执行任务过程
Manus AI接收到任务后,其内部的虚拟团队便开始了高效的协同工作。如图1.14所示,这远比线性的单智能体或双智能体对话要复杂。其内部的规划智能体首先像项目经理一样,将任务分解为清晰的项目蓝图。随后多个执行智能体像开发团队一样并行工作,分别处理门户页面、全局样式和各个独立的游戏模块,在验证智能体进行代码审查和功能测试后,交付智能体最终会将所有文件打包。最终产出的,便是一个可以直接解压部署的完整项目,如图1.15的“PIXEL DEMO”项目实况所示,一个结构完整、功能可用的多页面网站。
图 1.15 PIXEL DEMO项目实况展示
Manus AI所代表的多智能体范式,其优势是显然的。它实现了从“生成内容”到“交付产品”的跨越,通过并行化处理,其开发效率远超单智能体或双智能体模式。然而,这种能力的背后是极高的编排复杂性。如何有效地管理和协调多个智能体、处理它们之间的依赖关系仍是一种巨大的技术挑战,并且整个过程对用户来说可能像一个黑箱。
从AgentGPT的单智能体循环,到CAMEL的双智能体协作,再到Manus AI的多智能体交互,我们清晰地看到了自主智能体从简单工具向代理式人工智能(Agentic AI)演进的技术脉络。每一种范式都在尝试解决前一种的局限,共同推动着我们与AI协作的边界。
当任务的复杂性超越单个计算实体的能力上限时,分布式协作便成为一种必要的架构选择。在探索人工智能的初期,我们很容易被一个宏大的愿景所吸引:创造一个无所不知、无所不能的通用人工智能(Artificial General Intelligence)。然而,当尝试将当前智能体技术应用于真实世界的复杂场景时,全能个体的理想便会遭遇一系列现实挑战。单个通用智能体在应对真实世界的复杂问题时,会遭遇其单体架构带来的一系列挑战:
这些局限性共同指向一个核心问题:试图用中心化的单体架构,去解决本质上分布式、异构的现实世界问题,存在着根本性的错配。多智能体系统(Multi-Agent System, MAS)正是为应对这一挑战而生的计算范式。
在学术界,MAS被定义为:一个由多个交互的、自主的智能体组成的计算系统,它们位于共享环境中,通过协作解决单个智能体难以完成的复杂问题。该系统由三个核心要素构成:智能体(Agent)、环境(Environment)和交互(Interaction)。鉴于前两部分已有探讨,本节的后续内容将聚焦于MAS的交互,并分析其通信、任务分配与协调策略。更多详细的多智能体介绍将会安排在后面的章节中。
本节通过一个具体案例(“为咖啡馆创建网站”)来阐述多智能体交互的三个核心机制:任务规划、通信与协作。
多智能体系统的首要步骤是将一个高层级目标映射为可执行的计划。该过程包括任务分解和角色分配。例如,一个“项目经理”智能体接收到初始目标后,其内部生成的规划(Thought)如下:
Thought:
Initial objective: "Create a website for a coffee shop".
Decomposition:
1. Frontend Development: Create a static page for the menu and contact info.
2. Backend Development: Create an API to handle contact form submissions.
Role Assignment:
- Assign `FrontendDeveloper` for task 1.
- Assign `BackendDeveloper` for task 2.
Next Action: Generate task instruction for `FrontendDeveloper`.
该规划将高层级目标转化为了结构化的子任务和明确的角色分工。
规划完成后,各智能体需通过结构化的通信协议交换信息。项目经理依据其规划,生成一条 JSON 格式的消息,用于任务分派:
{
"sender": "ProjectManager",
"receiver": "FrontendDeveloper",
"action": "ASSIGN_TASK",
"data": {
"task_id": "T-101",
"description": "Create a static user-facing webpage for the coffee shop. It should include sections for our coffee menu and a contact form.",
"dependencies": ["Backend_API_for_contact_form"]
}
}
JSON作为一种机器可读格式,确保了指令的无歧义性。通信模式可分为直接通信(如API调用)和基于共享内存的间接通信,后者耦合度更低,扩展性更好。
协作策略定义了智能体间的工作流与依赖关系。在集中式协调中,存在一个编排者节点,负责任务分发与状态监控。其交互流程如下所示:
1. PM -> FrontendDev: [ASSIGN_TASK T-101: Create frontend page]
2. PM -> BackendDev: [ASSIGN_TASK T-102: Create backend API]
3. BackendDev -> PM: [REPORT_STATUS T-102: Complete, API is at /api/contact]
4. PM -> FrontendDev: [UPDATE_INFO T-101: Backend API is ready, proceed with integration]
该模式下,项目经理是控制中心。而在分布式协调中,各智能体节点对等,通过协商来确定行动顺序与资源分配,无需中心节点介入。通过任务规划定义“做什么”,通过通信明确“怎么说”,再通过协作策略管理“如何做”,一个完整的多智能体交互流程便形成了闭环,使一群独立的智能体能够作为一个有凝聚力的整体,共同完成复杂的目标。
早在深度学习革命之前,多智能体系统的主流范式是基于符号主义AI构建的。这一时期的智能体,其智能源于人类专家编码的知识库和推理规则。它们是典型的基于知识的系统(Knowledge-Based System),通过审议式推理(Deliberative Reasoning)进行决策。智能体之间则采用高度形式化的智能体通信语言(ACL)和协调协议(如模拟商业招标的合同网协议)进行交互,确保了通信的精确性和行为的可预测性。不过缺点也比较明显,即为智能体手动构建知识库成本极高(即知识工程瓶颈),且系统面对规则之外的未知情况时表现得非常脆弱。
大语言模型的出现,从根本上重塑了多智能体系统,突破了传统范式的核心瓶颈。
不过将基于LLM的新范式与传统的符号型范式完全对立起来,是一种过于简化的视角。LLM的出现并非宣告了符号主义的终结,恰恰相反,它为解决符号主义的固有瓶颈提供了新的工具,也让两种范式的融合成为可能。要理解这一点,我们首先需要对二者进行一个直观的对比,如表1.3所示。
表 1.3 符号型与LLM驱动的多智能体系统对比
综上,LLM的融入并非局部改良,而是一场范式革命。它将多智能体系统从一个需要被精确编程的、基于知识的系统,转变为一个可通过自然语言引导的、基于能力的通用问题解决器。
但这并非简单的线性替代,而是一个螺旋上升的融合过程。新旧范式在能力上形成了鲜明的互补:符号主义的严谨、精确、可解释,恰好能弥补LLM的灵活性有余而可靠性不足(如“幻觉”问题)。因此,未来的前沿方向,很可能就是将LLM的归纳推理能力与符号系统的演绎推理能力深度结合,例如让LLM负责生成初步方案,再由符号系统进行严格的验证和约束。通过这种融合,在创造力与精确性、灵活性与可靠性之间取得更好的平衡,从而构建出更值得信赖的多智能体系统。
在本章中,我们共同踏上了探索智能体的初识之旅。我们的旅程从最基本的问题开始:
通过本章的学习,我们建立了一个关于智能体的基础认知框架:从单个智能体的定义与分类,到其与环境的交互,再到多智能体系统的协作模式。那么,它是如何一步步从最初的构想演进至今的呢?在下一章中,我们将探索智能体的发展历史,一段追本溯源的旅程即将开始!
[1] RUSSELL S, NORVIG P. Artificial Intelligence: A Modern Approach[M]. 4th ed. London: Pearson, 2020.
[2] KAHNEMAN D. Thinking, Fast and Slow[M]. New York: Farrar, Straus and Giroux, 2011.