Hermes深入理解及源码解析(二):Hermes的记忆机制

这里写自定义目录标题

Hermse的偏好存储

简介

  • 源码位置:tools/memory_tool.py
  • 存储内容为两个文件,放在 ~/.hermes/memories/:
    • MEMORY.md:Agent 自己的笔记(环境事实、项目约定、工具坑、学到的东西)------ 上限 2200 字符
    • USER.md:关于用户的画像(角色、偏好、沟通风格)------ 上限 1375 字符

存储和读取机制

存储机制

智能体的一个工具叫 memory, 可以进行如下的操作:

  • memory(action="add", target="memory"|"user", content="...")
  • memory(action="replace", target="...", old_text="子串", content="新内容")
  • memory(action="remove", target="...", old_text="子串")
    该工具的描述如下:
bash 复制代码
    "description": (
        "Save durable information to persistent memory that survives across sessions. "
        "Memory is injected into future turns, so keep it compact and focused on facts "
        "that will still matter later.\n\n"
        "WHEN TO SAVE (do this proactively, don't wait to be asked):\n"
        "- User corrects you or says 'remember this' / 'don't do that again'\n"
        "- User shares a preference, habit, or personal detail (name, role, timezone, coding style)\n"
        "- You discover something about the environment (OS, installed tools, project structure)\n"
        "- You learn a convention, API quirk, or workflow specific to this user's setup\n"
        "- You identify a stable fact that will be useful again in future sessions\n\n"
        "PRIORITY: User preferences and corrections > environment facts > procedural knowledge. "
        "The most valuable memory prevents the user from having to repeat themselves.\n\n"
        "Do NOT save task progress, session outcomes, completed-work logs, or temporary TODO "
        "state to memory; use session_search to recall those from past transcripts.\n"
        "If you've discovered a new way to do something, solved a problem that could be "
        "necessary later, save it as a skill with the skill tool.\n\n"
        "TWO TARGETS:\n"
        "- 'user': who the user is -- name, role, preferences, communication style, pet peeves\n"
        "- 'memory': your notes -- environment facts, project conventions, tool quirks, lessons learned\n\n"
        "ACTIONS: add (new entry), replace (update existing -- old_text identifies it), "
        "remove (delete -- old_text identifies it).\n\n"
        "SKIP: trivial/obvious info, things easily re-discovered, raw data dumps, and temporary task state."
    ),

根据以上描述,为防止记忆膨胀(Memory Bloat)并避免存储无用的临时垃圾,智能体制订了严格的调用策略。智能体必须主动执行记忆操作,而非被动等待用户命令。

✅ 应该立即存储的信号(Proactive Saving)

当以下情况发生时,智能体应当毫不犹豫地调用 memory(action="add", ...)

  • 用户纠正了你
    如果用户说"不要用 pip,用 poetry"或"记住这个错误",这是最高优先级的信号。防止用户重复纠错是记忆系统的核心价值。
  • 用户分享了偏好
    包括名字、角色、时区、代码风格(如"我喜欢 TypeScript strict mode")。这些信息属于 target="user"
  • 发现了环境事实
    智能体探测到了操作系统(Ubuntu 22.04)、安装了某个工具(pnpm)、或者项目结构。这些信息属于 target="memory"
  • 学到了特定约定
    比如"这个仓库的 API 有 Rate Limit"或"部署必须用 Docker"。这是避免未来踩坑的关键。
🚫 严禁存储的内容(Strict Boundaries)

为避免将记忆变成"垃圾堆",以下情况绝对不能 调用 memory

  • 临时任务状态:正在做的 TODO、当前的进度条、还没完成的步骤。
  • 会话日志:刚刚完成了什么工作、输出了什么结果。
  • 琐碎常识:地球是圆的、Python 是编程语言(这些属于基础模型知识,无需存储)。
  • 原始数据:大段的日志、代码 dump。

该记忆的加载时机

看 tools/memory_tool.py:118-142 的 MemoryStore:

load_from_disk(): # 会话开始时调用一次

  • MEMORY.md / USER.md → entries 列表
  • 把当前快照存到 self._system_prompt_snapshot # 冻结

之后会话期间无论 agent 怎么 memory(add/...):

  • 磁盘立即更新(带文件锁 + 原子 rename)
  • 内存里 live state 更新(tool 返回的字段反映最新状态)
  • 但 system prompt 这次会话不再改

Hermess的全会话存储

⚠️ 重要区分 :这是 Hermes 的全对话历史存储 ,与 MEMORY.md(长期事实记忆)完全不同。

源码与存储位置

  • 核心源码hermes_state.py (~2966 行)
  • 搜索工具tools/session_search_tool.py (~612 行)
  • 存储文件~/.hermes/state.db (单个 SQLite 文件)

表结构设计

会话元数据 (sessions)

存储每一次交互的上下文信息。

字段 描述
id 会话唯一 ID
source 来源 (cli, telegram, discord, gateway, cron)
user_id 用户标识
parent_session_id 压缩/分支链:指向父会话
message_count 消息总数
*_tokens 各类 Token 计数 (input, output, cache, reasoning)
estimated_cost_usd 预估成本
title 会话标题
handoff_state 交接状态

消息记录 (messages)

