初识智能体 Part 3:详解 Agent Loop 与 5 分钟手写智能体实战

在上篇中,我们完成了智能体的分类与环境定义的理论铺垫。本篇将进入核心机制——深入解构智能体的“感知-思考-行动”循环,并动手用 Python 从零构建一个真正的智能旅行助手。

1.2.2 智能体的运行机制

在定义了智能体所处的任务环境后,我们来探讨其核心的运行机制。智能体并非一次性完成任务,而是通过一个持续的循环与环境进行交互,这个核心机制被称为智能体循环 (Agent Loop)

该循环描述了智能体与环境之间的动态交互过程,构成了其自主行为的基础。

Agent

Thought

Action

Observation

Environment

State Change
状态改变

Perception
感知

Planning
规划

Tool Selection
工具选择

这个循环主要包含以下几个相互关联的阶段 :

  1. 感知 (Perception)
    这是循环的起点。智能体通过其传感器(例如,API 的监听端口、用户输入接口)接收来自环境的输入信息。
    这些信息即观察 (Observation),既可以是用户的初始指令,也可以是上一步行动所导致的环境状态变化反馈。

  2. 思考 (Thought)
    接收到观察信息后,智能体进入其核心决策阶段。对于 LLM 智能体而言,这通常是由大语言模型驱动的内部推理过程。

    • 规划 (Planning):基于当前的观察和内部记忆,更新对任务和环境的理解,制定或调整行动计划(例如分解子任务)。
    • 工具选择 (Tool Selection):根据当前计划,从可用工具库中选择最适合执行下一步骤的工具,并确定调用参数。
  3. 行动 (Action)
    决策完成后,智能体通过执行器 (Actuators) 执行具体行动。
    通常表现为调用一个选定的工具(如代码解释器、搜索引擎 API),从而对环境施加影响。

  4. 观察 (Observation)
    行动并非终点。行动会引起环境 (Environment)状态变化 (State Change),环境随即会产生一个新的观察作为结果反馈,进入下一轮循环。

1.2.3 智能体的感知与行动

在工程实践中,为了让 LLM 能够有效驱动这个循环,我们需要一套明确的交互协议 (Interaction Protocol) 来规范其与环境之间的信息交换 。

结构化输出协议

智能体的输出不再是单一的回复,而是一段遵循特定格式的文本,包含两个核心部分 :

  • Thought (思考):智能体内部决策的“快照”。以自然语言阐述分析、反思和规划过程。
  • Action (行动):基于思考后,决定对环境施加的具体操作,通常以函数调用的形式表示。

示例:智能旅行助手的输出

Thought: 用户想知道北京的天气。我需要调用天气查询工具。
Action: get_weather("北京")

💡 注解
这里展示的是基于文本解析(ReAct 风格)的早期智能体模式。在现代开发中(如 OpenAI Function Calling),Action 部分往往被结构化的 JSON 对象替代,但核心逻辑依然是“先思考(CoT),再行动”。

感知系统的职责

外部解析器 (Parser) 捕捉指令并执行 get_weather 函数后,环境会返回原始数据(如 JSON)。感知系统的一个重要职责是将这些原始数据封装成简洁、清晰的自然语言文本,即 Observation

示例:封装后的观察

Observation: 北京当前天气为晴,气温25摄氏度,微风。

这段文本将被反馈给智能体,作为下一轮循环的输入。


1.3 动手体验:5分钟实现第一个智能体

理论知识固然重要,但最好的学习方式是亲手实践。在本节中,我们将使用 Python 从零开始构建一个可以工作的智能旅行助手 。

任务定义:“你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点。”
挑战:智能体需要展现逻辑规划能力——先查天气,再根据天气查景点。

1.3.1 准备工作

我们需要安装以下库来支持网络请求和 LLM 调用 :

pip install requests tavily-python openai

  • requests: HTTP 库。
  • tavily-python: AI 搜索 API 客户端。
  • openai: 调用 LLM 服务。
(1) 指令模板 (System Prompt)

这是智能体的“说明书”,告诉 LLM 它扮演的角色、拥有的工具以及必须遵循的格式 。

AGENT_SYSTEM_PROMPT = """
你是一个智能旅行助手。你的任务是分析用户的请求,并使用可用工具一步步地解决问题。

# 可用工具:
- get_weather(city: str): 查询指定城市的实时天气。
- get_attraction(city: str, weather: str): 根据城市和天气搜索推荐的旅游景点。

# 行动格式:
你的回答必须严格遵循以下格式。首先是你的思考过程,然后是你要执行的具体行动。
Thought: [这里是你的思考过程和下一步计划]
Action: [这里是你要调用的工具,格式为 function_name(arg_name="arg_value")]

# 任务完成:
当你收集到足够的信息,能够回答用户的最终问题时,你必须在 Action: 字段后使用 finish(answer="...") 来输出最终答案。
"""

(2) 工具 1:查询真实天气 (get_weather)

使用免费的 wttr.in 服务获取天气 。

import requests
import json

def get_weather(city: str) -> str:
    """通过调用 wttr.in API 查询真实的天气信息"""
    # API端点,我们请求JSON格式的数据
    url = f"https://wttr.in/{city}?format=j1"
    
    try:
        # 发起网络请求
        response = requests.get(url)
        # 检查响应状态码是否为200(成功)
        response.raise_for_status()
        
        # 解析返回的JSON数据
        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}"

