Hermes Agent (NousResearch)
一句话定位
Hermes Agent 是 Nous Research(Hermes 模型系列 / Nomos / Psyche 的训练方)自建自用的
重型生产级 agent harness:“模型训练团队自己造 harness” 的代表案例——不是 demo,是
一个约 25,000 测试 / ~1,250 测试文件、单文件动辄数百 KB(cli.py 743KB)的大型工程化
代码库,同时承担”日常可用的 agent 产品”和”给下一代 tool-calling 模型生成/压缩训练轨迹的
数据管道”双重角色。
核心架构总览(目录结构关键路径 + 引用的 commit)
仓库地址 https://github.com/NousResearch/hermes-agent,MIT 协议(LICENSE:
Copyright (c) 2025 Nous Research)。分析基于 git clone --depth 1 拉取的 main 分支
单一 commit 5431bf29214681fb2fd25254568b58c9da8ce6e0(commit message:
“fix(desktop): default HERMES_DESKTOP_CWD to cwd when —cwd omitted”,commit 时间
2026-06-06 08:50:11 -0700,2026-07-07 clone)。注意:官方文档站
(hermes-agent.nousresearch.com/docs)当时已披露更新的公开版本 v0.18.0,说明
main 在 clone 之后又向前推进了;本页所有论断均以这个 SHA 为准,不代表绝对最新版。
顶层规模约 80 个条目,是”monolith-with-modules”风格的大工程:
hermes-agent/
├── agent/ — 116 files,核心 agent 内部逻辑(loop/memory/prompt/adapter/curator...)
├── tools/ — 92 files,一个工具一个文件 + 中央 registry
├── gateway/ — 43 files,消息平台接入(Discord/Feishu/HomeAssistant 等)
├── hermes_cli/ — 145 files,CLI 子命令
├── acp_adapter/ — IDE 集成(Agent Client Protocol)
├── cron/ — 定时任务调度
├── docs/ — 手写设计文档(含 observability、security、kanban 等)
├── website/ — 公开文档站(Docusaurus)源码
├── skills/、optional-skills/ — 内置 + 可选 skill 树
└── tests/ — 官方文档称 ~25,000 tests / ~1,250 files
Agent Loop(主循环 / 何时继续何时停)
核心实现:agent/conversation_loop.py::run_conversation()(起始于第 518 行,直接读源码确认)。
- 循环条件(第 633 行):
while (api_call_count < agent.max_iterations and agent.iteration_budget.remaining > 0) or agent._budget_grace_call: - 继续条件:assistant 响应带
tool_calls→ 派发工具、以{"role": "tool", ...}追加结果、回到循环头部(官方 Agent Loop 文档 “Turn Lifecycle” 第 8-9 步印证)。 - 停止条件:纯文本响应(
finish_reason=stop且无 tool_calls)→ 设置_turn_exit_reason = "text_response(...)"并break(约第 5213 行);中断请求 (第 638-643 行,interrupted=True);迭代预算耗尽(第 654-658 行,_turn_exit_reason = "budget_exhausted");此外通过 grep 发现十余种不同的_turn_exit_reason字符串(各类 guardrail / 空响应 / 恢复路径),诊断粒度较细。 - 默认 iteration budget 为 90 次(
agent.max_turns);每个 subagent 拥有独立预算, 默认上限 50(delegation.max_iterations)——因此父子 agent 的总迭代数可以超过父级 自身的上限。预算耗尽时 agent 优雅停止并返回已完成工作的摘要,而非硬崩溃。 - 3 种 API 模式(
chat_completions/codex_responses/anthropic_messages)在调用 前后统一收敛为一种内部 OpenAI 风格消息格式;模式解析优先级:显式参数 > provider 特定 > base-URL 启发式 > 默认chat_completions。 - 严格的消息角色交替规则(User→Assistant→User…,工具调用批次夹在 Assistant→Tool→Tool→…→Assistant 之间,不允许连续两个 assistant/user)。
- 工具执行:单个工具调用内联执行;多个工具调用通过
ThreadPoolExecutor并发执行(例外: 标记为 “interactive” 的工具如clarify强制串行);结果按原始调用顺序回填,不受完成顺序影响。 - API 调用可中断:
_interruptible_api_call()在后台线程执行 HTTP 调用,主线程在 {响应就绪、中断事件、超时} 之间竞速;中断会放弃响应,不向历史注入任何部分结果。 - 主模型失败(429/5xx/401/403)时按
fallback_providers列表顺序回退;401/403 会先尝试 凭证刷新再判定失败。辅助任务(视觉、压缩、web 抽取)各自拥有独立的auxiliary.*回退链。 agent.api_mode == "codex_app_server"是一种特殊旁路(第 624 行):整个 turn 交给 Codex app-server 子进程处理,此时默认 Hermes 循环完全跳过——与常规codex_responsesAPI 模式不同。
记忆与上下文管理(压缩、长期记忆、会话持久化)
- 两文件有界记忆(
agent/memory_manager.py+ 官方文档确认):MEMORY.md(agent 自己的 笔记,2,200 字符 / 约 800 token 上限)与USER.md(用户画像,1,375 字符 / 约 500 token 上限),均存于~/.hermes/memories/。 - 冻结快照模式:记忆仅在会话开始时渲染进 system prompt 一次,会话中途不再变化(保持 LLM prefix cache 稳定);agent 的实时写入立即落盘,但要到下一个会话才会出现在 prompt 里——文档中明确点名的设计取舍。
- 记忆工具动作:
add、replace(基于old_text子串匹配)、remove(子串匹配)——无read动作,因为记忆内容始终已在上下文里。 - 硬性容量约束:超出字符上限的写入会被拒绝,并返回结构化错误列出当前条目,强制 agent 在 同一 turn 内先整理/精简再重试——无静默自动压缩。
- 重复条目拒绝(精确匹配去重),以及对记忆条目的安全扫描(防提示注入/凭证外泄模式、 隐藏 Unicode),因为记忆内容会在下次会话重新进入 system prompt。
- 会话持久化:SQLite(
hermes_state.py,275KB)+ FTS5 全文检索(~/.hermes/state.db)。session_search工具查询实际存储的消息(无 LLM 摘要/截断)——与 MEMORY.md/USER.md 系统 相互独立。压缩事件会创建带新 lineage ID 的”子”会话(父子链保留)。 - 上下文压缩:通过
ContextEngine抽象基类(agent/context_engine.py,231 行)插件化 ——should_compress()→compress()生命周期,可通过context.engine配置切换(默认"compressor")。默认实现ContextCompressor(agent/context_compressor.py,3045 行) 对中间轮次做有损摘要。 - 压缩触发阈值(按官方文档):API 调用前预检查若超过上下文窗口 50%;网关层在轮次之间
做更激进的自动压缩,阈值 85%。记忆先落盘(防数据丢失),再摘要中间轮次,末尾 N 条消息
完整保留(
compression.protect_last_n,默认 20),工具调用/结果对不会被拆分。 - 可选外部记忆 provider 走插件系统(
agent/memory_provider.pyABC)——同一时间只允许一个 外部 provider 生效(拒绝第二次注册,避免工具 schema 膨胀/后端冲突)。发现 Honcho (github.com/plastic-labs/honcho)集成散布在toolsets.py、cli.py、tools/lazy_deps.py、tools/mcp_tool.py、hermes_cli/plugins.py等多个文件中,文档 描述为 “dialectic user modeling”。
工具体系(定义/调用协议/注册/权限)
- 中央自注册 registry:
tools/registry.py。每个工具文件在模块级调用registry.register(...);discover_builtin_tools()(第 58 行)遍历tools/*.py, 用 AST 解析检查是否存在模块体(非函数内部)的顶层registry.register()调用 (_module_registers_tools,第 43 行,刻意只匹配模块体语句以避免误发现),再importlib.import_module()逐个导入匹配模块。无需手工维护工具清单。 ToolEntry对象字段:name、toolset、schema、handler、check_fn(可用性探测)、 requires_env、is_async、description、emoji、max_result_size_chars、 dynamic_schema_overrides(在get_definitions()时应用的可调用对象,使 schema 文本能 反映实时配置,例如 delegate_task 的描述会体现实际配置的max_concurrent_children)。check_fn结果 TTL 缓存 30 秒,并带 60 秒的失败宽限机制——一次瞬时探测失败(例如一次docker version超时)在宽限窗口内沿用上一次已知良好的”可用”结论,避免工具状态抖动; 代码注释明确指出这是为修复 issue 5304(delegate_task 子 agent 因单次探测抖动 而丢失工具)。- 约 92 个工具文件,官方架构文档称”70+ 已注册工具,约 28 个 toolset”。
- 按文件名可见的工具类别:文件系统、终端/执行、浏览器(5 后端)、web、消息平台
(Discord/Feishu/HomeAssistant)、媒体(图像/视频生成、TTS、转写)、
记忆/skill(
memory_tool.py、skill_manager_tool.py、skills_hub.py、skills_sync.py、skills_ast_audit.py、skills_guard.py)、安全 (tirith_security.py、threat_patterns.py、url_safety.py、osv_check.py)、 委派(delegate_tool.py、async_delegation.py)、审批 (approval.py、write_approval.py、slash_confirm.py)、MCP (mcp_tool.py、mcp_oauth.py)、kanban/计划(kanban_tools.py)、cron (cronjob_tools.py)。 - 4 个工具在 registry 之前被 agent 层拦截(官方 Agent Loop 文档):
todo、memory、session_search、delegate_task——这些直接修改 agent 状态并返回合成工具结果,完全绕过handle_function_call()/registry 派发。 - 派发流程(官方文档 “Execution Flow”):从 registry 解析 handler → 触发
pre_tool_call插件钩子 → 危险指令检查(tools/approval.py)→ 若危险,调用审批回调并阻塞等待用户响应 → 用参数+task_id 执行 handler → 触发post_tool_call钩子 → 追加{"role": "tool", "content": result}。
Prompt 设计(系统提示结构、动态组装)
- 由
agent/system_prompt.py(536 行,全文读完)+agent/prompt_builder.py(1971 行) 完成组装。 - 三层结构,以
\n\n拼接(模块 docstring 明确记录):stable—— 身份(SOUL.md 或DEFAULT_AGENT_IDENTITY)、工具指引、computer-use 指引、 Nous 订阅信息块、工具使用强制规则 + 逐模型操作指引、skills prompt、Alibaba 模型名兼容 workaround、环境提示、平台提示。context—— 调用方提供的system_message+TERMINAL_CWD下发现的上下文文件 (AGENTS.md / .cursorrules 等)。volatile—— 记忆快照、USER.md 画像、外部记忆 provider 信息块、 时间戳/会话/模型/provider 行。
- prompt 稳定性作为明确设计原则(官方架构文档 “Design Principles” 表):“System prompt
doesn’t change mid-conversation. No cache-breaking mutations except explicit user actions
(
/model)“。每个会话只构建一次,跨轮次复用;只有上下文压缩会触发重建。这是为了保持上游 provider 的 prefix cache 热度(成本/延迟优化),docstring 中明确引用了内部开发文档references/system-prompt-invariant.md、references/self-improvement-loop.md(这两份引用文档未包含在这次 shallow clone 里,未验证是否公开)。 - 逐 provider 的工具 schema 消毒印证了 prompt/schema 与具体模型的协同设计:
agent/gemini_schema.py::sanitize_gemini_schema()(全文读过)剥离 GeminiFunctionDeclaration.parameters不接受的 OpenAPI/JSON-Schema 键(如$schema、additionalProperties被剥离;约 24 个键的白名单,如type、format、enum、anyOf、propertyOrdering)。同名兄弟文件agent/moonshot_schema.py(未打开细读)为 Moonshot/Kimi 做同类处理。 - Anthropic 专属的 prompt caching:
agent/prompt_caching.py应用 cache_control 断点 (conversation_loop.py约第 881 行注释:“inject cache_control breakpoints (system + last 3 messages)”)。
Router / 编排(任务分解、多 agent、子 agent)
- 子 agent 委派:
tools/delegate_tool.py(3445 行)——delegate_task工具,是 4 个 agent 级拦截工具之一。默认扁平:MAX_DEPTH = 1(第 125 行)——父级(depth 0)可生成子级 (depth 1);孙级除非在配置里调高delegation.max_spawn_depth否则被拒绝。设计上没有硬性 深度/并发上限——_get_max_concurrent_children()(第 354 行)和_get_max_spawn_depth()(第 467 行)读配置且有合理默认值,但极端值只记警告日志而非硬性截断。 - 子 agent 隔离:
_register_subagent/_unregister_subagent/interrupt_subagent/list_active_subagents(第 169-217 行)——每个被委派的子 agent 都有独立 subagent_id 追踪,可单独中断。 - 异步/后台委派变体:
tools/async_delegation.py(531 行)。此外官方文档 Key Features 提到 “Programmatic Tool Calling viaexecute_codecollapses multi-step pipelines into single inference calls”——指通过code_execution_tool.py执行的 Python 脚本内以 RPC 方式调用工具,让 agent 无需每次都经 LLM 往返即可批量调用工具,是区别于 delegate_task 的 “零上下文成本”编排机制。 - Mixture-of-Agents (MoA):
agent/moa_loop.py(1073 行)——由/moa斜杠命令触发的 模式。明确不是 model tool;它把某一个用户轮次标记为 MoA-enabled,常规 Hermes agent loop 仍然掌控工具调用/轮次终止,而moa_loop.py在每次迭代前用ThreadPoolExecutor(上限_MAX_REFERENCE_WORKERS = 8)并发调用参考模型获取”顾问意见”并作为上下文喂入。各 参考模型有独立的成本/用量核算(_RefAccounting),不同 provider/模型的顾问按各自费率 计价,不并入聚合器的成本。 - 可观测性文档确认专门的子 agent 生命周期钩子:
subagent_start/subagent_stop,带 父子会话+轮次 ID 关联字段(parent_session_id、child_session_id、parent_subagent_id、child_subagent_id、child_role、child_goal、child_summary、duration_ms)。 - 在已读文件范围内未发现独立于 LLM 之外的”规划器”/DAG 任务分解组件——任务分解看起来
完全由 LLM 通过工具调用(delegate_task)驱动,没有单独的编排层。
hermes_cli/kanban_decompose.py和tools/kanban_tools.py命名上暗示可能存在 kanban 式任务分解,但本轮未读,留待后续验证。
Skill / 插件体系
- Skill 被明确定义为”程序性记忆”(
tools/skill_manager_tool.pydocstring):区别于 MEMORY.md/USER.md 的”宽泛、陈述性”记忆,skill 是”狭窄、可执行”的,记录如何完成某类具体任务。 - 目录布局:
~/.hermes/skills/<skill-name>/SKILL.md+ 可选的references/、templates/、scripts/、assets/子目录;也可按category-name/another-skill/分组。 skill_manage工具动作:create、edit(全量重写 SKILL.md)、patch(在 SKILL.md 或任意支持文件内做定向查找替换)、delete、write_file、remove_file。- 仓库自带两棵 skill 树:
skills/(始终可用,含 apple、autonomous-ai-agents、 computer-use、creative、data-science、dogfood、email、github 等类别)与optional-skills/(需显式安装,含 blockchain、communication、devops、finance、 gaming、health、mcp、migration、payments 等)。 - 开放标准兼容:README/文档声明兼容
agentskills.io开放 skill 标准,并有公开的 “Skills Hub” 供社区贡献(可移植/可分享)。 - 独立的插件系统(官方架构文档):三种发现来源——
~/.hermes/plugins/(用户级)、.hermes/plugins/(项目级)、pip entry points。插件通过上下文 API (ctx.register_hook(...))注册工具/钩子/CLI 命令。两类”单选”插件槽位:记忆 provider (plugins/memory/)与上下文引擎(plugins/context_engine/),同一时间各自只能有一个生效。
自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)
- The Curator(
agent/curator.py,1976 行):官方称为”后台 skill 维护编排器”。 以辅助模型任务的形式运行,由空闲状态触发(无常驻 cron 守护进程)——maybe_run_curator()在 agent 空闲且距上次 curator 运行超过interval_hours(默认DEFAULT_INTERVAL_HOURS = 24*7,即每周;DEFAULT_MIN_IDLE_HOURS = 2;DEFAULT_STALE_AFTER_DAYS = 30;DEFAULT_ARCHIVE_AFTER_DAYS = 90)时触发。 - Curator 职责(自身 docstring):根据派生的活动时间戳自动转换 skill 生命周期状态;派生一个
后台 review agent(fork 出的
AIAgent),可以通过skill_manage对 agent 创建的 skill 做 pin/archive/consolidate/patch;curator 状态(last_run_at、paused等)持久化在.curator_state。 - 明确的强不变式(代码注释而非仅文档层面):只触碰 agent 创建的 skill(通过
tools/skill_usage.is_agent_created检查);从不自动删除,只归档(可恢复);已 pin 的 skill 跳过所有自动转换;使用独立的”辅助 client”,确保 review fork 不会碰到主会话的 prompt cache。 - 学习图谱(
agent/learning_graph.py,328 行):为桌面 UI 构建”可见化学习”图——节点是 已学习/画像类 skill(非内置)加上 MEMORY.md/USER.md 记忆片段;skill-skill 边来自声明的related_skills;memory-skill 边由词法重叠推导得出。这是对同一套自我改进数据的 可视化/内省层,不是独立的学习机制。 - “自我改进 agent”的说法有具体落地:(a) skill 在正常工具使用过程中从经验中创建 (skill_manager_tool);(b) curator 周期性地用自己的辅助 LLM 调用来 review/整合/归档这批 skill;(c) 记忆条目跨会话持久化事实;(d) session_search + FTS5 提供跨会话回忆,不依赖有界 的 MEMORY.md。
- 未发现 harness 内的 RL/eval 驱动权重更新——这是程序性/陈述性记忆的自我策展,不是 harness 内的模型微调。模型层面的改进(如果有)通过轨迹导出管道(见”轨迹利用”一节)流向 Nous Research 独立的训练栈(Atropos,文档中提到的独立 RL 环境项目,不属于本仓库)。
可观测性(日志 / trace 格式)
- 一等公民、带版本号的 observer-hook 契约,
docs/observability/README.md全文读完 ——明确设计为面向 Langfuse、OpenTelemetry 风格采集器、“NeMo Relay” 的稳定、后端中立集成面。 - Payload 版本标签:
telemetry_schema_version = "hermes.observer.v1",由插件管理器注入 每个钩子 payload。 - 钩子 fail-open:回调中的异常会被捕获、记为 warning 日志,agent loop 继续运行——钩子 不能使 agent 崩溃。
- 关联 ID 表(文档化、稳定):
session_id、task_id、turn_id、api_request_id(不透明、按 provider 尝试次数区分的 ID,文档明确警告”不要解析其字符串格式”)、api_call_count、tool_call_id、parent_session_id/child_session_id、parent_subagent_id/child_subagent_id、parent_turn_id。 - 已文档化的事件族:会话生命周期(
on_session_start/on_session_end/on_session_finalize/on_session_reset,文档特别注明on_session_end是 turn-scoped,不一定是会话的最终生命周期边界);轮次级 LLM 钩子 (pre_llm_call/post_llm_call);请求级 API 钩子 (pre_api_request/post_api_request/api_request_error,各带详细字段,含脱敏后的 请求/响应 payload、耗时、token 用量、finish_reason);工具生命周期 (pre_tool_call/post_tool_call/transform_tool_result,带status枚举ok/error/blocked/cancelled);审批生命周期 (pre_approval_request/post_approval_response,仅观察,不能从这些钩子预先应答/否决); 子 agent 生命周期(subagent_start/subagent_stop)。 - 少数钩子被明确列为”影响行为”的例外(不属于纯观察契约):
pre_llm_call(可返回字符串/字典注入临时上下文)、pre_tool_call(可返回{"action": "block", "message": ...}阻止工具执行)、transform_tool_result(可替换工具结果字符串)、transform_llm_output(可替换最终 assistant 文本)。这是刻意 设计的窄口径逃生舱,其余全部是纯遥测。 - 另有
hermes_logging.py(31KB)作为进程级日志实现,本轮未深读,留待后续核实具体日志 格式/文件轮转细节。
安全与权限(审批门、密钥管理)
- 7 层安全模型(官方
/docs/user-guide/security,全文读完):- 用户授权(消息平台的 allowlist、DM 配对)
- 危险指令审批(human-in-the-loop)
- 容器隔离(Docker/Singularity/Modal 加固配置)
- MCP 凭证过滤(MCP 子进程的环境变量隔离)
- 上下文文件扫描(对项目文件如 AGENTS.md/.cursorrules 的提示注入检测)
- 跨会话隔离(会话之间不能互相触碰数据;cron 任务存储路径加固防路径穿越)
- 输入消毒(终端工具的工作目录参数按白名单校验,防 shell 注入)
- 危险指令检测:
tools/approval.py::DANGEROUS_PATTERNS(第 546 行起,全文读过)——一份 精心维护的大型正则列表,覆盖rm -rf /各变体、Windowscmd/powershell破坏性删除 (刻意锚定避免对含”del”的良性路径误判)、chmod 777/全局可写、chown -R root、mkfs、dd if=、写入/dev/sd*、不带WHERE/TRUNCATE的 SQLDROP/DELETE FROM、systemctl stop/restart/disable/mask、kill -9 -1、pkill -9、killall的 SIGKILL 变体、fork bomb、-c方式的 shell 调用、curl|wget管道到 shell、命令替换式 远程内容执行(eval $(curl ...))、base64/base32/base16 解码管道到 shell(对混淆有 感知)、xxd -r反向 hex 转 shell。 - 审批模式(
approvals.mode配置项):manual(默认,始终提示)、smart(辅助 LLM 风险评估——低风险自动批准,高风险自动拒绝,不确定则升级为人工提示)、off(等价于--yolo,完全不提示)。 - YOLO 模式:3 条激活路径(
--yoloCLI 参数、/yolo斜杠切换命令、HERMES_YOLO_MODE=1环境变量)。在模块导入时即冻结,专门防止运行中的 skill 通过中途设置 环境变量来悄悄提权(tools/approval.py第 29-32 行左右有明确安全注释)。激活期间有持续 视觉提醒(红色横幅 + 状态栏标记)。 - 硬线阻止列表(
UNRECOVERABLE_BLOCKLIST,文档中提及,与DANGEROUS_PATTERNS不是 同一份列表):一份小而固定、代码内置的灾难性指令集合(含--no-preserve-root的rm -rf /、fork bomb、对已挂载根分区执行mkfs、dd清零物理磁盘、把不可信 URL 管道到 rootfs 顶层的sh),任何机制都无法绕过——不是--yolo,不是approvals.mode: off,不是 cron 的 approve 模式,也不是用户点击”always allow”。这是 比 YOLO 模式更底层的一道地板,在审批层看到指令之前就已触发。 - 用户可编辑的拒绝规则(
approvals.deny):fnmatch glob 模式,大小写不敏感,匹配 归一化/去混淆后的指令变体(因此git pu""sh --force这类引号花招无法绕过),在--yolo//yolo/approvals.mode: off之前检查。文档中明确描述为 “yolo-with-exceptions”。容器隔离的后端完全跳过这套防护栈,因为其中运行的任何东西都无法 触达宿主机。 - 代码本身(非仅文档)中的并发安全处理相当成熟:
_hermes_interactive_ctx使用contextvars.ContextVar而非全局环境变量,专门规避一个代码注释中直接引用 CVE 编号 (GHSA-96vc-wcxf-jjff)的竞态问题——共享ThreadPoolExecutor上的并发 ACP 会话可能出现 一个会话的finally块环境变量还原覆盖另一个会话的设置,导致危险指令悄悄落入非交互式 自动批准路径。 - 审批钩子在遥测契约中仅供观察(见”可观测性”一节)——插件无法用它们预先应答或绕过审批
提示;只有
pre_tool_call能在指令到达审批层之前将其拦下。
沙箱与执行隔离
- 6 种终端执行后端,代码(
tools/environments/:base.py、local.py、docker.py、ssh.py、singularity.py、modal.py、managed_modal.py、modal_utils.py、file_sync.py)与官方文档/README 均确认:local、Docker、SSH、 Singularity、Modal、Daytona。 tools/terminal_tool.py模块 docstring 明确将其框定为一个权衡谱系:local = 最快但无 隔离(直接宿主机执行);Docker = 隔离但需要 Docker daemon;Modal = 云沙箱(直连或经 “managed gateway”模式)。README 中特别指出 Daytona 和 Modal 提供无服务器持久化——环境 空闲时休眠,“会话之间几乎零成本”。- 云沙箱注意事项在工具 docstring 中直接写明:持久化文件系统能跨沙箱重建保留工作状态, 但不保证同一个存活的沙箱/长期运行进程能挺过清理、空闲回收或 Hermes 退出——即文件系统 持久化不等于进程持久化。
- Docker 的网络出站隔离是单独文档化的加固层(
docs/security/network-egress-isolation.md, 全文读过):默认network_mode: host给予无限制出站访问;文档提供一份docker-compose.override.yml模式,把一个无默认路由/无外网的internalDocker 网络 (agent/dashboard/gateway 都在这里)与一个可访问外网的egress网络(只有 egress-proxy 如 squid/envoy 驻留、带 allowlist)分离,gateway 服务双宿以接收入站平台消息,同时让 agent 核心不直接暴露在公网。明确框定为防御提示注入驱动的数据外泄 (工具生成的 shell 命令通过curl/wget/原始 HTTP)——是终端后端边界之外的第二层。 - 架构文档系统图中还提到 5 种浏览器自动化后端(“Browser (5 backends)”),本轮未逐一点名;
tools/browser_camofox.py、tools/browser_cdp_tool.py暗示至少包含一个基于 Camoufox 的隐身后端和一个原生 CDP 后端,留待后续验证。
与模型的协同设计
- 3 种内部 API 模式(
chat_completions、codex_responses、anthropic_messages)各自 有专门的适配/转换代码,说明 harness 是为适应真实的逐 provider API 形态差异而构建,而非 强行统一为一种线格式:agent/anthropic_adapter.py(Anthropic Messages API)、agent/codex_responses_adapter.py(OpenAI Responses API)、agent/bedrock_adapter.py、agent/vertex_adapter.py、agent/azure_identity_adapter.py、agent/gemini_native_adapter.py(文件名/存在性通过ls确认,未逐一深读)。 - 逐 provider 工具 schema 消毒:全文读过
agent/gemini_schema.py,确认 Gemini 的FunctionDeclaration.parameters只接受 OpenAPI/JSON-Schema 的一个严格子集 (硬编码约 24 个键的白名单),因此 Hermes 的 OpenAI 风格工具 schema 在发给 Google 之前 会被剥离/重写。同名兄弟文件agent/moonshot_schema.py为 Moonshot/Kimi 的 schema 特性 做同类处理(未打开细读)。 agent/model_metadata.py(上下文长度、token 估算)和agent/models_dev.py(与社区models.dev注册表的集成)构成一个 provider/模型能力数据库——未深读,但存在与 命名本身证实 harness 追踪逐模型的上下文窗口大小及(隐含的)能力标记,用于驱动压缩阈值和 提示注入决策(例如prompt_builder.py导出的GOOGLE_MODEL_OPERATIONAL_GUIDANCE、OPENAI_MODEL_EXECUTION_GUIDANCE、TOOL_USE_ENFORCEMENT_MODELS等逐模型操作指引块)。- 推理/思考内容作为一等公民的独立字段处理:官方 Agent Loop 文档指出扩展思考模型的推理内容
存于
assistant_msg["reasoning"](不与content混在一起),通过专门的reasoning_callback暴露。 - 分散在多个小文件中的 provider 特定处理:
agent/lmstudio_reasoning.py(LM Studio 推理格式特性)、agent/portal_tags.py(Nous Portal 特定标签)、agent/nous_rate_guard.py(Nous 特定限流)——证实该 harness 由同一个运营模型服务门户 (Nous Portal)的团队构建,围绕其具体行为做协同设计,与 README 中”由模型训练团队打造” 的说法一致(Nous Research 同时训练 Hermes 模型系列、Nomos、Psyche)。 - 容错/可靠性逻辑(
agent/retry_utils.py、agent/rate_limit_tracker.py、agent/credential_pool.py、agent/credential_sources.py)将 provider 不稳定性作为 一等公民问题处理,有逐 (provider, 凭证池条目) 的重试计数逻辑(conversation_loop.py第 612-617 行直接可见:agent._auth_pool_refresh_counts每轮重置,内联注释引用了 GitHub issue #26080,修复一个持续 401 导致无限刷新凭证的 bug)。
轨迹利用(session/trajectory 是否反哺训练/评测)
- 是——明确的一等公民训练数据管道,这是证据最充分的维度之一。
agent/trajectory.py(56 行,全文读完):save_trajectory()以 ShareGPT 格式 ({"conversations": [...], "timestamp": ..., "model": ..., "completed": bool}) 将对话追加到trajectory_samples.jsonl(成功)或failed_trajectories.jsonl(失败)——成功和失败两类结果都被捕获,不只是成功案例。还有convert_scratchpad_to_think()——把<REASONING_SCRATCHPAD>标签归一化为<think>标签,即主动将推理轨迹重新格式化为特定的训练友好标签约定。batch_runner.py(57KB,读过模块 docstring):专门的并行批处理运行器,用于”跨数据集 多个 prompt 运行 agent”,带 checkpoint/续跑能力,以及”以正确格式保存轨迹(from/value 对)“和”跨所有批次聚合工具使用统计”。这是一个专门构建的规模化合成轨迹生成系统,不是附带 日志。trajectory_compressor.py(69KB,模块 docstring 全文读过):专门针对训练数据的后处理 压缩管道——保护首轮(system/human/first-gpt/first-tool)和末尾 N 轮原样不变,只压缩中间 区域至目标 token 预算,用单条摘要消息替换,同时保持 agent 后续工具调用完整(“model continues working after summary”)。带有采样数据集百分比(--sample_percent)和设置 目标 token 预算的 CLI 参数。这强烈暗示这些轨迹直接进入 SFT/工具调用模型的训练数据准备流程 ——不仅仅是留存审计。- 官方文档(README/首页)声明:“Research-ready — Batch trajectory generation, trajectory compression for training the next generation of tool-calling models”, 以及单独的 “RL training with Atropos”——Atropos 被指名为一个独立的 Nous Research RL 环境仓库(不属于 hermes-agent),大概率消费这里导出的轨迹数据; hermes-agent 自身的职责是生成/压缩,而非 RL 循环本身。
- 存在专门的官方文档页
/docs/developer-guide/trajectory-format(描述”来自 agent 会话 的 ShareGPT 格式轨迹,用于训练数据生成”,按架构文档的 Major Subsystems 列表), 本轮未抓取/深读——留待后续验证的高价值项。 - 与临时轨迹导出不同:
session_search/SQLite+FTS5(“记忆”一节)是面向存活 agent 的 运行时回忆机制,不属于这条训练轨迹管道,两个系统在 dossier 中不应混为一谈。
与同类 harness 的关键差异(1-3 条)
以下先给出基于本次调研可支撑的初步观察,完整的跨 harness 系统对比留待 synthesis 阶段:
- “模型训练团队自建 harness”这一身份贯穿多处代码细节——Nous Portal 专属限流/标签代码
(
nous_rate_guard.py、portal_tags.py)、面向”下一代 tool-calling 模型”训练的显式 ShareGPT 轨迹导出+压缩管道(trajectory.py/batch_runner.py/trajectory_compressor.py),以及与独立 RL 项目 Atropos 的明确分工,构成了一条从 “agent 产品使用”到”模型训练数据”的完整闭环叙事,这在同类开源 harness 中较为罕见(多数 harness 或者不做轨迹导出,或者做了但不像这里这样有专门的压缩/采样后处理工具)。 - skill 自我维护(Curator)机制的成熟度——不是简单的”agent 可以创建 skill 文件”,而是 有独立的、按空闲时间触发的后台 review agent,带严格的不变式(只碰 agent 创建的 skill、 从不自动删除只归档、pin 后跳过自动转换),比多数 harness 里”skill = 静态 markdown 文件” 的做法更进一步。
- 安全模型的层次感明显强于常规实现:
DANGEROUS_PATTERNS(可配置审批门)与UNRECOVERABLE_BLOCKLIST(任何模式都无法绕过的地板)分层设计,加上针对已知 CVE (GHSA-96vc-wcxf-jjff)的contextvars竞态修复,显示出比”agent 产品”更贴近”生产基础设施” 的安全工程投入。
原始源码定位
- repo: https://github.com/NousResearch/hermes-agent
- commit/version analyzed:
5431bf29214681fb2fd25254568b58c9da8ce6e0(2026-06-06 提交, 2026-07-07 clone;官方文档站彼时已披露更新版本 v0.18.0,本 SHA 非绝对最新) - 关键文件列表(相对路径):
agent/conversation_loop.py(5294 行,主循环run_conversation())agent/system_prompt.py(536 行)、agent/prompt_builder.py(1971 行)agent/context_engine.py(231 行)、agent/context_compressor.py(3045 行)agent/memory_manager.py(1086 行)agent/learning_graph.py(328 行)、agent/curator.py(1976 行)agent/trajectory.py(56 行)、agent/moa_loop.py(1073 行)agent/gemini_schema.py、agent/moonshot_schema.pyagent/anthropic_adapter.py、agent/bedrock_adapter.py、agent/vertex_adapter.py、agent/codex_responses_adapter.py、agent/gemini_native_adapter.py、agent/azure_identity_adapter.pyagent/model_metadata.py、agent/models_dev.pyagent/lmstudio_reasoning.py、agent/portal_tags.py、agent/nous_rate_guard.pyagent/retry_utils.py、agent/rate_limit_tracker.py、agent/credential_pool.py、agent/credential_sources.pytools/registry.py(766 行)、tools/approval.py(2985 行)tools/delegate_tool.py(3445 行)、tools/async_delegation.py(531 行)tools/terminal_tool.py、tools/environments/(base/local/docker/ssh/singularity/modal/managed_modal/modal_utils/file_sync)tools/skill_manager_tool.pyhermes_state.py(275KB,SQLite+FTS5 会话存储)batch_runner.py(57KB)、trajectory_compressor.py(69KB)docs/observability/README.md、docs/session-lifecycle.md、docs/security/network-egress-isolation.mdacp_adapter/(server.py、session.py、permissions.py、edit_approval.py、tools.py、 events.py、provenance.py、auth.py)cron/(jobs.py、scheduler.py、scheduler_provider.py、lifecycle_guard.py、 blueprint_catalog.py、suggestion_catalog.py)- 未深读、留待后续验证:
tools/mcp_tool.py、tools/kanban_tools.py、hermes_cli/kanban_decompose.py、hermes_logging.py
一手源存档(sources/)
/Users/zhao/projects/self-wiki/ai-research/sources/harness/hermes-agent/:
NOTES.md—— 完整调研笔记(含全部文件路径、行号引用、summary)code-snapshots/:approval_excerpt.py、context_engine.py、conversation_loop_excerpt.py、curator_excerpt.py、delegate_tool_excerpt.py、gemini_schema.py、learning_graph_excerpt.py、memory_manager_excerpt.py、skill_manager_tool_excerpt.py、system_prompt.py、terminal_tool_excerpt.py、tools_registry.py、trajectory.py、trajectory_compressor_excerpt.pynetwork-egress-isolation.md、observability-README.md、session-lifecycle.md(从仓库docs/保存的完整文档)
official-docs/(Docusaurus 文档站抓取):agent-loop.md、architecture.md、docs-index.md、memory.md、security.md、session-storage.md、skills.md
尚未抓取(stage 2 遗留项,未来若需更深覆盖可补):官方文档站的
/docs/llms-full.txt(1.8MB 全站单文件 dump)、prompt-assembly、
context-compression-and-caching、gateway-internals、provider-runtime、
tools-runtime、acp-internals、cron-internals、trajectory-format、
memory-provider-plugin 等页面;源码侧 tools/mcp_tool.py、kanban_tools.py/
kanban_decompose.py、hermes_logging.py。