
当前 AI Agent 框架正陷入一个尴尬的境地:LangChain 过于厚重,抽象层级过多导致调试困难、响应延迟高;AutoGen 虽擅长多智能体对话,但缺乏对结构化工具调用的严格约束;而原生 API 调用又让我们陷入重复造轮子的泥潭。
HermesAI —— 受 NousResearch Hermes 系列模型(以卓越的函数调用能力著称)启发,并非一个现成的第三方黑盒,而是一套 以函数调用(Function Calling)为绝对核心、采用确定性状态机驱动 的轻量级 Agent 框架设计范式。本文将完整拆解其核心架构、ReAct 循环的硬编码实现、多智能体协作模式,以及在生产环境中的性能调优策略。
笔者基于该框架已在内部落地了 SQL 智能运维助手(与上篇 MySQL 文章联动)和 云成本分析 Agent,日均处理任务 5000+,P95 延迟控制在 1.8s 以内。
HermesAI 摒弃了冗长的 Chain 抽象,仅保留六个核心模块:
设计铁律:
from dataclasses import dataclass
from typing import Any, List, Dict
from datetime import datetime
import json
@dataclass(frozen=True) # 不可变
class AgentContext:
session_id: str
user_query: str
plan: List[str] # 步骤列表
current_step: int
tool_calls: List[Dict] # 已执行的工具调用记录
observations: List[str] # 观察结果
final_answer: str = ""
def append_tool_call(self, tool_name: str, args: Dict, result: Any):
new_calls = self.tool_calls + [{"name": tool_name, "args": args, "result": result, "ts": datetime.utcnow().isoformat()}]
new_obs = self.observations + [f"{tool_name} -> {str(result)[:100]}"]
return AgentContext(
session_id=self.session_id,
user_query=self.user_query,
plan=self.plan,
current_step=self.current_step + 1,
tool_calls=new_calls,
observations=new_obs,
final_answer=self.final_answer
)利用装饰器 + Pydantic 实现“声明即文档”:
from pydantic import BaseModel, Field
from typing import Callable, Dict, Type, Any
class ToolDefinition:
def __init__(self, func: Callable, schema: Type[BaseModel], description: str):
self.func = func
self.schema = schema
self.description = description
class ToolRegistry:
_tools: Dict[str, ToolDefinition] = {}
@classmethod
def register(cls, name: str, description: str, schema: Type[BaseModel]):
def decorator(func: Callable):
cls._tools[name] = ToolDefinition(func, schema, description)
return func
return decorator
# ---------- 业务示例 ----------
class GetSlowQueryArgs(BaseModel):
time_range: str = Field(..., description="时间范围,如 'last_30min'")
threshold: float = Field(1.0, description="慢查询阈值(秒)")
@ToolRegistry.register("get_slow_queries", "获取指定时间段的慢查询列表", GetSlowQueryArgs)
def fetch_slow_logs(time_range: str, threshold: float = 1.0) -> List[Dict]:
# 伪代码:实际查询 performance_schema
return [{"sql": "select * from orders...", "duration": 5.2}]LLM 调用时的提示词构造:将 ToolDefinition 序列化为 OpenAI 兼容的 tools 参数格式,确保模型严格遵循 Schema。
HermesAI 不强依赖 LangChain 的 AgentExecutor,而是手写一个带 最大步数限制 和 提前终止 的确定性循环。
import asyncio
from openai import AsyncOpenAI
class HermesAgent:
def __init__(self, client: AsyncOpenAI, registry: ToolRegistry, max_steps: int = 5):
self.client = client
self.registry = registry
self.max_steps = max_steps
async def run(self, query: str) -> str:
ctx = AgentContext(
session_id="sess_001",
user_query=query,
plan=[],
current_step=0,
tool_calls=[],
observations=[]
)
messages = self._build_initial_messages(query)
for step in range(self.max_steps):
# 1. 调用 LLM
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=self._get_openai_tools(),
tool_choice="auto"
)
msg = response.choices[0].message
# 2. 检查是否结束
if not msg.tool_calls:
ctx = AgentContext(
**{**ctx.__dict__, "final_answer": msg.content} # 简易更新,生产用专用方法
)
return msg.content
# 3. 执行工具(并行优化)
tool_results = await asyncio.gather(*[
self._execute_tool_call(tc) for tc in msg.tool_calls
])
# 4. 追加工具结果到消息上下文
messages.append(msg) # 助手消息(带 tool_calls)
for tc, result in zip(msg.tool_calls, tool_results):
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 5. 更新上下文(用于观测)
# ... (省略 ctx 更新逻辑)
raise TimeoutError(f"Agent 执行超过最大步数 {self.max_steps}")对于独立无依赖的工具(如同时查 CPU 和 慢日志),利用 asyncio.gather 可将等待时间从串行的 2s 压缩到并行的 800ms。
HermesAI 不采用“圆桌会议”式的多 Agent 自由对话(容易跑题),而是采用 Router-Worker 分层调度。
代码实现:Router 本身也是一个 Agent,但它的工具列表里注册了 call_worker 方法,每个 Worker 拥有独立的 Prompt 和工具集。
@ToolRegistry.register("call_worker", "异步调用子智能体", CallWorkerArgs)
async def call_worker(worker_type: str, task: str):
if worker_type == "sql_optimizer":
return await SqlOptimizerAgent.run(task)
elif worker_type == "report_generator":
return await ReportAgent.run(task)
...这种模式极大地降低了单次 LLM 调用的上下文长度,且每个 Worker 可以独立迭代升级。
大模型 Agent 经常“忘记”之前的信息。HermesAI 实现三层记忆:
层级 | 存储介质 | 生命周期 | 内容 |
|---|---|---|---|
短期记忆 | Redis (TTL 300s) | 单次会话 | 工具调用历史、中间结果 |
工作记忆 | 上下文 Messages | 单次请求 | 当前步骤的思维链 |
长期记忆 | Milvus / PGVector | 持久化 | 历史案例、错误解决方案(Embedding 检索) |
当 Agent 遇到重复错误时,自动检索长期记忆中的“解决方案案例”,注入 Prompt 进行纠偏。
延续上篇文章的场景,HermesAI 充当 DBA 副驾驶:
performance_schema.events_statements_summary_by_digest 获取 Top 5 慢查询。EXPLAIN,提取 type/rows/extra。hypothetical indexes 或直接在生产从库验证,估算收益。压测数据(基于 16C32G 服务器,并发 50):
指标 | LangChain (基础) | HermesAI (本框架) |
|---|---|---|
P50 延迟 | 2.8s | 1.4s |
P95 延迟 | 5.5s | 1.9s |
Token 消耗(含工具结果) | 基准 | 降低 32%(因上下文精简) |
工具调用准确率(参数校验通过率) | 78% | 96% |
Agent 可能反复调用同一个无效工具。 对策:在上下文中检测重复模式(相似度 > 0.9 的工具调用连续出现 2 次),强制中断并提示“请更换策略”。
LLM 可能将 2026-08-08 传入定义为 Integer 的字段。
对策:在 _execute_tool_call 中先用 Pydantic 反序列化,失败则向 LLM 返回明确的 ValidationError 信息,让模型“自己纠正”。
思否读者关注的流式输出(SSE)下,状态更新难以回滚。 对策:采用 Event Sourcing(事件溯源),每个 Action 都是一个 Event,恢复时重放 Event。
数据库连接池在异步环境下易泄漏。
对策:所有工具函数使用 contextlib.aclosing 管理异步生成器,强制资源回收。
工具调用往往附带大量数据(如查询结果 5000 行)。
对策:在工具层面截断(如 result[:50]),并提供 get_full_result 的二次检索接口,按需加载。
为了压榨硬件性能,HermesAI 将 LLM 推理(GPU 密集型) 和 工具执行(I/O 密集型) 部署在不同进程池:
anyio 线程池,连接池复用。通过 RabbitMQ 作为任务缓冲,Agent 的吞吐量提升了 3.6 倍。
下一阶段,我们计划为 HermesAI 引入 Reflexion(反思机制)。当任务失败时,启动一个独立的“Critic”模型分析失败原因,并自动更新长期记忆库中的策略权重,实现“越用越聪明”。
HermesAI Agent 框架的核心哲学是 “克制与确定性” 。它没有盲目追求所谓的“端到端自动驾驶”,而是将 Agent 定义为一种 可观测、可干预、可降级的中间件。
通过本文的深度拆解,我们看到了:
如果你正在为生产环境的 Agent 延迟和不可控而苦恼,不妨抛弃重框架,基于 HermesAI 的理念自研一套轻量级方案。欢迎在评论区分享你的实践经验或质疑,我们一起推动 AI 基础设施的务实落地。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。