智能体的定义 Perception & Action
在AI领域中的智能体:我们希望LLM不再局限于有问必答的问答工具,而是成为一个能自主规划、调用工具、解决复杂问题的“行动者”。
智能体的演变可以从简单到复杂:
最简单的反射智能体:例如空调,决策核心由工程师明确设计的“条件-动作 ”规则(Condition & Action)构成。被动感知温度,进行制冷行动。
基于模型的反射智能体:例如智驾汽车,即便看不到路况,内部也会维护速度状态模型。
基于目的的反射智能体:例如GPS导航, 主动 规划(Planning)出一条最优路径
学习型智能体:强化学习概念的具体落地,比如AlphaGo下棋。一个学习型智能体包括性能元件(上面的几种简单智能体)和学习元件。这个学习元件会观测性能元件在环境中的行动所带来的结果 来不断修正性能元件的决策策略。
所以简单来说,现阶段我们的研发需求正从 开发专用应用软件工具 转为 构建能够自主解决问题的系统 。我们希望通过引导一个全能的大脑进行规划、行动和学习。
智能体的分类 基于时间和反应性的分类 反应式智能体 典型代表就是驾驶系统、安全气囊系统。
这类智能体的优点是反应迅速开销低,缺点是短视无法规划,容易陷入局部最优 ,难以完成需要多步骤协调的复杂任务。
规划式智能体 典型代表就是AlphaGo机器人和导航。优点是能够规划任务有远见,缺点是耗时久开销大。
混合式智能体 也就是现代LLM智能体的通用折衷解决方案。
其核心执行机制是 思考——行动——观察 的循环。
Thought —— Action —— Observation
思考reasoning就是规划, LLM 分析当前状况,规划出下一步的合理行动。这是一个审议过程。
而行动Action&Observe阶段,智能体则是通过调用工具/接口、对外部环境做出实时反应。
通过规划和反应循环来完成复杂任务。
基于知识表示的分类 在这个分类中,我们想要知道, 智能体用以决策的知识,究竟是以何种形式存于其“思想”之中。
也就是说,智能 到底源自哪里 ?
符号主义AI(Symbolic AI) 符号主义AI 坚持智能源于对符号的逻辑操作 。这里的符号是人类可读的实体(如词语、概念),操作则遵循严格的逻辑规则。
比如:学习 猫有四条腿、毛茸茸、会喵喵叫,这就是符号主义中的一种规则 。
在这种模式下, “智能 “依赖于一个完备的规则体系。
但在充满模糊和例外的现实世界中,任何未被覆盖的新情况都可能导致系统失灵,这就是所谓的“知识获取瓶颈”。
亚符号主义AI(Sub-symbolic AI) 亚符号主义AI认为知识并非显式的规则,而是内隐地分布在一个由大量神经元组成的复杂网络中,是从海量数据中学习到的统计模式 。神经网络和深度学习 是其代表。
例如:在看过成千上万张猫的图片后,大脑中的神经网络 能辨识出“猫”这个概念的视觉模式。
这种方法的强大之处在于其模式识别能力和对噪声数据的鲁棒性 。它能够轻松处理图像、声音等非结构化数据 ,这在符号主义 AI 看来是极其困难的任务。
神经符号主义AI(Neuro-Symbolic AI) 符号主义AI严格遵守周围环境的体系规则,优点是可读可结构化,但是缺点是在变幻莫测的环境中容易出现知识获取瓶颈。
而亚符号主义AI则是另一面,是基于海量数据学习的统计模式。能够轻松处理非结构化数据但是也伴随着不透明性。亚符号主义系统通常被视为一个黑箱(Black Box) 。它能以惊人的准确率识别出图片中的猫,但你若问它“为什么你认为这是猫?”,它很可能无法给出一个合乎逻辑的解释。此外,它在纯粹的逻辑推理任务上表现不佳,有时会产生看似合理却事实错误的幻觉 。
那么有没有一种方式能够兼具二者之长呢?在计算机科学领域,最经典的折中思想又一次得到运用:神经符号主义AI
神经符号主义AI 融合两大范式的优点,兼具二者之长。创造出一个既能像神经网络一样从数据中学习、提升直觉 ,又能像符号系统一样掌握规则进行逻辑推理 的混合智能体。
神经符号主义AI 试图弥合感知与认知 、直觉与理性 之间的鸿沟。
在著作《思考,快与慢》(Thinking, Fast and Slow)中提出的双系统理论也能够完美帮助我们理解将符号主义AI和亚符号主义AI结合的神经符号主义核心思想。
系统 1是快速、凭直觉、并行的思维模式,类似于亚符号主义 AI 强大的模式识别能力。
系统 2是缓慢、有条理、基于逻辑的审慎思维,恰如符号主义 AI 基于世界规则的严密推理过程。
智能体的构成与运行原理
智能体的运行机制:Agent Loop
Perception & Observation 感知与观察: 用户的初始指令 / 上一步行动所导致的环境状态变化反馈
Thought 思考:核心决策阶段, 通常是由LLM驱动的内部推理过程,具体可以再细分为
Planning: 将复杂目标分解为一系列更具体的子任务。
Tool Selection:根据当前计划,智能体从可用的工具库中,选择最适合执行下一步骤的工具,并确定调用该工具所需的具体参数。
Action 行动:执行具体行动,对环境施加影响, 意图改变环境的状态。
实验 这边我们使用python来快速搭建一个简单Agent Demo,主要的目的就是为了验证现代智能体的核心运行机制:Agent Loop:观察——思考——行动 这一循环。
Demo 的需求定位比较简单,我们希望通过自然语言询问AI,让AI给出某地的旅游经典推荐。
这是一个标准的工具&提示词工程的应用场景。也对应当下主流Agent框架中ReAct智能体范式核心设计思想。
01 - 定义 ReAct范式系统prompt,要求LLM严格遵守 Reasoning和Acting的流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 AGENT_SYSTEM_PROMPT = """ 你是一个智能旅行助手。你的任务是分析用户的请求,并使用可用工具一步步地解决问题。 # 可用工具: - `get_weather(city: str)`: 查询指定城市的实时天气。 - `get_attraction(city: str, weather: str)`: 根据城市和天气搜索推荐的旅游景点。 # 输出格式要求: 你的每次回复必须严格遵循以下格式,包含一对Thought和Action: Thought: [你的思考过程和下一步计划] Action: [你要执行的具体行动] Action的格式必须是以下之一: 1. 调用工具:function_name(arg_name="arg_value") 2. 结束任务:Finish[最终答案] # 重要提示: - 每次只输出一对Thought-Action - Action必须在同一行,不要换行 - 当收集到足够信息可以回答用户问题时,必须使用 Action: Finish[最终答案] 格式结束 请开始吧! """
02 - 声明工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 import requestsdef get_weather (city: str ) -> str : """ 通过调用 wttr.in API 查询真实的天气信息。 """ url = f"https://wttr.in/{city} ?format=j1" try : response = requests.get(url) response.raise_for_status() data = response.json() current_condition = data['current_condition' ][0 ] weather_desc = current_condition['weatherDesc' ][0 ]['value' ] temp_c = current_condition['temp_C' ] return f"{city} 当前天气:{weather_desc} ,气温{temp_c} 摄氏度" except requests.exceptions.RequestException as e: return f"错误:查询天气时遇到网络问题 - {e} " except (KeyError, IndexError) as e: return f"错误:解析天气数据失败,可能是城市名称无效 - {e} " import osfrom tavily import TavilyClientdef get_attraction (city: str , weather: str ) -> str : """ 根据城市和天气,使用Tavily Search API搜索并返回优化后的景点推荐。 """ api_key = os.environ.get("TAVILY_API_KEY" ) if not api_key: return "错误:未配置TAVILY_API_KEY。" tavily = TavilyClient(api_key=api_key) query = f"'{city} ' 在'{weather} '天气下最值得去的旅游景点推荐及理由" try : response = tavily.search(query=query, search_depth="basic" , include_answer=True ) if response.get("answer" ): return response["answer" ] formatted_results = [] for result in response.get("results" , []): formatted_results.append(f"- {result['title' ]} : {result['content' ]} " ) if not formatted_results: return "抱歉,没有找到相关的旅游景点推荐。" return "根据搜索,为您找到以下信息:\n" + "\n" .join(formatted_results) except Exception as e: return f"错误:执行Tavily搜索时出现问题 - {e} " available_tools = { "get_weather" : get_weather, "get_attraction" : get_attraction, }
03 - 配置LLM客户端并调用LLM,处理LLM返回的响应数据并更新会话历史,进入下一循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 from openai import OpenAIclass OpenAICompatibleClient : """ 一个用于调用任何兼容OpenAI接口的LLM服务的客户端。 """ def __init__ (self, model: str , api_key: str , base_url: str ): self.model = model self.client = OpenAI(api_key=api_key, base_url=base_url) def generate (self, prompt: str , system_prompt: str ) -> str : """调用LLM API来生成回应。""" print ("正在调用大语言模型..." ) try : messages = [ {'role' : 'system' , 'content' : system_prompt}, {'role' : 'user' , 'content' : prompt} ] 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 "错误:调用语言模型服务时出错。" import re API_KEY = "" BASE_URL = "" MODEL_ID = "" os.environ['TAVILY_API_KEY' ] = "" llm = OpenAICompatibleClient( model=MODEL_ID, api_key=API_KEY, base_url=BASE_URL ) user_prompt = "你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点。" prompt_history = [f"用户请求: {user_prompt} " ]print (f"用户输入: {user_prompt} \n" + "=" *40 )for i in range (5 ): print (f"--- 循环 {i+1 } ---\n" ) full_prompt = "\n" .join(prompt_history) llm_output = llm.generate(full_prompt, system_prompt=AGENT_SYSTEM_PROMPT) match = re.search(r'(Thought:.*?Action:.*?)(?=\n\s*(?:Thought:|Action:|Observation:)|\Z)' , llm_output, re.DOTALL) if match : truncated = match .group(1 ).strip() if truncated != llm_output.strip(): llm_output = truncated print ("已截断多余的 Thought-Action 对" ) print (f"模型输出:\n{llm_output} \n" ) prompt_history.append(llm_output) action_match = re.search(r"Action: (.*)" , llm_output, re.DOTALL) if not action_match: observation = "错误: 未能解析到 Action 字段。请确保你的回复严格遵循 'Thought: ... Action: ...' 的格式。" observation_str = f"Observation: {observation} " print (f"{observation_str} \n" + "=" *40 ) prompt_history.append(observation_str) continue action_str = action_match.group(1 ).strip() if action_str.startswith("Finish" ): final_answer = re.match (r"Finish\[(.*)\]" , action_str).group(1 ) print (f"任务完成,最终答案: {final_answer} " ) break tool_name = re.search(r"(\w+)\(" , action_str).group(1 ) args_str = re.search(r"\((.*)\)" , action_str).group(1 ) kwargs = dict (re.findall(r'(\w+)="([^"]*)"' , args_str)) if tool_name in available_tools: observation = available_tools[tool_name](**kwargs) else : observation = f"错误:未定义的工具 '{tool_name} '" observation_str = f"Observation: {observation} " print (f"{observation_str} \n" + "=" *40 ) prompt_history.append(observation_str)
运行我们的第一个Agent,可以看到结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 用户输入: 你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点。 ======================================== --- 循环 1 --- 正在调用大语言模型... 大语言模型响应成功。 模型输出: Thought: 用户要求查询北京今天的天气,然后根据天气推荐旅游景点。我需要先调用天气查询工具获取北京的实时天气信息。 Action: get_weather(city="北京") Observation: 北京当前天气:Light rain shower, mist,气温16摄氏度 ======================================== --- 循环 2 --- 正在调用大语言模型... 大语言模型响应成功。 已截断多余的 Thought-Action 对 模型输出: Thought: 已经获取到北京今天的天气信息:小雨、雾,气温16摄氏度。现在我需要根据这个天气情况来搜索适合的旅游景点。 Action: get_ attraction(city="北京", weather="Light rain shower, mist")Observation: 在北京下雨天,最值得去的景点是中国国家博物馆和什刹海,这里的景色在雨中更加迷人。 ======================================== --- 循环 3 --- 正在调用大语言模型... 大语言模型响应成功。 模型输出: Thought: 我已经获取到了北京今天的天气信息(小雨、雾,气温16摄氏度)以及根据天气推荐的旅游景点(中国国家博物馆和什刹海)。现在我有足够的信息来回答用户的问题,可以结束任务了。 Action: Finish[北京今天天气是小雨、雾,气温16摄氏度。根据这样的天气情况,推荐您去中国国家博物馆和什刹海,这两个景点在雨中景色更加迷人,是下雨天不错的选择。] 任务完成,最终答案: 北京今天天气是小雨、雾,气温16摄氏度。根据这样的天气情况,推荐您去中国国家博物馆和什刹海,这两个景点在雨中景色更加迷人,是下雨天不错的选择。
上门的例子展示了基于Thought-Action-Observation范式的智能体所具备的四项基本能力:任务分解、工具调用、上下文理解和结果合成。
通过这个循环的不断迭代,智能体才得以将一个模糊的用户意图,转化为一系列具体、可执行的步骤,并最终达成目标。
总结 什么是大语言模型驱动的智能体?
是让LLM成为不再局限于有问必答的问答工具,而是成为一个能自主规划、调用工具、解决现实复杂问题的“行动者”。
智能体是如何工作的?
通过感知处理环境信息,通过思考自主决策,通过行动影响环境并再次感知更新后的环境与预期目标的距离不断循环迭代向目标持续推进。
如何构建一个智能体?
本文中我们构建了一个简单的遵循ReAct范式的智能体,核心步骤是通过:系统提示词指定 、工具定义 、上下文历史管理 以及消息处理 这几部分来实现。
Workflow 和 Agent 的区别?
在于是否基于LLM自由度自主性。