Hermes Agent 项目学习指南

面向从未接触过该项目的开发者,帮助你快速上手并深入理解 Hermes Agent。


1. 项目简介

一句话说明

Hermes Agent 是由 Nous Research 开发的自我进化 AI 智能体——它能从经验中创建技能(Skills)、在使用中自我改进,并可运行在终端、Telegram、Discord、Slack 等多种平台上。

核心功能列表

  • 交互式终端 CLI:全功能 TUI,支持多行编辑、斜杠命令自动补全、流式工具输出
  • 多平台消息网关:Telegram、Discord、Slack、WhatsApp、Signal、钉钉、飞书等,单进程统一管理
  • 闭环学习系统:自动创建技能、FTS5 全文搜索历史会话、LLM 摘要跨会话召回、Honcho 用户建模
  • 40+ 内置工具:终端执行、文件操作、网页搜索/抓取、浏览器自动化、代码执行、图像生成、TTS 等
  • MCP 协议支持:通过 Model Context Protocol 接入任意外部工具服务器
  • 多终端后端:本地、Docker、SSH、Modal(Serverless)、Daytona、Singularity 六种执行环境
  • 定时任务(Cron):自然语言描述的定时自动化,结果推送到任意平台
  • 子智能体委托:并行派生隔离子 Agent,支持 Python RPC 调用工具
  • RL 研究支持:批量轨迹生成、Atropos RL 环境、轨迹压缩用于训练下一代工具调用模型
  • 多 Profile 隔离:多实例完全隔离,各自独立配置、记忆、技能

技术栈总览

类别技术 / 依赖版本
语言Python≥ 3.11
LLM SDKopenai(兼容 OpenAI 格式)≥ 2.21.0
LLM SDKanthropic(原生 Anthropic)≥ 0.39.0
CLI 渲染rich(终端富文本)≥ 14.3.3
CLI 交互prompt_toolkit(输入框/自动补全)≥ 3.0.52
配置pyyaml、python-dotenv≥ 6.0.2 / ≥ 1.2.1
HTTPhttpx、requests≥ 0.28.1 / ≥ 2.33.0
数据验证pydantic≥ 2.12.5
重试tenacity≥ 9.1.4
模板jinja2≥ 3.1.5
数据库SQLite(内置,FTS5 扩展)stdlib
消息平台python-telegram-bot、discord.py、slack-bolt≥ 22.6 / ≥ 2.7.1 / ≥ 1.18.0
MCPmcp≥ 1.2.0
定时任务croniter≥ 6.0.0
网页工具firecrawl-py、parallel-web、exa-py≥ 4.16.0 / ≥ 0.4.2 / ≥ 2.9.0
TTSedge-tts(免费)、elevenlabs(可选)≥ 7.2.7
语音识别faster-whisper(可选)≥ 1.0.0
测试pytest、pytest-asyncio、pytest-xdist≥ 9.0.2
包管理setuptools / uv(推荐)

2. 目录结构说明

hermes-agent/

├── hermes                      # CLI 启动脚本(入口包装器)
├── hermes_constants.py         # 全局常量:HERMES_HOME 路径、环境检测工具函数
├── hermes_state.py             # SQLite 会话存储(FTS5 全文搜索)
├── hermes_logging.py           # 日志配置
├── hermes_time.py              # 时间工具函数
├── model_tools.py              # 工具编排层:发现工具、分发工具调用
├── toolsets.py                 # 工具集定义:_HERMES_CORE_TOOLS 列表
├── utils.py                    # 通用工具函数(原子写文件等)

├── run_agent.py                # AIAgent 核心类:对话循环主体
├── cli.py                      # HermesCLI 类:交互式 CLI 编排器

├── hermes_cli/                 # CLI 子命令与配置
│   ├── main.py                 # 所有 `hermes` 子命令入口(Profile 覆盖在此处理)
│   ├── config.py               # DEFAULT_CONFIG、OPTIONAL_ENV_VARS、配置迁移
│   ├── commands.py             # 斜杠命令定义 + SlashCommandCompleter
│   ├── callbacks.py            # 终端回调(clarify、sudo、approval)
│   ├── setup.py                # 交互式安装向导
│   ├── skin_engine.py          # 皮肤/主题引擎
│   ├── models.py               # 模型目录、提供商模型列表
│   ├── model_switch.py         # /model 切换流水线(CLI + Gateway 共用)
│   ├── auth.py                 # 提供商凭证解析
│   ├── skills_hub.py           # /skills 斜杠命令(搜索、浏览、安装)
│   ├── skills_config.py        # `hermes skills` — 按平台启用/禁用技能
│   ├── tools_config.py         # `hermes tools` — 按平台启用/禁用工具
│   ├── banner.py               # 启动横幅渲染
│   └── doctor.py               # 诊断配置和依赖

