Hermes 与 Claude CodeHermes 与 Claude Code第 12 章 · 14 章Chapter 12 of 14
全文目录Contents
  1. 这个网页怎么用
  2. 1 · 零基础前置知识
    1. 1.1 大语言模型是什么
    2. 1.2 token 是什么
    3. 1.3 上下文与上下文窗口是什么
    4. 1.4 智能体与聊天机器人的区别
    5. 1.5 工具调用是什么,它到底怎么工作
    6. 1.6 什么是流式输出
    7. 1.7 什么是 API
    8. 1.8 提示词缓存 —— 全文最重要的技术概念
    9. 1.9 还会遇到的几个词
  3. 2 · 两个系统的宏观定位与架构总图
    1. 2.1 用一句话说清各自的定位
    2. 2.2 架构总图
    3. 2.3 关键数字对照
    4. 2.4 第一个值得记住的洞察
  4. 3 · 垂直分层与水平分区
    1. 3.1 垂直分层:六层模型
    2. 3.2 水平分区:同一层内部怎么切
    3. 3.3 一个反直觉的观察:巨型文件
    4. 3.4 分层之外:穿透所有层的四类逻辑
  5. 4 · 智能体主循环与错误恢复状态机
    1. 4.1 教科书版本的循环,以及它会死在哪
    2. 4.2 Claude Code 的做法:写成显式状态机
    3. 4.3 错误扣留:可恢复的错误不能立刻往外发
    4. 4.4 中断的正确处理姿势
    5. 4.5 切换备用模型:一个想不到的坑
    6. 4.6 Hermes 的做法:预算驱动的循环
    7. 4.7 Hermes 独有的能力:轮次中途插话
    8. 4.8 两家对照与取舍
  6. 5 · 工具抽象层与工具执行编排
    1. 5.1 Claude Code 的工具接口:一个教科书级抽象
    2. 5.2 渐进式工具加载:工具搜索机制
    3. 5.3 工具清单的装配:一个只有深度用过缓存才知道的坑
    4. 5.4 执行编排:并发分区
    5. 5.5 流式工具执行器:边流边执行
    6. 5.6 Hermes 的工具层:中心分发 + 参数强制矫正
    7. 5.7 两家对照与取舍
  7. 6 · 上下文治理阶梯 ★ 全文核心
    1. 6.1 Claude Code 的做法:五级流水线
    2. 6.2 第 ① 级:工具结果预算与落盘
    3. 6.3 第 ③ 级:缓存编辑 —— 全文最精彩的一处
    4. 6.4 第 ⑤ 级:自动摘要压缩的工程细节
    5. 6.5 上下文真的超了之后:三级恢复瀑布
    6. 6.6 Hermes 的做法:把整条阶梯抽象成一个插座
    7. 6.7 两家横向对照
  8. 7 · 权限模型与安全边界
    1. 7.1 Claude Code 的做法:十级决策级联
    2. 7.2 自动模式:用模型判断安全性,加三级快速通道
    3. 7.3 Hermes 的做法:正则红线 + 对抗性解析
    4. 7.4 Hermes 的第二道防线:执行环境隔离
    5. 7.5 一个常被忽略的攻击面:错误消息回灌
    6. 7.6 两家对照与取舍
  9. 8 · 多智能体协作编排
    1. 8.1 子智能体到底解决什么问题
    2. 8.2 Claude Code 的三种子智能体形态
    3. 8.3 分叉子智能体:把提示词缓存用到极致
    4. 8.4 子智能体的工具限制
    5. 8.5 Hermes 的做法:任务委派 + 看板协作
    6. 8.6 一个两家共同的硬约束:中断的级联
  10. 9 · 记忆系统与扩展体系
    1. 9.1 记忆:两种截然不同的答案
    2. 9.2 Hermes 的全息记忆值得单独看
    3. 9.3 Claude Code 的记忆预取:藏在流水线里的优化
    4. 9.4 扩展体系:四种扩展点
    5. 9.5 Hermes 的网关层:Claude Code 完全没有的一层
  11. 10 · 两个系统的横向对照总表
    1. 10.1 机制对照
    2. 10.2 两条架构路线各自的账本
    3. 10.3 两家一致的地方 = 事实上的行业共识
  12. 11 · 可以搬到自己项目里的实现范式
    1. 11.1 骨架一:带恢复状态机的主循环
    2. 11.2 骨架二:上下文治理阶梯
    3. 11.3 骨架三:工具抽象 + 并发分区
    4. 11.4 骨架四:按信任边界配置工具面
    5. 11.5 骨架五:不可绕过的安全底座
    6. 11.6 自建智能体的决策清单
    7. 11.7 一页纸检查清单
  13. 12 · 面试话术卡
    1. Q1 · 说说你理解的智能体架构
    2. Q2 · 上下文满了怎么办
    3. Q3 · 怎么防止智能体执行危险命令
    4. Q4 · 多工具并行怎么保证不出竞态
    5. Q5 · 智能体循环怎么防止无限循环
    6. Q6 · 什么时候该用子智能体
    7. Q7 · 智能体的长期记忆怎么做
    8. Q8 · 你怎么优化智能体的成本和延迟
    9. Q9 · 反问环节可以问的问题
    10. 最后:这份文档的正确用法
  14. 13 · 术语表
    1. 13.1 模型与调用
    2. 13.2 提示词缓存(全文最重要的概念组)
    3. 13.3 智能体与工具
    4. 13.4 上下文治理
    5. 13.5 编程与架构概念
    6. 13.6 两个系统的关键模块名

