构建你的 Agent 框架
一句话
从零开始构建HelloAgents智能体框架,实现多提供商支持、本地模型集成和自动检测机制。
什么时候翻这页
当你需要理解Agent框架设计原理,或想从使用者转变为框架构建者时。
核心概念
- 自建Agent框架:为解决现有框架的局限性,从零开始构建的智能体框架
- HelloAgentsLLM:统一的大语言模型调用接口,支持多提供商和本地模型
- 自动检测机制:根据环境信息智能推断所使用的LLM服务类型
- Agent基类:定义智能体通用行为和属性的抽象基类
- 工具系统:将Memory、RAG、MCP等模块统一抽象为"工具"的设计理念
- ReAct:推理与行动相结合的智能体范式
- Plan-and-Solve:先规划后执行的智能体范式
- Reflection:具有自我反思能力的智能体范式
怎么做
框架整体架构设计
-
为何需要自建Agent框架
- 市面框架存在过度抽象复杂性、快速迭代不稳定性、黑盒化实现逻辑和依赖关系复杂等问题
- 从使用者到构建者的能力跃迁,能深度理解Agent工作原理
- 满足特定领域的优化需求、性能与资源的精确控制以及学习与教学的透明性要求
-
HelloAgents框架的设计理念
- 轻量级与教学友好的平衡
- 基于标准API的务实选择
- 渐进式学习路径的精心设计
- 统一的"工具"抽象:万物皆为工具
-
框架架构
hello-agents/ ├── hello_agents/ │ ├── core/ # 核心框架层 │ ├── agents/ # Agent实现层 │ └── tools/ # 工具系统层
HelloAgentsLLM扩展
-
支持多提供商
- 通过继承
HelloAgentsLLM类扩展新供应商支持 - 重写
__init__方法处理特定供应商逻辑
- 通过继承
-
本地模型调用
- VLLM:高性能本地模型部署方案
- Ollama:简化的本地模型管理和部署工具
-
自动检测机制
- 检查特定服务商的环境变量
- 根据
base_url进行判断 - 分析API密钥格式辅助判断
框架接口实现
-
Message类
- 定义统一的消息格式
- 支持角色限制:user、assistant、system、tool
- 提供与OpenAI API兼容的转换方法
-
Config类
- 集中管理配置参数
- 支持从环境变量读取配置
- 提供合理的默认值
-
Agent抽象基类
- 定义智能体通用行为和属性
- 强制子类实现
run方法 - 提供历史记录管理功能
Agent范式的框架化实现
-
SimpleAgent
- 基础对话范式
- 支持可选工具调用功能
- 实现多轮工具调用逻辑
-
ReActAgent
- 推理与行动相结合的范式
- 实现思考-行动-观察循环
-
ReflectionAgent
- 具有自我反思能力的范式
- 实现"执行-反思-优化"循环
-
PlanAndSolveAgent
- 先规划后执行的范式
- 将复杂任务分解为子任务
工具系统实现
-
工具系统基础
- Tool基类的抽象设计
- ToolParameter参数定义系统
- ToolRegistry注册表的实现
-
自定义工具开发
- 函数注册方式
- 类方式实现复杂工具
- 工具测试与集成
-
多源搜索工具
- 统一接口设计
- TAVILY与SERPAPI搜索源整合
- 搜索结果统一格式化
-
工具系统高级特性
- 工具链式调用机制
- 异步工具执行支持
- 工具链管理器实现
命令 / 代码速查
安装HelloAgents框架
# hello-agents 框架代码可见链接:https://github.com/jjyaoao/HelloAgents
# Python 版本需要>=3.10
pip install "hello-agents==0.1.1"
快速体验HelloAgents
# 配置好同级文件夹下.env中的大模型API
from hello_agents import SimpleAgent, HelloAgentsLLM
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 创建LLM实例 - 框架自动检测provider
llm = HelloAgentsLLM()
# 创建SimpleAgent
agent = SimpleAgent(
name="AI助手",
llm=llm,
system_prompt="你是一个有用的AI助手"
)
# 基础对话
response = agent.run("你好!请介绍一下自己")
print(response)
# 添加工具功能
from hello_agents.tools import CalculatorTool
calculator = CalculatorTool()
# 需要实现MySimpleAgent进行调用,后续章节会支持此类调用方式
# agent.add_tool(calculator)
# 现在可以使用工具了
response = agent.run("请帮我计算 2 + 3 * 4")
print(response)
# 查看对话历史
print(f"历史消息数: {len(agent.get_history())}")
自定义LLM类
# my_llm.py
import os
from typing import Optional
from openai import OpenAI
from hello_agents import HelloAgentsLLM
class MyLLM(HelloAgentsLLM):
"""
一个自定义的LLM客户端,通过继承增加了对ModelScope的支持。
"""
def __init__(
self,
model: Optional[str] = None,
api_key: Optional[str] = None,
base_url: Optional[str] = None,
provider: Optional[str] = "auto",
**kwargs
):
# 检查provider是否为我们想处理的'modelscope'
if provider == "modelscope":
print("正在使用自定义的 ModelScope Provider")
self.provider = "modelscope"
# 解析 ModelScope 的凭证
self.api_key = api_key or os.getenv("MODELSCOPE_API_KEY")
self.base_url = base_url or "https://api-inference.modelscope.cn/v1/"
# 验证凭证是否存在
if not self.api_key:
raise ValueError("ModelScope API key not found. Please set MODELSCOPE_API_KEY environment variable.")
# 设置默认模型和其他参数
self.model = model or os.getenv("LLM_MODEL_ID") or "Qwen/Qwen2.5-VL-72B-Instruct"
self.temperature = kwargs.get('temperature', 0.7)
self.max_tokens = kwargs.get('max_tokens')
self.timeout = kwargs.get('timeout', 60)
# 使用获取的参数创建OpenAI客户端实例
self._client = OpenAI(api_key=self.api_key, base_url=self.base_url, timeout=self.timeout)
else:
# 如果不是 modelscope, 则完全使用父类的原始逻辑来处理
super().__init__(model=model, api_key=api_key, base_url=base_url, provider=provider, **kwargs)
Message类实现
"""消息系统"""
from typing import Optional, Dict, Any, Literal
from datetime import datetime
from pydantic import BaseModel
# 定义消息角色的类型,限制其取值
MessageRole = Literal["user", "assistant", "system", "tool"]
class Message(BaseModel):
"""消息类"""
content: str
role: MessageRole
timestamp: datetime = None
metadata: Optional[Dict[str, Any]] = None
def __init__(self, content: str, role: MessageRole, **kwargs):
super().__init__(
content=content,
role=role,
timestamp=kwargs.get('timestamp', datetime.now()),
metadata=kwargs.get('metadata', {})
)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典格式(OpenAI API格式)"""
return {
"role": self.role,
"content": self.content
}
def __str__(self) -> str:
return f"[{self.role}] {self.content}"
Config类实现
"""配置管理"""
import os
from typing import Optional, Dict, Any
from pydantic import BaseModel
class Config(BaseModel):
"""HelloAgents配置类"""
# LLM配置
default_model: str = "gpt-3.5-turbo"
default_provider: str = "openai"
temperature: float = 0.7
max_tokens: Optional[int] = None
# 系统配置
debug: bool = False
log_level: str = "INFO"
# 其他配置
max_history_length: int = 100
@classmethod
def from_env(cls) -> "Config":
"""从环境变量创建配置"""
return cls(
debug=os.getenv("DEBUG", "false").lower() == "true",
log_level=os.getenv("LOG_LEVEL", "INFO"),
temperature=float(os.getenv("TEMPERATURE", "0.7")),
max_tokens=int(os.getenv("MAX_TOKENS")) if os.getenv("MAX_TOKENS") else None,
)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return self.dict()
Agent基类实现
"""Agent基类"""
from abc import ABC, abstractmethod
from typing import Optional, Any
from .message import Message
from .llm import HelloAgentsLLM
from .config import Config
class Agent(ABC):
"""Agent基类"""
def __init__(
self,
name: str,
llm: HelloAgentsLLM,
system_prompt: Optional[str] = None,
config: Optional[Config] = None
):
self.name = name
self.llm = llm
self.system_prompt = system_prompt
self.config = config or Config()
self._history: list[Message] = []
@abstractmethod
def run(self, input_text: str, **kwargs) -> str:
"""运行Agent"""
pass
def add_message(self, message: Message):
"""添加消息到历史记录"""
self._history.append(message)
def clear_history(self):
"""清空历史记录"""
self._history.clear()
def get_history(self) -> list[Message]:
"""获取历史记录"""
return self._history.copy()
def __str__(self) -> str:
return f"Agent(name={self.name}, provider={self.llm.provider})"
自定义工具开发
# my_calculator_tool.py
import ast
import operator
import math
from hello_agents import ToolRegistry
def my_calculate(expression: str) -> str:
"""简单的数学计算函数"""
if not expression.strip():
return "计算表达式不能为空"
# 支持的基本运算
operators = {
ast.Add: operator.add, # +
ast.Sub: operator.sub, # -
ast.Mult: operator.mul, # *
ast.Div: operator.truediv, # /
}
# 支持的基本函数
functions = {
'sqrt': math.sqrt,
'pi': math.pi,
}
try:
node = ast.parse(expression, mode='eval')
result = _eval_node(node.body, operators, functions)
return str(result)
except:
return "计算失败,请检查表达式格式"
def _eval_node(node, operators, functions):
"""简化的表达式求值"""
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = _eval_node(node.left, operators, functions)
right = _eval_node(node.right, operators, functions)
op = operators.get(type(node.op))
return op(left, right)
elif isinstance(node, ast.Call):
func_name = node.func.id
if func_name in functions:
args = [_eval_node(arg, operators, functions) for arg in node.args]
return functions[func_name](*args)
elif isinstance(node, ast.Name):
if node.id in functions:
return functions[node.id]
def create_calculator_registry():
"""创建包含计算器的工具注册表"""
registry = ToolRegistry()
# 注册计算器函数
registry.register_function(
name="my_calculator",
description="简单的数学计算工具,支持基本运算(+,-,*,/)和sqrt函数",
func=my_calculate
)
return registry
与 Python / Claude Code 手册的联系
- Python面向对象编程:Agent基类的抽象基类实现
- Python类型提示:Message类和Config类的类型定义
- Python环境变量管理:Config类从环境变量读取配置
- Python异步编程:异步工具执行器的实现
- Python设计模式:单例模式在Config类中的应用
初学者易错点
- 过度依赖框架抽象:框架简化了开发,但可能掩盖了底层原理,建议同时理解底层实现
- 工具链执行顺序:工具链中的步骤顺序很重要,错误的顺序可能导致结果不符合预期
- 自动检测机制限制:自动检测并非万能,复杂环境可能需要手动指定provider
- 异步工具执行:异步执行虽然提高性能,但需要注意错误处理和资源管理
- Agent基类继承:实现自定义Agent时必须实现run方法,否则会引发抽象方法错误
相关词条
- ReAct:推理与行动相结合的智能体范式
- Plan-and-Solve:先规划后执行的智能体范式
- Reflection:具有自我反思能力的智能体范式
- 工具系统:Agent能力延伸的核心组件
- MCP:模型上下文协议,被抽象为工具的一种
- LangGraph:一种智能体框架,被HelloAgents借鉴设计理念