├── agent/                      # Agent 内部机制
│   ├── prompt_builder.py       # 系统提示词组装(身份、平台提示、技能索引、上下文文件)
│   ├── context_compressor.py   # 自动上下文压缩(长对话摘要)
│   ├── context_engine.py       # 上下文引擎基类
│   ├── memory_manager.py       # 记忆管理器(内置 + 外部插件)
│   ├── memory_provider.py      # 记忆提供商抽象基类
│   ├── auxiliary_client.py     # 辅助 LLM 客户端(视觉、摘要)
│   ├── prompt_caching.py       # Anthropic Prompt Caching 支持
│   ├── model_metadata.py       # 模型上下文长度、Token 估算
│   ├── models_dev.py           # models.dev 注册表集成
│   ├── display.py              # KawaiiSpinner、工具预览格式化
│   ├── skill_commands.py       # 技能斜杠命令(CLI/Gateway 共用)
│   ├── skill_utils.py          # 技能文件解析工具函数
│   ├── smart_model_routing.py  # 智能模型路由
│   ├── usage_pricing.py        # Token 用量与费用追踪
│   └── trajectory.py           # 轨迹保存辅助函数

├── tools/                      # 工具实现(每个工具一个文件)
│   ├── registry.py             # 中央工具注册表(Schema、Handler、分发)
│   ├── terminal_tool.py        # 终端执行(本地/Docker/Modal/SSH/Singularity/Daytona)
│   ├── file_tools.py           # 文件读写/搜索/Patch
│   ├── web_tools.py            # 网页搜索/抓取(并行 + Firecrawl)
│   ├── browser_tool.py         # 浏览器自动化(Browserbase)
│   ├── mcp_tool.py             # MCP 客户端(~1050 行)
│   ├── memory_tool.py          # 记忆工具
│   ├── todo_tool.py            # 待办事项工具(Agent 级别拦截)
│   ├── delegate_tool.py        # 子 Agent 委托
│   ├── code_execution_tool.py  # 代码执行沙箱
│   ├── vision_tools.py         # 图像分析
│   ├── image_generation_tool.py # 图像生成(fal.ai)
│   ├── tts_tool.py             # 文字转语音
│   ├── session_search_tool.py  # 会话历史搜索
│   ├── skill_manager_tool.py   # 技能管理工具
│   ├── approval.py             # 危险命令检测
│   ├── process_registry.py     # 后台进程管理
│   ├── path_security.py        # 路径安全检查
│   └── environments/           # 终端后端实现
│       ├── local.py            # 本地执行
│       ├── docker.py           # Docker 容器
│       ├── ssh.py              # SSH 远程
│       ├── modal.py            # Modal Serverless
│       ├── daytona.py          # Daytona 云开发环境
│       └── singularity.py      # Singularity HPC 容器

├── gateway/                    # 消息平台网关
│   ├── run.py                  # 主循环、斜杠命令、消息分发
│   ├── session.py              # SessionStore — 对话持久化
│   ├── config.py               # 网关配置
│   └── platforms/              # 平台适配器
│       ├── telegram.py         # Telegram Bot
│       ├── discord.py          # Discord Bot
│       ├── slack.py            # Slack App
│       ├── whatsapp.py         # WhatsApp
│       ├── signal.py           # Signal
│       ├── dingtalk.py         # 钉钉
│       ├── feishu.py           # 飞书
│       ├── wecom.py            # 企业微信
│       ├── matrix.py           # Matrix 协议
│       └── homeassistant.py    # Home Assistant

├── cron/                       # 定时任务调度器
│   ├── scheduler.py            # 调度器主体
│   └── jobs.py                 # 任务定义与管理

