> TL;DR:让 Agent 7×24 小时跑在生产环境的四根柱子。Profile(多身份隔离,每个 profile 有独立的 config/skills/memory)、Cron(自主定时唤醒,无需人工介入)、MCP(动态扩展工具集,零重启)、Plugin(全生命周期钩子)。这篇是系列收尾——拆完八篇,你看到的不是"一个框架",是一个可以自我运作的 Agent 生态。
前七篇拆了子系统全景、Agent Loop、System Prompt、工具系统、记忆矩阵、模型调度、技能进化。最后一篇拆让这一切能够 7×24 小时自动运转的基础设施。
1. Profile:多身份隔离
Profile 是 Hermes 实现"一台机器跑多个人格"的基础设施。每个 Profile 拥有独立的 config.yaml、skills/、plugins/、cron/、memories/。
# hermes_cli/profiles.py
def _get_profiles_root() -> Path:
"""Return the directory where named profiles are stored.
Anchored to the hermes root, NOT to the current HERMES_HOME.
"""
return _get_default_hermes_home() / "profiles"
目录结构:
~/.hermes/
├── config.yaml # default profile 的配置
├── skills/ # default profile 的技能
├── plugins/ # default profile 的插件
├── cron/ # default profile 的定时任务
├── memories/ # default profile 的记忆
└── profiles/
├── work/ # 另一个身份
│ ├── config.yaml
│ ├── skills/
│ ├── cron/
│ └── memories/
└── personal/
└── config.yaml
Profile 切换通过 active_profile 文件持久化:
def _get_active_profile_path() -> Path:
"""Return the path to the sticky active_profile file."""
return _get_default_hermes_home() / "active_profile"
这个文件简单存一个 Profile 名。Hermes 启动时读这个文件,如果存在就覆盖默认路径——~/.hermes/ → ~/.hermes/profiles/<name>/。
hermes_constants.py 中 get_hermes_home() 会根据 active_profile 动态解析路径。而且 Profile 切换是线程安全的——使用 ContextVar 而非全局变量,不同线程可以跑不同 Profile:
_HERMES_HOME_OVERRIDE: ContextVar[str | object] = ContextVar(
"_HERMES_HOME_OVERRIDE", default=_UNSET
)
def set_hermes_home_override(path: str | Path | None) -> Token:
"""Set a context-local Hermes home override and return its reset token.
This is for in-process, per-task scoping. It deliberately does not mutate
os.environ because that is shared by every thread in the process.
"""
value: str | object = _UNSET if path is None else str(path)
return _HERMES_HOME_OVERRIDE.set(value)
os.environ 是进程级别的全局状态——所有线程共享,改一次所有线程受影响。ContextVar 是 Python 3.7 引入的协程安全变量,每个协程/线程有自己的副本,互不干扰。
Profile 克隆时还会跳过基础设施工件:
def _clone_all_copytree_ignore(source_dir: Path):
"""Exclude infrastructure artifacts when cloning a profile via --clone-all."""
def _ignore(directory: str, names: List[str]) -> List[str]:
ignored: list[str] = []
for entry in names:
# 跳过 .git、__pycache__、node_modules、.env、state.db、*.log
...
return _ignore
克隆时跳过 .env(含密码)、state.db(会话数据库)、.git(版本库)等不属于"身份设置"的内容。
2. Cron:自主定时调度
Cron 系统让 Hermes 能在无用户介入的场景下自主运行。实现了 cronjob 工具,Agent 可以自己给自己设置定时任务。
2.1 调度接口
# tools/cronjob_tools.py — cronjob 工具的注册与实现
registry.register(
name="cronjob",
toolset="cron",
schema={
"description": "管理定时 cron 任务 — 创建、暂停、恢复、删除、执行",
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["create", "list", "update", "pause", "resume", "remove", "run"]
},
"schedule": {"type": "string", "description": "定时表达式 或 '30m' 等自然格式"},
"prompt": {"type": "string", "description": "任务触发时执行的 prompt"},
"name": {"type": "string", "description": "可读名称"},
}
}
},
handler=cronjob_handler,
)
2.2 调度粒度
Cron 任务支持多种调度格式:
| 格式 | 示例 | 说明 |
|------|------|------|
| 自然语言间隔 | "30m"、"every 2h" | 从创建时间开始,每 N 分钟/小时 |
| Cron 表达式 | "0 9 * * *" | 标准 5 段 cron |
| ISO 时间戳 | "2026-07-01T09:00:00" | 一次性定时任务 |
和系统 cron 的区别:
# hermes_cli/cron.py
# schema 中 action="list" 返回所有已注册任务
# action="create" 写入 ~/.hermes/cron/ 下的持久化任务文件
Hermes Cron 的存储不在系统 crontab,而在 ~/.hermes/cron/ 目录下。每个 Profile 有自己的 cron 目录,互不干扰。
2.3 cron 任务执行
Cron 任务在触发时,Hermes 会:
1. 从 ~/.hermes/cron/ 读取任务定义
2. 按 deliver 配置发送结果(origin/local/all/指定平台)
3. 支持 skills 字段——任务运行时先加载指定的 Skill 再执行 prompt
4. 支持 model 字段——用指定模型运行该任务(不依赖当前会话模型)
这种设计让一个 cron 任务可以独立于任何用户会话运行——Agent 在被唤醒时没有上下文,但任务自己的 prompt 已经包含了全部所需信息。
3. MCP:动态工具扩展
Model Context Protocol(MCP)是 Anthropic 提出的开放协议,用于向大模型动态注入工具。Hermes 原生支持 MCP 客户端,MCP 工具和其他内置工具一样进入 ToolRegistry。
# hermes_cli/mcp_config.py
# MCP 服务器在 config.yaml 中配置:
# mcp:
# servers:
# my-server:
# transport: "stdio"
# command: "node"
# args: ["/path/to/server.js"]
MCP 工具的加载机制:
MCP 服务器启动 → 通过 JSON-RPC 暴露工具列表
→ Hermes MCP 客户端接收工具 Schema
→ 调用 registry.register() 注册为 toolset="mcp-{server_name}"
→ 工具立即可用,无需重启 Hermes
MCP 服务器发生变更时,Hermes 能实时处理:
# MCP server 发送 notifications/tools/list_changed
# → registry.deregister() 移除旧工具
# → 重新拉取新列表 → registry.register() 注册新工具
# → self._generation += 1 触发缓存失效
这解决了插件系统的热加载问题。传统 Plugin 系统需要重启 Agent 才能加载新工具,MCP 不需要——工具在运行中增删,下次 LLM 调用时自动生效。
4. Plugin:全生命周期钩子
Plugin 是 Hermes 的最大扩展点。Plugin 可以注册工具、钩子(hooks)和 CLI 命令。
4.1 工具注册
Plugin 也可以通过 registry.register() 注册工具,但有一个限制——跨工具集重名保护。
# tools/registry.py
if existing and existing.toolset != toolset:
if not override:
logger.error(
"Tool registration REJECTED: '%s' (toolset '%s') would "
"shadow existing tool from toolset '%s'.",
name, toolset, existing.toolset,
)
return
Plugin 的工具如果与内置工具同名,会被拒绝注册,除非 override=True。
4.2 Hook 生命周期
Plugin 可以注册以下生命周期钩子:
| 钩子 | 触发时机 | 用途 |
|------|---------|------|
| pre_llm_call | LLM 调用前 | 注入额外上下文 |
| post_llm_call | LLM 调用后 | 转换或审计 LLM 输出 |
| transform_llm_output | 响应返回前 | 修改 LLM 回复内容 |
| Memory Provider | 完整记忆周期 | Hindsight/Honcho 等外部记忆后端 |
4.3 Plugin 配置
Plugin 在 config.yaml 中声明:
# config.yaml
plugins:
- my-custom-plugin # 从 ~/.hermes/plugins/ 加载
- memory:
provider: hindsight # 外部记忆 plugin
Plugin 目录:
~/.hermes/plugins/
├── my-custom-plugin/
│ ├── __init__.py
│ └── plugin.py
Plugin 加载逻辑简化:
# hermes_cli/plugins.py(示意)
def load_plugins():
plugin_dir = HERMES_HOME / "plugins"
for entry in config.get("plugins", []):
if isinstance(entry, dict):
if "memory" in entry:
# 初始化记忆 provider
provider = _init_memory_provider(entry["memory"]["provider"])
memory_manager.add_provider(provider)
elif isinstance(entry, str):
# 注册工具和钩子
importlib.import_module(f"plugins.{entry}")
5. 四根柱子的协同
Profile、Cron、MCP、Plugin 四者不是孤立的:
Profile A(生产环境)
├── cron/ → 每天 9 点抓取数据
│ └── MCP Server → 实时查询数据库
├── plugins/memory-hindsight → 记忆持久化
└── skills/ → 生产运维技能
Profile B(个人写作)
├── cron/ → 每 30 分钟检查 CSDN 收益
├── plugins/wechat-login → 公众号自动发文
└── skills/ → 自媒体写作技能
Profile 隔离了不同场景的完整运行环境。每个 Profile 内的 Cron 任务自动继承该 Profile 的配置和技能。MCP 工具扩展了 Agent 在运行时的能力边界。Plugin 为特化场景提供了定制的能力。
系列收官总结
八篇文章,一张完整的 Hermes Agent 底层架构地图:
| 篇次 | 子系统 | 核心源码文件 | 行数 |
|------|--------|-------------|------|
| 01 | 模块全景 | — | 37 个模块速查 |
| 02 | Agent Loop | agent/conversation_loop.py | 4,836 |
| 03 | System Prompt | agent/system_prompt.py + prompt_builder.py | 406 + 1,756 |
| 04 | 工具系统 | tools/registry.py + model_tools.py | 589 + 1,174 |
| 05 | 记忆矩阵 | agent/memory_manager.py + memory_provider.py + hermes_state.py | 653 + 296 + 4,216 |
| 06 | 模型调度 | hermes_cli/runtime_provider.py + auth.py | 1,694 + 7,706 |
| 07 | 技能进化 | tools/skills_tool.py + agent/skill_commands.py | 1,545 + 527 |
| 08 | 基础设施 | hermes_cli/profiles.py + tools/cronjob_tools.py + hermes_cli/plugins.py | 多文件 |
总计约 25,000 行源码被拆解覆盖——不是讲 API 怎么说,是把实际跑的代码翻出来看。
本系列基于 Hermes Agent v0.15.2 源码。八篇全部完成。
本文由 admin 原创,转载请注明出处。
评论
0