12 · 面试话术卡

被问到的概率排序。每张卡的结构是:先给一句能立住的判断,再给结构化展开,最后给一个能证明你真读过源码的细节。

用法提醒

别把这些当稿子背。面试官真正在测的是「你有没有自己的判断」,所以每张卡的第一句话(判断)才是核心,后面的展开只是支撑。

如果你只能记住一样东西,记住第一句。

Q1 · 说说你理解的智能体架构

最高频的开场题。答得越具体越好,别背定义。

判断:智能体系统的复杂度不在「循环」本身,而在循环之外的四件事:上下文治理、工具调度、权限边界、错误恢复。

展开:标准的六层分层是 —— 入口层 / 会话层 / 智能体循环层 / 工具执行层 / 供应商适配层 / 持久化层。

关键是循环层和工具执行层必须分开:循环层是有状态的状态机(它要跨轮次记住「我压缩过几次」「我切换过备用模型没有」),工具执行层是无状态的调度器(给一批工具调用,还一批执行结果,做完就忘)。

揉在一起的直接后果是:错误恢复逻辑没法单独测试 —— 你想测「压缩失败后会不会正确重试」,就必须先造一堆假工具。这是很多自建智能体项目后期极难维护的根本原因。

细节:我对比读过 Claude Code 和 Hermes 的源码。Hermes 的代码量是 Claude Code 的 3.7 倍(191 万行对 51 万行),但两者的核心循环体量几乎相同。那 3.7 倍的差距全在外围 —— Hermes 的 22 个聊天平台适配器、十几种模型供应商适配、插件系统。这说明智能体的能力密度集中在很小的一块代码里,其余都是集成工程量。

Q2 · 上下文满了怎么办

区分「用过智能体」和「做过智能体」的分水岭题。

判断:摘要压缩是最后一级,前面还有三级更便宜的。上来就答摘要,说明没做过。

展开:一条成本递增的阶梯 ——

  1. 不让它进来:单条工具结果超限就写到磁盘,只回预览和文件路径。成本 0。
  2. 删掉确定没用的:旧的文件读取和搜索结果,按工具调用 id 精确删除。成本 0。
  3. 结构化折叠:折成可展开的摘要,保留粒度和可重放性。成本低。
  4. 整段摘要:一次完整的模型调用,有损、不可逆。成本高。

顺序很重要:如果第 3 级已经降到阈值以下,第 4 级就直接跳过 —— 从而保住细粒度上下文,而不是把它变成一坨摘要。Claude Code 源码里有一句注释就是讲这个:「keep granular context instead of a single summary」

细节(这个是杀手锏):缓存冷热应该成为压缩策略的输入。

提示词缓存是前缀匹配的 —— 改动上下文中段,从那里往后的缓存全部失效。所以缓存热的时候,改本地数据会让整段缓存作废,省下的 token 还不如重建缓存贵;Claude Code 的做法是发一条 cache_edits 指令让服务端在缓存内部删除,本地一个字不改。