├── acp_adapter/                # ACP 服务器(VS Code / Zed / JetBrains 集成)
├── environments/               # RL 训练环境(Atropos)
├── plugins/                    # 插件系统(memory 等)
├── tests/                      # Pytest 测试套件(~3000 个测试)
├── batch_runner.py             # 并行批处理
├── trajectory_compressor.py    # 轨迹压缩(用于 RL 训练数据)
├── pyproject.toml              # 项目元数据与依赖声明(权威来源)
└── AGENTS.md                   # 开发者指南(AI 编码助手专用)

3. 架构设计

整体架构模式

Hermes Agent 采用分层 + 插件注册的架构:

  • 分层:入口层(CLI/Gateway)→ 编排层(AIAgent)→ 工具层(Tools)→ 存储层(SQLite/文件系统)
  • 插件注册:每个工具文件在模块导入时自动向中央注册表(tools/registry.py)注册,无需手动维护工具列表
  • 同步优先:核心 Agent 循环完全同步(run_conversation),异步工具通过 _run_async() 桥接

核心模块划分与职责

┌─────────────────────────────────────────────────────────────┐
│                      入口层 (Entry)                          │
│  hermes_cli/main.py  ←→  cli.py  ←→  gateway/run.py        │
│  (子命令路由)              (交互 TUI)    (消息平台网关)         │
└────────────────────────┬────────────────────────────────────┘

┌────────────────────────▼────────────────────────────────────┐
│                    编排层 (Orchestration)                     │
│                      run_agent.py                            │
│              AIAgent.run_conversation()                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │prompt_builder│  │context_comp- │  │  memory_manager  │  │
│  │(系统提示组装) │  │ressor(压缩)  │  │  (记忆管理)      │  │
│  └──────────────┘  └──────────────┘  └──────────────────┘  │
└────────────────────────┬────────────────────────────────────┘

