乐于分享
好东西不私藏

你家的 AI 助手会做梦吗?从 Hermes Agent 学到的 7 个架构设计最佳实践

你家的 AI 助手会做梦吗?从 Hermes Agent 学到的 7 个架构设计最佳实践

📋 摘要: 不管用什么框架,好的设计理念是通用的。本文从一个开源 AI Agent 项目的开发指南出发,聊聊那些值得每个 AI 项目抄作业的架构实践。


🎬 引言

你家的 AI 助手会做梦吗?💭

如果你的 AI 助手用的是 OpenClaw,答案是——真的会。我们之前研究过 OpenClaw 的 “Dreaming” 功能,Agent 会在空闲时自动整理记忆、生成摘要,就像人在睡眠中巩固记忆一样。🌙

但今天我想聊的不是 OpenClaw 怎么做梦,而是我最近在研究另一个优秀的开源 AI Agent 项目 —— Hermes Agent 时,从它的 AGENTS.md 开发指南里挖到的宝藏。💎

作为一个基于 Python 的开源 AI 智能体框架,Hermes 专注于 CLI 和消息平台(Telegram、Discord、Slack 等)的集成。它的代码量不算特别大,但开发指南写得异常扎实。读完之后我最大的感受是:

好的架构设计,不是用了多先进的技术栈,而是把简单的事情做得足够好。✨

下面这些设计原则,不管你在用什么框架、写什么 AI 项目,都可以直接抄作业。📝


📌 一、中央命令注册表 —— 一处定义,处处同步

❓ 问题

假设你要开发一个支持多平台的 AI Agent,用户可以在 CLI 里输入 /help,在 Telegram 里发送 /help,在 Discord 里用 /help……

最常见的做法是什么?每个平台各写一份命令定义。

平台
命令定义位置
要改的地方
CLI
cli/commands.py
1
Telegram Bot
telegram/handlers.py
2
Discord Bot
discord/slash_cmds.py
3
Slack
slack/bolt_handlers.py
4
自动补全
autocomplete/registry.json
5

改一个命令的 help 文案,要改 5 个地方。漏了一个,用户就会在不同平台看到不一致的提示。😫

🧪 Hermes 的做法

Hermes 搞了一个 COMMAND_REGISTRY所有命令在一个地方定义

💡 以下为简化示意代码,展示核心思想。Hermes 实际使用 CommandDef 对象列表而非字典。

# 简化示意:所有命令在一个地方定义
COMMAND_REGISTRY = [
    CommandDef("help""Show available commands""Info",
               aliases=("h",), args_hint=""),
    CommandDef("memory""Manage agent memory""Configuration",
               aliases=("mem",), args_hint="<action>"),
# ... 更多命令
]

每个 CommandDef 包含命令名、描述、分类、别名、参数提示、适用平台等字段。CLI 菜单、Telegram 命令列表、Discord 应用命令、Slack 路由、自动补全——全部从这个单一列表自动派生

💡 核心思想

Single Source of Truth(单一数据源)

改一个地方,处处生效。这不是什么高深的设计模式,但很多项目就是做不到——因为”先快速跑起来”的时候,顺手就在每个平台各写了一份。等技术债积累到一定程度,再想重构就难了。🔧

我们的启发: 当你需要扩展自定义命令时,第一件事不是去对应平台的 handler 里加代码,而是先问自己——能不能把它加到中央注册表里?🤔


🔧 二、工具自动发现 —— 注册即生效

📦 常见做法

很多 AI Agent 项目里,添加工具需要同时做几件事:

# tools/__init__.py —— 手动维护导入列表
from .weather import get_weather
from .calendar import get_events
from .search import web_search
from .email import send_email
from .github import create_issue
# 每新增一个工具,这里加一行 import
# 然后下面还要注册……

TOOL_REGISTRY = [
    get_weather,
    get_events,
    web_search,
    send_email,
    create_issue,
# 每新增一个工具,这里再加一行
]

两个地方都要改,漏一个工具就”消失”了。🫥

🌟 Hermes 的做法

工具文件本身就负责注册:

# tools/weather.py — 简化示意
# 实际 Hermes 使用 registry.register() 函数调用,handler 返回 JSON 字符串
import json
from tools.registry import registry

