如果说大语言模型是一个满腹经纶却四肢不协调的学者,那么 Hermes Agent 就是给他配备了机械臂、望远镜、键盘和一张全球通票——而且还装了个"防止他把自己搞崩溃"的安全气囊。


一、开篇:为什么你需要了解 Hermes Agent

2024 年以来,"AI Agent"这个词的出镜率比任何流量明星都高。各路大厂、开源社区都在喊:「我们的 Agent 能自主完成任务!」但真正打开代码一看,很多不过是用 LangChain 套了几个函数调用,美其名曰"智能体"。

Nous Research 的 Hermes Agent 不一样。这是一个从生产级多平台部署出发设计的完整 AI 代理框架,代码量超过 15 万行,支持从命令行、Telegram、Discord、Slack、飞书到微信、DingTalk 等十余种消息平台,内置工具数量超过 70 个,还有一套精密的错误恢复、上下文压缩和插件机制。

更难得的是,整个系统的设计理念非常清晰:**让模型尽量专注"思考",让框架负责"手脚协调"**。本文将带你深入其架构核心,一探这套"让 AI 长出手脚"的工程哲学。


二、项目全景:一张地图先看懂

在钻进代码细节之前,先把 Hermes Agent 的整体版图摆出来:

用户层
  ├── CLI (交互式终端)          ← cli.py / hermes_cli/
  ├── TUI (Ink 终端 UI)         ← ui-tui/ + tui_gateway/
  ├── 消息网关 (多平台)         ← gateway/
  └── ACP Server (IDE 插件)     ← acp_adapter/

核心引擎层
  ├── AIAgent (对话主循环)      ← run_agent.py
  ├── 工具系统                  ← model_tools.py + tools/
  └── Agent 内核                ← agent/

基础设施层
  ├── 工具注册表                ← tools/registry.py
  ├── 工具集定义                ← toolsets.py
  ├── 会话存储 (SQLite FTS5)    ← hermes_state.py
  └── 插件系统                  ← hermes_cli/plugins.py

这个架构有一个显著特点:分层清晰,依赖单向tools/registry.py 没有任何上层依赖,工具模块只依赖注册表,model_tools.py 负责发现和调度,run_agent.py 在最上面消费一切。这种设计使得任何一层都可以独立测试,任何一个工具的改动都不会在项目里引发蝴蝶效应。


三、大脑:AIAgent 的对话主循环

3.1 一切的起点

run_agent.py 里的 AIAgent 类是整个项目的大脑,足足有 15,000+ 行代码。别被这个数字吓到,核心循环其实逻辑非常清晰:

# 极简版伪代码,展示核心逻辑
while iterations < max_iterations and budget.remaining > 0:
    if interrupt_requested:
        break
    
    # 调用 LLM
    response = llm_client.chat.completions.create(
        model=model, messages=messages, tools=tool_schemas
    )
    
    if response.tool_calls:
        # 执行工具,把结果追加到对话
        for tool_call in response.tool_calls:
            result = handle_function_call(tool_call.name, tool_call.args)
            messages.append(tool_result_message(result))
        iterations += 1
    else:
        # 模型不再调用工具,返回最终答案
        return response.content

这个循环有几个关键设计决策值得展开讲。

3.2 预算管理:防止 AI "无限刷卡"

IterationBudget 是一个线程安全的迭代计数器,初始化时设置最大迭代次数(默认 90 次):

class IterationBudget:
    def consume(self) -> bool:
        """尝试消耗一次迭代,返回是否允许继续"""
        with self._lock:
            if self._used >= self.max_total:
                return False
            self._used += 1
            return True

    def refund(self) -> None:
        """退还一次迭代(用于 execute_code 这类不消耗预算的调用)"""
        with self._lock:
            if self._used > 0:
                self._used -= 1

这里有个有趣的细节:execute_code 工具(让模型写 Python 脚本批量调用其他工具)调用完后会 退还 本次迭代预算。为什么?因为 execute_code 的目的是减少 LLM 轮次,如果反而消耗预算,就本末倒置了。

父 Agent 最大 90 次,每个子 Agent 独立最大 50 次——这样既防止了无限循环,又让复杂的委托任务有足够的空间完成。

3.3 并行工具调用:让 AI 学会"同时做多件事"

当 LLM 一次性返回多个工具调用时,Hermes 会智能判断能否并行执行:

