写作现场:2026 年 7 月 20 日。 本文基于 Quicksilver 版本。项目方报告首轮消息到首个 token 的等待时间由约 4.3 秒降至约 0.9 秒;该数字不是独立复测。比延迟更值得分析的是记忆的一致性模型:磁盘内容、system prompt、模型实际输入和历史记录并不共享同一个提交时刻。

四类状态与两条生效路径

Hermes 同时维护四类状态:

  1. MEMORY.mdUSER.md:少量、可人工修改的长期事实;
  2. MemoryProvider:针对当前输入执行的动态召回;
  3. SQLite session history:用户、模型与工具实际经过的消息序列;
  4. 回合结束后的后台写回:把新经历提交给记忆后端。

内置 MemoryStore 还区分 live state 与 _system_prompt_snapshot。记忆工具可以立即修改文件,但当前 session 已缓存的 system prompt 不会在每轮重新组装;通常要等新 session 或 compaction 触发 prompt 重建,修改才进入稳定前缀。这是一种有意的延迟可见性:临时观察不会立刻获得 system prompt 的高优先级,同时保留缓存与前缀稳定性。

动态召回走另一条路径:

system_prompt_block()  provider 的静态说明
prefetch()             本轮调用前召回
sync_turn()            完整回合后吸收
queue_prefetch()       为下一轮预热

因此,一条刚写入的端口信息可以在下一轮通过 recall 被模型读取,却仍未进入 system prompt。这里需要明确区分 retrieval consistency 与 prompt consistency:前者可以接近逐轮更新,后者按 session 生命周期更新。

可重放输入与完整回合提交

Hermes 为 user message 保留两个视图:content 是用户原文,api_content 是原文与召回上下文组合后的真实模型输入。

message["content"] = user_text
message["api_content"] = compose(user_text, recalled_memory)
persist(message)
send_to_model(message["api_content"])

如果只持久化 content,恢复 session 时就无法重建当时影响回答的 memory context,历史只能重放表面消息,不能解释模型为何作出原判断。编辑用户消息时删除旧 api_content,则避免已删除内容通过侧车重新进入请求。这个字段本质上是一份输入 provenance,但也要求所有编辑、导出和重放路径理解它的生命周期。

写回只在完整 turn 结束后执行。assistant 已产生文字或 tool call,并不代表本轮形成了可提交经历;用户中止的半个回合不会进入 sync_turn()。完成轮被送入单 worker FIFO,以维持第 N 轮先于第 N+1 轮吸收,但该队列仍是 best-effort:关机只进行有限 drain,provider 卡住时可能丢失末尾写回。

对个人助手,这种取舍可接受;对医疗、财务或审计任务,则需要 durable outbox、幂等提交、重试上限和可查询的写回状态。产品层还应暴露来源、时间、有效期、冲突与本次回答实际使用的记忆。Hermes 的核心价值不是“记得更多”,而是把稳定 prompt、动态检索、事件历史和异步学习拆成可单独推理的状态机。

版本与源码

信息边界:本文只采用 2026-07-20 及此前已经公开的事实和 v2026.7.20 源码,不使用发布日之后的主分支变化。