defcheck_requirements():
returnTrue# 检查 API Key 等环境

defget_weather(location: str) -> str:
return json.dumps({"location": location, "temperature"22})

registry.register(
    name="weather",
    toolset="core",
    schema={"name""weather""description""Get weather""parameters": {...}},
    handler=lambda args, **kw: get_weather(args.get("location")),
    check_fn=check_requirements,
)

文件放对位置、调用 register(),完事。 框架在启动时自动扫描 tools/ 目录,发现注册调用就完成了加载。注册、分发、可用性检查、错误封装——全部由 registry 处理。

工具文件本身?只写业务逻辑。✅

💡 核心思想

关注点分离:框架负责”怎么管”,开发者只写”做什么”。

这和 Django 的 apps.py、Spring 的 @Component 扫描是一个道理。好的框架让你少写”胶水代码”,把精力留给真正的业务逻辑。🎯


🎨 三、纯数据驱动的主题引擎 —— 零代码定制

Hermes 有一个 Skin/主题引擎,用 YAML 定义皮肤。从 banner 颜色到 spinner 表情到 prompt 符号,全部是数据,不是代码

# skins/cyberpunk.yaml — 用户自定义皮肤
name:cyberpunk
description:Neon-soakedterminaltheme

colors:
banner_border:"#FF00FF"
banner_title:"#00FFFF"
banner_accent:"#FF1493"

spinner:
thinking_verbs:["jackingin","decrypting","uploading"]
wings:
-["⟨⚡","⚡⟩"]

branding:
agent_name:"Cyber Agent"
response_label:" ⚡ Cyber "

tool_prefix:"▏"

💡 以上是用户自定义皮肤的 YAML 示例(来自原文)。激活只需 /skin cyberpunk 或在 config.yaml 里设 display.skin: cyberpunk

换一个皮肤?换一个 YAML 文件就行。零代码改动。 🎭

💡 核心思想

配置化 > 代码化:把可变的东西抽成数据。

如果你在设计一个系统,问自己:“这个部分将来会不会经常改?” 如果答案是”会”,那就把它抽成配置——YAML、JSON、环境变量都行。把变化关在数据层,代码层保持稳定。🔒

这个道理放之四海而皆准:

  • 按钮颜色不要硬编码在 CSS 里,用 CSS 变量 🎨
  • API endpoint 不要散落在各个文件里,用配置文件集中管理 🔗
  • AI 的 system prompt 不要写死在代码里,用模板引擎 📋

⚠️ 四、Known Pitfalls —— 踩过的坑就是最好的文档

Hermes 的 AGENTS.md 里有一个非常实在的部分:Known Pitfalls(已知坑)

不是那种空洞的”最佳实践”,而是明明白白告诉你:

## Known Pitfalls

❌ DO NOT hardcode `~/.hermes` paths
  - Use `get_hermes_home()` instead
  - Fixed in PR #247

❌ DO NOT use `simple_term_menu`
  - Causes crashes on macOS with Python 3.12+
  - Fixed in PR #312, replaced with `questionary`

❌ DO NOT rebuild system prompt mid-conversation
  - Breaks prompt caching, costs 3x more

甚至标注了是哪个 PR 修的这个坑。📎

💡 核心思想

经验沉淀比文档模板更有价值。

很多项目的文档只告诉你”应该怎么做”,却不告诉你”千万别怎么做”。但后者往往更有价值——因为”应该怎么做”可以猜,”千万别怎么做”只有踩过坑才知道。💪

我们自己也踩过不少坑:

  • 🌙 Dreaming 功能污染日志:Agent 在后台做梦时产生的日志混入了正常会话日志,排查问题的时候一头雾水
  • 🤖 Main Agent 越位干活:本该交给 subagent 处理的任务,main agent 自己冲上去干了,导致职责混乱

把这些踩过的坑写进文档,比写一百页”架构规范”都有用。📖


🔒 五、Prompt Caching 保护策略 —— 明确”不能做什么”

Hermes 对 Prompt Caching 有明确的保护规定:

## Prompt Caching Rules

DO NOT modify context mid-conversation
DO NOT change the toolset during a session
DO NOT rebuild the system prompt after initialization

为什么?因为 cache-breaking 会导致成本大幅上升。💰