存储每一轮的详细内容,包括推理过程。

字段 描述
role user, assistant, tool, system
content 文本内容
tool_call_id 工具调用 ID
tool_name 调用的工具名
reasoning 模型的推理痕迹
codex_reasoning_items Codex 相关推理详情

全文索引 (messages_fts)

为了实现高效搜索,系统维护了两套 FTS5 索引:

  1. messages_fts :使用 unicode61 tokenizer,适合英文/分词语言。
  2. messages_fts_trigram :使用 trigram tokenizer(3字节滑窗),专门为 CJK(中日韩) 及子串查询设计。

写入机制:何时、写什么

触发时机

写入发生在每个 Turn 结束时 ,由 run_agent.py:4469_flush_messages_to_session_db 触发。

写入内容

通过 SessionDB.append_message (hermes_state.py:1478) 写入:

  • User 输入:用户的原始文本。
  • Assistant 回复 :包含 tool_calls 的 JSON 结构和 reasoning 字段。
  • Tool 结果:工具返回的数据。

防膨胀策略

为了防止数据库体积爆炸,多模态内容(如图片)不会 存储 Base64 数据。_flush_messages_to_session_db 会在 run_agent.py:4491-4501 中将其转换为文本摘要(例如 [screenshot])。

如果说 MEMORY.md 是智能体的长期大脑 ,那么 session_search 就是它的档案管理员。两者职责严格分离,不可混淆。

工具定义与系统约束

session_search 作为一个独立的工具注册在系统中(session_search_tool.py:550-594)。为了让智能体正确使用它,System Prompt(agent/prompt_builder.py:159)中明确下达了禁令

"Do NOT save task progress, session outcomes, completed-work logs ... to memory; use session_search to recall those from past transcripts."

这句话确立了 Hermes 的核心设计原则:

存储目标 存储位置 数据类型
持久偏好/事实 MEMORY.md 我是谁、我喜欢什么、环境配置
任务进度/历史 session_search (FTS5) 我刚才做了什么、Bug 是怎么修的

两种调用模式

智能体可以根据需求选择两种不同的调用方式:

  • 浏览模式(零成本)
    session_search()

    不带参数调用时,工具会直接列出最近的会话列表,帮助智能体快速回顾上下文,且不消耗 LLM 推理资源。

  • 搜索模式(关键词)
    session_search(query="docker deploy")

    带有查询参数时,触发 FTS5 全文检索。

支持的 FTS5 语法
类型 示例 说明
关键词 docker deployment 默认匹配
短语 "exact phrase" 精确匹配引号内内容
布尔 docker OR kubernetes 逻辑或
排除 python NOT java 逻辑非
前缀 deploy* 通配符匹配

3. 检索流程详解

当智能体发起搜索时,后端执行一套复杂的流水线处理,确保返回的信息既相关又精简:

  1. 查询净化 (_sanitize_fts5_query)

    转义 "(* 等特殊字符,防止 SQL 注入,同时保留合法的 FTS5 布尔操作符。

  2. 相关性排序

    执行 SELECT ... FROM messages_fts JOIN messages JOIN sessions WHERE MATCH ? ORDER BY rank

    这里的 rank 基于 BM25 算法,确保越相关的会话排名越高。

  3. 高亮片段

    使用 snippet() 函数提取命中关键词周围的文本,并用 >>><<< 标记出来,方便快速预览。

  4. 会话去重与过滤

    如果一个会话中有多条消息命中,仅计为一次命中;同时过滤掉当前正在进行的会话谱系,避免"自己搜自己"。

  5. 上下文截断

    对排名前 N(默认 3)的会话,拉取完整对话。使用 _truncate_around_matches 策略,以命中位置为中心取 100K 字符窗口,而不是简单地截断开头或结尾,确保上下文连贯。

  6. 辅助模型总结

    将截断后的长文本并发发送给辅助模型 (配置见 cli-config.yaml.example:430,默认复用主模型),为每个会话生成一段精炼的总结。

  7. 返回结果

    最终向智能体返回每个会话的总结、发生时间及来源模型。

相关推荐
kidwjb1 小时前
Linux共享内存
linux·服务器·进程间通信
飘尘1 小时前
WebAssembly 是什么?它为什么重要?
前端·javascript
情绪总是阴雨天~1 小时前
大模型 Function Call(函数调用)详解:原理、实践与数据库智能查询 Agent
前端·数据库·人工智能
Ting-yu1 小时前
Spring AI Alibaba零基础速成(1) ---- 项目创建与配置
java·人工智能·spring
喜欢coding的谢同学2 小时前
ArthasClaw:用自然语言诊断 JVM 的 AI 助手,告别繁琐的 Arthas 命令
java·人工智能·arthas
GalenZhang8882 小时前
OpenClaw (2026.4.x 至 2026.5.12) 升级问题及解决
前端·chrome·openclaw
QuestLab2 小时前
Ollama在Linux上安装的详细记录
linux·运维·服务器
Ww.xh2 小时前
鸿蒙Web组件中Hash路由传登录态方案
前端·哈希算法·harmonyos
架构源启2 小时前
Spring AI完整学习路线:从Java开发到AI Agent的进阶之路(附15篇实战教程)
java·人工智能·spring