_PARALLEL_SAFE_TOOLS = frozenset({
    "read_file", "search_files", "web_search", "web_extract",
    "vision_analyze", "session_search", ...
})

_PATH_SCOPED_TOOLS = frozenset({"read_file", "write_file", "patch"})
_NEVER_PARALLEL_TOOLS = frozenset({"clarify"})  # 需要用户交互,必须串行

对于路径相关的工具,系统会额外检查两个操作是否针对不同路径——如果都要读同一个文件,自然没必要并行,而且可能会出问题。这个判断逻辑虽然朴素,但在工程实践中足够实用。

最大并发工作线程数限制在 8 个,避免线程爆炸。

3.4 "Grace Call":给 AI 最后一次发言机会

有个不起眼但很贴心的细节:当预算用完时,系统会给模型一次 额外的最终调用机会_budget_grace_call),但这次不允许再使用工具,只能输出文字。这样即使任务没完全完成,模型也能礼貌地告知用户当前进度,而不是突然断电般消失。


四、手脚:工具系统的精妙设计

4.1 注册表模式:自动发现,无需手动维护

工具系统的核心是 tools/registry.py 里的 ToolRegistry 单例。每个工具文件在模块顶层调用 registry.register(),在 Python 导入时自动完成注册:

# tools/web_tool.py 示例(简化)
from tools.registry import registry

registry.register(
    name="web_search",
    toolset="web",
    schema={
        "name": "web_search",
        "description": "Search the web for information",
        "parameters": {
            "type": "object",
            "properties": {"query": {"type": "string"}},
            "required": ["query"]
        }
    },
    handler=lambda args, **kw: web_search(query=args["query"]),
    check_fn=lambda: True,  # 总是可用
)

注册表通过 AST 分析(而非执行)来检测哪些文件包含 registry.register() 调用,再按需导入:

def _module_registers_tools(module_path: Path) -> bool:
    """用 AST 扫描而非执行,安全高效"""
    source = module_path.read_text(encoding="utf-8")
    tree = ast.parse(source)
    return any(_is_registry_register_call(stmt) for stmt in tree.body)

这样,添加一个新工具只需:

  1. 创建 tools/your_tool.py 并调用 registry.register()

  2. 把工具名加入 toolsets.py 里的某个工具集

不需要修改任何主程序文件。这是教科书级别的开闭原则实践。

4.2 工具集:分层的权限管理

toolsets.py 定义了一套工具集体系,核心是 _HERMES_CORE_TOOLS 列表——这是默认给所有平台的基础工具包,包含:

  • 网络web_searchweb_extract

  • 终端terminalprocess

  • 文件read_filewrite_filepatchsearch_files

  • 浏览器自动化browser_navigatebrowser_clickbrowser_type 等 12 个

  • 内存与规划todomemory

  • 委托delegate_task(启动子 Agent)

  • 智能家居ha_*(Home Assistant 全套,条件可用)

  • 多 Agent 协调kanban_*(看板任务系统)

每个工具支持 check_fn 做可用性检查。比如 Home Assistant 工具只在设置了 HASS_TOKEN 环境变量时才出现在工具列表里,避免模型在没有 HA 的环境中乱用。

4.3 防止 AI "犯强迫症":工具护栏系统

agent/tool_guardrails.py 是一个完全无副作用的纯函数护栏控制器,专门对付 AI 的"重复行为":

情况 警告阈值 阻断阈值
完全相同的调用失败 2次 5次
同一工具持续失败 3次 8次
幂等工具无进展 2次 5次

这套系统能识别两类问题:

  • 精确循环:模型用相同参数反复调用同一个工具(通常意味着卡住了)

  • 无效探索:反复读同一个文件但每次都没推进对话(原地打转)

护栏控制器只返回"建议",不直接执行。真正的决策权在 run_agent.py 里,这保证了护栏逻辑的可测试性——你可以独立对 ToolCallGuardrailController 写单元测试,完全不需要启动 LLM。


五、记忆:跨会话持久化的艺术

5.1 上下文压缩:不得不说的工程难题

长对话是 AI 代理最头疼的问题之一。上下文超出限制怎么办?直接截断会让模型失去前文——就像让人从第200页开始读一本书。