LLM 的 prompt caching 机制依赖于 prompt 的前缀不变。如果你中途改了 system prompt、增删了工具定义、或者在上下文里插入了大段内容导致缓存失效——下一次请求就要重新计算所有 token,成本可能是原来的 3-5 倍

💡 核心思想

规则不只是告诉你”能做什么”,更重要的是”不能做什么”。

这在我们的 AI 项目中同样适用:

  • 不要在对话中途换 model(缓存失效 + context 丢失)🚫
  • 不要动态增删 tool definitions(触发重新解析)🔄
  • 不要在 system prompt 里塞会变化的内容(比如当前时间戳——放 user message 里)⏰

“不能做什么”的清单,往往比”能做什么”的清单更重要。 📌


🏗️ 六、多实例 Profile 系统 —— 隔离的艺术

Hermes 从一开始就设计了 Profile 系统。每个 profile 是独立的:

~/.hermes/
├── profiles/
│   ├── work/
│   │   ├── config.yaml
│   │   ├── api_keys.json
│   │   ├── memory/
│   │   └── sessions/
│   ├── personal/
│   │   ├── config.yaml
│   │   ├── api_keys.json
│   │   ├── memory/
│   │   └── sessions/
│   └── experiment/
│       ├── config.yaml
│       ├── api_keys.json
│       ├── memory/
│       └── sessions/
└── hermes.yaml  # 全局配置

每个 profile 有自己的配置、API Key、记忆、会话。所有路径通过 get_hermes_home() 获取,绝不硬编码。 📁

💡 核心思想

从一开始就设计隔离,比后来补救容易得多。

很多项目开始时只有一个”默认实例”,跑得好好的。直到有一天用户说”我想同时跑两个不同的 agent”——然后发现路径全硬编码了、状态全混在一起了、配置文件互相覆盖……😵

隔离不是过度设计,是远见。 🔭


🧪 七、测试纪律 —— ~3000 个测试的安全网

Hermes 项目有大约 3000 个测试用例

不是什么 fancy 的自动化测试框架,就是朴素的纪律:

# 每次 push 之前
pytest tests/ -v

# 测试文件使用隔离的 temp dir
# 不污染开发者工作区
# 不依赖外部服务(用 mock)

3000 个测试听起来很多,但对于一个多平台、多工具的 Agent 项目来说,这意味着:

  • ✅ 改了 CLI 的命令解析?Telegram 的 handler 不会被意外破坏
  • ✅ 更新了 weather 工具?email 工具的单元测试不会受影响
  • ✅ 重构了 profile 系统?所有已有功能依然在测试覆盖下

💡 核心思想

测试不是 QA 的工作,是长期项目的安全网。 🛡️

对于个人项目或者小团队,不要求你也写 3000 个测试。但至少要做到:

  • 改了核心逻辑,跑一遍测试再 push 🏃
  • 测试用临时目录,别污染工作区 📂
  • 测试要能本地跑,别依赖 CI 环境 🖥️

🎯 总结:最值得立刻借鉴的 4 点

回过头来看,从 Hermes 项目学到的架构设计中,我认为最值得立刻应用到任何 AI Agent 项目的是这 4 点:

#
实践
一句话总结
1️⃣
中央命令注册表
一个地方定义命令,所有平台自动同步
2️⃣
工具自动发现
注册即生效,告别手动维护导入列表
3️⃣
Known Pitfalls 文档
踩过的坑写下来,比架构文档更有价值
4️⃣
Prompt Caching 保护
明确”不能做什么”,守住成本底线

好的架构设计从来不是关于用了什么花哨的技术栈。它关于:

  • 把可变的东西抽成数据 📊
  • 把重复的事情自动化 🤖
  • 把踩过的坑记录下来 📝
  • 从一开始就设计隔离 🏰

Hermes 把这些简单的事情做好了,所以它成了一个可靠的、可维护的、可生长的项目。🌱


🔗 Hermes Agent 项目:详见项目仓库(GitHub 搜索 “hermes agent”)

💬 欢迎在评论区交流——你在做 AI Agent 项目时,踩过哪些坑?又学到了哪些好的架构实践?


📤 如果你觉得这篇文章有帮助,欢迎转发给同样在折腾 AI Agent 的朋友。