Hermes Agent 需要同时承接 ACP 协议调用、桌面端交互、 TUI 终端指令,以及 Telegram 、 Slack 、 Discord 等十余种消息平台的输入。多入口现实带来的首要风险不是底层 LLM 能力不足,而是入口膨胀与编排核心的泥石流式耦合——异构入口一旦直接穿透到决策与工具调度逻辑,系统会退化成一堆条件分支。
Hermes Agent 的应对是把后端 Python 服务切分为三层:协议适配层挡住外部协议碎片化,编排层吸收 LLM 供应商差异,扩展层消化业务能力增减。分层是否守住了边界,不能只看目录结构,必须用源码的规模分布和符号依赖方向来验证。
三层拓扑与依赖汇聚
三层从上到下依次是协议适配层(acp_adapter、gateway、tui_gateway)、编排层(agent)、扩展层(plugins)。划分的核心依据是变化频率的错位:外部协议演进最快, LLM 供应商切换次之,业务能力增减相对独立。把三类变化源塞进同一层,任何一处改动都会波及全局。

上图展示了三层的依赖方向。所有外部入口都单向依赖内部的agent 模块,没有反向穿透。但单向依赖不等于解耦——依赖分析显示hermes_cli 对agent 的依赖不是单一通道,而是对编排层内部多个子模块的多点扇入。agent 模块因此成为事实上的耦合枢纽,内部接口的任何变更都会在 CLI 层产生放大效应。这是汇聚式架构的隐性成本:接口稳定性要求极高,且适配层、网关层与编排层之间不是均匀的单线连接,而是 CLI 扇入远重于 ACP 间接桥接的不对称依赖。
协议适配层:用体量换隔离
协议适配层的存在价值是把外部请求格式、资源标识与认证机制翻译成内部表示,让新增消息平台只动适配层、不碰编排层。但隔离不是免费的。
协议适配层主文件达到 2042 行(证据:acp_adapter/server.py),内部包含资源 URI 到内部表示的非平凡映射逻辑(证据:_resource_display_name 符号)。这个规模证明协议适配层不是简单的透传代理,而是承担了实质性的翻译工作。收益是编排层完全不需要理解外部 URI 结构,代价是适配层自身积累了 2000+ 行的内部复杂度,存在进一步模块化的空间。
更隐蔽的代价在桥接方式上。依赖方向分析揭示了一个非对称现象: CLI 入口对编排层使用标准的显式导入,而 ACP 适配器头部完全由协议 schema 导入构成,未命中任何对编排层的直接 import 。 ACP 适配器到编排层通过运行时间接桥接而非静态 import 连接。这实现了"外部协议变化不侵入编排层"的隔离目标,但牺牲了链路可追溯性——ACP 主链路一旦出问题,静态分析看不到入口层与编排层的连接点,排查难度上升。
编排枢纽层:有状态的工具调度
请求穿过适配层后进入编排层。这层对上层入口形态保持无知,只管 ReAct 循环、 LLM 供应商路由和工具分发。它承受了来自所有入口的依赖汇聚,内部用"瘦委托、厚辅助"模式组织代码,但体量并未因此降低。
编排层核心辅助文件达到 2527 行(证据:agent/agent_runtime_helpers.py),内部采用延迟引用设计(证据:_ra 符号)来规避循环依赖。这个设计证明 helpers 从主循环文件抽离但单文件体量依然庞大,"瘦委托厚辅助"在本项目中更多是代码组织手段而非真正的复杂度分解。收益是测试层可以拦截主循环而不引入编译期耦合,代价是编排层的内部复杂度仍然集中,进一步拆分的空间存在但未实施。
LLM 调用侧,编排层内置了"池化凭证轮换+传输重建"的容错机制,把多供应商限流当成常态而非异常。收益是避免无脑重试导致的雪崩,代价是引入了凭证池状态管理和传输层重建的复杂度。
工具调度侧做了一个更根本的取舍。源码中硬编码了一个需要强感知的工具集合,这些工具执行后会在编排层触发专属 post-hook 。这意味着工具调用不是无状态分发——记忆写入、会话状态变更、任务委派等副作用需要 agent 运行时主动感知。系统在工具分发节点放弃了纯度,换来了对关键业务副作用的确定性控制。
胖网关层:配置收口与治理过载
hermes_cli 不是单薄的命令行入口,而是承担了模型目录管理和多供应商凭证池治理的"胖网关"。把这些逻辑放在 CLI 层而非编排层,收益是核心编排循环不关心"有哪些模型可用"或"怎么鉴权",实现了核心层与业务配置的解耦。
模型管理模块达到 3992 行(证据:hermes_cli/models.py),内部集中了模型目录筛选与供应商匹配逻辑(证据:_codex_curated_models 符号)。这个规模证明模型管理确实被完整收口在网关层,边界清晰。
但凭证治理的收口代价藏不住。凭证治理模块膨胀到 7864 行(证据:hermes_cli/auth.py,ProviderConfig 符号)。这个规模证明强力收口在凭证治理场景下已触及单文件承载极限——多种供应商的 OAuth 、凭证池与密钥解析被压在一个文件里,严重违背单一职责。强力收口降低了权限绕过风险,但代码审查成本和并发合并冲突概率会急剧上升。这是"网关层做收口"策略的风险边界:当收口对象本身的复杂度超过单文件承载极限时,收口反而成为新的瓶颈。
外部输入到 Agent 编排链路
理解三层拓扑的最终方式是追踪"外部输入到 Agent 编排"链路:外部请求通过 ACP 协议适配器进入,资源 URI 被映射后交给 agent 模块的主循环处理。以 ACP 协议请求为例,控制权转移经历输入、处理、输出与副作用三个阶段。