Hermes 的 ContextCompressor 用一个辅助的小模型(便宜+快速)来总结中间的对话轮次,同时保护头尾。总结有精确的 token 预算控制:

_MIN_SUMMARY_TOKENS = 2000      # 总结最少要这么详细
_SUMMARY_RATIO = 0.20           # 总结占压缩内容的20%
_SUMMARY_TOKENS_CEILING = 12_000  # 再长也不超过这个

总结注入时会有明确的前缀标记:

[CONTEXT COMPACTION — REFERENCE ONLY] Earlier turns were compacted... Your current task is identified in the '## Active Task' section...

这个前缀非常关键:它告诉模型"这是历史摘要,不是新指令,请不要重复做已完成的事"。这个细节展现了工程师对 LLM 行为模式的深刻理解。

5.2 记忆管理:记住什么,忘记什么

agent/prompt_builder.py 里有一段对记忆系统的精妙指导,值得原文引用:

"Do NOT save task progress, session outcomes, completed-work logs, or temporary TODO state to memory... If a fact will be stale in a week, it does not belong in memory."

"Write memories as declarative facts, not instructions to yourself. 'User prefers concise responses' ✓ — 'Always respond concisely' ✗"

这不只是工程约束,更是一种认知架构哲学:记忆应该是关于"世界是什么样"的事实,而非"我该怎么做"的指令。指令式记忆在后续会话中会被模型错误地当作系统指令执行,造成行为漂移。

5.3 提示词注入防护

prompt_builder.py 里还有一个默默保护用户安全的扫描器,在加载 AGENTS.mdSOUL.md 等上下文文件前,会检测可能的 prompt 注入攻击:

_CONTEXT_THREAT_PATTERNS = [
    (r'ignore\s+(previous|all|above|prior)\s+instructions', "prompt_injection"),
    (r'do\s+not\s+tell\s+the\s+user', "deception_hide"),
    (r'curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)', "exfil_curl"),
    (r'cat\s+[^\n]*(\.env|credentials|\.netrc|\.pgpass)', "read_secrets"),
    # ... 更多模式
]

如果文件里藏着试图让 AI 泄露密钥或覆盖指令的恶意文本,系统会直接拦截并记录日志。在多平台网关场景下,这个保护尤其重要——你的 Telegram 机器人读取的是网络上的文档,随时可能遭遇"越狱陷阱"。


六、消息网关:把 AI 送进每个聊天软件

6.1 平台支持的广度令人叹为观止

Gateway 层支持的平台数量,看了真让人感叹开源社区的力量:

类别 平台
国际社交 Telegram、Discord、Slack、Signal、Matrix、Mattermost
国内平台 微信(Weixin)、企业微信(WeCom)、飞书(Feishu)、钉钉(DingTalk)、QQ机器人
特殊用途 Home Assistant、Email、SMS、BlueBubbles(iMessage)、Webhook、API Server
内部平台 元宝(YuanBao)

每个平台适配器继承自 gateway/platforms/base.py,实现统一的接口。这意味着核心 Agent 逻辑完全不感知自己是在回复 Telegram 消息还是企业微信消息——完美的抽象。

6.2 会话缓存:长驻 Gateway 的内存管理

Gateway 是个长驻进程,同时服务多个用户/频道。每个会话对应一个 AIAgent 实例(包含 LLM 客户端、工具 Schema、记忆提供者等),所以需要精心的缓存管理:

_AGENT_CACHE_MAX_SIZE = 128        # 最多缓存128个活跃会话
_AGENT_CACHE_IDLE_TTL_SECS = 3600  # 1小时无活动就驱逐

LRU 驱逐 + 空闲 TTL,避免长期运行的网关吃光内存。


七、错误韧性:当一切都在出错时

7.1 错误分类与分级响应

agent/error_classifier.py 定义了一套 API 错误分类体系,将各种奇形怪状的错误归类为标准的 FailoverReason

auth           → 刷新 token / 轮换凭证
billing        → 立即切换到下一个 API key
rate_limit     → 退避等待,然后轮换
context_overflow → 压缩上下文,不是 failover
timeout        → 重建客户端,重试
model_not_found → 降级到备用模型

注意 context_overflow 的处理方式:不是换一个 API key,而是压缩上下文再重试。分类器理解了不同错误的本质原因,而不是一律"换个密钥试试"。

7.2 凭证池:多 Key 自动轮换