反过来,如果距上次响应已经超过缓存有效期、缓存已经凉了,那前缀反正要全部重新处理 —— 这时候正是大刀阔斧清理旧内容的最佳时机

同一个目标,两条完全相反的路。大多数自建智能体根本没有「缓存现在是热还是凉」这个概念,所以策略只有一套,在两种场景下各错一半。而判断冷热只需要一个时间戳,成本为零。

Q3 · 怎么防止智能体执行危险命令

服务端岗位必问。答案的层次感最重要。

判断:最有效的防护不是「拦住危险命令」,而是「那个危险工具根本不在模型能看到的清单里」

展开:四层,从外到内 ——

  1. 工具面收窄。按信任边界配置工具集:交互式会话给全量,后台任务给只读,公开 webhook 只给联网搜索。Hermes 的注释写得很直白:webhook 事件可能来自不可信的第三方内容(公开代码仓库的合并请求标题、评论),所以默认工具集刻意收窄,避免提示词注入触发本地文件读写或命令执行。模型无法调用一个它不知道存在的工具。
  2. 规则级联 + 不可绕过的底座。允许用户关掉烦人的确认(否则自动化就没价值),但保留一层他们关不掉的检查。Claude Code 的权限判定链里,「工具自己拒绝」「需要人在场」「用户显式配的规则」「敏感路径」这四类排在 bypassPermissions 检查之前 —— 开了 --dangerously-skip-permissions 也照样拦得住。顺序就是设计。
  3. 语义判定。规则匹配不了意图,需要模型看完整对话记录来判断。但分类器很贵(每次一个额外 API 请求),前面必须挡快速通道。
  4. 执行隔离。前三层都是软的,真正的边界是容器、沙箱、独立用户账号。

细节:「命令」和「数据」必须区分。

朴素的 if "rm -rf /" in cmd 会拦掉 git commit -m "fix: block rm -rf / spellings" —— 这是 Hermes 真实修过的 bug,用户没法提交一条说明文字里含这段字符的代码提交。

