实现一个 AI Agent 框架是一个很有挑战性的项目,它需要将感知、决策、记忆和行动等多个模块有机地结合起来。下面我会从零开始,逐步引导你构建一个基础但可扩展的 Agent 框架。我们将采用**大语言模型(LLM)**作为核心推理引擎,因为这是当前 AI Agent 的主流方案。框架设计会尽量保持模块化,方便你后续替换或增加新功能。

1. 核心概念
一个 AI Agent 通常包含以下要素:
- 感知:接收来自用户或环境的输入。
- 记忆:存储历史对话、知识或短期上下文。
- 规划:将复杂任务分解为子任务,决定下一步动作。
- 工具:执行具体操作(如搜索、计算、调用 API)。
- 行动:生成输出或调用工具,影响环境。
我们的框架将围绕 ReAct(Reason + Act) 范式构建,即 Agent 循环地“思考”(推理)然后“行动”(执行工具或输出最终答案)。
2. 整体架构设计
我们将框架分为以下几个核心模块:
+-------------------+
| Agent | (主控制器,协调各模块)
+-------------------+
|
| 调用
v
+-------------------+ +-------------------+
| Planner | <--> | Memory |
| (决策与规划模块) | | (短期/长期记忆) |
+-------------------+ +-------------------+
|
| 决定执行工具
v
+-------------------+
| Tool | (工具集合,如计算器、搜索)
+-------------------+
|
| 执行结果返回
v
+-------------------+
| Environment | (外部环境,如文件系统、网络)
+-------------------+
- Agent:接收用户输入,调用 Planner 生成行动,管理 Memory 的读写。
- Planner:与 LLM 交互,将当前状态(用户输入+记忆+工具描述)转化为下一步行动(思考或工具调用)。
- Memory:存储对话历史、向量化知识等,支持检索。
- Tool:定义一组函数,Agent 可通过名称和参数调用它们。
- Environment:封装实际执行工具的环境,通常 Tool 直接调用系统功能,所以 Environment 可以简化。
3. 从零开始实现
3.1 定义基础接口
首先定义几个抽象基类,明确各模块的职责。
from abc import ABC, abstractmethod
from typing import Dict, List, Any, Optional
class Tool(ABC):
"""工具基类,所有具体工具需继承并实现 execute 方法"""
name: str
description: str
@abstractmethod
def execute(self, **kwargs) -> str:
pass
class Memory(ABC):
"""记忆模块接口"""
@abstractmethod
def add(self, role: str, content: str) -> None:
"""添加一条消息到记忆"""
pass
@abstractmethod
def get_context(self, query: str, max_tokens: int = 2000) -> str:
"""获取与当前查询相关的上下文(如最近对话或检索到的知识)"""
pass
class Planner(ABC):
"""规划模块,决定下一步动作"""
@abstractmethod
def plan(self, user_input: str, context: str, tools: List[Tool]) -> Dict[str, Any]:
"""返回一个动作描述,例如:
{"type": "think", "content": "我需要计算..."}
或 {"type": "tool", "name": "calculator", "args": {"expression": "2+2"}}
或 {"type": "final", "content": "最终答案"}
"""
pass
3.2 实现一个基于 LLM 的 Planner
这里我们假设使用 OpenAI 的 API 作为 LLM 后端。你需要安装 openai 库并设置 API Key。
Planner 的核心是构造一个合适的 Prompt,要求模型输出结构化的动作。我们可以采用 JSON 格式的输出,方便解析。
import openai
import json
class LLMPlanner(Planner

411

被折叠的 条评论
为什么被折叠?



