最近在尝试将大语言模型LLM的能力集成到实际工作流中时发现市面上的 Agent 框架要么像 Codex、Claude Code 那样与特定 IDE 深度绑定学习成本高、灵活性受限要么就是架构过于复杂动辄十几个模块让初学者望而却步。有没有一种方案既能实现智能体Agent的核心功能——理解、规划、执行、反思又能保持极简的架构和清晰的逻辑让开发者快速上手并应用到自己的项目中本文将分享一个名为 “Pi” 的极简 Agent 设计与实现全攻略。它不依赖任何复杂的第三方框架核心代码可能只有几百行却能完整演绎 Agent 的工作流。我们将从零开始手把手带你理解 Agent 的核心思想并用 Python 实现一个具备工具调用、记忆和反思能力的可运行 Agent。无论你是想深入理解 AI Agent 原理还是希望为自己的项目添加一个轻量级智能助手这篇文章都能提供一套完整、可复现的解决方案。1. 背景与核心概念什么是 AI Agent在深入代码之前我们有必要厘清几个关键概念。这能帮助我们在纷繁的信息中抓住本质理解我们到底要构建什么。1.1 从 LLM 到 Agent能力的延伸大型语言模型LLM如 GPT、Claude、DeepSeek 等本质上是强大的“文本预测器”。给定一段输入提示词它们能生成一段相关的、连贯的文本输出。然而LLM 本身是“静态”的知识截止无法获取训练数据之外的最新信息。无法执行不能操作数据库、调用 API、运行代码或操作文件系统。缺乏持续性每次对话相对独立难以维持复杂的、多步骤的任务状态尽管有上下文窗口但管理复杂。AI Agent智能体就是为了突破这些限制而生的架构。它以 LLM 为“大脑”负责理解、规划和决策同时为这个大脑配备**“身体”工具/函数和“记忆”**短期/长期存储使其能够与环境交互完成更复杂的任务。简单类比LLM 是一个学识渊博但足不出户的顾问而 Agent 是这个顾问配备了一个能听令行事的助理团队和一个资料库可以真正去执行调研、操作和汇报。1.2 Agent 的核心循环ReAct 模式当前最主流的 Agent 推理范式是ReAct (Reasoning Acting)。其核心是一个循环思考ThinkLLM 分析当前情况用户目标、已有信息、可用工具决定下一步该做什么。行动Act根据思考结果选择并调用一个合适的工具如搜索网络、执行计算、查询数据库或者直接给出最终答案。观察Observe获取工具执行的结果或环境反馈。循环将观察到的结果纳入上下文再次进行思考直到任务完成或达到终止条件。这个思考 - 行动 - 观察的循环是几乎所有复杂 Agent如 AutoGPT, BabyAGI的基石。我们的“Pi” Agent 也将基于此模式构建。1.3 为何选择“极简”像 LangChain、LlamaIndex 这样的框架功能强大但抽象层级多概念复杂Chains, Agents, Tools, Memory, Indexes...对于理解核心原理和快速原型开发有时显得笨重。而 Codex、Claude Code 更多是面向代码生成的特定场景 Agent。我们的“Pi” Agent 目标不同大道至简聚焦 ReAct 核心循环用最少量的代码实现一个可工作的 Agent。透明可控每一行代码你都能看懂知道信息如何流动决策如何做出。易于定制由于其简单性你可以轻松地为其添加新的工具、修改记忆策略或替换 LLM 后端。教学意义通过构建它你将从根本上理解 Agent 是如何运作的这是使用任何高级框架的坚实基础。接下来我们将进入实战环节从环境准备开始。2. 环境准备与版本说明我们将使用 Python 作为实现语言因为它拥有丰富的 AI 生态库。本项目力求最小化依赖。2.1 基础环境操作系统Windows 10/11, macOS, 或 Linux (Ubuntu 20.04) 均可。Python 版本 3.8。推荐使用 3.9 或 3.10 以获得最佳兼容性。包管理工具pip。2.2 核心依赖库我们将主要依赖openai库来调用 LLM API例如 OpenAI GPT 或兼容 OpenAI API 的模型如 DeepSeek。同时我们会用requests来演示工具调用。创建一个新的项目目录例如pi_agent并在其中创建requirements.txt文件# requirements.txt openai1.0.0 requests2.28.0 python-dotenv0.19.0 # 用于管理环境变量安装依赖cd pi_agent pip install -r requirements.txt2.3 LLM API 配置你需要一个 LLM API 的密钥。本文以 OpenAI API 为例但代码设计上兼容任何提供 OpenAI 格式兼容接口的服务如 DeepSeek, Azure OpenAI 等。获取 OpenAI API Key访问 OpenAI Platform 创建密钥。创建.env文件来安全存储密钥切记不要将此文件提交到版本控制系统。# .env OPENAI_API_KEY你的-api-key-here OPENAI_BASE_URLhttps://api.openai.com/v1 # 如果使用其他兼容服务修改此处 OPENAI_MODELgpt-3.5-turbo # 或 gpt-4, deepseek-chat等我们将使用python-dotenv在代码中加载这些配置。2.4 项目结构预览在开始编码前先看下我们最终的项目结构这有助于理解代码组织pi_agent/ ├── .env # 环境变量配置文件勿提交 ├── requirements.txt # 依赖列表 ├── pi_agent.py # Agent 核心类定义 ├── tools.py # 工具函数定义 ├── memory.py # 记忆系统本文先实现简单记忆 └── main.py # 主程序演示如何使用 Agent现在环境已经就绪让我们开始构建 Agent 的核心大脑。3. 核心组件拆解大脑、工具与记忆一个极简 Agent 主要由三部分组成LLM 客户端大脑、工具集手脚和记忆系统经验。我们将分别实现它们。3.1 LLM 客户端封装首先我们创建一个与 LLM 交互的模块。为了灵活性我们将其封装成一个类。# pi_agent.py import os import json from openai import OpenAI from dotenv import load_dotenv # 加载环境变量 load_dotenv() class PiAgent: def __init__(self, modelNone, base_urlNone, api_keyNone): 初始化 Pi Agent。 :param model: 使用的模型名称默认从环境变量读取 :param base_url: API 基础地址默认从环境变量读取 :param api_key: API 密钥默认从环境变量读取 self.model model or os.getenv(OPENAI_MODEL, gpt-3.5-turbo) self.base_url base_url or os.getenv(OPENAI_BASE_URL, https://api.openai.com/v1) self.api_key api_key or os.getenv(OPENAI_API_KEY) if not self.api_key: raise ValueError(OPENAI_API_KEY 未设置。请在 .env 文件中配置。) # 初始化 OpenAI 客户端 self.client OpenAI( api_keyself.api_key, base_urlself.base_url ) # 初始化工具和记忆 self.tools [] # 工具列表元素为字典格式 self.memory [] # 对话历史记忆 self.max_memory_turns 10 # 保留最近N轮对话 def _call_llm(self, messages, toolsNone): 内部方法调用 LLM API。 :param messages: 消息列表格式遵循 OpenAI ChatCompletion :param tools: 可选可用的工具描述列表 :return: LLM 的响应消息 try: kwargs { model: self.model, messages: messages, temperature: 0.1, # 低温度使输出更稳定 } if tools: kwargs[tools] tools response self.client.chat.completions.create(**kwargs) message response.choices[0].message return message except Exception as e: print(f调用 LLM 时出错: {e}) # 返回一个简单的错误响应避免程序崩溃 return {role: assistant, content: f抱歉思考过程出现错误{e}}这个PiAgent类初始化了 LLM 客户端并预留了tools和memory属性。_call_llm是核心的通信方法。3.2 工具系统实现工具是 Agent 与外界交互的手段。每个工具都是一个 Python 函数并配有一个符合 OpenAIfunction calling格式的描述。# tools.py import requests import json from datetime import datetime # ---------- 工具函数定义 ---------- def get_weather(city: str) - str: 获取指定城市的当前天气信息模拟函数。 在实际应用中这里应调用真实的天气 API。 :param city: 城市名例如 北京 :return: 天气信息字符串 # 这是一个模拟实现。真实情况请替换为如 OpenWeatherMap 的 API 调用 weather_data { 北京: 晴15°C北风2级, 上海: 多云18°C东南风1级, 广州: 阵雨22°C南风3级, 深圳: 阴24°C南风2级, } return weather_data.get(city, f未找到{city}的天气信息。已知城市{, .join(weather_data.keys())}) def calculate(expression: str) - str: 计算数学表达式。警告使用 eval 有安全风险仅用于演示。 在生产环境中应使用安全的表达式解析库如 ast.literal_eval。 :param expression: 数学表达式如 3 5 * 2 :return: 计算结果字符串 try: # 严重安全警告eval 会执行任意代码此处仅用于演示。 # 绝对不要在生产环境或接收不可信输入时使用 result eval(expression, {__builtins__: None}, {}) return f{expression} {result} except Exception as e: return f计算错误{e} def search_web(query: str) - str: 使用 DuckDuckGo 即时答案 API 进行简单搜索模拟。 注意这是一个简化的示例实际 API 调用可能需要处理更复杂的情况。 :param query: 搜索关键词 :return: 搜索结果的摘要 try: # DuckDuckGo 即时答案 API (无需密钥) url fhttps://api.duckduckgo.com/ params { q: query, format: json, no_html: 1, skip_disambig: 1 } resp requests.get(url, paramsparams, timeout10) data resp.json() abstract data.get(AbstractText) if abstract: return f关于 {query} 的摘要{abstract[:200]}... # 截断 else: return f未找到关于 {query} 的即时答案。 except requests.RequestException as e: return f网络搜索请求失败{e} def get_current_time() - str: 获取当前日期和时间。 now datetime.now() return now.strftime(%Y-%m-%d %H:%M:%S) # ---------- 工具描述供 LLM 识别 ---------- # 每个工具描述都是一个字典遵循 OpenAI 的 function calling 格式 TOOL_DESCRIPTIONS [ { type: function, function: { name: get_weather, description: 获取指定城市的当前天气情况。, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如北京、上海, } }, required: [city], additionalProperties: False } } }, { type: function, function: { name: calculate, description: 计算一个数学表达式的结果。, parameters: { type: object, properties: { expression: { type: string, description: 数学表达式例如3 5 * 2, (10 - 4) / 2, } }, required: [expression], additionalProperties: False } } }, { type: function, function: { name: search_web, description: 在互联网上搜索信息并返回摘要。, parameters: { type: object, properties: { query: { type: string, description: 搜索查询关键词, } }, required: [query], additionalProperties: False } } }, { type: function, function: { name: get_current_time, description: 获取当前的日期和时间。, parameters: { type: object, properties: {}, # 此工具无需参数 required: [], additionalProperties: False } } } ] # 工具名称到函数对象的映射 TOOL_MAP { get_weather: get_weather, calculate: calculate, search_web: search_web, get_current_time: get_current_time, }关键点工具函数每个函数都有明确的类型提示和文档字符串LLM 依靠这些信息来理解如何调用。工具描述TOOL_DESCRIPTIONS列表中的字典严格遵循 OpenAI 的function calling格式。这会被发送给 LLMLLM 据此决定在需要时调用哪个工具。工具映射TOOL_MAP字典将工具名称字符串映射到实际的 Python 函数对象便于后续调用。3.3 记忆系统简化版记忆让 Agent 拥有上下文感知能力。我们先实现一个简单的“对话历史”记忆它只保存最近的几轮交互。# memory.py class SimpleMemory: 简单的对话记忆保存最近的交互历史。 def __init__(self, max_turns10): self.memory [] # 列表项为 (role, content) 元组 self.max_turns max_turns def add(self, role: str, content: str): 添加一条记忆。 self.memory.append((role, content)) # 如果记忆超过最大轮次移除最早的记录 if len(self.memory) self.max_turns * 2: # 每轮包含 user 和 assistant 两条 self.memory self.memory[2:] def get_context(self, as_openai_messagesFalse): 获取记忆上下文。 :param as_openai_messages: 如果为 True返回 OpenAI 消息格式的列表 :return: 记忆列表或格式化后的消息列表 if not as_openai_messages: return self.memory.copy() else: # 转换为 OpenAI API 需要的消息格式 messages [] for role, content in self.memory: # 处理工具调用和返回的特殊格式稍后完善 if isinstance(content, dict) and content.get(role) tool: messages.append(content) else: messages.append({role: role, content: str(content)}) return messages def clear(self): 清空记忆。 self.memory.clear()这个记忆类非常基础后续可以扩展为支持向量数据库的长期记忆、摘要记忆等高级功能。现在我们已经有了所有零件接下来就是组装它们实现 ReAct 循环的核心逻辑。4. 核心引擎实现 ReAct 循环这是“Pi” Agent 最精彩的部分。我们将修改PiAgent类整合工具和记忆并实现思考 - 行动 - 观察的循环。# pi_agent.py (续) class PiAgent: # ... __init__ 和 _call_llm 方法保持不变 ... def add_tools(self, tool_descriptions, tool_map): 为 Agent 添加工具。 :param tool_descriptions: 工具描述列表 (TOOL_DESCRIPTIONS) :param tool_map: 工具名称到函数的映射 (TOOL_MAP) self.tools tool_descriptions self.tool_map tool_map def add_memory(self, memory_obj): 设置记忆系统。 self.memory_system memory_obj def _execute_tool(self, tool_call): 执行工具调用。 :param tool_call: OpenAI 响应中的 tool_calls 对象 :return: 工具执行结果字符串 func_name tool_call.function.name try: # 解析 LLM 提供的参数 arguments json.loads(tool_call.function.arguments) # 从映射中获取函数 func_to_call self.tool_map.get(func_name) if not func_to_call: return f错误未知工具 {func_name} # 调用函数 result func_to_call(**arguments) return str(result) except json.JSONDecodeError: return f错误无法解析工具参数 {tool_call.function.arguments} except TypeError as e: return f错误调用工具 {func_name} 时参数不匹配{e} except Exception as e: return f错误执行工具 {func_name} 时发生异常{e} def run(self, user_input: str, max_steps: int 5) - str: 运行 Agent处理用户输入。 实现 ReAct 循环。 :param user_input: 用户的问题或指令 :param max_steps: 最大循环步数防止无限循环 :return: Agent 的最终回复 # 1. 初始化对话历史 messages [] # 添加系统提示词定义 Agent 的角色和能力 system_prompt 你是一个名为 Pi 的智能助手。你可以使用工具来获取信息或执行操作。 请遵循以下步骤 1. 思考用户的问题判断是否需要使用工具。 2. 如果需要请精确地调用一个合适的工具。 3. 等待工具返回结果。 4. 根据结果思考可以继续调用工具或直接给出最终答案。 你的回答应清晰、简洁、有帮助。 messages.append({role: system, content: system_prompt}) # 添加记忆中的历史对话如果有 if hasattr(self, memory_system): history_messages self.memory_system.get_context(as_openai_messagesTrue) messages.extend(history_messages) # 添加当前用户输入 messages.append({role: user, content: user_input}) # 2. ReAct 循环 step 0 final_answer None while step max_steps and final_answer is None: step 1 print(f\n--- 步骤 {step} ---) # A. 思考并决定行动 llm_response self._call_llm(messages, toolsself.tools if self.tools else None) print(f思考结果: {llm_response.content or [工具调用]}) # B. 检查是否需要行动调用工具 if llm_response.tool_calls: # 有工具需要调用 for tool_call in llm_response.tool_calls: print(f决定调用工具: {tool_call.function.name} 参数: {tool_call.function.arguments}) # 执行工具 tool_result self._execute_tool(tool_call) print(f工具执行结果: {tool_result}) # 将工具调用和结果添加到消息历史供 LLM 下一轮观察 messages.append(llm_response) # 添加 LLM 包含工具调用的消息 messages.append({ role: tool, content: tool_result, tool_call_id: tool_call.id }) else: # 没有工具调用直接给出最终答案 final_answer llm_response.content print(f生成最终答案: {final_answer}) # 将助手的最终回复也添加到消息中为了记忆的一致性 messages.append(llm_response) break # 退出循环 # 3. 循环结束处理 if final_answer is None: final_answer f经过 {max_steps} 步仍未完成请求。可能任务过于复杂或需要更多信息。 print(final_answer) # 4. 更新记忆 if hasattr(self, memory_system): # 将本轮完整的交互存入记忆 # 简单起见我们存入用户输入和最终答案 self.memory_system.add(user, user_input) self.memory_system.add(assistant, final_answer) return final_answer代码逻辑详解初始化设置系统提示词加载历史记忆加入用户当前输入。循环开始思考调用_call_llm传入当前消息历史和可用工具描述。LLM 会返回一个响应这个响应可能包含纯文本内容也可能包含一个或多个tool_calls工具调用请求。判断检查响应中是否有tool_calls。如果有进入“行动”阶段。遍历每个工具调用通过_execute_tool执行对应的 Python 函数获取结果。观察将 LLM 的请求包含工具调用和工具执行的结果都追加到messages列表中。这样在下一轮循环中LLM 就能“看到”它上次行动的结果并基于此进行新的思考。如果没有说明 LLM 认为已经可以给出最终答案跳出循环。循环终止达到最大步数或得到最终答案后退出。更新记忆将本轮的用户输入和 Agent 的最终回答存入记忆系统供后续对话使用。这就是 ReAct 模式的核心实现代码量不大但完整地体现了智能体“感知-思考-行动”的闭环。5. 完整实战组装并运行你的第一个 Agent现在让我们把所有的部件组装起来并运行一个完整的示例。5.1 创建主程序创建一个main.py文件作为程序的入口。# main.py from pi_agent import PiAgent from tools import TOOL_DESCRIPTIONS, TOOL_MAP from memory import SimpleMemory def main(): print( 启动 Pi Agent ) # 1. 初始化 Agent agent PiAgent() # 2. 为 Agent 装备工具 print(加载工具...) agent.add_tools(TOOL_DESCRIPTIONS, TOOL_MAP) # 3. 为 Agent 装备记忆 print(初始化记忆系统...) memory SimpleMemory(max_turns5) agent.add_memory(memory) # 4. 运行示例对话 print(\n--- 开始对话 ---) queries [ 现在北京天气怎么样, 那上海呢, 计算一下 (15 27) * 3 等于多少, 现在几点了, 搜索一下关于人工智能的最新发展。, 我们刚才聊了哪些城市 # 测试记忆 ] for query in queries: print(f\n[用户]: {query}) response agent.run(query, max_steps3) print(f[Pi Agent]: {response}) print(\n 对话结束 ) if __name__ __main__: main()5.2 运行与结果分析在终端中确保你的.env文件已正确配置 API 密钥然后运行cd /path/to/pi_agent python main.py你应该能看到类似以下的输出具体内容因模型和 API 返回而异 启动 Pi Agent 加载工具... 初始化记忆系统... --- 开始对话 --- [用户]: 现在北京天气怎么样 --- 步骤 1 --- 思考结果: [工具调用] 决定调用工具: get_weather 参数: {city: 北京} 工具执行结果: 晴15°C北风2级 --- 步骤 2 --- 思考结果: 北京当前的天气是晴天气温15摄氏度北风2级。 生成最终答案: 北京当前的天气是晴天气温15摄氏度北风2级。 [Pi Agent]: 北京当前的天气是晴天气温15摄氏度北风2级。 [用户]: 那上海呢 --- 步骤 1 --- 思考结果: [工具调用] 决定调用工具: get_weather 参数: {city: 上海} 工具执行结果: 多云18°C东南风1级 --- 步骤 2 --- 思考结果: 上海当前的天气是多云气温18摄氏度东南风1级。 生成最终答案: 上海当前的天气是多云气温18摄氏度东南风1级。 [Pi Agent]: 上海当前的天气是多云气温18摄氏度东南风1级。 [用户]: 计算一下 (15 27) * 3 等于多少 --- 步骤 1 --- 思考结果: [工具调用] 决定调用工具: calculate 参数: {expression: (15 27) * 3} 工具执行结果: (15 27) * 3 126 --- 步骤 2 --- 思考结果: 计算结果为126。 生成最终答案: (15 27) * 3 的计算结果是 126。 [Pi Agent]: (15 27) * 3 的计算结果是 126。 [用户]: 现在几点了 --- 步骤 1 --- 思考结果: [工具调用] 决定调用工具: get_current_time 参数: {} 工具执行结果: 2024-05-27 14:30:15 --- 步骤 2 --- 思考结果: 当前时间是2024年5月27日 14:30:15。 生成最终答案: 当前时间是2024年5月27日 14:30:15。 [Pi Agent]: 当前时间是2024年5月27日 14:30:15。 [用户]: 搜索一下关于人工智能的最新发展。 --- 步骤 1 --- 思考结果: [工具调用] 决定调用工具: search_web 参数: {query: 人工智能 最新发展} 工具执行结果: 关于 人工智能 最新发展 的摘要人工智能领域近期在大型语言模型、多模态AI和具身智能方面进展迅速... --- 步骤 2 --- 思考结果: 根据搜索人工智能领域在大型语言模型、多模态AI和具身智能等方面有显著进展。 生成最终答案: 根据网络信息人工智能领域近期在大型语言模型如GPT系列、多模态AI能同时处理文本、图像、声音以及具身智能AI与物理世界交互等方面取得了快速进展。 [Pi Agent]: 根据网络信息人工智能领域近期在大型语言模型如GPT系列、多模态AI能同时处理文本、图像、声音以及具身智能AI与物理世界交互等方面取得了快速进展。 [用户]: 我们刚才聊了哪些城市 --- 步骤 1 --- 思考结果: 根据我们的对话历史我们刚才聊到了北京和上海的天气。 生成最终答案: 在我们之前的对话中我们查询了北京和上海的天气情况。 [Pi Agent]: 在我们之前的对话中我们查询了北京和上海的天气情况。 对话结束 结果分析工具调用Agent 成功识别了需要工具的场景天气、计算、搜索、时间并正确调用了函数。参数解析LLM 能够根据函数描述生成正确的 JSON 参数如{city: 北京}。ReAct 循环每个任务都经历了“思考-行动-观察-再思考”的过程。例如对于天气查询第一步是调用工具第二步是根据工具结果生成面向用户的答案。记忆测试最后一个问题“我们刚才聊了哪些城市”Agent 没有调用工具而是直接从对话历史记忆中提取信息并回答。这证明了我们简单记忆系统的有效性。至此你已经成功构建并运行了一个功能完整的极简 AI Agent6. 常见问题与排查思路在实践过程中你可能会遇到一些问题。以下是常见问题的排查指南。问题现象可能原因解决思路ModuleNotFoundError: No module named openai依赖未安装。运行pip install -r requirements.txt确保所有依赖已安装。检查 Python 环境是否正确。openai.AuthenticationErrorAPI 密钥错误或未设置。1. 检查.env文件中的OPENAI_API_KEY是否正确。2. 确保.env文件在项目根目录且python-dotenv已安装。3. 尝试在代码中直接打印os.getenv(“OPENAI_API_KEY”)的前几位确认是否加载成功。openai.APIConnectionError或超时网络问题或 API 地址错误。1. 检查网络连接。2. 如果使用非 OpenAI 官方服务如 DeepSeek检查OPENAI_BASE_URL是否正确。3. 尝试增加超时设置在_call_llm的client.chat.completions.create中添加timeout30参数。Agent 不调用工具直接回答1. 系统提示词不够清晰。2. 工具描述不准确。3. 模型能力不足如使用gpt-3.5-turbo在某些复杂场景下。1. 强化系统提示词明确要求“在需要时使用工具”。2. 检查TOOL_DESCRIPTIONS中的description和parameters是否清晰无歧义。3. 尝试使用更强大的模型如gpt-4。4. 在_call_llm中提高temperature到 0.3-0.5增加创造性但可能降低稳定性。工具调用参数错误LLM 生成的参数 JSON 格式错误或与函数签名不匹配。1. 在_execute_tool函数中加强错误处理和日志打印出错的参数。2. 在工具描述parameters中提供更详细的description和示例。3. 确保工具函数的参数名与描述中的properties键名完全一致。无限循环或步数过多任务过于复杂或 LLM 陷入逻辑循环。1. 设置合理的max_steps如 5-10。2. 在系统提示词中增加约束如“如果三步内无法解决请告知用户并请求更具体的指令”。3. 实现更复杂的循环终止逻辑例如检测到重复的工具调用。记忆不起作用记忆系统未正确添加或获取上下文。1. 检查memory.py中的add和get_context逻辑。2. 在pi_agent.py的run方法中打印history_messages查看记忆是否被正确加载到messages中。7. 进阶优化与最佳实践我们的“Pi” Agent 是一个教学原型要用于生产环境或更复杂的场景还需要进行一系列优化。7.1 增强系统提示词Prompt Engineering系统提示词是 Agent 的“宪法”决定了它的行为模式。一个强大的提示词可以显著提升表现。# 一个更强大的系统提示词示例 ADVANCED_SYSTEM_PROMPT 你是一个名为 Pi 的高级智能助手。你的核心原则是**先思考再行动**。 **能力** 1. 你可以使用工具来获取实时信息、进行计算或执行操作。 2. 你拥有当前对话的短期记忆。 **工作流程** 1. **分析需求**仔细理解用户的问题判断是否需要使用工具以及使用哪个工具。 2. **精确调用**如果需要工具请生成**唯一且精确**的工具调用请求。确保参数格式完全正确。 3. **整合信息**收到工具结果后分析其是否回答了用户问题。如果已足够则给出清晰、完整的最终答案。如果不够可以继续调用其他工具。 4. **保持简洁**最终答案应直接回应问题避免冗余。如果使用了工具可以在答案中简要说明信息来源例如“根据天气数据...”“根据网络搜索...”。 **约束** - 如果用户问题模糊请先请求澄清而不是盲目猜测。 - 如果连续3次工具调用后仍未解决问题请停止并告知用户当前进展和困难。 - 不要编造工具不存在的信息。 - 对于计算类问题请务必使用calculate工具进行验证。 将pi_agent.py中run方法的system_prompt替换为此提示词观察 Agent 行为的变化。7.2 实现更强大的记忆系统简单的对话历史记忆很快会耗尽上下文窗口。我们可以实现更高级的记忆摘要记忆定期将长对话历史总结成一段摘要既保留关键信息又节省 Token。向量记忆使用向量数据库如 Chroma, FAISS存储对话片段。当需要回忆时通过语义搜索召回最相关的历史信息。这需要引入sentence-transformers等嵌入模型库。7.3 工具执行的异步与超时当前工具调用是同步的如果某个工具如网络请求很慢会阻塞整个 Agent。可以使用asyncio库进行异步改造并为工具调用设置超时。import asyncio async def _execute_tool_async(self, tool_call): # ... 异步执行工具 ... # 例如使用 aiohttp 进行网络请求 pass7.4 安全性与错误处理强化工具安全彻底移除calculate函数中不安全的eval。可以使用ast.literal_eval或numexpr等安全库或者只实现一个简单的四则运算解析器。输入验证对所有从 LLM 解析出来的工具参数进行严格的类型和范围验证。速率限制为 LLM API 调用和工具调用添加速率限制防止意外超支或被封禁。结构化输出要求 LLM 以更结构化的格式如 JSON输出最终答案便于下游程序处理。7.5 可观测性与日志在生产中详细的日志对于调试和监控至关重要。可以引入logging模块为不同级别DEBUG, INFO, WARNING, ERROR的事件记录日志包括接收到的用户输入。LLM 的原始请求和响应。工具调用的开始、结束和结果。记忆的存储和读取。最终输出的答案。通过构建这个极简的“Pi” Agent我们不仅实现了一个可工作的智能体更重要的是我们透彻地理解了 Agent 架构的核心——ReAct 循环。这个简单的框架是一个强大的起点你可以基于它通过添加上面提到的进阶功能去构建解决特定领域问题的复杂智能体比如自动客服、数据分析助手、智能运维机器人等。记住复杂源于简单的叠加而理解简单是驾驭复杂的第一步。