正确做法是只在命令位置匹配(行首 / ;&&|| 分隔符后 / $( 子 shell 后 / sudo 包装后),并对引号内容做遮蔽。但双引号里的 $(...) 不能遮蔽,因为 shell 真的会执行它;而遇到 sh -c / eval 这类 shell 载体时,遮蔽整个失效,因为那里引号内容就是代码。源码里一句话总结:「quoting is not a bypass」

最后补一句判断力:误报率过高的安全措施等于没有安全措施 —— 用户会直接把它整个关掉。

Q4 · 多工具并行怎么保证不出竞态

别答"加锁",那是在错误的层次上解决问题。

判断:并发安全性应该由工具自己声明,调度器不认识任何具体工具。

展开:

  1. is_concurrency_safe(参数) 必须是接收参数的 —— 同一个 Bash 工具,跑 ls 安全、跑 rm 不安全。安全性取决于这次要做什么,不取决于工具类型。所以它是一个方法而不是一个静态标记。
  2. 贪心分区,不是全排序。把相邻的安全工具合并成一个并行批,遇到不安全的就切断并单独串行。既拿到并行的速度收益,又完整保留了模型隐含的顺序语义(模型可能依赖「先改文件再读回来验证」的顺序)。
  3. 失败时倒向保守。参数格式解析失败、安全判定函数自己抛异常 —— 全部当作不安全。Claude Code 专门为此写了 try/catch,注释是「Bash 命令的引号解析失败时保守处理」。

细节:两级中止作用域。

一批并行的 Bash 命令里有一个失败了(比如编译报错),其他几个跑完毫无意义 —— 但如果用同一个全局中止开关去停它们,整个轮次就结束了,模型收不到错误信息,也就没法重试

Claude Code 的做法是创建一个父控制器的子控制器:批内失败时中止子控制器,兄弟子进程立刻死掉省资源;父控制器不动,所以本轮不结束,模型正常收到错误并重试。

任何有「批内失败」概念的并发执行器,都应该有一个可以独立触发的子作用域。

Q5 · 智能体循环怎么防止无限循环

看你有没有真踩过坑。

判断:真正的无限循环几乎都不来自主流程,而来自两条恢复逻辑互相触发

展开:

  1. 硬闸(最大轮次 / 最大美元花费 / 最长运行时间)—— 这是兜底,正常情况不该碰到它。
  2. 每条恢复路径独立限次,而且只在正常推进时重置。这是核心。
  3. 软着陆 —— 预算快耗尽时给一次「宽限调用」让模型收尾,比硬切断的体验好得多。这是 Hermes 的做法。

细节:Claude Code 源码里留了一条事故记录。有人在「结束钩子」分支里把 hasAttemptedReactiveCompact(是否已尝试反应式压缩)这个幂等锁重置成了 false,结果形成死循环:压缩 → 还是超 → 报错 → 结束钩子判定不合格要求重试 → 又去压缩 → …… 烧掉了几千次 API 调用。

请注意这个循环的形状:它不是一条路径自己转圈,而是两条恢复路径互相触发。压缩路径和钩子路径各自看起来都有终止条件,但组合起来就成了死循环。

还有一个相关的:上下文超长导致的失败明确不走结束钩子。因为那个钩子会往上下文里注入反馈内容,越注入越超 —— 源码里管这叫 death spiral(死亡螺旋)。失败路径必须能识别「这一类失败不该触发常规的质量重试机制」。

Q6 · 什么时候该用子智能体

判断:子智能体的第一性原理是上下文隔离,不是并行。并行只是副产品。

展开:要读 20 个文件才能得出一个结论时,自己读会让那 20 个文件的内容永久占用主上下文、每一轮都重发一遍;派子智能体去读,它的上下文用完即弃,主智能体只收到一句结论。40,000 token 换成 15 token。

  • 该用:探索型任务(结论远小于探索过程)、需要不同工具面或不同权限的任务、可并行且互不依赖的任务。
  • 不该用:需要主智能体完整上下文才能做对的任务(分叉模式除外,因为它本来就继承全部上下文)、需要和用户交互的任务(子智能体通常被禁用「向用户提问」工具)、单步就能完成的任务(派生开销大于收益)。

细节:扇出时的缓存策略。

N 个子智能体如果能让请求前缀达到字节级一致,后 N−1 个全是缓存命中,输入成本降到 1/3 以下。Claude Code 为此付出了四个看起来不优雅的代价:
· 给子智能体一堆用不到的工具(因为工具定义是前缀的一部分)
· 传父智能体已渲染好的系统提示词字节,而不是重新生成(重新生成可能因为特性开关的冷热变化而产生不同字节)
· 用完全相同的占位内容填充所有工具结果
· 把递归分叉的守卫从接口层下移到调用层(因为从工具池里移除会改变工具定义,破坏缓存)

只让最后一个文本块携带各自不同的指令。这是很具体、可量化的架构决策。

Q7 · 智能体的长期记忆怎么做

判断:先分清三种记忆,别一股脑塞进向量数据库。

  • 指令性记忆(偏好、约定、项目规范)—— 不该用检索。应该是人类可读、可审阅、可以用 git 管理的纯文本,每次全量加载。用户改了要立刻生效,而且必须能看到自己写了什么。Claude Code 的 CLAUDE.md 就是这个定位。
  • 事实性记忆 —— 需要检索。词法检索 + 向量检索混合优于纯向量,因为事实里全是专有名词,而向量检索恰好对专有名词不敏感。
  • 过程性记忆 —— 本质是会话历史检索,存对话记录 + 全文索引。

两个容易漏的工程点:

  • 信任衰减。Hermes 用 trust_scorerecord_feedback(fact_id, helpful):有用的上浮,误导过人的沉底。没有这个机制,一条早期的错误记忆会永久污染后续所有会话 —— 比如智能体误以为「这个项目用 npm」,实际用的是 pnpm,之后每次都会先执行错的命令。
  • 注入去重。模型自己刚 Read 过的文件不要再作为记忆注入一遍。Claude Code 用跨迭代累积的已读文件状态过滤 —— 注意是跨迭代累积,只看本次迭代会漏掉早期读过的。

细节:Hermes 的全息记忆用 SHA-256 确定性生成原子向量,而不是用神经网络生成 embedding。

好处是:同一个词在任何机器、任何 Python 版本上编码结果完全一致 —— 彻底避开了「换了 embedding 模型就要重算全库」这个运维噩梦,而且向量可以直接存进数据库的二进制字段跨机器同步。

代价是:它是词袋级的符号组合,没有语义泛化能力("docker" 和 "container" 相似度接近 0),所以必须配合词法检索使用,而不是替代它。这个权衡本身就很值得讨论。

Q8 · 你怎么优化智能体的成本和延迟

判断:智能体的成本大头是输入 token,不是输出。因为每一轮都要重发整个历史。所以优化的核心是提示词缓存的命中率

四个手段:

  1. 保护缓存前缀。任何会改动历史前缀的操作都要重新评估。举个极端例子:Claude Code 里内建工具和外部 MCP 工具是分别排序后拼接的,不是合并排序 —— 因为服务端在「最后一个内建工具」之后放缓存分界点,统一排序会让外部工具插进内建工具中间,把区间劈开。结果是用户每装一个 MCP 服务,所有人的系统提示词缓存就全崩。
  2. 渐进式披露。工具的参数说明、技能正文、MCP 工具、记忆内容 —— 全部「目录常驻 + 内容按需展开」。Claude Code 甚至有一个函数专门估算所有技能头部元数据的常驻成本。
  3. 流式执行。工具在模型流式返回的过程中就开始跑,不等整个响应结束。
  4. 把慢操作藏进流式窗口。模型流式输出要 5 到 30 秒,这段时间 CPU 闲着。Claude Code 在这个窗口里塞了记忆预取、技能发现预取、上一批工具的小模型摘要生成 —— 实测技能预取的完成率大于 98%。关键是消费点必须设计成「好了就用,没好就跳过」,绝不阻塞。一旦开始等,这个优化就变成负优化。

细节:还有一个很小但很实在的例子 —— backfillObservableInput(回填可观测输入)。

工具有时需要给日志、钩子、开发工具包补一些派生字段,但绝不能改那个要发回 API 的原始参数对象,因为字节变了缓存就没了。Claude Code 的做法是只修改一个克隆副本,而且只有当补充操作真的新增了字段时才产生克隆 —— 如果只是覆写了已有字段,连克隆都不做,因为那会改变对话记录的序列化结果、破坏测试固件的哈希。

这个级别的克制程度,能说明「保护缓存」在这个系统里是一等公民约束。

Q9 · 反问环节可以问的问题

这些问题能同时展示你的深度,也能帮你判断这家公司值不值得去:

  • 「你们的智能体是绑定单一模型供应商,还是做了多供应商抽象?这个选择当时是怎么权衡的?」
    直接切到第 11.6 节第 1 条决策。对方的回答质量能立刻告诉你团队的技术深度 —— 如果对方能讲出「我们为了拿到某个私有能力接受了绑定」或者「我们为了合规必须支持私有部署所以做了抽象」,说明是真的想过。
  • 「上下文压缩是自己实现的还是用框架的?摘要之前有没有更便宜的层?」
    如果答案是「直接调框架的压缩接口」,说明这块还很早期。
  • 「工具执行有沙箱吗?是容器级还是进程级?」
  • 「线上遇到过智能体死循环吗?最后定位到是什么原因?」
    这个问题几乎一定能问出真实故事,而故事最能反映团队的工程成熟度。
  • 「提示词缓存的命中率现在是多少?有专门监控它吗?」
    如果对方没有监控这个指标,说明成本优化还很早期 —— 对你是机会,也是风险。

最后:这份文档的正确用法

你手上现在有两套真实系统的完整源代码。

面试里最强的表达不是「我读过 Claude Code 的源码」,而是「我遇到 X 问题时参考了它的 Y 做法,因为它的约束和我们的类似 / 不类似」。

所以最好的下一步是:挑一个你自己的小项目,把第 11 章的骨架实际写一遍。哪怕只实现主循环 + 工具并发分区 + 两级上下文治理,你在面试里能讲的东西会立刻变得具体十倍 —— 因为你会有自己踩坑的故事,而故事比知识更有说服力

文档里任何看不懂或想深挖的地方,选中那段文字点「提问」就行。术语忘了含义就翻下一章的术语表。