上图对比了两条主链路的差异。 ACP 链路(虚线)从外部请求进入协议适配层,经过协议转换后通过间接桥接到达编排层; CLI 链路(实线)从用户命令进入网关层,通过直接 import 到达同一个编排主循环。两条链路最终汇入同一枢纽,但桥接方式截然不同。
输入阶段:外部 ACP 请求进入协议适配层,资源 URI 被映射为内部资源表示。前端入口受制于 Python/TypeScript 语言边界,天然退化为无状态展示层——语言隔离本身就是系统中最硬的模块边界,不需要额外架构机制保障。这一阶段的架构判断是:异构输入形态在进入系统边界后立即被归一化,编排层永远不会看到原始的外部协议结构。
处理阶段:适配层完成参数标准化后,控制权通过运行时间接桥接移交编排层,进入主循环触发 LLM 调用。遇到供应商限流时,链路进入凭证池轮换与传输重建的容错分支,而不是简单抛错。这一阶段的核心架构判断是:编排层对入口形态完全无知,它只接收标准化后的内部表示,不关心请求来自 ACP 客户端还是 CLI 终端。
输出与副作用阶段:这是链路的分叉点。 LLM 决策下发到工具调度器后,普通工具执行完直接返回结果;但特定工具执行后,编排层的 post-hook 会被激活,主动介入记忆写入、会话状态变更等有状态副作用。控制权从"无状态分发"切换为"有状态干预"——系统在工具调度节点放弃了纯度,换取对关键业务链路的确定性控制。
这条链路揭示了一个关键风险:入口与编排耦合过紧时,参数校验、错误恢复和副作用会混在一起。 Hermes Agent 通过把校验推到适配层、把副作用收束到 post-hook 集合,在编排层内部维持了"正常路径无状态、副作用有明确触发点"的 discipline 。但 post-hook 集合是硬编码的,新增需要强感知的工具必须改动编排核心代码,扩展性受限。
设计取舍与风险边界
三层拓扑在隔离外部变化上有效:新增平台只动适配层,替换 LLM 只动编排层,增加能力只动扩展层。但三个结构性代价正在吞噬分层收益。
第一,编排模块作为唯一枢纽承受了所有入口的扇入汇聚,内部接口稳定性要求极高。 CLI 入口跨层直接导入编排层的 LLM 供应商适配器实现就是边界违反的具体案例——入口层不仅依赖编排接口,还穿透到适配实现层,供应商适配器内部变更时 CLI 入口会意外受影响。
第二,治理逻辑向单文件堆积。凭证治理模块的 7864 行证明"网关层收口"策略在凭证治理场景下已触及单文件承载极限。
第三,工具 post-hook 的硬编码集合限制了扩展层接入核心副作用链路的自由度。扩展层通过注册机制接入工具链,但只有被硬编码列入 post-hook 集合的工具才能触发编排层的强感知处理。
当外部接入渠道超过 5 种、底层执行引擎存在多供应商切换需求时,采用三层漏斗是合理的边界划分。但必须在网关层尽早按供应商或职责域做垂直拆分,并将 post-hook 的触发规则从硬编码改为声明式配置,否则分层收益会被内部堆积的复杂度抵消。
下一篇,我们将把视角拉近到协议边界,拆解 ACP 适配器内部如何处理认证审批与资源映射,看看这层"并不轻盈"的壳是如何做隔离的。
篇间导航
上一篇:无,本篇为系列起点 下一篇:协议边界架构: ACP 适配器如何隔离外部协议与内部编排
夜雨聆风