agent/credential_pool.py 实现了生产级的凭证管理:

  • 策略fill_first(用满再换)、round_robin(轮询)、random(随机)、least_used(最少使用)

  • 状态:每个 key 独立追踪是否被限速(429)、余额耗尽(402)、认证失败(401)

  • 冷却时间:认证失败冷却 5 分钟,限速/余额问题冷却 1 小时

  • Provider 级:支持的 reset_at 时间戳会精确覆盖默认冷却时间

对于需要部署多个 API key 以提高吞吐量的生产场景,这套机制即插即用。

7.3 "安全写":防止破管道崩溃

有个藏在底层却至关重要的小设计:_SafeWriter——一个 sys.stdout/sys.stderr 的透明代理:

class _SafeWriter:
    def write(self, data):
        try:
            return self._inner.write(data)
        except (OSError, ValueError):
            # 管道破了?没关系,静默失败,不崩溃
            return len(data) if isinstance(data, str) else 0

当 Hermes 运行在 Docker 容器、systemd 服务或无头守护进程中,stdout 管道可能随时断开。没有这个包装,任何一个 print() 都可能让整个 Agent 崩溃。这种防御性编程在生产环境中才能体会到它的价值——等到线上崩了再加,已经晚了。


八、插件系统:让 Hermes 长出无限可能

8.1 四个插件来源

插件系统支持从四处发现插件:

  1. 仓库内置plugins/<name>/(随项目发布)

  2. 用户插件~/.hermes/plugins/<name>/(个人定制)

  3. 项目插件./.hermes/plugins/<name>/(项目级,需开关)

  4. pip 包:通过 hermes_agent.plugins entry-point 分发

后来的覆盖先来的——你的个人插件可以完全替换内置插件的同名版本。

8.2 钩子系统:无侵入式扩展

插件可以注册以下生命周期钩子:

  • pre_tool_call / post_tool_call:工具调用前后

  • pre_llm_call / post_llm_call:LLM 调用前后

  • on_session_start / on_session_end:会话开始/结束

想加一个"所有工具调用都记录到你的数据库"的可观测性插件?三行代码注册一个 post_tool_call 钩子就够了,完全不需要动主程序。

8.3 记忆提供者插件

记忆系统是独立的插件体系,支持多个后端:honchomem0supermemorybyteroverhindsight 等。每个实现 MemoryProvider ABC,提供标准的 sync_turn()prefetch()shutdown() 接口。

有趣的限制:只允许同时激活一个外部记忆提供者。这是有意为之——防止多个记忆后端向 LLM 的上下文窗口注入重复或冲突的信息,导致 schema 膨胀和行为混乱。


九、皮肤引擎:认真对待"颜值"

不少严肃的工程师可能觉得 CLI 的外观不重要,但 Hermes 有一套完整的皮肤引擎 hermes_cli/skin_engine.py——纯数据驱动,无需改代码就能定制整个界面风格。

内置四套皮肤:

  • default:经典 Hermes 金/卡哇伊风格

  • ares:深红战神主题,带自定义旋转翅膀

  • mono:简洁灰度单色

  • slate:冷蓝开发者风格

用户可以在 ~/.hermes/skins/ 放置 YAML 文件定制一切:颜色、加载动画表情、旋转动词("forging"、"plotting"...)、工具前缀符号、品牌名称……

# cyberpunk.yaml
name: cyberpunk
colors:
  banner_border: "#FF00FF"
  banner_title: "#00FFFF"
spinner:
  thinking_verbs: ["jacking in", "decrypting", "uploading"]
branding:
  agent_name: "Cyber Agent"

/skin cyberpunk 即时生效。这不是炫技,这是让工具成为工具使用者自己的一部分——当你的 AI 助手有着你自己定制的外观,你和它的关系就不一样了。


十、TUI 与 Dashboard:浏览器里跑终端

Hermes 有一个基于 Ink(React for terminal)的现代 TUI,通过 hermes --tui 启动。更有意思的是 hermes dashboard 命令——它会启动一个本地 Web 服务,在浏览器里嵌入真实的 hermes --tui 进程,通过 xterm.js 渲染。

关键设计决策在于:Dashboard 嵌入的不是一个 Web 版仿品,而是真实的终端进程。前后端通过 WebSocket PTY 桥接(ptyprocess on POSIX)。