┌────────────────────────▼────────────────────────────────────┐
│                    工具层 (Tools)                             │
│  model_tools.py  →  tools/registry.py  →  tools/*.py        │
│  (工具发现/分发)      (中央注册表)          (具体工具实现)      │
└────────────────────────┬────────────────────────────────────┘

┌────────────────────────▼────────────────────────────────────┐
│                    存储层 (Storage)                           │
│  hermes_state.py(SQLite)  ~/.hermes/(文件系统)               │
│  会话/消息/FTS5搜索         config/memory/skills/logs        │
└─────────────────────────────────────────────────────────────┘

模块间调用关系与数据流向

工具注册链(导入时):

tools/registry.py(无依赖)
    ↑ 被导入
tools/*.py(各自调用 registry.register())
    ↑ 被导入
model_tools.py(触发工具发现)
    ↑ 被导入
run_agent.py / cli.py / batch_runner.py

对话数据流(运行时):

用户输入
  → cli.py / gateway/run.py(接收消息)
  → AIAgent.run_conversation()(主循环)
    → prompt_builder.py(组装系统提示)
    → memory_manager.prefetch_all()(召回记忆)
    → LLM API 调用(OpenAI/Anthropic 格式)
    → 若有工具调用 → model_tools.handle_function_call()
      → tools/registry.dispatch()
      → 具体工具实现(terminal/file/web 等)
      → 工具结果追加到 messages
    → 循环直到无工具调用
    → memory_manager.sync_all()(持久化记忆)
    → hermes_state.py(保存会话到 SQLite)
  → 返回最终响应给用户

4. 核心流程解析

4.1 应用启动流程

hermes(shell 命令)
  → hermes_cli/main.py: main()
    → _apply_profile_override()          # 1. 最先执行:解析 --profile/-p,设置 HERMES_HOME 环境变量
    → argparse 解析子命令
    → 若无子命令 → 启动 CLI 模式
      → cli.py: HermesCLI.__init__()
        → load_cli_config()              # 2. 加载 ~/.hermes/config.yaml
        → load_hermes_dotenv()           # 3. 加载 ~/.hermes/.env(API Keys)
        → AIAgent.__init__()             # 4. 初始化 Agent
          → _discover_tools()            # 5. 导入所有 tools/*.py,触发 registry.register()
          → MemoryManager 初始化         # 6. 初始化记忆管理器
        → HermesCLI.run()               # 7. 进入交互循环(prompt_toolkit)

关键点_apply_profile_override() 必须在所有模块导入之前执行,因为许多模块在导入时就会缓存 HERMES_HOME 路径。

4.2 对话主循环(最核心流程)

# run_agent.py: AIAgent.run_conversation()
while api_call_count < self.max_iterations:
    # 1. 调用 LLM API(OpenAI 格式)
    response = client.chat.completions.create(
        model=model,
        messages=messages,
        tools=tool_schemas
    )
    
    # 2. 若模型请求工具调用
    if response.tool_calls:
        for tool_call in response.tool_calls:
            # 3. 分发到对应工具实现
            result = handle_function_call(
                tool_call.name,
                tool_call.args,
                task_id
            )
            # 4. 将工具结果追加到消息历史
            messages.append(tool_result_message(result))
        api_call_count += 1
    else:
        # 5. 无工具调用 → 返回最终响应
        return response.content

消息格式遵循 OpenAI 标准:{"role": "system/user/assistant/tool", "content": "..."}

4.3 工具注册与调用流程

注册(模块导入时,一次性):

# tools/terminal_tool.py(示例)
from tools.registry import registry

registry.register(
    name="terminal",
    toolset="terminal",
    schema={...},                    # JSON Schema,传给 LLM
    handler=lambda args, **kw: ...,  # 实际执行函数
    check_fn=check_requirements,     # 可用性检查(如检查环境变量)
    requires_env=["TERMINAL_ENV"],
)

调用(运行时):

# model_tools.py: handle_function_call()
def handle_function_call(function_name, function_args, task_id):
    entry = registry.get(function_name)
    if entry.is_async:
        return _run_async(entry.handler(function_args, task_id=task_id))
    return entry.handler(function_args, task_id=task_id)
    # 所有 handler 必须返回 JSON 字符串

4.4 上下文压缩流程

当对话历史接近模型上下文窗口限制时自动触发:

检测 Token 用量 > 阈值(默认 context_length × 0.8)
  → ContextCompressor.compress()
    → 1. 剪枝旧工具输出(廉价预处理,无 LLM 调用)
    → 2. 保护头部消息(系统提示 + 首轮对话)
    → 3. 保护尾部消息(最近 ~20K tokens)
    → 4. 用辅助 LLM(便宜/快速)摘要中间轮次
    → 5. 若已有摘要,迭代更新(保留跨多次压缩的信息)
  → 压缩后的 messages 替换原始 messages

注意:压缩是唯一允许修改历史上下文的操作,其他任何修改都会破坏 Prompt Caching。

4.5 记忆系统流程

每轮对话结束后:
  MemoryManager.sync_all(user_msg, assistant_response)
    → BuiltinMemoryProvider.sync()
      → 检测 Agent 是否调用了 memory 工具
      → 若有 → 更新 ~/.hermes/MEMORY.md
    → 外部插件 Provider.sync()(如 Honcho)

下一轮对话开始前:
  MemoryManager.prefetch_all(user_message)
    → 从 MEMORY.md 读取相关记忆
    → 注入到系统提示(用 <memory-context> 标签包裹)

5. 关键设计与实现

5.1 使用的设计模式

模式应用场景代码位置
注册表模式(Registry)工具自注册,解耦工具实现与编排层tools/registry.py
策略模式(Strategy)终端后端可替换(local/docker/ssh/modal)tools/environments/
模板方法(Template Method)上下文引擎基类定义压缩流程骨架agent/context_engine.py
观察者/回调(Callback)终端 UI 回调(clarify、sudo 审批)hermes_cli/callbacks.py
单例(Singleton)工具注册表全局唯一实例tools/registry.py: registry
适配器(Adapter)各消息平台统一接口gateway/platforms/base.py
数据驱动(Data-Driven)皮肤/主题系统纯数据配置,无需改代码hermes_cli/skin_engine.py

5.2 数据模型 / 数据库设计

Hermes 使用 SQLite + FTS5 存储会话数据,文件位于 ~/.hermes/state.db

-- 会话表:存储每次对话的元数据
CREATE TABLE sessions (
    id TEXT PRIMARY KEY,
    source TEXT NOT NULL,          -- 来源平台:'cli', 'telegram', 'discord' 等
    model TEXT,                    -- 使用的模型名称
    started_at REAL NOT NULL,      -- 开始时间(Unix 时间戳)
    message_count INTEGER,
    input_tokens INTEGER,
    output_tokens INTEGER,
    estimated_cost_usd REAL,       -- 估算费用
    title TEXT,                    -- 会话标题(自动生成)
    ...
);

-- 消息表:存储每条消息
CREATE TABLE messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT REFERENCES sessions(id),
    role TEXT NOT NULL,            -- 'user', 'assistant', 'tool'
    content TEXT,
    tool_name TEXT,
    timestamp REAL NOT NULL,
    ...
);

-- FTS5 虚拟表:全文搜索
CREATE VIRTUAL TABLE messages_fts USING fts5(...);

文件系统存储~/.hermes/):

~/.hermes/
├── config.yaml      # 所有配置项
├── .env             # API Keys(不提交到 git)
├── state.db         # SQLite 会话数据库
├── MEMORY.md        # 持久化记忆
├── USER.md          # 用户画像
├── SOUL.md          # Agent 人格定义
├── skills/          # 用户技能目录
├── logs/            # 日志文件
└── profiles/        # 多 Profile 隔离目录
    └── <name>/      # 每个 Profile 有独立的上述所有文件

5.3 状态管理 / 数据流方案

  • 对话历史:存储在内存中的 messages 列表(OpenAI 格式),每轮结束后持久化到 SQLite
  • 记忆:通过 MemoryManager 管理,支持内置(文件)和外部(Honcho)两种提供商
  • 配置config.yaml(设置项)+ .env(密钥),通过 load_cli_config() 加载到内存
  • 工具状态:无状态设计,每次工具调用独立执行;后台进程通过 process_registry.py 追踪

5.4 错误处理与日志策略

  • 工具调用错误:所有工具 handler 必须返回 JSON 字符串,错误通过 tool_error() 包装返回给 LLM,而非抛出异常
  • LLM API 重试:通过 tenacity 库实现指数退避重试(agent/retry_utils.py
  • 上下文压缩失败:有 600 秒冷却期,避免频繁失败
  • 日志:使用 Python 标准 logging 模块,日志文件存储在 ~/.hermes/logs/
  • 危险命令检测tools/approval.py 检测高风险命令,触发用户审批流程

5.5 安全机制

  • 命令审批:危险命令(如 rm -rfsudo 等)需用户确认,可配置白名单
  • 路径安全tools/path_security.py 防止路径穿越攻击
  • Prompt 注入检测agent/prompt_builder.py 扫描上下文文件中的注入模式(隐形 Unicode、ignore previous instructions 等)
  • MCP 凭证保护:MCP 工具调用错误信息中自动剥离凭证信息
  • DM 配对:消息平台通过配对机制限制访问用户
  • 环境变量过滤:MCP stdio 子进程的环境变量经过白名单过滤

6. 环境搭建与运行

环境依赖与前置条件

  • Python 3.11+(必须)
  • uv(推荐,速度更快)或 pip
  • Git
  • 至少一个 LLM API Key(OpenAI、Anthropic、OpenRouter 等任选其一)

安装步骤

方式一:一键安装(推荐)

curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
source ~/.bashrc    # 或 source ~/.zshrc
hermes              # 启动!

方式二:开发者安装(贡献代码用)

# 1. 克隆仓库
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent

# 2. 安装 uv(Rust 编写的极速 Python 包管理器)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 3. 创建虚拟环境(必须 Python 3.11+)
uv venv venv --python 3.11
source venv/bin/activate    # Linux/macOS
# venv\Scripts\activate     # Windows(不支持,请用 WSL2)

# 4. 安装所有依赖(含开发依赖)
uv pip install -e ".[all,dev]"

# 5. 运行测试验证安装
python -m pytest tests/ -q

# 6. 启动
hermes

方式三:最小安装(仅核心功能)

uv pip install -e "."    # 仅安装核心依赖

配置步骤

# 运行交互式配置向导(推荐首次使用)
hermes setup

# 或手动配置
hermes model          # 选择 LLM 提供商和模型
hermes tools          # 配置启用哪些工具
hermes config set model.name "anthropic/claude-opus-4.6"

启动命令

# 交互式 CLI(最常用)
hermes

# 启动消息平台网关(后台服务)
hermes gateway start

# 查看网关状态
hermes gateway status

# 运行诊断
hermes doctor

# 批量处理(研究用)
python batch_runner.py --input tasks.jsonl --output results.jsonl

关键环境变量说明

变量名说明示例
HERMES_HOMEHermes 数据目录(默认 ~/.hermes/opt/hermes-data
OPENAI_API_KEYOpenAI API Keysk-...
ANTHROPIC_API_KEYAnthropic API Keysk-ant-...
OPENROUTER_API_KEYOpenRouter API Key(200+ 模型)sk-or-...
TERMINAL_ENV终端后端(local/docker/modal/sshlocal
TELEGRAM_BOT_TOKENTelegram Bot Token(网关用)123456:ABC...
DISCORD_BOT_TOKENDiscord Bot Token(网关用)MTI...
EXA_API_KEYExa 搜索 API Keyexa-...
FIRECRAWL_API_KEYFirecrawl 网页抓取 API Keyfc-...
FAL_KEYfal.ai 图像生成 API Key...

所有 API Key 存储在 ~/.hermes/.env,不要提交到 git。


7. 推荐学习路线

阶段一:入门(1-2 天)

目标:理解项目是什么、能做什么,跑通基本流程

  1. 先读文档

    • README.md — 了解项目定位和核心功能
    • AGENTS.md — 开发者指南,理解整体架构
  2. 理解配置系统

    • hermes_constants.py — 理解 get_hermes_home() 的设计(Profile 隔离的基础)
    • hermes_cli/config.py — 了解 DEFAULT_CONFIG 有哪些配置项
  3. 跑通启动流程

    • hermes_cli/main.py 前 100 行 — 理解 _apply_profile_override() 为何必须最先执行
    • 实际运行 hermes setuphermes,感受 CLI 交互

理解的核心概念

  • HERMES_HOME 是所有数据的根目录
  • Profile 是多实例隔离的机制
  • config.yaml + .env 是两套配置(设置 vs 密钥)

阶段二:进阶(3-5 天)

目标:深入理解 Agent 核心循环和工具系统

  1. 工具注册机制(最重要)

    • tools/registry.py — 完整阅读,理解 ToolRegistryToolEntry
    • tools/terminal_tool.py 前 80 行 — 看一个具体工具如何注册
    • model_tools.py — 理解工具发现(_discover_tools())和分发(handle_function_call()
  2. Agent 主循环

    • run_agent.py — 重点阅读 AIAgent.__init__()run_conversation()
    • 理解 messages 列表的结构和工具调用的消息格式
  3. 系统提示组装

    • agent/prompt_builder.py — 理解系统提示由哪些部分组成
    • agent/prompt_caching.py — 理解为何不能随意修改历史上下文
  4. 上下文压缩

    • agent/context_compressor.py — 理解长对话如何被摘要压缩
  5. 工具集系统

    • toolsets.py — 理解 _HERMES_CORE_TOOLS 和工具集组合

动手实践

# 查看当前工具列表
hermes tools

# 在 Python 中直接使用 AIAgent
python -c "
from run_agent import AIAgent
agent = AIAgent(model='openai/gpt-4o-mini')
print(agent.chat('Hello! What tools do you have?'))
"

阶段三:实践(1 周+)

目标:能够扩展项目功能,理解所有核心机制

  1. 添加一个新工具(最佳实践练习)

    • 参考 AGENTS.md 的”Adding New Tools”章节
    • tools/ 下创建新文件,调用 registry.register()
    • model_tools.py_discover_tools() 中添加 import
    • toolsets.py_HERMES_CORE_TOOLS 中添加工具名
  2. 添加一个斜杠命令

    • 参考 AGENTS.md 的”Adding a Slash Command”章节
    • hermes_cli/commands.pyCOMMAND_REGISTRY 中添加 CommandDef
    • cli.pyprocess_command() 中添加处理逻辑
  3. 理解消息网关

    • gateway/run.py — 网关主循环
    • gateway/platforms/telegram.py — 一个平台适配器的完整实现
    • gateway/platforms/ADDING_A_PLATFORM.md — 如何添加新平台
  4. 记忆系统深入

    • agent/memory_manager.py — 记忆管理器设计
    • agent/memory_provider.py — 提供商抽象基类
    • tools/memory_tool.py — 记忆工具实现
  5. 运行测试套件

    source venv/bin/activate
    python -m pytest tests/ -q                          # 全量测试
    python -m pytest tests/test_model_tools.py -q       # 工具集解析
    python -m pytest tests/tools/ -q                    # 工具级测试
    python -m pytest tests/gateway/ -q                  # 网关测试

8. 常见问题与注意事项

容易踩的坑

1. 忘记激活虚拟环境

# 每次开发前必须执行
source venv/bin/activate

2. 硬编码 ~/.hermes 路径

# ❌ 错误:破坏 Profile 隔离
config_path = Path.home() / ".hermes" / "config.yaml"

# ✅ 正确:使用 get_hermes_home()
from hermes_constants import get_hermes_home
config_path = get_hermes_home() / "config.yaml"

3. 工具 handler 抛出异常而非返回错误 JSON

# ❌ 错误:会导致整个 Agent 循环崩溃
def my_tool(args):
    raise ValueError("something went wrong")

# ✅ 正确:返回 JSON 字符串,让 LLM 处理错误
def my_tool(args):
    return json.dumps({"error": "something went wrong"})

4. 在对话中途修改工具集或系统提示

  • 这会破坏 Anthropic Prompt Caching,导致费用大幅增加
  • 唯一允许的例外是上下文压缩

5. 使用 simple_term_menu 做交互菜单

  • 在 tmux/iTerm2 中有渲染 bug(滚动时残影)
  • 应使用 curses(标准库),参考 hermes_cli/tools_config.py

6. 在 Spinner/Display 代码中使用 \033[K(ANSI 清除到行尾)

  • prompt_toolkitpatch_stdout 下会泄漏为字面量 ?[K
  • 应使用空格填充:f"\r{line}{' ' * pad}"

代码中的特殊约定

  • 所有工具 handler 必须返回 JSON 字符串,不能是 Python 对象
  • todomemory 工具是 Agent 级别工具,在 run_agent.py 中被拦截,不经过 handle_function_call()
  • _last_resolved_tool_names 是进程全局变量,子 Agent 执行期间会临时修改,注意并发安全
  • 工具 Schema 描述中不能跨工具集引用工具名(如 browser_navigate 不能提到 web_search),因为对方工具集可能未启用
  • 测试不能写入 ~/.hermes/tests/conftest.py_isolate_hermes_home fixture 会重定向到临时目录

值得注意的技术债务

  • model_tools.py 注释提到原始版本有 2400 行,已重构为薄编排层,但历史包袱仍存在
  • MCP 客户端(tools/mcp_tool.py)约 1050 行,是代码库中最复杂的单文件
  • hermes_cli/ 目录文件数量较多(30+ 文件),功能边界有时不够清晰
  • 异步桥接(_run_async())的多线程事件循环管理较复杂,是潜在的并发问题来源
  • [待确认] 部分 RL 训练相关代码(environments/rl_cli.py)与主流程耦合度较低,文档较少

附录:快速参考

常用命令速查

hermes                    # 启动交互式 CLI
hermes setup              # 配置向导
hermes model              # 切换模型
hermes tools              # 管理工具
hermes gateway start      # 启动消息网关
hermes doctor             # 诊断问题
hermes update             # 更新版本
hermes -p <name>          # 使用指定 Profile

斜杠命令速查(CLI 内使用)

/new, /reset     # 开始新对话
/model           # 切换模型
/compress        # 手动压缩上下文
/usage           # 查看 Token 用量
/skills          # 浏览技能
/retry           # 重试上一轮
/undo            # 撤销上一轮
/help            # 查看所有命令

关键文件速查

想了解什么看哪个文件
如何添加新工具AGENTS.md + tools/terminal_tool.py(参考)
如何添加斜杠命令hermes_cli/commands.py
配置项有哪些hermes_cli/config.py: DEFAULT_CONFIG
Agent 主循环run_agent.py
工具注册机制tools/registry.py
系统提示如何组装agent/prompt_builder.py
会话数据库结构hermes_state.py: SCHEMA_SQL
如何添加消息平台gateway/platforms/ADDING_A_PLATFORM.md