|
|
@@ -0,0 +1,1203 @@
|
|
|
+# 初识智能体
|
|
|
+
|
|
|
+欢迎来到智能体的世界!在人工智能浪潮席卷全球的今天,**智能体(Agent)**已成为驱动技术变革与应用创新的核心概念之一。无论你的志向是成为AI领域的研究者、工程师,还是希望深刻理解技术前沿的观察者,掌握智能体的本质,都将是你知识体系中不可或缺的一环。
|
|
|
+
|
|
|
+因此,在本章,让我们回到原点,一起探讨几个问题:智能体是什么?它有哪些主要的类型?它又是如何与我们所处的世界进行交互的?通过这些讨论,希望能为你未来的学习和探索打下坚实的基础。
|
|
|
+
|
|
|
+## 1.1 什么是智能体?
|
|
|
+
|
|
|
+在探索任何一个复杂概念时,我们最好从一个简洁的定义开始。在人工智能领域,智能体被定义为任何能够通过**传感器(Sensors)**感知其所处**环境(Environment)**,并**自主**地通过**执行器(Actuators)**采取**行动(Action)**以达成特定目标的实体。
|
|
|
+
|
|
|
+这个定义包含了智能体存在的四个基本要素。环境是智能体所处的外部世界。对于自动驾驶汽车,环境是动态变化的道路交通;对于一个交易算法,环境则是瞬息万变的金融市场。智能体并非与环境隔离,它通过其传感器持续地感知环境状态。摄像头、麦克风、雷达或各类**应用程序编程接口(Application Programming Interface, API)**返回的数据流,都是其感知能力的延伸。
|
|
|
+
|
|
|
+获取信息后,智能体需要采取行动来对环境施加影响,它通过执行器来改变环境的状态。,执行器可以是物理设备(如机械臂、方向盘)或虚拟工具(如执行一段代码、调用一个服务)。
|
|
|
+
|
|
|
+然而,真正赋予智能体“智能”的,是其**自主性(Autonomy)**。智能体并非只是被动响应外部刺激或严格执行预设指令的程序,它能够基于其感知和内部状态进行独立决策,以达成其设计目标。这种从感知到行动的闭环,构成了所有智能体行为的基础,如图1.1所示。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-0.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.1 智能体与环境的基本交互循环</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+### 1.1.1 传统视角下的智能体
|
|
|
+
|
|
|
+在当前**大语言模型(Large Language Model, LLM)**的热潮出现之前,人工智能的先驱们已经对“智能体”这一概念进行了数十年的探索与构建。这些如今我们称之为“传统智能体”的范式,并非单一的静态概念,而是经历了一条从简单到复杂、从被动反应到主动学习的清晰演进路线。
|
|
|
+
|
|
|
+这个演进的起点,是那些结构最简单的**反射智能体(Simple Reflex Agent)**。它们的决策核心由工程师明确设计的“条件-动作”规则构成,如图1.2所示。经典的自动恒温器便是如此:若传感器感知的室温高于设定值,则启动制冷系统。
|
|
|
+
|
|
|
+这种智能体完全依赖于当前的感知输入,不具备记忆或预测能力。它像一种数字化的本能,可靠且高效,但也因此无法应对需要理解上下文的复杂任务。它的局限性引出了一个关键问题:如果环境的当前状态不足以作为决策的全部依据,智能体该怎么办?
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-1.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.2 简单反射智能体的决策逻辑示意图</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+为了回答这个问题,研究者们引入了“状态”的概念,发展出**基于模型的反射智能体(Model-Based Reflex Agent)**。这类智能体拥有一个内部的**世界模型(World Model)**,用于追踪和理解环境中那些无法被直接感知的方面。它试图回答:“世界现在是什么样子的?”。例如,一辆在隧道中行驶的自动驾驶汽车,即便摄像头暂时无法感知到前方的车辆,它的内部模型依然会维持对那辆车存在、速度和预估位置的判断。这个内部模型让智能体拥有了初级的“记忆”,使其决策不再仅仅依赖于瞬时感知,而是基于一个更连贯、更完整的世界状态理解。
|
|
|
+
|
|
|
+然而,仅仅理解世界还不够,智能体需要有明确的目标。这促进了**基于目标的智能体(Goal-Based Agent)**的发展。与前两者不同,它的行为不再是被动地对环境做出反应,而是主动地、有预见性地选择能够导向某个特定未来状态的行动。这类智能体需要回答的问题是:“我应该做什么才能达成目标?”。经典的例子是GPS导航系统:你的目标是到达公司,智能体会基于地图数据(世界模型),通过搜索算法(如A*算法)来规划(Planning)出一条最优路径。这类智能体的核心能力体现在了对未来的考量与规划上。
|
|
|
+
|
|
|
+更进一步,现实世界的目标往往不是单一的。我们不仅希望到达公司,还希望时间最短、路程最省油并且避开拥堵。当多个目标需要权衡时,**基于效用的智能体(Utility-Based Agent)**便随之出现。它为每一个可能的世界状态都赋予一个效用值,这个值代表了满意度的高低。智能体的核心目标不再是简单地达成某个特定状态,而是最大化期望效用。它需要回答一个更复杂的问题:“哪种行为能为我带来最满意的结果?”。这种架构让智能体学会在相互冲突的目标之间进行权衡,使其决策更接近人类的理性选择。
|
|
|
+
|
|
|
+至此,我们讨论的智能体虽然功能日益复杂,但其核心决策逻辑,无论是规则、模型还是效用函数,依然依赖于人类设计师的先验知识。如果智能体能不依赖预设,而是通过与环境的互动自主学习呢?
|
|
|
+
|
|
|
+这便是**学习型智能体(Learning Agent)**的核心思想,而**强化学习(Reinforcement Learning, RL)**是实现这一思想最具代表性的路径。一个学习型智能体包含一个性能元件(即我们前面讨论的各类智能体)和一个学习元件。学习元件通过观察性能元件在环境中的行动所带来的结果来不断修正性能元件的决策策略。
|
|
|
+
|
|
|
+想象一个学习下棋的AI。它开始时可能只是随机落子,当它最终赢下一局时,系统会给予它一个正向的奖励。通过大量的自我对弈,学习元件会逐渐发现哪些棋路更有可能导向最终的胜利。AlphaGo是这一理念的一个里程碑式的成就。它在围棋这一复杂博弈中,通过强化学习发现了许多超越人类既有知识的有效策略。
|
|
|
+
|
|
|
+从简单的恒温器,到拥有内部模型的汽车,再到能够规划路线的导航、懂得权衡利弊的决策者,最终到可以通过经验自我进化的学习者。这条演进之路,展示了传统人工智能在构建机器智能的道路上所经历的发展脉络。它们为我们今天理解更前沿的智能体范式,打下了坚实而必要的基础。
|
|
|
+
|
|
|
+### 1.1.2 大语言模型驱动的新范式
|
|
|
+
|
|
|
+以**GPT(Generative Pre-trained Transformer)**为代表的大语言模型的出现,正在显著改变智能体的构建方法与能力边界。由大语言模型驱动的智能体,其核心决策机制与传统智能体存在本质区别,从而赋予了其一系列全新的特性。
|
|
|
+
|
|
|
+这种转变,可以从两者在核心引擎、知识来源、交互方式等多个维度的对比中清晰地看出,如表1.1所示。简而言之,传统智能体的能力源于工程师的显式编程与知识构建,其行为模式是确定且有边界的;而LLM智能体则通过在海量数据上的预训练,获得了隐式的世界模型与强大的涌现能力,使其能够以更灵活、更通用的方式应对复杂任务。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <p>表 1.1 传统智能体与LLM驱动智能体的核心对比</p>
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-2.png" alt="图片描述" width="90%"/>
|
|
|
+</div>
|
|
|
+
|
|
|
+这种差异使得LLM智能体可以直接处理高层级、模糊且充满上下文信息的自然语言指令。它不需要用户将需求拆解成机器可以理解的结构化输入,只需要输入人类的自然语言即可。
|
|
|
+
|
|
|
+以“策划一场团队研讨会”为例,LLM智能体的一种工作方式是:
|
|
|
+
|
|
|
+1. **分解与规划**:将大目标拆解成多个小步骤(如确认预算、搜索场地、设计议程)。
|
|
|
+2. **使用工具**:调用搜索引擎、预订网站等外部API来获取实时信息。
|
|
|
+3. **记忆与修正**:记住用户的反馈(如“场地太贵了”)并根据新情况调整计划。
|
|
|
+
|
|
|
+总而言之,我们正从开发专用自动化工具转向构建能自主解决问题的系统。核心不再是编写代码,而是引导一个通用的“大脑”去规划、行动和学习。
|
|
|
+
|
|
|
+### 1.1.3 智能体的类型
|
|
|
+
|
|
|
+继上文回顾智能体的演进后,本节将从三个互补的维度对智能体进行分类。
|
|
|
+
|
|
|
+(1)**基于内部决策架构的分类**
|
|
|
+
|
|
|
+第一种分类维度是依据智能体内部决策架构的复杂程度,这个视角在《Artificial Intelligence: A Modern Approach》中系统性地提出[1]。正如 1.1.1 节所述,传统智能体的演进路径本身就构成了最经典的分类阶梯,它涵盖了从简单的**反应式**智能体,到引入内部模型的**模型式**智能体,再到更具前瞻性的**基于目标**和**基于效用**的智能体。此外,**学习能力**则是一种可赋予上述所有类型的元能力,使其能通过经验自我改进。
|
|
|
+
|
|
|
+(2)**基于时间与反应性的分类**
|
|
|
+
|
|
|
+除了内部架构的复杂性,还可以从智能体处理决策的时间维度进行分类。这个视角关注智能体是在接收到信息后立即行动,还是会经过深思熟虑的规划再行动。这揭示了智能体设计中一个核心权衡:追求速度的**反应性(Reactivity)**与追求最优解的**规划性(Deliberation)**之间的平衡,如图1.3所示。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-3.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.3 智能体决策时间与质量关系图</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+- **反应式智能体 (Reactive Agents)**
|
|
|
+
|
|
|
+这类智能体对环境刺激做出近乎即时的响应,决策延迟极低。它们通常遵循从感知到行动的直接映射,不进行或只进行极少的未来规划。上文的**简单反应式**和**基于模型**的智能体都属于此类别。
|
|
|
+
|
|
|
+其核心优势在于**速度快、计算开销低**,这在需要快速决策的动态环境中至关重要。例如,车辆的安全气囊系统必须在碰撞发生的毫秒内做出反应,任何延迟都可能导致严重后果;同样,高频交易机器人也必须依赖反应式决策来捕捉稍纵即逝的市场机会。然而,这种速度的代价是“短视”,由于缺乏长远规划,反应式智能体容易陷入局部最优,难以完成需要多步骤协调的复杂任务。
|
|
|
+
|
|
|
+- **规划式智能体(Deliberative Agents)**
|
|
|
+
|
|
|
+与反应式智能体相对,规划式(或称审议式)智能体在行动前会进行复杂的思考和规划。它们不会立即对感知做出反应,而是会先利用其内部的世界模型,系统地探索未来的各种可能性,评估不同行动序列的后果,以期找到一条能够达成目标的最佳路径 。**基于目标**和**基于效用**的智能体是典型的规划式智能体。
|
|
|
+
|
|
|
+可以将其决策过程类比为一位棋手。他不会只看眼前的一步,而是会预想对手可能的应对,并规划出后续几步甚至十几步的棋路。这种深思熟虑的能力使其能够处理复杂的、需要长远眼光的任务,例如制定一份商业计划或规划一次长途旅行。它们的优势在于决策的战略性和远见。然而,这种优势的另一面是高昂的时间和计算成本。在瞬息万变的环境中,当规划式智能体还在深思熟虑时,采取行动的最佳时机可能早已过去。
|
|
|
+
|
|
|
+- **混合式智能体(Hybrid Agents)**
|
|
|
+
|
|
|
+现实世界的复杂任务,往往既需要即时反应,也需要长远规划。例如,一个火星探测车既要能快速躲避滚落的岩石(反应性),又要能规划抵达下一个考察点的长期路径(规划性)。因此,**混合式智能体**应运而生,它旨在结合两者的优点,实现反应与规划的平衡。
|
|
|
+
|
|
|
+一种经典的混合架构是分层设计:底层是一个快速的反应模块,处理紧急情况和基本动作;高层则是一个审慎的规划模块,负责制定长远目标。而现代的LLM智能体,则展现了一种更灵活的混合模式。它们通常在一个“思考-行动-观察”的循环中运作,巧妙地将两种模式融为一体:
|
|
|
+
|
|
|
+- **规划 (Reasoning)**:在“思考”阶段,LLM分析当前状况,规划出下一步的合理行动。这是一个审议过程。
|
|
|
+- **反应 (Acting & Observing)**:在“行动”和“观察”阶段,智能体与外部工具或环境交互,并立即获得反馈。这是一个反应过程。
|
|
|
+
|
|
|
+通过这种方式,智能体将一个需要长远规划的宏大任务,分解为一系列“规划-反应”的微循环。这使其既能灵活应对环境的即时变化,又能通过连贯的步骤,最终完成复杂的长期目标。
|
|
|
+
|
|
|
+**(3)基于知识表示的分类**
|
|
|
+
|
|
|
+这是一个更根本的分类维度,它探究智能体用以决策的知识,究竟是以何种形式存于其“思想”之中。这个问题是人工智能领域一场持续半个多世纪的辩论核心,并塑造了两种截然不同的AI文化。
|
|
|
+
|
|
|
+- **符号主义AI(Symbolic AI)**
|
|
|
+
|
|
|
+符号主义,常被称为传统人工智能,其核心信念是:智能源于对符号的逻辑操作。这里的符号是人类可读的实体(如词语、概念),操作则遵循严格的逻辑规则,如图1.4左侧所示。这好比一位一丝不苟的图书管理员,将世界知识整理为清晰的规则库和知识图谱。
|
|
|
+
|
|
|
+其主要优势在于透明和可解释。由于推理步骤明确,其决策过程可以被完整追溯,这在金融、医疗等高风险领域至关重要。然而,其“阿喀琉斯之踵”在于脆弱性:它依赖于一个完备的规则体系,但在充满模糊和例外的现实世界中,任何未被覆盖的新情况都可能导致系统失灵,这就是所谓的“知识获取瓶颈”。
|
|
|
+
|
|
|
+- **亚符号主义AI(Sub-symbolic AI)**
|
|
|
+
|
|
|
+亚符号主义,或称连接主义,则提供了一幅截然不同的图景。在这里,知识并非显式的规则,而是内隐地分布在一个由大量神经元组成的复杂网络中,是从海量数据中学习到的统计模式。神经网络和深度学习是其代表。
|
|
|
+
|
|
|
+如图1.4中间所示,如果说符号主义AI是图书管理员,那么亚符号主义AI就像一个牙牙学语的孩童 。他不是通过学习“猫有四条腿、毛茸茸、会喵喵叫”这样的规则来认识猫的,而是在看过成千上万张猫的图片后,大脑中的神经网络能辨识出“猫”这个概念的视觉模式 。这种方法的强大之处在于其模式识别能力和对噪声数据的鲁棒性 。它能够轻松处理图像、声音等非结构化数据,这在符号主义AI看来是极其困难的任务。
|
|
|
+
|
|
|
+然而,这种强大的直觉能力也伴随着不透明性。亚符号主义系统通常被视为一个**黑箱(Black Box)**。它能以惊人的准确率识别出图片中的猫,但你若问它“为什么你认为这是猫?”,它很可能无法给出一个合乎逻辑的解释。此外,它在纯粹的逻辑推理任务上表现不佳,有时会产生看似合理却事实错误的幻觉 。
|
|
|
+
|
|
|
+- **神经符号主义AI(Neuro-Symbolic AI)**
|
|
|
+
|
|
|
+长久以来,符号主义和亚符号主义这两大阵营如同两条平行线,各自发展。为克服上述两种范式的局限,一种“大和解”的思想开始兴起,这就是神经符号主义AI,也称神经符号混合主义。它的目标,是融合两大范式的优点,创造出一个既能像神经网络一样从数据中学习,又能像符号系统一样进行逻辑推理的混合智能体。它试图弥合感知与认知、直觉与理性之间的鸿沟。诺贝尔经济学奖得主丹尼尔·卡尼曼(Daniel Kahneman)在其著作《思考,快与慢》(Thinking, Fast and Slow)中提出的双系统理论,为我们理解神经符号主义提供了一个绝佳的类比[2],如图1.4所示:
|
|
|
+
|
|
|
+- **系统1**是快速、凭直觉、并行的思维模式,类似于亚符号主义AI强大的模式识别能力。
|
|
|
+- **系统2**是缓慢、有条理、基于逻辑的审慎思维,恰如符号主义AI的推理过程。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-4.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.4 符号主义、亚符号主义与神经符号混合主义的知识表示范式</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+人类的智能,正源于这两个系统的协同工作。同样,一个真正鲁棒的AI,也需要兼具二者之长。大语言模型驱动的智能体是神经符号主义的一个极佳实践范例。其内核是一个巨大的神经网络,使其具备模式识别和语言生成能力。然而,当它工作时,它会生成一系列结构化的中间步骤,如思想、计划或API调用,这些都是明确的、可操作的符号。通过这种方式,它实现了感知与认知、直觉与理性的初步融合。
|
|
|
+
|
|
|
+## 1.2 智能体与环境交互
|
|
|
+
|
|
|
+前一节我们讲解了智能体的不同类型。然而,仅有内部决策逻辑不足以实现目标,智能体必须通过与外部环境的持续互动来执行任务。其运作的核心是一个持续的**智能体循环(Agent Loop)**,它将复杂的任务分解为一系列标准的交互步骤,通常包括:
|
|
|
+
|
|
|
+1. **感知 (Perception)**:智能体接收并解析来自用户或环境的输入信息,例如用户指令或上一步的行动结果。
|
|
|
+2. **思考 (Thought):**基于感知到的信息,智能体的核心模型进行规划,更新一个行动计划。这可能包括将复杂任务分解为子任务,或在众多可用工具中选择最合适的一个。
|
|
|
+3. **行动 (Action)**:智能体调用选定的工具执行计划中的具体步骤,对环境施加影响。
|
|
|
+4. **观察 (Observation)**:智能体评估行动产生的结果,并将其作为新一轮循环的输入,用以调整后续计划。
|
|
|
+
|
|
|
+这个循环构成了所有LLM智能体运作的基本模式,如图1.5所示。1.2.1节将从环境的构成入手,进一步探讨该交互机制的属性及其对智能体设计的影响。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-5.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.5 智能体与环境交互的基本循环</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+### 1.2.1 任务环境的特性
|
|
|
+
|
|
|
+要理解智能体的运作,我们必须先理解它所处的**任务环境**。在人工智能领域,通常使用 **PEAS 模型**来精确描述一个任务环境,即分析其**性能度量 (Performance)、环境 (Environment)、执行器 (Actuators) 和 传感器 (Sensors)**。以一个旅行规划智能体为例,下表1.2展示了如何运用PEAS模型对其任务环境进行规约。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <p>表 1.2 旅行规划智能体的PEAS描述</p>
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-6.png" alt="图片描述" width="90%"/>
|
|
|
+</div>
|
|
|
+
|
|
|
+在实践中,LLM智能体所处的数字环境展现出若干复杂特性,这些特性直接影响着智能体的设计。
|
|
|
+
|
|
|
+首先,环境通常是**部分可观察的**。例如,一个购物智能体无法一次性看到所有商品信息,只能通过逐页访问来逐步构建对环境的认知,这就要求智能体必须具备记忆和状态追踪能力。
|
|
|
+
|
|
|
+其次,行动的结果也并非总是确定的。根据结果的可预测性,环境可分为**确定性**和**随机性**。当智能体执行本地代码进行数学计算时,结果是确定的;但当它调用一个实时变化的搜索引擎API时,结果便带有随机性,这就要求智能体必须具备容错和处理不确定性的能力。
|
|
|
+
|
|
|
+此外,环境中还可能存在其他行动者,从而形成**多**智能体** **(Multi-agent)** 环境。在这种情况下,智能体之间需要协作或竞争,一个智能体的行动会成为另一个智能体环境中的变量,这对智能体的沟通和协调能力提出了更高要求。
|
|
|
+
|
|
|
+最后,几乎所有任务都发生在**序贯**且**动态**的环境中。“序贯”意味着当前动作会影响未来;而“动态”则意味着环境自身可能在智能体决策时发生变化。这就要求智能体的“感知-思考-行动-观察”循环必须能够快速、灵活地适应持续变化的世界。
|
|
|
+
|
|
|
+### 1.2.2 环境交互的协议与接口
|
|
|
+
|
|
|
+LLM智能体与环境的互动需要一套明确的**交互协议(Interaction Protocol)**来规范信息的格式与流程。该协议的核心,体现在对智能体行动的结构化定义上。
|
|
|
+
|
|
|
+在诸如**ReAct(Reasoning and Acting)**等现代框架中,智能体的每一次输出通常是一段特殊格式的文本。其中不仅包含了要执行的行动本身,还明确展示了该行动之前的思考过程。
|
|
|
+
|
|
|
+这个“思考”部分是智能体内部决策的快照,它阐述了智能体如何**分解任务**、如何根据上一步的观察结果进行**自我反思**,以及最终决定下一步具体行动的**策略规划**。例如,一个正在规划旅行的智能体可能会生成如下格式化文本:
|
|
|
+
|
|
|
+```Bash
|
|
|
+Thought: 用户想知道北京的天气。我需要调用天气查询工具。
|
|
|
+Action: get_weather("北京")
|
|
|
+```
|
|
|
+
|
|
|
+这里的Action部分就是智能体对其执行器的指令。一个外部的解析器会捕捉到这个指令,并真正地去执行相应的`get_weather`函数。智能体的感知,即其传感
|
|
|
+
|
|
|
+器的输入,则是上述行动执行后的结果。当外部工具执行完`get_weather("北京")`后,它可能得到一个包含温度、湿度、风力等信息的JSON对象。这个原始数据对于LLM来说过于冗长和非自然。因此,传感器的角色需要将这个JSON对象处理并封装成一段清晰、简洁的自然语言文本,例如:
|
|
|
+
|
|
|
+```Bash
|
|
|
+Observation: 北京当前天气为晴,气温25摄氏度,微风。
|
|
|
+```
|
|
|
+
|
|
|
+这段Observation文本会被拼接在下一轮提供给LLM的输入中,成为其后续进行新一轮思考和行动的依据。
|
|
|
+
|
|
|
+通过这个由`Thought`, `Action`, `Observation`构成的循环,LLM智能体得以将内部的语言推理能力,与外部环境的真实信息和工具操作能力结合起来,从而在一个明确的接口上,完成对复杂任务的逐步拆解和执行。因此,设计一个清晰、稳定且功能恰当的工具接口,是实现有效LLM智能体行为的工程学前提。
|
|
|
+
|
|
|
+**标准化接口组件定义**
|
|
|
+
|
|
|
+Perception-Thought-Action-Observation循环是通过一套标准化的接口组件来实现的。为确保系统的可扩展性与可维护性,这些接口遵循单一职责原则,分别对应循环中的一个关键环节。下面我们将对这四个核心组件进行定义。
|
|
|
+
|
|
|
+**接口1:感知器**
|
|
|
+
|
|
|
+感知器负责处理输入信息,将原始数据转化为智能体可理解的格式:
|
|
|
+
|
|
|
+~~~Python
|
|
|
+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:思考器**
|
|
|
+
|
|
|
+思考器基于感知结果进行推理和规划:
|
|
|
+
|
|
|
+```Python
|
|
|
+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:执行器**
|
|
|
+
|
|
|
+执行器负责将计划转化为具体的工具调用:
|
|
|
+
|
|
|
+```Python
|
|
|
+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:观察器**
|
|
|
+
|
|
|
+观察器处理执行结果,生成反馈信息:
|
|
|
+
|
|
|
+```Python
|
|
|
+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
|
|
|
+```
|
|
|
+
|
|
|
+**统一的智能体接口**
|
|
|
+
|
|
|
+这四个组件通过一个统一的智能体接口进行协调:
|
|
|
+
|
|
|
+```Python
|
|
|
+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),并最终组装成一个完整的智能体的基本示例。
|
|
|
+
|
|
|
+### 1.2.3 智能体的行动循环
|
|
|
+
|
|
|
+智能体的行动循环是其自主性的核心体现。它是一个从信息输入(感知),经过内部状态转换(思考),到行为输出(行动),再到结果反馈(观察)的完整闭环。这个持续运行的流程,确保了智能体能够响应外部世界,并根据结果动态调整其行为。
|
|
|
+
|
|
|
+这里有必要澄清一个关键点:通常被描述为“思考-行动-观察”的循环,为何在这里以“感知”作为第一步。可以这样理解:思考-行动-观察是智能体内部的核心认知循环。然而,这个循环必须由一个外部刺激来启动。感知与理解阶段正是处理这种外部刺激的入口,它负责将外部数据转化为智能体内部可以处理的格式,从而触发核心认知循环的第一次迭代。
|
|
|
+
|
|
|
+接下来,我们将把这个循环分解为四个逻辑阶段,并逐一探讨实现这些阶段所需的核心组件。
|
|
|
+
|
|
|
+**第一步:感知与理解**
|
|
|
+
|
|
|
+感知是整个信息处理流程的起点,是智能体接收外部输入的接口。其核心职责是将来自外部世界的原始、非结构化数据(如用户的自然语言查询、API的JSON响应等),转换为后续模块(尤其是思考模块)能够处理的结构化内部表述 (Internal Representation)。
|
|
|
+
|
|
|
+此阶段的输出质量直接决定了智能体后续所有决策的上限。一个精确的感知模块能够准确地捕捉意图、提取关键参数,为高质量的规划奠定基础。
|
|
|
+
|
|
|
+在 `PerceptionImpl` 类的实现中,`process_user_input` 方法承担了此项职能。它接收原始输入字符串,通过意图识别和实体提取等技术,将其转换为一个包含 `intent` 和 `entities` 键的字典。这个过程是自然语言理解的一个简化示例。
|
|
|
+
|
|
|
+```Python
|
|
|
+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` 方法则基于该分析和可用的工具列表,生成一个包含目标工具和所需参数的结构化指令。
|
|
|
+
|
|
|
+```Python
|
|
|
+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` 方法则充当调度器,根据指定的工具名称和参数,调用相应的函数,并以标准化的格式返回执行结果。
|
|
|
+
|
|
|
+```Python
|
|
|
+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} 的天气信息。")
|
|
|
+```
|
|
|
+
|
|
|
+**第四步:观察与学习**
|
|
|
+
|
|
|
+行动的完成并不意味着流程的结束,而是形成反馈闭环的关键一步。观察模块负责接收和评估执行阶段的输出,并将其转化为智能体内部可以理解的观察结果。
|
|
|
+
|
|
|
+此阶段的核心功能是:
|
|
|
+
|
|
|
+1. **评估行动结果**:判定上一步行动的成败,并解析成功时返回的数据或失败时产生的错误信息。
|
|
|
+2. **决策后续流程**:根据评估结果,确定下一步的走向。例如,成功获取数据则准备向用户响应;失败则可能需要将错误信息反馈给思考模块以进行重新规划。
|
|
|
+
|
|
|
+这个观察结果将作为新的信息输入,反馈给认知循环的下一个迭代,从而使智能体能够根据其行为的实际效果来调整后续策略。
|
|
|
+
|
|
|
+在 `ObservationImpl` 的实现中,`process_result` 方法负责将执行结果转化为结构化的观察结论,而 `format_response` 则用于将最终结论格式化为面向用户的输出。
|
|
|
+
|
|
|
+```Python
|
|
|
+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所示。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-7.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.6 智能体行动循环的实现流程</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+每一次对 `process_request` 方法的调用,都代表了一次完整的“感知-思考-执行-观察”循环的执行过程。
|
|
|
+
|
|
|
+```Python
|
|
|
+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.4 典型环境中的智能体案例
|
|
|
+
|
|
|
+在前述的 1.2.1 至 1.2.3 小节中,我们已经为智能体与环境的交互补充了理论基础:从任务环境的宏观介绍,到交互协议与接口的具体定义,再到一个基础智能体行动循环的实现。为了具体地了解智能体是如何在不同特性的环境中进行感知、规划与行动的,在本案例中,我们将构建一个实际的网络信息检索智能体。
|
|
|
+
|
|
|
+准备工作:在开始编码之前,我们需要先安装几个Python库。
|
|
|
+
|
|
|
+- `ddgs`: 这是一个用于调用DuckDuckGo搜索引擎的客户端库,我们可以无需使用API来进行基本的搜索网页功能实现。
|
|
|
+- `openai`: openai 提供了统一的 API 接口格式,简化了我们与多种大语言模型(LLM)交互的流程,可以选择自己所拥有的API进行适配。
|
|
|
+- `requests`: 这是Python中处理网络请求的基础库,`openai`库依赖它来发送和接收数据。
|
|
|
+
|
|
|
+请打开你的终端(命令行工具),然后运行下面的命令来安装它们:
|
|
|
+
|
|
|
+```Bash
|
|
|
+pip install ddgs openai requests
|
|
|
+```
|
|
|
+
|
|
|
+智能体需要一个核心组件来理解和生成语言,这个角色由LLM承担。考虑到LLM服务的多样性,为了保证代码的模块化与可扩展性,我们首先创建一个统一的**客户端(Client)**来封装与LLM的交互。首先,我们定义一个标准接口。在面向对象编程中,这通常通过**抽象基类(Abstract Base Class)**来实现。该基类定义了一个所有LLM客户端都必须遵守的规范,即它们都必须实现一个名为 `generate` 的方法。这种设计模式确保了主逻辑的稳定性:无论未来底层实现如何变更,主程序都依赖于统一的接口进行调用。
|
|
|
+
|
|
|
+```Python
|
|
|
+class BaseLLM:
|
|
|
+ """
|
|
|
+ 定义所有LLM客户端都应遵循的基本接口。
|
|
|
+ 这是一个抽象基类,用于确保所有子类都有一个 generate 方法。
|
|
|
+ """
|
|
|
+ def generate(self, prompt: str) -> str:
|
|
|
+ """根据输入的提示生成文本。"""
|
|
|
+ raise NotImplementedError("子类必须实现这个方法")
|
|
|
+```
|
|
|
+
|
|
|
+接下来,我们继承 `BaseLLM` 接口,创建一个具体的、可以和任何兼容OpenAI接口的服务进行通信的客户端。
|
|
|
+
|
|
|
+这个类主要负责以下三项任务:
|
|
|
+
|
|
|
+1. **初始化 (`init`)**: 实例化时,接收API密钥、服务地址和模型名称作为参数,并使用这些信息配置底层的 `openai` 客户端。
|
|
|
+2. **生成文本 (`generate`)**: 封装了调用LLM的核心逻辑。它接收一个提示(prompt),构建符合API规范的消息结构,发送请求,然后解析并返回模型生成的文本。
|
|
|
+3. **错误处理**: 使用 `try...except` 结构来捕获执行过程中可能出现的网络或API异常,以增强程序的鲁棒性。
|
|
|
+
|
|
|
+```Python
|
|
|
+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` 函数的逻辑如下:
|
|
|
+
|
|
|
+1. 接收一个查询字符串(query)作为参数。
|
|
|
+2. 通过 `ddgs` 库向DuckDuckGo搜索引擎发起查询。
|
|
|
+3. 通过 `region='cn-zh'` 参数,建议搜索引擎返回与中文区域更相关的结果。
|
|
|
+4. 解析返回结果,提取每条内容的文本摘要(snippet),并将其组织成一个列表返回。
|
|
|
+
|
|
|
+```Python
|
|
|
+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` 扮演了主控流程的角色,负责协调各个模块。该流程遵循了经典的“思考-行动-观察”循环,这也是许多智能体系统的核心工作范式。
|
|
|
+
|
|
|
+```Python
|
|
|
+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)
|
|
|
+```
|
|
|
+
|
|
|
+最后,程序的入口部分需要进行以下处理:
|
|
|
+
|
|
|
+1. **配置**: 定义与LLM API通信所需的凭证,如API密钥、服务URL和模型标识符。
|
|
|
+2. **实例化**: 根据配置信息,创建 `OpenAICompatibleClient` 的实例。
|
|
|
+3. **启动**: 调用 `information_retrieval_agent` 函数,传入一个示例问题以演示智能体的工作流程。
|
|
|
+4. **交互**: 提供一个命令行输入接口,允许用户提交自定义问题,与智能体进行交互。
|
|
|
+
|
|
|
+```Python
|
|
|
+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年代起逐渐发展,成为一种重要的分布式计算技术和复杂系统分析与模拟的方法。多智能体系统不仅在计算机科学和人工智能领域发挥着重要作用,还在解决分离的智能体和单层系统
|
|
|
+难以处理的复杂问题上展现出显著优势。通过多个智能体之间的协作与协调,多智能体系统能够提升整体性能和鲁棒性。
|
|
|
+==================================================
|
|
|
+```
|
|
|
+
|
|
|
+至此,一个功能完整的网络信息检索智能体就构建完成了。
|
|
|
+
|
|
|
+### 1.2.5 智能体应用的协作模式
|
|
|
+
|
|
|
+上一节,我们通过亲手构建一个智能体,深入理解了其内部的运作循环。不过在更广泛的应用场景中,我们的角色正越来越多地转变为使用者与协作者。基于智能体在任务中的角色和自主性程度,其协作模式主要分为两种:一种是作为高效工具,深度融入我们的工作流;另一种则是作为自主的协作者,与其他智能体协作完成复杂目标。
|
|
|
+
|
|
|
+本节将探讨这两种交互模式,通过具体案例,展示我们如何与LLM的智能体的构建者”,转变为其“用户”、“伙伴”乃至“管理者”。
|
|
|
+
|
|
|
+**(1)作为开发者工具的智能体**
|
|
|
+
|
|
|
+在这种模式下,智能体被深度集成到开发者的工作流中,作为一种强大的辅助工具。它增强而非取代开发者的角色,通过自动化处理繁琐、重复的任务,让开发者能更专注于创造性的核心工作。这种人机协同的方式,极大地提升了软件开发的效率与质量。
|
|
|
+
|
|
|
+目前,市场上涌现了多款优秀的AI编程辅助工具,它们虽然均能提升开发效率,但在实现路径和功能侧重上各有千秋:
|
|
|
+
|
|
|
+- **GitHubCopilot**: 作为该领域最具影响力的产品之一,Copilot 由 GitHub 与 OpenAI 联合开发。它深度集成于 Visual Studio Code等主流编辑器中,以其强大的代码自动补全能力而闻名。开发者在编写代码时,Copilot 能实时提供整行甚至整个函数块的建议。近年来,它也通过 Copilot Chat 扩展了对话式编程的能力,允许开发者在编辑器内通过聊天解决编程问题。
|
|
|
+- **Tabnine:** Tabnine 是另一款广受欢迎的代码补全工具。它的一个显著特点是支持在本地环境中运行模型,这对于注重代码隐私和安全的企业来说具有很强的吸引力。Tabnine 同样能够学习特定代码库的模式和风格,从而提供更加个性化和贴合项目规范的代码建议。
|
|
|
+- **Codeium**: Codeium 作为一个强劲的竞争者而备受关注,它以惊人的速度和个人免费版迅速获得了大量用户。Codeium 在代码补全速度上表现优异,并且支持广泛的编辑器。除了代码补全,它也提供了对话式的聊天功能,使其成为 GitHub Copilot 的替代品,尤其受到独立开发者和对成本敏感的用户的青睐。
|
|
|
+- **Cursor**: 与上述主要作为插件或集成功能存在的工具不同,Cursor 则选择了一条更具整合性的路径,它本身就是一个AI原生的代码编辑器。它并非在现有编辑器上增加AI功能,而是在设计之初就将AI交互作为核心。除了具备顶级的代码生成和聊天能力外,它更强调让AI理解整个代码库的上下文,从而实现更深层次的问答、重构和调试。
|
|
|
+
|
|
|
+当然还有许多优秀的工具没有例举,为了更具体地展示此类工具如何与开发者进行日常协同,我们将选择 Cursor 作为使用案例。因为它编辑器即智能体的设计理念,能完整地体现AI作为开发者工具的交互模式。下面,我们将通过几个常见的开发场景,展示如何与Cursor这样的工具型智能体进行协作。
|
|
|
+
|
|
|
+**场景一:快速生成代码,从零到一创建一个“贪吃蛇”游戏。**
|
|
|
+
|
|
|
+本场景将演示如何利用 Cursor 从一个完全空白的项目开始,通过一次综合性的自然语言指令,生成一个包含多个文件的完整网页应用。我们的目标是创建一个经典的“贪吃蛇”游戏,以此展示 AI 在项目启动阶段快速生成原型代码的能力。
|
|
|
+
|
|
|
+整个操作流程非常高效。首先,在 Cursor 编辑器中创建一个空项目,并预先建立三个核心文件:`index.html` 用于定义网页结构,`style.css` 用于控制界面样式,`script.js` 用于实现游戏逻辑。这一步是为了给 AI 提供一个明确的操作目标和上下文环境。
|
|
|
+
|
|
|
+接下来是关键的指令下达环节。在聊天侧边栏中,我们首先使用 `@` 符号将这三个文件全部引用,确保 AI 能够理解这是一个多文件协作的项目。随后,我们输入一段详细描述需求的指令,将任务清晰地分配给每个文件:
|
|
|
+
|
|
|
+```Plain
|
|
|
+# Prompt
|
|
|
+@index.html @style.css @script.js
|
|
|
+你好,请帮我创建一个经典版的“贪吃蛇”网页游戏。
|
|
|
+在 index.html 中,设置好基本的HTML结构,包含一个游戏画布(canvas)和一个显示分数的元素。
|
|
|
+在 style.css 中,为游戏界面添加一些简单的样式,比如让画布居中,设置一个深色的背景。
|
|
|
+在 script.js 中,实现游戏的全部逻辑: 绘制游戏区域、蛇和食物。 通过键盘的上下左右箭头控制蛇的移动方向。 实现蛇吃到食物后身体变长、分数增加的逻辑。 处理游戏结束的条件(撞到墙壁或自己)。 包含一个重新开始游戏的功能。
|
|
|
+```
|
|
|
+
|
|
|
+Cursor 接收到指令后,会立即分析需求,并同时为这三个文件生成对应的代码。它不会直接覆写文件,而是在聊天窗口中以代码差异的形式,清晰地展示将要应用的全部修改,如图 1.7 所示。这为开发者提供了一个审查和确认的环节。在确认 AI 的方案无误后,只需点击视为接受的按钮,所有代码就会被自动、准确地写入对应的文件中。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-8.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.7 Cursor界面展示了AI为三个文件生成的代码</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+最终,我们得到了一个功能完备、可直接在浏览器中运行的“贪吃蛇”游戏,如图 1.8 所示。这个过程将传统开发中需要数小时的手动编码工作,压缩为一次与 AI 的自然语言交互,极大地提升了从概念到可运行原型的开发效率。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-9.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.8 贪吃蛇游戏运行界面</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+**场景二:理解与重构现有代码,优化一个复杂的函数。**
|
|
|
+
|
|
|
+软件开发不仅仅是创造新功能,更多的时候是在维护和优化已有的代码。随着项目迭代,我们经常会遇到一些“代码坏味道”,其中最常见的就是逻辑臃肿、职责不清的全能函数。本场景将演示如何利用 Cursor,将一个难以维护的复杂函数,优雅地重构为清晰、模块化的代码。
|
|
|
+
|
|
|
+假设我们在一个电商项目的代码库中,遇到了一个名为 `processOrder` 的函数。这个函数最初可能很简单,但随着业务逻辑的增加(如添加优惠券、模拟支付、更新库存等),它逐渐膨胀到上百行,将订单处理的所有步骤都混合在一起。
|
|
|
+
|
|
|
+这样的函数存在明显的问题:
|
|
|
+
|
|
|
+- **难以阅读:** 任何开发者想理解完整的订单流程,都必须从头到尾阅读整个函数。
|
|
|
+- **难以修改:** 如果只想修改库存更新的逻辑,也必须小心翼翼地在庞大的函数体中寻找目标代码,稍有不慎就可能影响到支付或验证等其他环节。
|
|
|
+- **难以测试:** 无法对验证、计价、支付等子任务进行独立的单元测试。
|
|
|
+
|
|
|
+以下是这个函数的原始代码 (order.js),它是一个典型的需要重构的对象:
|
|
|
+
|
|
|
+```JavaScript
|
|
|
+// 一个难以维护的函数
|
|
|
+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` 函数体。然后,在选中的代码上方激活内联聊天框。在这里,我们输入一条重构指令:
|
|
|
+
|
|
|
+```Plain
|
|
|
+# Prompt
|
|
|
+
|
|
|
+“请将这个函数重构。把验证、计算总价、处理支付、更新库存和发送邮件这几个步骤,分别拆分成独立的、职责单一的私有函数。同时为每个新函数添加清晰的JSDoc注释。”
|
|
|
+```
|
|
|
+
|
|
|
+Cursor 的 AI 会立刻理解你的意图,分析函数内部的逻辑块,并生成重构方案。它不会直接修改你的代码,而是提供一个清晰的差异对比预览。如图1.9所示,你可以清楚地看到哪些代码被移除(红色),哪些是新增的(绿色),确保所有改动都在你的掌控之中。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-10.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.9 Cursor界面展示函数代码重构过程</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+确认方案后,点击确认接受的按钮,重构便即刻完成。原来的函数被一个清晰的主流程函数和多个职责单一的辅助函数所取代。最终,我们没有手动修改一行代码。通过一条自然语言指令,一个臃肿的函数就被重构了。重构后的 `processOrder` 函数本身变得极为简洁,其代码几乎就像是业务流程的伪代码,清晰地描述了处理订单的每一个步骤。而每个具体的步骤则被封装在独立的、命名清晰的私有函数中,它们易于理解、易于独立测试,也更易于未来的维护和扩展。这充分展示了 AI 在代码理解和重构方面的强大能力,使其成为提升现有代码库质量的得力助手。
|
|
|
+
|
|
|
+**场景三:辅助调试,快速定位并修复运行时错误。**
|
|
|
+
|
|
|
+调试是软件开发中不可或缺的一环,但有时排查一个看似简单的运行时错误也可能耗费大量时间。本场景将展示当程序抛出错误时,如何利用 Cursor 快速理解错误原因、定位问题,并获得高质量的修复方案,从而显著提高调试效率。
|
|
|
+
|
|
|
+假设我们正在开发一个简单的用户信息展示功能。代码逻辑很简单:获取一个 DOM 元素,然后将用户信息填充进去。然而,在浏览器中运行时,程序并未如期执行,反而在控制台抛出了一个常见的 `TypeError`。下面是存在问题的代码 (app.js):
|
|
|
+
|
|
|
+```JavaScript
|
|
|
+function displayUserGreeting(user) {
|
|
|
+ // 尝试获取ID为 'greeting' 的元素
|
|
|
+ const greetingElement = document.getElementById('greeting');
|
|
|
+
|
|
|
+ // 如果用户存在,就显示欢迎信息
|
|
|
+ if (user) {
|
|
|
+ greetingElement.textContent = `你好, ${user.name}!`;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 模拟获取用户信息
|
|
|
+const currentUser = { name: "Alice" };
|
|
|
+displayUserGreeting(currentUser);
|
|
|
+```
|
|
|
+
|
|
|
+在浏览器开发者工具的控制台中,我们看到了如下截图所示的错误信息,它明确指出了错误类型和发生位置:
|
|
|
+
|
|
|
+```JavaScript
|
|
|
+Uncaught TypeError: Cannot set properties of null (setting 'textContent')
|
|
|
+```
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-11.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.10 Cursor开发程序报错提示</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+如图1.10所示,程序试图为一个值为 `null` 的东西设置 `textContent` 属性,这在 JavaScript 中是不允许的。Cursor 提供了一种更直接的调试方式。我们只需将控制台的完整错误信息复制到剪贴板,然后在 Cursor 的聊天侧边栏中,`@` 引用相关的代码文件并发起提问:
|
|
|
+
|
|
|
+```JavaScript
|
|
|
+# prompt
|
|
|
+@app.js 我的程序报了下面这个错误,请帮我分析一下原因,并告诉我如何修复它。 Uncaught TypeError: Cannot set properties of null (setting 'textContent')
|
|
|
+```
|
|
|
+
|
|
|
+Cursor 会结合错误信息和 `app.js` 的源代码进行综合分析,迅速给出诊断和解决方案。它不仅会解释发生了什么,还会深入说明为什么会发生,并提供一段可以直接应用的、更健壮的代码。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-12.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.11 Cursor开发程序报错提示</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+如图1.11所示,通过一次简单的“复制-粘贴-提问”,我们完成了传统调试中多个步骤才能完成的工作。我们不仅立刻明白了错误的根本原因(HTML 结构与 JavaScript 脚本不匹配),还直接获得了一段经过优化的修复代码。这段新代码通过增加一个前置检查,提高了程序的容错性,能够有效避免未来同类错误的发生。
|
|
|
+
|
|
|
+**(2)作为自主协作者的智能体**
|
|
|
+
|
|
|
+与作为工具辅助人类不同,第二种交互模式将智能体的自动化程度提升到了一个全新的层次,自主协作者。在这种模式下,我们不再是手把手地指导AI完成每一步,而是将一个高层级的目标委托给它。智能体会像一个真正的项目成员一样,独立地进行规划、推理、执行和反思,直到最终交付成果。这种从助手到协作者的转变,使得LLM智能体更深的进入了大众的视野。它标志着我们与AI的关系从“命令-执行”演变为“目标-委托”。智能体不再是被动的工具,而是主动的目标追求者。
|
|
|
+
|
|
|
+当前,实现这种自主协作的思路百花齐放,涌现了大量优秀的框架和产品,如BabyAGI、AutoGPT、CrewAI、AutoGen等。它们虽然在具体实现上各有侧重,但其核心思想都是赋予AI更大程度的自主权。为了清晰地展示这一领域的关键思想脉络,我们将选取三个具有里程碑意义的案例进行介绍。它们分别代表了三种截然不同的架构范式:
|
|
|
+
|
|
|
+1. **AgentGPT**:它是一个典型的单智能体、递归循环的范例。其核心在于一个强大的通用智能体通过“思考-规划-行动”的闭环,不断自我提示,以完成一个开放式的高层级目标。
|
|
|
+2. **CAMEL**:它引入了双智能体、角色扮演的协作框架。通过为两个智能体(一个“任务规划者”和一个“任务执行者”)设定明确的角色和沟通协议,让它们在一个结构化的对话中协同完成任务。
|
|
|
+3. **Manus AI**:这是一个多智能体、多模型的集成系统,模拟了一个真实的企业部门或专家团队。它内部包含多个各司其职的专业子智能体(如规划、研究、执行、验证),它们并行协作,共同完成一个复杂的端到端任务。
|
|
|
+
|
|
|
+接下来,我们将通过具体的案例,逐一剖析这三种自主协作模式的技术特点。
|
|
|
+
|
|
|
+**案例一:AgentGPT**
|
|
|
+
|
|
|
+AgentGPT是最早引发大众对自主智能体广泛关注的开源项目之一。其核心机制在于一个强大的通用智能体,通过一个持续的“思考-规划-行动”闭环,不断地自我提示,以完成一个开放式的、高层级的目标。用户仅需提供一个最终目标,智能体便会自主地进行任务分解,然后利用各种工具(如网页搜索、文件读写、代码执行)去逐一完成子任务,并根据执行结果不断反思和调整后续计划。
|
|
|
+
|
|
|
+本场景将深入探讨这个智能体项目。与前面案例中通过单次、详尽指令完成任务的模式不同,AgentGPT的核心魅力在于其自主规划和持续迭代的能力。它模拟了一个拥有独立思考能力的“研究员”,仅需一个高层级的开放式目标,便能自主地启动一个持续的“思考-规划-行动-观察”闭环,直至达成最终目的。我们将通过一个经典的商业研究任务,来具象化AgentGPT是如何像一个不知疲倦的个体主义者一样,独立完成复杂项目的。
|
|
|
+
|
|
|
+假设我们将要在芝加哥市中心开设一家新的精品咖啡店并进行市场分析。项目成员就是AgentGPT。我们不需要为它制定详细的工作计划,只需要向AgentGPT下达一个不包含任何具体步骤的高层级指令。这比起“贪吃蛇”案例中需要明确告知每个文件具体做什么会简洁不少。
|
|
|
+
|
|
|
+```Plain
|
|
|
+# Prompt
|
|
|
+目标:为在芝加哥市中心开设一家新的精品咖啡店进行市场分析,并生成一份总结报告。
|
|
|
+```
|
|
|
+
|
|
|
+这句指令就是一次彻底的“委托”。提交之后,人类的角色便从“指挥官”转变为“观察者”。AgentGPT的内部循环被激活,一场自主的探索之旅就此展开。
|
|
|
+
|
|
|
+接收到目标后,AgentGPT并不会立即执行单一动作,而是首先进行一次全面的任务规划。它会将“为精品咖啡店进行市场分析”这个高层级目标,分解成一个详尽的任务列表。正如真实操作界面所示,它会生成一系列具体的子任务,如图1.12所示。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-13.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.12 AgentGPT运行过程</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+
|
|
|
+这个初始计划构成了它的行动蓝图。随后,AgentGPT会从列表的第一个任务开始,自主选择合适的工具(如网页搜索)来执行。这个发现并没有结束,反而成为了下一个行动的催化剂。这展现了AgentGPT作为自主智能体的核心优势:它无需人类提示下一步,便能根据已有信息自主规划并深化研究路径。它会继续这个循环,深挖竞争对手的优劣势、研究本地的消费趋势,并将所有收集到的信息,包括人口数据、竞争列表、消费热点等,自动写入一个文本文件中,作为它的工作笔记。整个过程就像一个不知疲倦的研究员,通过不断的自我对话和自我纠偏来逼近最终目标。当它判断信息足够支撑一份报告时,便会着手整合信息,最终生成一份结构化的分析文档。
|
|
|
+
|
|
|
+AgentGPT的实操过程淋漓尽致地展现了单智能体范式的力量。它拥有极高的自主性,能够将一个模糊的开放式目标,层层分解为具体、可执行的步骤,这在处理探索性任务时效率惊人。然而,这种个体主义的工作模式也并非完美。作为一个通用的思考者,它缺乏特定领域的深度知识。它能找到关于咖啡市场的数据,但它并不真正懂咖啡。因此,它的分析可能广度有余,而深度不足。
|
|
|
+
|
|
|
+更核心的缺陷在于其递归循环的脆弱性。这个不知疲倦的循环也可能使其陷入低效的自证陷阱,在某个不重要的细节上反复搜索,或因为一次错误的解读而导致后续所有步骤跑偏,消耗大量时间和计算资源。由于缺少一个批判者或是合作者的角色来审视其规划,它的策略完全依赖于自身的推理链。一旦最初的思路出现偏差,整个过程便可能走向错误的方向,而无人制止。
|
|
|
+
|
|
|
+总而言之,AgentGPT作为一个单智能体循环项目的典范,证明了“目标-委托”模式的可行性。它像一个能力全面的独立顾问,能独自处理复杂的项目。但它的成功和其固有的单打独斗的局限性,也自然而然地引出了下一个问题:如果一个智能体容易犯错,那么引入另一个智能体进行监督和协作,是否会更有效?这便是我们下一个案例,CAMEL的**角色扮演(Role-Playing)**协作范式。
|
|
|
+
|
|
|
+**案例二:CAMEL**
|
|
|
+
|
|
|
+如果说AgentGPT是一个独自完成所有工作的个体主义者,那么CAMEL框架则探索了截然不同的协作路径。通过精心设计的**初始提示(Inception Prompting)**技术,CAMEL为两个AI智能体分配了不同的角色,一个扮演“任务规划者”(AI User),另一个扮演“任务执行者”(AI Assistant),让它们在一个高度结构化的对话中,通过相互启发和协作来完成任务。这种方案模拟真实世界中专家之间的合作。规划者负责提出想法、需求和高层级的方向,而执行者则负责提供技术方案、实现细节和可行性分析。在一定程度上,它解决了单智能体容易陷入自我逻辑闭环、缺乏外部视角纠偏的问题。
|
|
|
+
|
|
|
+为了体验这种合作模式,我们设定一个需要金融领域知识和编程技术深度结合的任务:为股票市场开发一个交易机器人。在这个场景中,我们不再是向智能体下达一个开放式的目标,而是为其设定好分工明确的角色和初始任务,并观察这场自主的、结构化的设计讨论如何展开。
|
|
|
+
|
|
|
+```Plain
|
|
|
+# Prompt
|
|
|
+初始任务:为股票市场开发一个交易机器人。
|
|
|
+
|
|
|
+角色分配:
|
|
|
+- AI User (规划者): 股票交易员 (Stock Trader)
|
|
|
+- AI Assistant (执行者): Python 程序员 (Python Programmer)
|
|
|
+```
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-14.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.13 CAMEL框架执行任务过程</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+如图1.13所示,这场对话会持续进行下去,遵循“提出方案-确认实现”的节奏,不断深化交易机器人的功能,从风险管理、回测系统,到与其他API的集成。规划者(股票交易员)始终聚焦于交易策略,而执行者(Python程序员)则专注于技术实现。当股票交易员认为机器人的核心功能已经足够完善时,它会发出一个特殊的终止指令`<CAMEL_TASK_DONE>`,整个协作过程便随之结束。最终的产出是一套功能明确的交易机器人原型代码。
|
|
|
+
|
|
|
+CAMEL的协作模式通过角色分工,它有效地避免了单智能体在专业深度上的不足。规划者和执行者各自专注于自己擅长的领域,使得最终方案在交易策略和技术可行性上都得到了保障。然而,这种模式的成功高度依赖于初始角色的设定。如果角色定义不清晰或不恰当,整个对话可能会变得低效甚至无效。此外,但它在处理极其开放、模糊的任务方面可能存在局限。不过总的来说,CAMEL为我们展示了一种通过分工与合作来提升AI能力的有效途径。这自然也引出了更进一步的思考:如果两个智能体的合作就能如此高效,那么一个模拟真实团队、拥有多个不同角色的多智能体系统,又将释放出怎样的潜力呢?Manus AI为我们提供了一种可行途径。
|
|
|
+
|
|
|
+**案例三:Manus AI**
|
|
|
+
|
|
|
+如果说AgentGPT是一个个体工作者,CAMEL是一个两人小组,那么Manus AI则代表了更高层次的组织形式:一个集成的、产品化的虚拟团队。它不再仅仅是一个开源框架或实验性项目,而是一个旨在交付完整、可用最终产品的自主系统。通过编排一个由多个各司职职的专业子智能体(如规划、研究、执行、验证)组成的团队,来处理复杂的端到端任务。用户只需提出一个高层级的需求,Manus AI就能像一个项目团队一样,在云端异步执行所有步骤,并最终交付一个成品,而非仅仅是文本或代码。
|
|
|
+
|
|
|
+为了充分展现其团队协作和项目交付能力,我们设定一个比单一网页更复杂的任务:创建一个名为“Pixel Demo”的在线迷你游戏网站。这个任务需要并行开发多个独立的游戏模块,并将其整合到一个统一的门户页面中。
|
|
|
+
|
|
|
+```Plain
|
|
|
+# Prompt
|
|
|
+创建一个名为“Pixel Demo”的在线迷你游戏网站。要求:
|
|
|
+- 风格:复古像素风。
|
|
|
+- 门户页面 (index.html): 包含网站标题和一个用于展示所有游戏的网格布局。
|
|
|
+- 游戏模块:
|
|
|
+ 1. 井字棋 (Tic-Tac-Toe)
|
|
|
+ 2. 贪吃蛇 (Snake)
|
|
|
+- 交付物:一个包含所有HTML, CSS, 和JavaScript文件的可运行项目压缩包。
|
|
|
+```
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-15.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.14 Manus AI执行任务过程</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+Manus AI接收到任务后,其内部的虚拟团队便开始了高效的协同工作。如图1.14所示,这远比线性的单智能体或双智能体对话要复杂。其内部的规划智能体首先像项目经理一样,将任务分解为清晰的项目蓝图。随后多个执行智能体像开发团队一样并行工作,分别处理门户页面、全局样式和各个独立的游戏模块,在验证智能体进行代码审查和功能测试后,交付智能体最终会将所有文件打包。最终产出的,便是一个可以直接解压部署的完整项目,如图1.15的“PIXEL DEMO”项目实况所示,一个结构完整、功能可用的多页面网站。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-16.png" alt="图片描述" width="90%"/>
|
|
|
+ <p>图 1.15 PIXEL DEMO项目实况展示</p>
|
|
|
+</div>
|
|
|
+
|
|
|
+Manus AI所代表的多智能体范式,其优势是显然的。它实现了从“生成内容”到“交付产品”的跨越,通过并行化处理,其开发效率远超单智能体或双智能体模式。然而,这种能力的背后是极高的编排复杂性。如何有效地管理和协调多个智能体、处理它们之间的依赖关系仍是一种巨大的技术挑战,并且整个过程对用户来说可能像一个黑箱。
|
|
|
+
|
|
|
+从AgentGPT的单智能体循环,到CAMEL的双智能体协作,再到Manus AI的多智能体交互,我们清晰地看到了自主智能体从简单工具向**代理式人工智能(Agentic AI)**演进的技术脉络。每一种范式都在尝试解决前一种的局限,共同推动着我们与AI协作的边界。
|
|
|
+
|
|
|
+## 1.3 多智能体系统简介
|
|
|
+
|
|
|
+### 1.3.1 从个体到协作
|
|
|
+
|
|
|
+当任务的复杂性超越单个计算实体的能力上限时,分布式协作便成为一种必要的架构选择。在探索人工智能的初期,我们很容易被一个宏大的愿景所吸引:创造一个无所不知、无所不能的**通用人工智能(Artificial General Intelligence)**。然而,当尝试将当前智能体技术应用于真实世界的复杂场景时,全能个体的理想便会遭遇一系列现实挑战。单个通用智能体在应对真实世界的复杂问题时,会遭遇其单体架构带来的一系列挑战:
|
|
|
+
|
|
|
+1. **专业深度的瓶颈** 真实世界的问题往往需要跨领域的深度知识。期望单个智能体同时具备多个领域(如软件工程、市场分析、创意设计)的顶尖专家能力,是不切实际的。这种单一实体承担所有角色的做法,其分析结果往往广度有余,深度不足。
|
|
|
+2. **信息获取的局限** 在分布式系统中,任何单一实体都只能拥有**局部视野(Local View)**,难以掌握全局的、实时的完整信息。例如,一个优化城市交通的智能体,无法瞬间获知每辆车的位置和每个信号灯的状态。基于不完整或延迟的信息进行决策,往往导致结果是次优解。
|
|
|
+3. **系统鲁棒性的脆弱** 单智能体的推理链较为脆弱。如果它在早期阶段做出一个错误的假设,后续所有规划都将建立在这个错误之上。由于缺乏外部的校验和修正机制,它**难以从早期错误中恢复**,可能因单点失败而导致整个任务的崩溃。
|
|
|
+4. **扩展与效率的挑战** 单体架构在可扩展性与效率方面也面临瓶颈。为一个庞大的单体智能体增加新功能,可能需要对核心架构进行复杂的修改。在效率上,它也只能线性处理任务。而通过将任务分解给多个并行的智能体(如Manus AI项目所展示的),则可以实现并行处理,极大提升复杂项目的执行效率。
|
|
|
+
|
|
|
+这些局限性共同指向一个核心问题:试图用中心化的单体架构,去解决本质上分布式、异构的现实世界问题,存在着根本性的错配。**多智能体系统(Multi-Agent System, MAS)**正是为应对这一挑战而生的计算范式。
|
|
|
+
|
|
|
+在学术界,MAS被定义为:一个由多个交互的、自主的智能体组成的计算系统,它们位于共享环境中,通过协作解决单个智能体难以完成的复杂问题。该系统由三个核心要素构成:**智能体(Agent)、环境(Environment)和交互(Interaction)**。鉴于前两部分已有探讨,本节的后续内容将聚焦于MAS的交互,并分析其通信、任务分配与协调策略。更多详细的多智能体介绍将会安排在后面的章节中。
|
|
|
+
|
|
|
+### 1.3.2 多智能体系统的交互机制
|
|
|
+
|
|
|
+本节通过一个具体案例(“为咖啡馆创建网站”)来阐述多智能体交互的三个核心机制:任务规划、通信与协作。
|
|
|
+
|
|
|
+1. 任务规划
|
|
|
+
|
|
|
+多智能体系统的首要步骤是将一个高层级目标映射为可执行的计划。该过程包括任务分解和角色分配。例如,一个“项目经理”智能体接收到初始目标后,其内部生成的规划(`Thought`)如下:
|
|
|
+
|
|
|
+```JSON
|
|
|
+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`.
|
|
|
+```
|
|
|
+
|
|
|
+该规划将高层级目标转化为了结构化的子任务和明确的角色分工。
|
|
|
+
|
|
|
+1. 通信机制
|
|
|
+
|
|
|
+规划完成后,各智能体需通过结构化的通信协议交换信息。`项目经理`依据其规划,生成一条 JSON 格式的消息,用于任务分派:
|
|
|
+
|
|
|
+```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. 协作策略
|
|
|
+
|
|
|
+协作策略定义了智能体间的工作流与依赖关系。在集中式协调中,存在一个编排者节点,负责任务分发与状态监控。其交互流程如下所示:
|
|
|
+
|
|
|
+```JSON
|
|
|
+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]
|
|
|
+```
|
|
|
+
|
|
|
+该模式下,`项目经理`是控制中心。而在分布式协调中,各智能体节点对等,通过协商来确定行动顺序与资源分配,无需中心节点介入。通过任务规划定义“做什么”,通过通信明确“怎么说”,再通过协作策略管理“如何做”,一个完整的多智能体交互流程便形成了闭环,使一群独立的智能体能够作为一个有凝聚力的整体,共同完成复杂的目标。
|
|
|
+
|
|
|
+### 1.3.3 多智能体系统的演进
|
|
|
+
|
|
|
+早在深度学习革命之前,多智能体系统的主流范式是基于符号主义AI构建的。这一时期的智能体,其智能源于人类专家编码的知识库和推理规则。它们是典型的**基于知识的系统(Knowledge-Based System)**,通过审议式推理(Deliberative Reasoning)进行决策。智能体之间则采用高度形式化的智能体通信语言(ACL)和协调协议(如模拟商业招标的合同网协议)进行交互,确保了通信的精确性和行为的可预测性。不过缺点也比较明显,即为智能体手动构建知识库成本极高(即知识工程瓶颈),且系统面对规则之外的未知情况时表现得非常脆弱。
|
|
|
+
|
|
|
+大语言模型的出现,从根本上重塑了多智能体系统,突破了传统范式的核心瓶颈。
|
|
|
+
|
|
|
+- **从显式知识库到隐式知识库**:LLM通过预训练内化了海量的世界知识,取代了需要手动构建的规则和事实,极大地降低了构建专业智能体的门槛。开发者只需通过**提示工程(Prompt Engineering)**即可“唤醒”其相应能力。
|
|
|
+- **从形式化语言到自然语言交互**:LLM使智能体能以自然语言为主要交互媒介,同时辅以JSON等结构化数据确保参数精确。这极大地提升了交互的灵活性和表现力,也便于人类的理解和介入。
|
|
|
+- **从逻辑匹配到生成式推理**:面对未知情况,LLM能够进行创造性的推理和规划,展现出强大的泛化能力,克服了传统符号系统的脆弱性。
|
|
|
+- **从静态角色到动态角色**:定义一个新角色,对LLM而言可能只是更换一段**系统提示(System Prompt)**,这为构建特质化的智能体团队提供了前所未有的便利。
|
|
|
+
|
|
|
+不过将基于LLM的新范式与传统的符号型范式完全对立起来,是一种过于简化的视角。LLM的出现并非宣告了符号主义的终结,恰恰相反,它为解决符号主义的固有瓶颈提供了新的工具,也让两种范式的融合成为可能。要理解这一点,我们首先需要对二者进行一个直观的对比,如表1.3所示。
|
|
|
+
|
|
|
+<div align="center">
|
|
|
+ <p>表 1.3 符号型与LLM驱动的多智能体系统对比</p>
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/hl-mas/main/docs/images/1-figures/1757242319666-17.png" alt="图片描述" width="90%"/>
|
|
|
+</div>
|
|
|
+
|
|
|
+综上,LLM的融入并非局部改良,而是一场范式革命。它将多智能体系统从一个需要被精确编程的、基于知识的系统,转变为一个可通过自然语言引导的、基于能力的通用问题解决器。
|
|
|
+
|
|
|
+但这并非简单的线性替代,而是一个螺旋上升的融合过程。新旧范式在能力上形成了鲜明的互补:符号主义的严谨、精确、可解释,恰好能弥补LLM的灵活性有余而可靠性不足(如“幻觉”问题)。因此,未来的前沿方向,很可能就是将LLM的归纳推理能力与符号系统的演绎推理能力深度结合,例如让LLM负责生成初步方案,再由符号系统进行严格的验证和约束。通过这种融合,在创造力与精确性、灵活性与可靠性之间取得更好的平衡,从而构建出更值得信赖的多智能体系统。
|
|
|
+
|
|
|
+## 1.4 本章小结
|
|
|
+
|
|
|
+在本章中,我们共同踏上了探索智能体的初识之旅。我们的旅程从最基本的问题开始:
|
|
|
+
|
|
|
+- **什么是智能体?** 我们首先回顾了其在传统计算机科学中的定义,随后将焦点转向了由大语言模型驱动的智能体,理解了现代智能体所具备的感知、推理与行动能力。
|
|
|
+- **智能体如何分类?** 我们从内部决策架构、时间反应性以及知识表示等多个维度,对智能体进行了系统的分类。这为我们理解不同智能体的特性和适用场景打下了坚实的基础。
|
|
|
+- **智能体如何工作?** 我们深入探讨了智能体与环境交互的核心机制,行动循环。通过“感知-规划-行动-学习”的闭环,智能体得以在复杂的环境中完成任务。结合AgentGPT等真实案例,可以直观地看到了智能体在不同场景和不同设计模式下的具体体现。
|
|
|
+- **智能体如何协作?** 最后,我们将视野从单个智能体扩展到了由多个智能体组成的多智能体系统。不仅探讨了其协作的核心要素(如通信、任务分配与协调),还讲述了多智能体系统的演进过程。
|
|
|
+
|
|
|
+通过本章的学习,我们建立了一个关于智能体的基础认知框架:**从单个智能体的定义与分类,到其与环境的交互,再到多智能体系统的协作模式**。那么,它是如何一步步从最初的构想演进至今的呢?在下一章中,我们将探索智能体的发展历史,一段追本溯源的旅程即将开始!
|
|
|
+
|
|
|
+## 参考文献
|
|
|
+
|
|
|
+[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.
|