AGENTS.md 里有一段对这个架构的警告,语气相当严肃:

"Do not re-implement the primary chat experience in React. The main transcript, composer/input flow... belong to the embedded hermes --tui — anything new you add to Ink shows up in the dashboard automatically. If you find yourself rebuilding the transcript or composer for the dashboard, stop and extend Ink instead."

这体现了一种工程纪律:不要因为"我在做 Web 前端"就去重新实现已经有的东西,应当找到正确的抽象层次去扩展。


十一、实际应用场景

场景一:个人全能助理

配置 Telegram Bot,Hermes Agent 立刻变成你的私人助理:

  • 早上问今天的新闻摘要 → web_search + 总结

  • 让它监控某个网页变化 → cronjob 定时任务

  • 远程执行服务器命令 → terminal + 安全审批

  • 告诉它你的习惯 → memory 持久化偏好

场景二:团队协作自动化

接入企业微信或飞书,让 Hermes 参与团队日常:

  • 用 Kanban 工具集拆解复杂项目到多个 Worker Agent 并行完成

  • send_message 工具让 Agent 在完成任务后主动通知相关人员

  • session_search 让 Agent 记住上次讨论的技术决策

场景三:开发流水线助手

结合代码仓库,Hermes 可以:

  • 读文件 → 分析代码 → 写文件 → 运行测试(一条龙)

  • delegate_task 让主 Agent 把子任务分配给多个并行的子 Agent

  • skill_manage 让 Agent 把学到的调试技巧存成可复用的"技能文档"

场景四:智能家居中枢

接入 Home Assistant,Hermes 变成能理解自然语言的智能家居控制器:

  • "开灯" → ha_call_service

  • "现在客厅温度多少" → ha_get_state

  • "每天晚上十点把卧室灯调暗" → cronjob + ha_call_service


十二、未来展望:架构蕴含的可能性

强化学习集成

项目里有一个 environments/ 目录,包含针对 Atropos 训练框架的 RL 环境实现。这意味着 Hermes Agent 正在探索通过实际任务执行来优化 Agent 行为的路径——不只是让 LLM 更强,而是让整个 Agent 循环更高效。

多 Agent 协作升级

现有的 Kanban 任务系统已经支持多个 Worker Agent 并行处理看板任务,并通过 SQLite 共享状态。这套机制的边界远未触到天花板:更复杂的任务依赖图、动态 Agent 生成、跨机器的分布式执行……

模型无关性的价值

目前已支持 OpenAI、Anthropic、Google Gemini、AWS Bedrock、Moonshot、本地 Ollama 等众多提供商,凭证池让多 Key 轮换无缝衔接。随着 AI 模型市场持续演化,这种提供商无关性会变得越来越值钱。


十三、总结:工程艺术与哲学的交汇点

读完 Hermes Agent 的代码,有几点感悟挥之不去:

一是"防御性"贯穿始终。_SafeWriter 防管道崩溃,到护栏系统防模型无限循环,再到 prompt 注入扫描,处处体现出"假设一切都会出错"的工程心态。这不是悲观主义,这是经验。

二是"抽象边界"的坚守。 工具注册表不知道 Agent 的存在,Agent 不知道具体跑在哪个消息平台上,TUI 的 Ink 层不知道 Python 的业务逻辑——每一层都在做好自己的事,通过清晰的接口对话。

三是"数据驱动 vs 代码驱动"的智慧选择。 皮肤系统、工具集定义、命令注册表都选择了数据驱动,让扩展成本降为零。而核心的 Agent 循环、错误恢复逻辑则坚守代码,保持精确控制。

四是对人机交互的尊重。 无论是 clarify 工具让 AI 在不确定时主动问用户,还是 _budget_grace_call 让 AI 在预算耗尽时体面地道别,都体现了"AI 是来辅助人的,不是来替代人判断的"这一根本立场。

Hermes Agent 不是一个"玩具级"的 AI 代理演示,它是一个认真思考过生产部署、安全边界、可扩展性和用户体验的系统。无论你是想学习 Agent 架构设计,还是直接把它当作自己的 AI 基础设施,都值得深入研究。


项目地址Hermes Agent - Nous Research
官方文档:https://hermes-agent.nousresearch.com/docs


更多AIGC文章

RAG技术全解:从原理到实战的简明指南

更多VibeCoding文章

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