(3) 工具 2:搜索并推荐旅游景点 (get_attraction)

使用 Tavily Search API 根据天气搜索景点 。

import os
from tavily import TavilyClient

def get_attraction(city: str, weather: str) -> str:
    """根据城市和天气,使用 Tavily Search API 搜索并返回推荐结果"""
    
    # 1. 从环境变量中读取 API 密钥
    api_key = os.environ.get("TAVILY_API_KEY")
    if not api_key:
        return "错误:未配置 TAVILY_API_KEY 环境变量。"
        
    # 2. 初始化 Tavily 客户端
    tavily = TavilyClient(api_key=api_key)
    
    # 3. 构造一个精确的查询
    query = f"'{city}'在'{weather}'天气下最值得去的旅游景点推荐及理由"
    
    try:
        # 4. 调用 API, include_answer=True 会返回一个综合性的回答
        response = tavily.search(query=query, search_depth="basic", include_answer=True)
        
        # 5. Tavily 返回的结果已经非常干净,可以直接使用
        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,
}

1.3.2 接入大语言模型

我们需要一个通用的客户端来连接兼容 OpenAI 接口的 LLM 服务 。

from openai import OpenAI

class OpenAICompatibleClient:
    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 "错误:调用语言模型服务时出错。"

1.3.3 执行行动循环 (The Agent Loop)

这是整合所有组件的“主循环”,它负责驱动 Thought -> Action -> Observation 的迭代 。

import re

# 配置 (请替换为您自己的 Key)
API_KEY = "YOUR_API_KEY"
BASE_URL = "YOUR_BASE_URL" 
MODEL_ID = "YOUR_MODEL_ID"
os.environ['TAVILY_API_KEY'] = "YOUR_TAVILY_API_KEY"

# 初始化 LLM
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)

# 运行主循环 (最大5次,防止死循环)
for i in range(5):
    print(f"--- 循环 {i+1} ---\n")
    
    # 3.1 构建 Prompt (拼接历史上下文)
    full_prompt = "\n".join(prompt_history)
    
    # 3.2 调用 LLM 进行思考
    llm_output = llm.generate(full_prompt, AGENT_SYSTEM_PROMPT)
    print(f"模型输出:\n{llm_output}\n")
    prompt_history.append(llm_output) # 将思考结果加入历史
    
    # 3.3 解析并执行行动 (Regex 匹配)
    action_match = re.search(r"Action: (.*)", llm_output, re.DOTALL)
    if not action_match:
        print("解析错误: 模型输出中未找到 Action。")
        break
        
    action_str = action_match.group(1).strip()
    
    # 检查是否任务完成
    if action_str.startswith("finish"):
        final_answer_match = re.search(r'finish\(answer="(.*)"\)', action_str)
        if final_answer_match:
            final_answer = final_answer_match.group(1)
            print(f"任务完成, 最终答案: {final_answer}")
        else:
            print("任务完成,但无法解析最终答案。")
        break
        
    # 解析工具调用 (提取函数名和参数)
    try:
        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}'"
            
    except Exception as e:
         observation = f"错误: 解析或执行工具时出错 - {e}"

    # 3.4 记录观察结果
    observation_str = f"Observation: {observation}"
    print(f"{observation_str}\n" + "="*40)
    prompt_history.append(observation_str) # 将观察结果加入历史,供下一轮参考

💡 深度解析
这个循环不仅是代码逻辑,更是 Agent 的“心跳”。

  1. Prompt 累积prompt_history 列表不断增长,包含了用户请求、Agent 的上一次思考、以及环境反馈的 Observation。这模拟了 Agent 的“短期记忆”。
  2. 正则解析:代码使用正则表达式提取 Action。在生产环境中,这通常是最脆弱的环节(因为 LLM 可能输出不规范的括号),但在学习阶段,它最直观地展示了原理。
【电动车】基于多目标优化遗传算法NSGAII的峰谷分时电价引导下的电动汽车充电负荷优化研究(Matlab代码实现)内容概要:本文围绕“基于多目标优化遗传算法NSGA-II的峰谷分时电价引导下的电动汽车充电负荷优化研究”展开,利用Matlab代码实现优化模型,旨在通过峰谷分时电价机制引导电动汽车有序充电,降低电网负荷波动,提升能源利用效率。研究融合了多目标优化思想遗传算法NSGA-II,兼顾电网负荷均衡性、用户充电成本和充电满意度等多个目标,构建了科学合理的数学模型,并通过仿真验证了方法的有效性实用性。文中还提供了完整的Matlab代码实现路径,便于复现进一步研究。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的高校研究生、科研人员及从事智能电网、电动汽车调度相关工作的工程技术人员。; 使用场景及目标:①应用于智能电网中电动汽车充电负荷的优化调度;②服务于峰谷电价政策下的需求侧管理研究;③为多目标优化算法在能源系统中的实际应用提供案例参考; 阅读建议:建议读者结合Matlab代码逐步理解模型构建算法实现过程,重点关注NSGA-II算法在多目标优化中的适应度函数设计、约束处理及Pareto前沿生成机制,同时可尝试调整参数或引入其他智能算法进行对比分析,以深化对优化策略的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值