从零构建AI智能体:基于ReAct框架的天气查询助手实战

发布时间:2026/8/18 22:03:49
从零构建AI智能体:基于ReAct框架的天气查询助手实战 最近在探索AI应用开发时你是否也对“智能体Agent”这个概念感到既兴奋又困惑看到各种框架和项目层出不穷想自己动手搭建一个却不知从何下手面对复杂的架构图和术语感到迷茫别担心这正是每个开发者入门Agent领域的必经之路。本文将彻底打破这种困境为你提供一份从零开始的、保姆级的Agent智能体搭建实战指南。我们将从一个最简单的“天气查询助手”开始逐步深入到记忆、工具调用、多智能体协作等核心概念手把手带你写出每一行代码理解每一个配置项最终构建出一个功能完整、可独立运行的AI智能体。无论你是刚接触AI的Python新手还是想将AI能力集成到现有业务的后端开发者都能从本文中找到清晰的路径和可直接复用的代码。1. 什么是AI Agent—— 从概念到落地在开始敲代码之前我们必须先厘清一个核心问题Agent智能体到底是什么它和我们常说的“大语言模型LLM”有什么区别简单来说你可以把大语言模型如GPT-4、Claude、DeepSeek看作是一个超级聪明但“四肢不勤”的大脑。它知识渊博能说会道可以回答你的问题、写诗、编程。但是它被“困”在对话窗口里无法主动去查看今天的天气、无法帮你发送邮件、无法查询数据库。它的一切输出都基于其训练时“记忆”的知识无法与真实世界互动。而Agent智能体则是给这个“大脑”装上了感知器官、手脚和记忆系统。它让LLM具备了以下关键能力思考与规划根据用户目标Goal拆解出具体的执行步骤Plan。使用工具调用外部API、函数或系统命令如搜索网络、查询数据库、发送邮件来获取信息或执行动作。记忆与学习记住与用户的对话历史、工具调用的结果并在后续决策中利用这些信息。自主执行在给定目标和工具集后能够自动运行一系列步骤直到完成任务或无法继续。一个生动的比喻LLM是坐在指挥中心的“指挥官”它知道战略。而Agent是配备了通信设备工具、拥有战场记忆记忆并可以调动坦克、飞机外部API的“前线作战单元”。指挥官LLM负责制定“夺取A高地”的计划而作战单元Agent则能自主执行“侦察敌情 - 呼叫炮火支援 - 步兵推进”等一系列动作。当前热门的Agent项目与框架根据网络热词我们可以看到这个领域的活跃度例如Hermes Agent、Pi Agent、DeepSeek Agent等它们都是基于类似理念构建的具体实现或框架。而Agent架构、多Agent协作、Agent记忆、Agent安全则是构建复杂Agent系统时必须深入研究的核心课题。理解了Agent是什么我们就能明确本教程的目标不是仅仅调用LLM的API而是构建一个能“思考-行动-观察-再思考”的循环系统。2. 环境准备与核心工具选型工欲善其事必先利其器。搭建Agent需要选择合适的编程语言、框架和模型服务。为了最大化降低入门门槛并保证实战性我们做出如下选择2.1 基础运行环境操作系统Windows 10/11, macOS, 或 Linux (如Ubuntu 20.04)。本教程示例在macOS/Linux环境下编写Windows用户请注意命令行的细微差别如使用dir代替ls。Python版本Python 3.8 - 3.11。这是绝大多数AI库稳定支持的版本范围。强烈建议使用pyenv或conda管理Python环境避免包冲突。包管理工具pip(Python自带)。2.2 核心库与框架选择我们不直接使用某个庞大的完整框架如LangChain而是先从零构建核心逻辑再引入轻量级框架辅助以确保你能理解底层原理。OpenAI SDK (openai)用于调用GPT系列模型这是目前最稳定、文档最丰富的LLM接口。我们将使用它作为Agent的“大脑”。LangChain Core (langchain-core,langchain-openai)LangChain是一个用于开发由语言模型驱动的应用程序的流行框架。我们主要利用其标准化的工具Tool定义、调用方式以及智能体Agent执行器这能极大简化开发避免重复造轮子。我们只使用其核心部分保持项目轻量。Requests (requests)用于构建自定义工具调用外部HTTP API如天气API。Dotenv (python-dotenv)管理敏感信息如API密钥避免硬编码在代码中。2.3 模型服务与API密钥LLM服务我们将使用OpenAI的GPT-3.5-turbo模型。它成本低、速度快完全满足学习需求。你也可以替换为GPT-4或其他兼容OpenAI API的模型如DeepSeek、Ollama本地模型。如何获取访问 OpenAI平台 注册并创建API Key。重要提示API Key是私密凭证切勿泄露或上传至GitHub等公开仓库。2.4 项目初始化打开终端跟随以下步骤创建你的第一个Agent项目# 1. 创建项目目录并进入 mkdir my_first_agent cd my_first_agent # 2. 创建虚拟环境强烈推荐 python -m venv venv # 3. 激活虚拟环境 # macOS/Linux: source venv/bin/activate # Windows: # venv\Scripts\activate # 4. 安装核心依赖 pip install openai langchain-core langchain-openai requests python-dotenv # 5. 创建项目文件 touch main.py tools.py .env你的项目结构现在应该是这样my_first_agent/ ├── venv/ # Python虚拟环境目录 ├── main.py # Agent主程序 ├── tools.py # 自定义工具定义 └── .env # 环境变量配置文件需要自己创建内容2.5 配置环境变量编辑.env文件填入你的OpenAI API Key。文件内容如下# .env OPENAI_API_KEYsk-your-actual-openai-api-key-here请将sk-your-actual-openai-api-key-here替换为你真实的Key。3. Agent核心架构与原理拆解在动手编码前我们需要在脑海中建立起Agent的核心运行循环这通常被称为ReAct (Reason Act) 框架。这是绝大多数Agent的底层逻辑。3.1 ReAct循环思考-行动-观察思考 (Reason)LLM根据用户输入和当前上下文记忆决定下一步该做什么。是直接回答还是需要调用某个工具行动 (Act)如果决定调用工具LLM会生成一个格式化的工具调用请求包含工具名和输入参数。观察 (Observe)系统执行指定的工具并将工具执行的结果成功或失败返回给LLM。循环LLM接收到观察结果结合之前的上下文再次进行“思考”决定下一步是继续调用工具还是汇总信息给出最终答案。这个循环会一直持续直到LLM认为任务完成输出最终答案Final Answer。3.2 关键组件详解LLM Core智能体的决策中心。我们使用ChatOpenAI来封装。Tools智能体的“手脚”。每个工具都是一个函数有明确的名称、描述和参数。LLM通过描述来理解工具的功能。Agent Executor驱动整个ReAct循环的“发动机”。它负责解析LLM的输出调用工具收集结果并把结果喂回给LLM进行下一轮思考。我们将使用LangChain的AgentExecutor。Memory智能体的“记忆”。可以是简单的对话历史ConversationBufferMemory也可以是更复杂的向量存储记忆。它保证了对话的连贯性。下面我们就将把这些组件一一实现。4. 实战搭建你的第一个天气查询Agent我们将构建一个能理解中文、可以查询实时天气的智能体。4.1 创建自定义工具Tools首先在tools.py中定义我们的“手脚”——一个天气查询工具。我们需要一个真实的天气API这里我们使用免费的 Open-Meteo API。# tools.py import requests from typing import Optional def get_current_weather(location: str, unit: Optional[str] celsius) - str: 获取指定城市的当前天气情况。 Args: location: 城市名称例如“北京”、“Shanghai”。 unit: 温度单位“celsius” 或 “fahrenheit”。默认为“celsius”。 Returns: 一个描述天气的字符串。 # 1. 构造API请求URL (使用Open-Meteo免费API) # 这里简单处理实际项目可能需要更精确的地理编码 base_url https://api.open-meteo.com/v1/forecast params { latitude: 39.9042, # 以北京为例实际应根据location动态获取 longitude: 116.4074, current_weather: true, timezone: auto, } # 2. 发送HTTP请求 try: response requests.get(base_url, paramsparams) response.raise_for_status() # 如果状态码不是200抛出异常 data response.json() except requests.exceptions.RequestException as e: return f请求天气API时出错{e} # 3. 解析返回数据 current data.get(current_weather, {}) temperature current.get(temperature) weather_code current.get(weathercode) wind_speed current.get(windspeed) # 4. 将天气代码转换为可读描述简化版 weather_desc _convert_weather_code(weather_code) # 5. 单位转换示例中API返回即为摄氏度 if unit fahrenheit: temperature temperature * 9/5 32 unit_str 华氏度 else: unit_str 摄氏度 # 6. 返回格式化的结果 return f{location}的当前天气是{weather_desc}温度{temperature:.1f}{unit_str}风速{wind_speed} km/h。 def _convert_weather_code(code: int) - str: 将Open-Meteo的天气代码转换为中文描述。 # 简化映射完整映射请参考Open-Meteo文档 weather_map { 0: 晴空, 1: 基本晴朗, 2: 局部有云, 3: 阴天, 45: 有雾, 48: 有雾, 51: 小雨, 61: 雨, 80: 阵雨, 95: 雷暴, } return weather_map.get(code, 未知天气)代码解释我们定义了一个get_current_weather函数它接受location和unit两个参数。函数有详细的文档字符串docstring。这至关重要LLM就是通过阅读这个描述来理解工具功能的。函数内部调用真实的天气API解析JSON数据并返回一个格式化的字符串结果。我们用一个辅助函数_convert_weather_code来处理天气代码。4.2 构建主Agent程序接下来在main.py中我们将组装所有部件。# main.py import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.memory import ConversationBufferMemory from langchain.tools import Tool # 导入我们自定义的工具函数 from tools import get_current_weather # 1. 加载环境变量从.env文件读取API Key load_dotenv() openai_api_key os.getenv(OPENAI_API_KEY) if not openai_api_key: raise ValueError(请在 .env 文件中设置 OPENAI_API_KEY) # 2. 初始化LLMAgent的大脑 # 使用gpt-3.5-turbo-1106模型它支持工具调用功能。 llm ChatOpenAI( modelgpt-3.5-turbo-1106, temperature0, # 温度设为0使输出更确定、更稳定 openai_api_keyopenai_api_key ) # 3. 将自定义函数包装成LangChain Tool对象 # Tool对象包含了函数、名称、描述是LLM能识别的标准格式。 weather_tool Tool( nameget_current_weather, funcget_current_weather, description当你需要查询某个城市的当前天气时使用此工具。 输入应该是一个包含城市名称例如‘北京’、‘上海’的字符串 以及可选的温度单位‘celsius’或‘fahrenheit’。 ) # 你可以在这里定义更多工具组成一个工具列表 tools [weather_tool] # 4. 创建Prompt模板指导Agent的行为 # 这是Agent的“性格”和“行为准则”设定非常关键。 prompt ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的中文AI助手。你可以使用工具来获取信息。 请遵循以下规则 1. 用中文思考和回答。 2. 如果用户的问题需要实时信息如天气请务必使用工具。 3. 使用工具时请清晰说明你将要做什么。 4. 根据工具返回的结果给出友好、完整的回答。 ), MessagesPlaceholder(variable_namechat_history), # 预留位置用于插入记忆对话历史 (human, {input}), # 用户输入的位置 MessagesPlaceholder(variable_nameagent_scratchpad), # 预留位置用于Agent思考过程 ]) # 5. 初始化记忆让Agent能记住对话上下文 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 6. 创建Agent # create_openai_tools_agent 是LangChain提供的一个便捷函数用于创建适配OpenAI工具调用格式的Agent。 agent create_openai_tools_agent(llmllm, toolstools, promptprompt) # 7. 创建Agent执行器 # 这是驱动整个ReAct循环的核心组件。 agent_executor AgentExecutor( agentagent, toolstools, memorymemory, # 注入记忆 verboseTrue, # 设置为True会在控制台打印详细的思考过程便于调试学习 handle_parsing_errorsTrue, # 处理解析错误避免因LLM输出格式不对而崩溃 ) # 8. 与Agent交互 if __name__ __main__: print(天气助手Agent已启动输入‘退出’或‘quit’结束对话。) print(- * 50) while True: user_input input(\n你: ) if user_input.lower() in [退出, quit, exit]: print(助手: 再见) break # 调用执行器传入用户输入 try: response agent_executor.invoke({input: user_input}) print(f\n助手: {response[output]}) except Exception as e: print(f\n出错啦: {e})4.3 运行与验证确保你的虚拟环境已激活并且.env文件已正确配置API Key。在终端运行你的Agentpython main.py你应该会看到类似以下的输出verboseTrue会让我们看到Agent内部的思考过程这对学习至关重要天气助手Agent已启动输入‘退出’或‘quit’结束对话。 -------------------------------------------------- 你: 今天北京天气怎么样 进入新的Agent执行链... 我可能需要查询北京的当前天气。用户问的是“今天北京天气怎么样”这需要实时天气信息。我应该使用天气查询工具。 Action: get_current_weather Action Input: {location: 北京, unit: celsius} Observation: 北京的当前天气是晴空温度12.3摄氏度风速15.2 km/h。 根据工具返回的结果北京现在是晴天温度12.3度风速15.2 km/h。我可以把这个信息组织成友好的回答。 Thought: 我现在有足够的信息来回答用户了。 Final Answer: 今天北京天气晴朗气温大约12.3摄氏度风速15.2公里每小时是个不错的日子。 助手: 今天北京天气晴朗气温大约12.3摄氏度风速15.2公里每小时是个不错的日子。恭喜你已经成功运行了你的第一个AI智能体。它理解了你的中文问题自动决定调用get_current_weather工具获取结果后组织语言给出了最终回答。这就是ReAct循环在起作用。5. 功能进阶为Agent添加记忆与更多工具一个只会查天气的Agent显然不够看。让我们增强它。5.1 增强记忆能力上面的例子使用了ConversationBufferMemory它只是简单地将所有对话历史保存在内存中。对于长对话这可能导致上下文过长超出LLM的Token限制。我们可以尝试更高级的记忆方式如ConversationSummaryMemory它会自动总结历史对话。# 在main.py中替换原来的memory初始化部分 from langchain.memory import ConversationSummaryMemory from langchain_openai import OpenAI # 使用一个单独的LLM来总结记忆为了节省成本可以用小模型这里仍用gpt-3.5-turbo示例 summary_llm ChatOpenAI(modelgpt-3.5-turbo-1106, temperature0, openai_api_keyopenai_api_key) memory ConversationSummaryMemory( llmsummary_llm, memory_keychat_history, return_messagesTrue )ConversationSummaryMemory会在每次交互后自动生成一个对话摘要而不是存储所有原始消息从而更高效地利用上下文窗口。5.2 添加更多工具让我们给Agent再装几个“技能”。在tools.py中添加新函数并在main.py的tools列表中注册。工具一简单计算器# 在 tools.py 中添加 def simple_calculator(expression: str) - str: 执行简单的数学计算。支持加()、减(-)、乘(*)、除(/)。 Args: expression: 数学表达式字符串例如“3 5 * 2”。 Returns: 计算结果字符串或错误信息。 # 警告使用eval有安全风险仅用于示例。生产环境应用安全解析库如ast.literal_eval。 try: # 极其简单的安全过滤切勿用于真实生产环境 if any(keyword in expression for keyword in [import, os, sys, __, open, eval, exec]): return 表达式包含不安全字符。 result eval(expression) return f{expression} {result} except Exception as e: return f计算表达式‘{expression}’时出错{e}工具二获取当前时间# 在 tools.py 中添加 from datetime import datetime def get_current_time(timezone: str Asia/Shanghai) - str: 获取指定时区的当前日期和时间。 Args: timezone: 时区字符串例如“Asia/Shanghai”、“America/New_York”。默认为“Asia/Shanghai”。 Returns: 格式化的日期时间字符串。 try: from zoneinfo import ZoneInfo tz ZoneInfo(timezone) except ImportError: # Python 3.8 兼容性回退 import pytz tz pytz.timezone(timezone) # 需要安装 pip install pytz except Exception: tz None now datetime.now(tz) if tz else datetime.now() return now.strftime(f%Y年%m月%d日 %H:%M:%S ({timezone}))更新main.py中的工具列表# main.py (更新tools列表部分) from tools import get_current_weather, simple_calculator, get_current_time weather_tool Tool(nameget_current_weather, funcget_current_weather, description...) calc_tool Tool(namesimple_calculator, funcsimple_calculator, description用于执行基础数学计算输入是一个数学表达式字符串如‘3 5 * 2’。) time_tool Tool(nameget_current_time, funcget_current_time, description获取指定时区的当前时间输入是时区字符串例如‘Asia/Shanghai’。”) tools [weather_tool, calc_tool, time_tool]现在重启你的main.py试试更复杂的对话你: 先算一下 (15 7) * 3 等于多少然后告诉我现在上海的时间。 进入新的Agent执行链... 用户有两个请求先计算一个表达式然后查询上海时间。我应该按顺序使用计算器和时间工具。 Action: simple_calculator Action Input: {expression: (15 7) * 3} Observation: (15 7) * 3 66 第一个任务完成结果是66。现在需要查询上海时间。 Action: get_current_time Action Input: {timezone: Asia/Shanghai} Observation: 2024年05月20日 14:30:25 (Asia/Shanghai) 两个工具都调用成功了。我可以把结果整合起来回答。 Thought: 我现在可以给出最终答案了。 Final Answer: 计算结果为(15 7) * 3 66。当前上海时间是2024年05月20日 14:30:25。 助手: 计算结果为(15 7) * 3 66。当前上海时间是2024年05月20日 14:30:25。看Agent已经可以自主规划任务顺序并连续使用多个工具了6. 常见问题与深度排查指南在搭建和运行Agent过程中你一定会遇到各种问题。以下是典型问题及解决方案。6.1 工具调用失败LLM不理解或错误调用工具现象Agent不调用工具直接回答或调用工具时参数格式错误。原因与解决工具描述不清检查Tool的description是否清晰、准确地描述了工具的功能、输入格式和输出。用自然语言写就像教一个新手如何使用它。Prompt引导不足在System Prompt中明确要求Agent“在需要实时信息时使用工具”。可以强化指令。模型能力GPT-3.5-turbo的工具调用能力已经很强但如果问题复杂可以尝试换用GPT-4。参数格式确保工具函数有类型注解Type Hints这能帮助LangChain更好地生成JSON Schema供LLM理解。6.2 上下文长度超限Token Overflow现象对话进行到后面Agent似乎“忘记”了之前的内容或者API返回长度错误。原因对话历史记忆太长超过了模型的最大上下文长度如GPT-3.5-turbo的16K。解决使用摘要记忆如前所述用ConversationSummaryMemory代替ConversationBufferMemory。滑动窗口记忆只保留最近N轮对话。向量存储记忆将历史对话存入向量数据库在需要时进行相关性检索召回。这是构建“长期记忆”的进阶方案可使用langchain.chat_message_histories和langchain.vectorstores实现。6.3 Agent陷入循环或执行低效现象Agent反复调用同一个工具或者在不必要时调用工具无法输出最终答案。原因ReAct循环没有正确终止。解决设置最大迭代次数在AgentExecutor中设置max_iterations和max_execution_time参数强制终止长时间运行。agent_executor AgentExecutor( agentagent, toolstools, memorymemory, verboseTrue, max_iterations5, # 最多思考-行动5次 early_stopping_methodgenerate, # 让LLM自己决定提前结束 )优化Prompt在System Prompt中明确写出“当你认为已经获得足够信息来回答问题后请输出最终答案Final Answer”。6.4 API密钥或网络问题现象openai.error.AuthenticationError或 网络超时。解决确认.env文件中的OPENAI_API_KEY正确无误且没有多余空格。确认账户有余额或该API Key有访问权限。对于国内用户可能需要配置网络代理请注意遵守相关法律法规此处不展开讨论技术细节。7. 工程化与最佳实践当你想要将这个小Demo升级为一个真正的项目时需要考虑以下方面7.1 项目结构优化一个标准的Agent项目可能包含以下模块my_agent_project/ ├── app/ │ ├── __init__.py │ ├── main.py # 应用入口 │ ├── agent/ # Agent核心逻辑 │ │ ├── __init__.py │ │ ├── builder.py # 构建Agent链 │ │ └── prompts.py # 存放各种Prompt模板 │ ├── tools/ # 工具集 │ │ ├── __init__.py │ │ ├── weather.py │ │ ├── calculator.py │ │ └── web_search.py │ ├── memory/ # 记忆管理 │ │ └── manager.py │ └── config.py # 配置文件 ├── tests/ # 单元测试 ├── requirements.txt # 依赖列表 ├── .env.example # 环境变量示例 └── README.md7.2 工具开发规范单一职责每个工具只做一件事。健壮性工具函数内部必须有完善的错误处理try-except返回明确的错误信息避免整个Agent崩溃。安全性绝对不要在工具中直接使用eval()或执行未经验证的用户输入。上面的计算器示例仅用于教学生产环境必须使用安全的数学表达式解析库如ast.literal_eval限制范围或使用numexpr。异步支持如果工具涉及网络I/O如调用API考虑将其定义为异步函数async def并使用支持异步的Agent执行器以提高性能。7.3 Prompt工程优化Prompt是Agent的“灵魂”直接决定其行为模式。角色设定在System Prompt中清晰定义Agent的角色、能力和边界。输出格式约束明确要求LLM以特定格式如“Action: ...\nAction Input: ...”进行思考这在与自定义解析逻辑配合时很重要。少样本示例Few-Shot在Prompt中提供几个“用户输入-Agent思考过程-最终输出”的完整示例能极大地提升Agent在复杂任务上的表现。7.4 切换与评估不同的LLM我们的架构并不绑定OpenAI。你可以轻松替换LLM后端。使用本地模型通过 Ollama 或 LM Studio 运行本地大模型如Llama 3, Qwen并使用ChatOllama等LangChain集成。from langchain_community.chat_models import ChatOllama llm ChatOllama(modelllama3:8b, base_urlhttp://localhost:11434)使用其他云服务LangChain支持Anthropic Claude、Google Gemini等只需更换ChatModel类并配置相应API Key。评估对于生产系统需要建立评估体系从准确性、工具调用成功率、响应时间、成本等维度对比不同模型。7.5 走向多智能体Multi-Agent协作当单个Agent无法处理复杂任务时就需要多Agent系统。例如编排者Orchestrator一个主管Agent负责接收用户任务并将其分解成子任务分发给其他专家Agent。专家Agent专门负责某一领域的Agent如数据分析Agent、文案撰写Agent、代码审查Agent。 他们之间通过共享工作区或消息队列进行通信。LangChain提供了MultiAgentCollaboration相关的实验性功能社区也有CrewAI、AutoGen等专门框架。8. 总结与学习路线至此你已经完成了一个功能完整的AI智能体从零到一的搭建。我们经历了理解Agent概念 - 准备环境 - 剖析ReAct原理 - 实现自定义工具 - 构建核心Agent循环 - 添加记忆与多工具 - 排查问题 - 探讨工程化的全过程。你的学习路线可以继续深入深入LangChain探索其更多的记忆后端向量数据库、复杂Agent类型ReAct文档检索、Self-Ask、**链Chain**的编排能力。探索其他框架了解AutoGen微软、CrewAI、Semantic Kernel等框架的设计哲学拓宽视野。集成真实工具将Agent与你的业务系统连接例如连接数据库SQLDatabaseToolkit、内部API、邮件系统、办公软件等。构建Web界面使用Gradio、Streamlit或FastAPI为你的Agent构建一个聊天机器人界面。关注安全与合规深入研究Agent安全包括工具使用的权限控制、防止Prompt注入、输出内容过滤等。学习智能体评估如何定量评估一个Agent的好坏建立测试数据集和评估指标。记住Agent开发的核心在于将大语言模型的推理能力与外部世界的执行能力相结合。从今天这个小小的天气查询助手出发你可以逐步构建出能自动处理工单、分析数据、生成报告甚至管理项目的强大智能体系统。动手去实验遇到问题就查阅文档和社区这才是学习AI应用开发最有效的方式。本文的所有代码都已提供你可以直接在此基础上进行修改和扩展祝你构建出令人惊叹的AI应用