Hermes Agent 内存系统实现分析
Hermes Agent 内存系统实现分析
本文用跨会话场景解释 Hermes Agent 的内存系统。重点回答四个问题:
- 模型为什么知道要调用
memory? - 模型为什么知道要调用
session_search? USER.md/MEMORY.md是怎么跨会话生效的?- 相关 prompt、tool description 在哪里起作用?
写法按“用户说 → 模型看到提示词/工具描述 → 模型判断 → 调用工具 → 写入或检索位置”展开。提示词和工具描述会在用到的场景附近给出英文原文和中文对照,不集中放在文末。
1. 一句话总览
memory 负责保存少量跨会话长期事实。
session_search 负责回查历史对话过程。
USER.md 保存用户画像。
MEMORY.md 保存 Agent 的环境/项目笔记。
运行上可以理解为:
用户说了某句话
↓
模型同时看到 system prompt 和 tools schema
↓
模型判断这句话是不是长期有用
↓
如果是用户长期偏好:调用 memory(add, target=user),写入 USER.md
如果是稳定环境事实:调用 memory(add, target=memory),写入 MEMORY.md
如果是历史会话问题:调用 session_search
如果只是当前任务约束:不保存
2. 模型为什么知道调用 memory
先看一个通俗场景。
用户:以后你分析 Agent 项目,都按入口循环、提示词、工具、状态持久化、跨会话行为这几个点讲,不要写成源码导读。
模型为什么会知道“这句话应该保存”?
因为它在本次 LLM 请求里同时看到了两类信息:
- system prompt 里的
MEMORY_GUIDANCE。 - tools schema 里的
memory工具描述。
代码不是用正则判断“用户说了以后,所以保存”。真正做判断的是 LLM。
2.1 用到的 system prompt:MEMORY_GUIDANCE
当 memory 工具在 valid_tool_names 中时,run_agent.py 会把 MEMORY_GUIDANCE 加入 system prompt。
英文原文:
You have persistent memory across sessions. Save durable facts using the memory tool: user preferences, environment details, tool quirks, and stable conventions. Memory is injected into every turn, so keep it compact and focused on facts that will still matter later.
Prioritize what reduces future user steering — the most valuable memory is one that prevents the user from having to correct or remind you again. User preferences and recurring corrections matter more than procedural task details.
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. 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.
Write memories as declarative facts, not instructions to yourself. 'User prefers concise responses' ✓ — 'Always respond concisely' ✗. 'Project uses pytest with xdist' ✓ — 'Run tests with pytest -n 4' ✗. Imperative phrasing gets re-read as a directive in later sessions and can cause repeated work or override the user's current request. Procedures and workflows belong in skills, not memory.
中文对照:
你拥有跨会话持久记忆。请使用 memory 工具保存长期有效的事实:用户偏好、环境细节、工具怪癖和稳定约定。Memory 会注入未来轮次,所以要保持紧凑,只关注以后仍然重要的事实。
优先保存能减少未来用户引导的信息。最有价值的记忆,是能避免用户再次纠正或提醒你的记忆。用户偏好和重复纠正比流程性任务细节更重要。
不要把任务进度、会话结果、完成日志或临时 TODO 保存到 memory;这些应通过 session_search 从过去 transcript 中回忆。如果你发现了一种新做法,或解决了以后可能再次需要的问题,应把它保存为 skill。
把记忆写成陈述事实,不要写成给自己的命令。例如 “User prefers concise responses” 是好的;“Always respond concisely” 不好。“Project uses pytest with xdist” 是好的;“Run tests with pytest -n 4” 不好。命令式表达在后续会话中会被重新读成指令,可能导致重复工作或覆盖用户当前请求。流程和工作方法属于 skills,不属于 memory。
这段提示词告诉模型:
- 有跨会话持久 memory。
- 应保存 durable facts。
- 用户偏好和纠正优先级高。
- 不要保存临时任务状态。
- 记忆要写成陈述事实,不要写成命令。
所以模型看到用户说:
以后你分析 Agent 项目,都按入口循环、提示词、工具、状态持久化、跨会话行为这几个点讲。
会判断:
这是“以后”都适用的用户偏好。
它能减少未来用户重复纠正。
它应该持久化。
2.2 用到的工具描述:MEMORY_SCHEMA.description
同一次请求里,模型还会看到 memory 工具 schema。这个工具 schema 的 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.
WHEN TO SAVE (do this proactively, don't wait to be asked):
- User corrects you or says 'remember this' / 'don't do that again'
- User shares a preference, habit, or personal detail (name, role, timezone, coding style)
- You discover something about the environment (OS, installed tools, project structure)
- You learn a convention, API quirk, or workflow specific to this user's setup
- You identify a stable fact that will be useful again in future sessions
PRIORITY: User preferences and corrections > environment facts > procedural knowledge. The most valuable memory prevents the user from having to repeat themselves.
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.
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.
TWO TARGETS:
- 'user': who the user is -- name, role, preferences, communication style, pet peeves
- 'memory': your notes -- environment facts, project conventions, tool quirks, lessons learned
ACTIONS: add (new entry), replace (update existing -- old_text identifies it), remove (delete -- old_text identifies it).
SKIP: trivial/obvious info, things easily re-discovered, raw data dumps, and temporary task state.
中文对照:
把长期有效的信息保存到跨会话持久 memory。Memory 会注入未来轮次,所以要保持紧凑,只关注以后仍然重要的事实。
什么时候保存(主动做,不要等用户要求):
- 用户纠正你,或者说“记住这个”/“以后别再这样”
- 用户分享偏好、习惯或个人细节,例如姓名、角色、时区、代码风格
- 你发现环境信息,例如操作系统、已安装工具、项目结构
- 你学到了这个用户环境中特定的约定、API 怪癖或工作流
- 你识别出未来会再次有用的稳定事实
优先级:用户偏好和纠正 > 环境事实 > 流程性知识。最有价值的记忆能避免用户重复说明。
不要把任务进度、会话结果、完成日志或临时 TODO 保存到 memory;这些应通过 session_search 从过去 transcript 中回忆。
如果你发现了一种新做法,或解决了以后可能再次需要的问题,应把它保存为 skill。
两个 target:
- 'user':用户是谁,例如姓名、角色、偏好、沟通风格、讨厌的做法
- 'memory':你的笔记,例如环境事实、项目约定、工具怪癖、经验教训
动作:
- add:新增 entry
- replace:更新已有 entry,用 old_text 定位
- remove:删除 entry,用 old_text 定位
跳过:琐碎/显然的信息、容易重新发现的信息、原始数据堆、临时任务状态。
这个 description 和 MEMORY_GUIDANCE 共同告诉模型:
看到用户说“以后你分析 Agent 项目都按某个结构讲”,这是用户偏好。
偏好属于 target=user。
当前还没有旧 entry,所以 action=add。
2.3 用到的参数描述:MEMORY_SCHEMA.parameters
模型还会看到参数级 description。
英文原文和中文对照:
action: The action to perform.
action:要执行的动作。
target: Which memory store: 'memory' for personal notes, 'user' for user profile.
target:选择哪个 memory store。'memory' 表示个人笔记,'user' 表示用户画像。
content: The entry content. Required for 'add' and 'replace'.
content:entry 内容。add 和 replace 必填。
old_text: Short unique substring identifying the entry to replace or remove.
old_text:用于定位要替换或删除 entry 的短唯一子串。
所以模型生成的 tool call 会像这样:
{
"action": "add",
"target": "user",
"content": "User prefers Agent project analysis to be organized by entry loop, system prompt, tool schema, tool-call execution, state persistence, and cross-session behavior rather than source-code walkthroughs."
}
然后 Agent 执行 memory 工具,把这条记忆写入:
$HERMES_HOME/memories/USER.md
3. 什么时候写 USER.md,什么时候写 MEMORY.md
3.1 写 USER.md:用户长期偏好
通俗例子:
用户:以后你给我写技术分析,先讲整体流程,再给关键 prompt,最后再讲源码位置。
模型根据 MEMORY_GUIDANCE 和 memory.description 判断:
“以后”说明跨会话有效。
“给我写技术分析”说明是任务类别。
“先讲整体流程,再给关键 prompt...”说明是稳定偏好。
这是用户画像的一部分,应该写 USER.md。
tool call:
{
"action": "add",
"target": "user",
"content": "User prefers technical analysis to start with the overall flow, then include key prompts, and only then discuss source-code locations."
}
写入位置:
$HERMES_HOME/memories/USER.md
3.2 写 MEMORY.md:稳定环境事实
通俗例子:
用户:这个长期工作区里,Hermes 的代码固定在 hermes-agent/ 下,别再去根目录找 run_agent.py。
模型根据 memory.description 判断:
这是 project structure。
它是长期工作区里的稳定事实。
以后查源码会复用。
这不是用户画像,而是 Agent 的环境笔记。
tool call:
{
"action": "add",
"target": "memory",
"content": "In the user's long-term workspace, Hermes Agent source code is under hermes-agent/, and run_agent.py should be looked up there rather than at the workspace root."
}
写入位置:
$HERMES_HOME/memories/MEMORY.md
3.3 不写 memory:一次任务约束
通俗例子:
用户:这次先只写一个草稿,暂时不要写 provider。
模型根据 MEMORY_GUIDANCE 判断:
“这次”“暂时”说明是当前任务约束。
不是跨会话稳定偏好。
不应该持久化。
所以不调用 memory。
如果错误保存为:
User does not want provider details.
未来用户让写 provider 时,模型会被误导。
判断口诀:
“以后 / 每次 / 我通常 / 不要再” 更可能进 memory。
“这次 / 这篇 / 当前任务 / 暂时” 通常不进 memory。
4. memory tool call 如何落盘
当模型生成:
{
"action": "add",
"target": "user",
"content": "User prefers technical analysis to start with the overall flow, then include key prompts, and only then discuss source-code locations."
}
Agent 的执行流程是:
run_agent.py 看到 function_name == "memory"
↓
调用 memory_tool(action, target, content, old_text, store)
↓
memory_tool 校验 target 和必要参数
↓
MemoryStore.add 执行安全扫描、加锁、重读、去重、限额检查
↓
写入 USER.md 或 MEMORY.md
↓
返回 tool result 给模型
写入不是只存在内存里,而是文件持久化:
$HERMES_HOME/memories/USER.md
$HERMES_HOME/memories/MEMORY.md
entry 分隔符:
\n§\n
写入时还会做安全扫描,避免把 prompt injection 或 secret exfiltration 写进未来 system prompt。
5. USER.md 和 MEMORY.md 如何跨会话生效
USER.md 和 MEMORY.md 是跨会话文件。
源码注释原文:
Provides bounded, file-backed memory that persists across sessions. Two stores:
- MEMORY.md: agent's personal notes and observations (environment facts, project
conventions, tool quirks, things learned)
- USER.md: what the agent knows about the user (preferences, communication style,
expectations, workflow habits)
Both are injected into the system prompt as a frozen snapshot at session start.
Mid-session writes update files on disk immediately (durable) but do NOT change
the system prompt -- this preserves the prefix cache for the entire session.
The snapshot refreshes on the next session start.
中文对照:
提供有边界的、基于文件的 memory,并且跨会话持久化。有两个 store:
- MEMORY.md:Agent 的个人笔记和观察,例如环境事实、项目约定、工具怪癖、学到的东西。
- USER.md:Agent 对用户的了解,例如偏好、沟通风格、期望、工作习惯。
两者都会在会话开始时作为 frozen snapshot 注入 system prompt。
会话中途的写入会立即更新磁盘文件,保证持久化,但不会改变当前 system prompt。
这样可以在整个会话中保持 prefix cache 稳定。
snapshot 会在下一次会话开始时刷新。
跨会话链路:
会话 A:用户说“以后...”
↓
模型调用 memory(add, target=user)
↓
写入 $HERMES_HOME/memories/USER.md
↓
会话 A 当前 system prompt 不变
↓
会话 B 新 Agent 启动
↓
load_from_disk() 读取 USER.md / MEMORY.md
↓
生成 frozen snapshot
↓
注入会话 B 的 system prompt
5.1 用到的 USER PROFILE 注入模板
英文原文:
══════════════════════════════════════════════
USER PROFILE (who the user is) [{pct}% — {current:,}/{limit:,} chars]
══════════════════════════════════════════════
{content}
中文对照:
══════════════════════════════════════════════
用户画像(用户是谁)[{pct}% — {current:,}/{limit:,} 字符]
══════════════════════════════════════════════
{content}
5.2 用到的 MEMORY 注入模板
英文原文:
══════════════════════════════════════════════
MEMORY (your personal notes) [{pct}% — {current:,}/{limit:,} chars]
══════════════════════════════════════════════
{content}
中文对照:
══════════════════════════════════════════════
记忆(你的个人笔记)[{pct}% — {current:,}/{limit:,} 字符]
══════════════════════════════════════════════
{content}
6. 新会话如何使用旧记忆
会话 A 写入了:
USER.md:
User prefers technical analysis to start with the overall flow, then include key prompts, and only then discuss source-code locations.
MEMORY.md:
In the user's long-term workspace, Hermes Agent source code is under hermes-agent/, and run_agent.py should be looked up there rather than at the workspace root.
会话 B 用户只说:
用户:继续分析 memory provider。
模型在 system prompt 中已经看到 USER PROFILE 和 MEMORY,因此会推断:
我要先讲整体流程,再给关键 prompt。
查源码时要去 hermes-agent/。
用户不需要重复告诉模型这些偏好。这就是跨会话 memory 的意义。
7. 用户修改长期偏好:用 replace
用户说:
用户:之前说关键 prompt 要完整给。补充一下,以后 tool description 和参数说明也要完整给英文原文和中文解释。
模型判断:
这是对旧偏好的扩展。
应该更新已有 USER.md entry。
如果直接 add,可能产生重复或冲突。
tool call:
{
"action": "replace",
"target": "user",
"old_text": "then include key prompts",
"content": "User prefers technical analysis to start with the overall flow, then include complete English originals and Chinese explanations for key prompts, tool descriptions, and parameter descriptions, and only then discuss source-code locations."
}
Agent 执行 memory 工具后,会用 old_text 找到旧 entry,并更新:
$HERMES_HOME/memories/USER.md
8. 模型为什么知道调用 session_search
现在看另一个场景。
用户:我们之前讲 FTS5 时,是怎么解释它在 session_search 里的作用的?
这句话不是“用户长期偏好”,也不是“项目稳定事实”。它问的是历史会话内容。
模型知道用 session_search,也是因为两类输入:
- system prompt 里的
SESSION_SEARCH_GUIDANCE。 - tools schema 里的
session_search工具描述。
8.1 用到的 system prompt:SESSION_SEARCH_GUIDANCE
当 session_search 工具在 valid_tool_names 中时,run_agent.py 会把 SESSION_SEARCH_GUIDANCE 加入 system prompt。
英文原文:
When the user references something from a past conversation or you suspect relevant cross-session context exists, use session_search to recall it before asking them to repeat themselves.
中文对照:
当用户引用过去对话中的内容,或者你怀疑存在相关跨会话上下文时,先使用 session_search 回忆,再考虑是否需要让用户重复说明。
模型看到用户说:
我们之前讲 FTS5 时...
会判断:
这是 past conversation reference。
应该先 session_search,而不是让用户重复,也不是写 memory。
8.2 用到的工具描述:SESSION_SEARCH_SCHEMA.description
英文原文:
Search your long-term memory of past conversations, or browse recent sessions. This is your recall -- every past session is searchable, and this tool summarizes what happened.
TWO MODES:
1. Recent sessions (no query): Call with no arguments to see what was worked on recently. Returns titles, previews, and timestamps. Zero LLM cost, instant. Start here when the user asks what were we working on or what did we do recently.
2. Keyword search (with query): Search for specific topics across all past sessions. Returns LLM-generated summaries of matching sessions.
USE THIS PROACTIVELY when:
- The user says 'we did this before', 'remember when', 'last time', 'as I mentioned'
- The user asks about a topic you worked on before but don't have in current context
- The user references a project, person, or concept that seems familiar but isn't in memory
- You want to check if you've solved a similar problem before
- The user asks 'what did we do about X?' or 'how did we fix Y?'
Don't hesitate to search when it is actually cross-session -- it's fast and cheap. Better to search and confirm than to guess or ask the user to repeat themselves.
Search syntax: keywords joined with OR for broad recall (elevenlabs OR baseten OR funding), phrases for exact match ("docker networking"), boolean (python NOT java), prefix (deploy*). IMPORTANT: Use OR between keywords for best results — FTS5 defaults to AND which misses sessions that only mention some terms. If a broad OR query returns nothing, try individual keyword searches in parallel. Returns summaries of the top matching sessions.
中文对照:
搜索你对过去对话的长期记忆,或浏览最近 sessions。这是你的 recall:每个过去 session 都可搜索,此工具会总结当时发生了什么。
两种模式:
1. 最近 sessions(无 query):不带参数调用,查看最近在做什么。返回标题、预览和时间戳。没有 LLM 成本,立即返回。当用户问“我们最近在做什么”或“我们之前做了什么”时,从这里开始。
2. 关键词搜索(带 query):在所有过去 sessions 中搜索特定主题。返回由 LLM 生成的匹配 session 摘要。
在这些情况下主动使用:
- 用户说“我们之前做过”“记得那次吗”“上次”“如我之前提到”
- 用户询问以前处理过但当前上下文没有的主题
- 用户提到似乎熟悉但不在 memory 里的项目、人物或概念
- 你想检查以前是否解决过类似问题
- 用户问“我们当时怎么处理 X?”或“我们怎么修好 Y?”
当确实是跨会话问题时,不要犹豫,直接搜索。搜索并确认比猜测或让用户重复更好。
搜索语法:用 OR 连接关键词做宽召回;用引号做精确短语;支持 boolean,例如 python NOT java;支持前缀,例如 deploy*。重要:最好用 OR 连接关键词,因为 FTS5 默认 AND,可能漏掉只包含部分关键词的 sessions。如果宽 OR 查询没有结果,尝试并行搜索单个关键词。返回最相关 sessions 的摘要。
8.3 用到的参数描述:SESSION_SEARCH_SCHEMA.parameters
英文原文和中文对照:
query: Search query — keywords, phrases, or boolean expressions to find in past sessions. Omit this parameter entirely to browse recent sessions instead (returns titles, previews, timestamps with no LLM cost).
query:搜索 query。用于在过去 sessions 中查找的关键词、短语或布尔表达式。完全省略该参数时,进入最近 sessions 浏览模式。
role_filter: Optional: only search messages from specific roles (comma-separated). E.g. 'user,assistant' to skip tool outputs.
role_filter:可选。只搜索特定 role 的消息,用逗号分隔。例如 'user,assistant' 可跳过工具输出。
limit: Max sessions to summarize (default: 3, max: 5).
limit:最多总结多少个 sessions,默认 3,最大 5。
因此模型调用:
{
"query": "FTS5 session_search role explanation",
"limit": 3
}
session_search 搜索的是历史 transcript,不是 USER.md / MEMORY.md。
9. session_search 如何总结历史会话
session_search 找到匹配 session 后,会让辅助模型总结。
9.1 用到的摘要 system prompt:_summarize_session.system_prompt
英文原文:
You are reviewing a past conversation transcript to help recall what happened. Summarize the conversation with a focus on the search topic. Include:
1. What the user asked about or wanted to accomplish
2. What actions were taken and what the outcomes were
3. Key decisions, solutions found, or conclusions reached
4. Any specific commands, files, URLs, or technical details that were important
5. Anything left unresolved or notable
Be thorough but concise. Preserve specific details (commands, paths, error messages) that would be useful to recall. Write in past tense as a factual recap.
中文对照:
你正在审查一段过去的对话记录,以帮助回忆当时发生了什么。请围绕搜索主题总结这段对话,包括:
1. 用户当时提出了什么需求或想完成什么
2. 执行了哪些动作以及结果如何
3. 关键决策、找到的解决方案或得出的结论
4. 重要的命令、文件、URL 或技术细节
5. 尚未解决或值得注意的内容
总结要详实但简洁。保留对回忆有帮助的具体细节,例如命令、路径、错误信息。用过去时写成事实回顾。
9.2 用到的摘要 user prompt 模板:_summarize_session.user_prompt
英文原文:
Search topic: {query}
Session source: {source}
Session date: {started}
CONVERSATION TRANSCRIPT:
{conversation_text}
Summarize this conversation with focus on: {query}
中文对照:
搜索主题:{query}
Session 来源:{source}
Session 日期:{started}
对话 transcript:
{conversation_text}
请围绕这个主题总结对话:{query}
10. USER.md / MEMORY.md 与 session_search 的区别
| 能力 | 存什么 | 何时使用 |
|---|---|---|
USER.md |
用户长期偏好、沟通风格、身份信息 | 每个新会话自动注入 |
MEMORY.md |
稳定环境事实、项目约定、工具怪癖 | 每个新会话自动注入 |
session_search |
历史对话 transcript | 用户问“之前/上次/我们做过什么”时按需搜索 |
通俗理解:
USER.md / MEMORY.md 是“常驻小抄”。
session_search 是“翻历史聊天记录”。
不要把历史任务过程写进 memory。例如:
用户:上次我们怎么解释 FTS5?
这不是长期偏好,应该 session_search。
11. 后台 review 如何补漏
有时主模型忙着完成任务,可能漏掉应该保存的长期偏好。Hermes 会定期 fork 一个后台 review agent。
11.1 用到的后台记忆提示词:_MEMORY_REVIEW_PROMPT
英文原文:
Review the conversation above and consider saving to memory if appropriate.
Focus on:
1. Has the user revealed things about themselves — their persona, desires, preferences, or personal details worth remembering?
2. Has the user expressed expectations about how you should behave, their work style, or ways they want you to operate?
If something stands out, save it using the memory tool. If nothing is worth saving, just say 'Nothing to save.' and stop.
中文对照:
审查上面的对话,并在合适时考虑保存到 memory。
重点关注:
1. 用户是否透露了关于自己的信息,例如 persona、愿望、偏好或值得记住的个人细节?
2. 用户是否表达了对你行为方式、他们的工作风格,或希望你如何运作的期望?
如果有突出的内容,就用 memory 工具保存。如果没有值得保存的内容,只说 “Nothing to save.” 然后停止。
通俗例子:
用户:以后最后汇报时,不要只说“完成了”,要说清楚覆盖了哪些流程。
如果主模型当场漏存,后台 review 看到这句话后,会判断:
这是用户对汇报方式的长期期望。
应该保存到 USER.md。
可能调用:
{
"action": "add",
"target": "user",
"content": "User wants final reports to state which flows or requirements were covered, not just say the task is complete."
}
11.2 用到的后台联合提示词:_COMBINED_REVIEW_PROMPT
当 memory 和 skill 都要检查时,用 combined review prompt。
英文原文:
Review the conversation above and update two things:
**Memory**: who the user is. Did the user reveal persona, desires, preferences, personal details, or expectations about how you should behave? Save facts about the user and durable preferences with the memory tool.
**Skills**: how to do this class of task. Be ACTIVE — most sessions produce at least one skill update. A pass that does nothing is a missed learning opportunity, not a neutral outcome.
Target shape of the skill library: CLASS-LEVEL skills with a rich SKILL.md and a `references/` directory for session-specific detail. Not a long flat list of narrow one-session-one-skill entries.
Signals that warrant a skill update (any one is enough):
• User corrected your style, tone, format, legibility, verbosity, or approach. Frustration is a FIRST-CLASS skill signal, not just a memory signal. 'stop doing X', 'don't format like this', 'I hate when you Y' — embed the lesson in the skill that governs that task so the next session starts fixed.
• Non-trivial technique, fix, workaround, or debugging path emerged.
• A skill that was loaded or consulted turned out wrong, missing, or outdated — patch it now.
Preference order for skills — pick the earliest that fits:
1. UPDATE A CURRENTLY-LOADED SKILL. Check what skills were loaded via /skill-name or skill_view in the conversation. If one of them covers the learning, PATCH it first. It was in play; it's the right place.
2. UPDATE AN EXISTING UMBRELLA (skills_list + skill_view to find the right one). Patch it.
3. ADD A SUPPORT FILE under an existing umbrella via skill_manage action=write_file. Three kinds: `references/<topic>.md` for session-specific detail OR condensed knowledge banks (quoted research, API docs excerpts, domain notes) written concise and task-focused; `templates/<name>.<ext>` for starter files meant to be copied and modified; `scripts/<name>.<ext>` for statically re-runnable actions (verification, fixture generators, probes). Add a one-line pointer in SKILL.md so future agents find them.
4. CREATE A NEW CLASS-LEVEL UMBRELLA when nothing exists. Name at the class level — NOT a PR number, error string, codename, library-alone name, or 'fix-X / debug-Y' session artifact. If the name only fits today's task, fall back to (1), (2), or (3).
User-preference embedding: when the user complains about how you handled a task, update the skill that governs that task — memory alone isn't enough. Memory says 'who the user is and what the current situation and state of your operations are'; skills say 'how to do this class of task for this user'. Both should carry user-preference lessons when relevant.
If you notice overlapping existing skills, mention it — the background curator handles consolidation.
Act on whichever of the two dimensions has real signal. If genuinely nothing stands out on either, say 'Nothing to save.' and stop — but don't reach for that conclusion as a default.
中文对照:
审查上面的对话,并更新两类内容:
**Memory**:用户是谁。用户是否透露了 persona、愿望、偏好、个人细节,或对你行为方式的期望?请用 memory 工具保存关于用户和长期偏好的事实。
**Skills**:如何完成这一类任务。要主动一些,大多数 session 至少会产生一个 skill 更新。什么都不做是错过学习机会,而不是中性结果。
Skill 库的目标形态:类级别 skills,带有丰富的 SKILL.md 和 `references/` 目录用于保存 session 特定细节。不要做成长长一串狭窄的“一次 session 一个 skill”的条目。
值得更新 skill 的信号(任意一个就足够):
• 用户纠正了你的风格、语气、格式、可读性、冗长度或方法。用户的不满是第一类 skill 信号,不只是 memory 信号。比如 “stop doing X”、“don't format like this”、“I hate when you Y”——要把这个经验嵌入管这类任务的 skill,让下一个 session 一开始就是修正后的状态。
• 出现了非平凡技巧、修复、 workaround 或调试路径。
• 本 session 加载或查看过的 skill 被发现错误、缺失或过时——现在就修补它。
Skill 更新优先顺序——选择最早匹配的一项:
1. 更新当前已加载的 skill。检查对话中通过 /skill-name 加载过或通过 skill_view 查看过的 skills。如果其中某个覆盖了这次学习内容,先 PATCH 它。它本来就在发挥作用,所以它是正确位置。
2. 更新已有 umbrella。通过 skills_list + skill_view 找到合适的已有 umbrella,并修补它。
3. 在已有 umbrella 下通过 skill_manage action=write_file 新增 support file。三种类型:`references/<topic>.md` 用于 session 特定细节,或者用于保存压缩后的知识库,例如引用的研究、API docs 摘录、领域笔记,并且要写得简洁、面向任务;`templates/<name>.<ext>` 用于可复制再修改的 starter files;`scripts/<name>.<ext>` 用于可静态重复运行的动作,例如 verification、fixture generators、probes。还要在 SKILL.md 里添加一行指针,让未来 agent 知道它存在。
4. 当没有任何合适 skill 时,创建新的类级别 umbrella。名称必须是类别级别,不要用 PR 编号、错误字符串、codename、单独的库名,或者 “fix-X / debug-Y” 这种 session artifact。如果这个名字只适合今天的任务,就回到 (1)、(2) 或 (3)。
用户偏好嵌入:当用户抱怨你处理任务的方式时,要更新管这类任务的 skill——只写 memory 不够。Memory 说明“用户是谁,以及你当前操作的情况和状态”;skills 说明“如何为这个用户完成这一类任务”。相关时,二者都应该承载用户偏好经验。
如果发现已有 skills 重叠,提一下——后台 curator 会处理合并。
根据两个维度里任何真实信号行动。如果确实两边都没有值得保存的内容,就说 “Nothing to save.” 并停止——但不要默认得出这个结论。
12. 场景:外部 provider 先召回相关记忆
除了内置的 USER.md / MEMORY.md,Hermes 还可以接外部 memory provider。外部 provider 更像语义记忆库:它可能保存更多历史片段,并在当前 turn 前主动召回相关内容。
通俗例子:
会话 A:
用户:以后写内存系统分析时,要从真实对话切入,不要只按源码模块罗列。
会话 B:
用户:继续写那篇内存系统文档。
这里容易误解:外部 provider 的“自动召回”不是模型发起的 tool call。它发生在模型 API call 之前,由 Hermes runtime 主动执行。
真实链路是:
Agent 启动
↓
读取 config 里的 memory.provider
↓
加载对应 plugins/memory/<provider>
↓
MemoryManager.initialize_all(...) 初始化 provider
↓
每个用户 turn 开始时,MemoryManager.on_turn_start(...)
↓
API call 之前,MemoryManager.prefetch_all(original_user_message)
↓
provider.prefetch(query) 返回相关记忆文本
↓
build_memory_context_block(raw_context) 包成 <memory-context>
↓
临时追加到当前 user message
↓
模型在同一次请求里看到这段召回上下文
也就是说,在会话 B 处理用户消息前,外部 provider 可能先查到会话 A 的偏好,然后 Hermes 把召回内容包进 <memory-context>,临时追加到当前 user message。模型看到后会知道:
这是被召回的持久记忆上下文,不是用户刚刚新说的话。
当前回答要参考它。
12.1 这是不是 tool call
自动召回不是 tool call。
判断标准很简单:
如果是 prefetch_all → provider.prefetch → <memory-context>,不是 tool call。
如果是模型输出 function_call,例如 honcho_search / supermemory_search,才是 tool call。
自动召回时,模型没有主动选择某个 provider 工具,也没有生成 JSON 参数。它只是收到一个已经被 runtime 注入的 user message 增强版:
用户原始消息:
继续写那篇内存系统文档。
实际发给模型的 user message:
继续写那篇内存系统文档。
<memory-context>
[System note: ...]
User prefers memory-system analysis documents to start from real dialogue scenarios.
</memory-context>
这也是为什么 <memory-context> 说明里强调它“NOT new user input”。它不是用户新说的话,而是 Agent 持久记忆召回出的参考数据。
12.2 用到的 memory-context 模板
英文原文:
<memory-context>
[System note: The following is recalled memory context, NOT new user input. Treat as authoritative reference data — this is the agent's persistent memory and should inform all responses.]
{clean}
</memory-context>
中文对照:
<memory-context>
[系统说明:以下内容是回忆出的记忆上下文,不是新的用户输入。请把它当作权威参考数据处理——这是 Agent 的持久记忆,应该影响所有回答。]
{clean}
</memory-context>
这段内容只影响当前 API call:
- 不写入用户原始消息。
- 不写入 session transcript。
- 不改变 system prompt 的 frozen snapshot。
12.3 外部 provider 什么时候才是 tool call
外部 provider 也可以暴露工具。区别是:工具必须出现在 provider 的 get_tool_schemas() 返回值里,然后由 Hermes 加到 tool surface,模型才可能主动调用。
初始化时的工具注入链路是:
memory.provider 配置了外部 provider
↓
MemoryManager.add_provider(provider)
↓
provider.get_tool_schemas()
↓
run_agent.py 把这些 schema append 到 self.tools
↓
工具名加入 valid_tool_names
↓
模型在 tools schema 里看到这些工具
↓
模型需要时输出 tool call
↓
MemoryManager.handle_tool_call(function_name, args)
↓
provider.handle_tool_call(...)
例如 Supermemory 暴露了这些工具:
supermemory_store: Store an explicit memory for future recall.
supermemory_search: Search long-term memory by semantic similarity.
supermemory_forget: Forget a memory by exact id or by best-match query.
supermemory_profile: Retrieve persistent profile facts and recent memory context.
中文对照:
supermemory_store:显式保存一条未来可召回的记忆。
supermemory_search:按语义相似度搜索长期记忆。
supermemory_forget:按精确 id 或最佳匹配 query 删除一条记忆。
supermemory_profile:取回持久用户画像事实和近期记忆上下文。
Honcho 也暴露了类似工具,例如:
honcho_search: Semantic search over Honcho's stored context about a peer. Returns raw excerpts ranked by relevance — no LLM synthesis. Cheaper and faster than honcho_reasoning. Good when you want to find specific past facts and reason over them yourself.
中文对照:
honcho_search:在 Honcho 保存的某个 peer 上下文里做语义搜索。返回按相关性排序的原始摘录,不做 LLM 综合。它比 honcho_reasoning 更便宜、更快。适合在你想找到具体历史事实,并自己基于这些事实推理时使用。
这时才是模型主动 tool call。例子:
用户:查一下我之前关于“文档例子要更通俗”的偏好。
模型看到 honcho_search / supermemory_search 的工具描述。
模型判断这是外部长期记忆搜索。
模型输出 tool call:honcho_search({"query": "文档例子 更通俗 用户偏好"})
MemoryManager 把调用路由给 Honcho provider。
12.4 外部 provider 如何持续写入
外部 provider 不是只读召回,也会在 turn 结束后接收新对话。
完成一次正常对话后,Hermes 会执行:
MemoryManager.sync_all(original_user_message, final_response)
↓
provider.sync_turn(user_content, assistant_content)
↓
外部 provider 异步保存或抽取这轮对话
MemoryManager.queue_prefetch_all(original_user_message)
↓
provider.queue_prefetch(query)
↓
提前为下一轮用户消息预热召回结果
如果当前 turn 被用户中断,Hermes 会跳过这一步。原因是中断输出不是用户真正看到的完整结果,把它写入外部记忆会污染未来召回。
还有一个桥接点:如果模型调用了内置 memory 工具并成功 add 或 replace,Hermes 会通知外部 provider:
memory(add/replace)
↓
写入 USER.md 或 MEMORY.md
↓
MemoryManager.on_memory_write(action, target, content, metadata)
↓
外部 provider 可以同步或镜像这条长期事实
所以外部 provider 有三类入口:
API call 前:prefetch 自动召回,不是 tool call。
tool loop 中:provider 工具调用,是 tool call。
turn 结束后:sync / queue_prefetch 写入和预热,不是 tool call。
13. 场景:USER.md / MEMORY.md 快满了怎么办
USER.md / MEMORY.md 会注入 system prompt,所以 Hermes 不允许它们无限增长。它的管理策略不是“先都存起来再慢慢总结”,而是从入口就限制规模。
默认限制是字符数,不是 token 数:
MEMORY.md 默认上限:2200 chars
USER.md 默认上限:1375 chars
这两个默认值来自 MemoryStore(memory_char_limit=2200, user_char_limit=1375),也可以通过配置里的 memory_char_limit 和 user_char_limit 覆盖。
13.1 写入前如何防止爆炸
当模型调用:
{
"action": "add",
"target": "user",
"content": "User prefers documentation examples to be plain dialogue examples."
}
MemoryStore.add() 不会直接追加。它会先做这些检查:
去掉首尾空白
↓
检查是否为空
↓
扫描 prompt injection / secret exfiltration 风险
↓
加文件锁
↓
从磁盘重读最新 USER.md
↓
去重
↓
计算追加后的总字符数
↓
如果超过上限,拒绝写入
超限时返回的错误大意是:
Memory at {current}/{limit} chars. Adding this entry ({len(content)} chars) would exceed the limit. Replace or remove existing entries first.
中文对照:
Memory 当前已经使用 {current}/{limit} 字符。新增这条 entry({len(content)} 字符)会超过限制。请先替换或删除已有 entries。
所以爆炸不会发生在文件已经写大以后才发现,而是在 add 阶段直接被挡住。
13.2 快满时模型应该怎么做
通俗例子:
用户:以后文档里的 prompt、tool description、参数说明都要完整英文原文和中文对照。
模型判断这是长期偏好,尝试写入:
{
"action": "add",
"target": "user",
"content": "User wants documents to include complete English originals and Chinese translations for prompts, tool descriptions, and parameter descriptions."
}
如果 USER.md 已接近上限,tool result 可能提示超限。此时模型不应该继续硬塞,而应该先整理已有记忆。
假设已有两条:
User prefers memory-system analysis to be scenario-driven.
§
User wants key prompts shown with Chinese explanations.
模型可以把它们合并为一条更紧凑的偏好:
{
"action": "replace",
"target": "user",
"old_text": "User prefers memory-system analysis",
"content": "User prefers memory-system analysis docs to be scenario-driven and to include complete English originals plus Chinese explanations for prompts, tool descriptions, and parameter descriptions."
}
这样不是增加 entry,而是把旧 entry 压缩更新成一条更有信息密度的事实。
如果某条已经没有长期价值,也可以删除:
{
"action": "remove",
"target": "user",
"old_text": "User wants key prompts shown"
}
13.3 replace/remove 如何避免误伤
replace 和 remove 不是按 ID 定位,而是用 old_text 这个短唯一子串定位 entry。
如果没有匹配,会返回:
No entry matched '{old_text}'.
如果匹配到多条不同 entry,会返回:
Multiple entries matched '{old_text}'. Be more specific.
这迫使模型提供更具体的 old_text,避免把多条相似记忆误删或误替换。
13.4 system prompt 里如何提醒用量
每个新会话启动时,Hermes 会把 frozen snapshot 注入 system prompt。注入 header 自带用量:
USER PROFILE (who the user is) [{pct}% — {current:,}/{limit:,} chars]
MEMORY (your personal notes) [{pct}% — {current:,}/{limit:,} chars]
这让模型在读 system prompt 时知道当前长期记忆已经用了多少空间。tool result 也会返回:
{
"usage": "72% — 990/1,375 chars",
"entry_count": 4
}
所以 Hermes 的容量管理是双层的:
写入前:硬性字符上限,超限拒绝。
使用时:system prompt 和 tool result 暴露 usage,提示模型主动压缩、替换、删除。
13.5 什么内容不应该靠 USER.md / MEMORY.md 管
防爆炸的关键不是“压缩算法很强”,而是边界清楚。
不该写入 USER.md / MEMORY.md 的内容:
一次任务进度:这篇文档已经写到第 12 节。
历史解释过程:我们上次怎么解释 FTS5。
大量原始日志:完整 terminal output。
临时 TODO:等下再补 provider。
复杂操作步骤:以后每次如何完整执行某类任务。
对应去处:
历史对话过程 → session_search
复杂可复用流程 → skill
大量语义记忆或文件资料 → 外部 memory provider
真正长期稳定的小事实 → USER.md / MEMORY.md
这也是 Hermes 防止内置 memory 爆炸的核心设计:USER.md / MEMORY.md 只做小而高价值的常驻上下文,不承担历史数据库职责。
14. 场景:Supermemory 自动抽取可长期复用的信息
Supermemory provider 可以在会话结束或 turn 捕获时,把清理后的对话发给外部服务做抽取。它不是把每句话都保存,而是用默认抽取指令判断哪些信息未来还会有用。
通俗例子:
用户:以后写这种分析文档时,例子要用普通对话,比如“用户说 xxx,模型判断 yyy,然后调用工具”。
Supermemory 收到清理后的 user-assistant conversation 后,会在下面这段指令约束下抽取。它会倾向保存:
User prefers analysis documents to use plain dialogue examples that show the user statement, model judgment, and tool call.
它不会保存:
Assistant is currently editing the document.
因为后者只是一次任务的进行中状态。
14.1 用到的 Supermemory 默认抽取指令
英文原文:
User-assistant conversation. Format: [role: user]...[user:end] and [role: assistant]...[assistant:end].
Only extract things useful in future conversations. Most messages are not worth remembering.
Remember lasting personal facts, preferences, routines, tools, ongoing projects, working context, and explicit requests to remember something.
Do not remember temporary intents, one-time tasks, assistant actions, implementation details, or in-progress status.
When in doubt, store less.
中文对照:
用户-助手对话。格式为 [role: user]...[user:end] 和 [role: assistant]...[assistant:end]。
只抽取未来对话中有用的内容。大多数消息都不值得记住。
记住长期个人事实、偏好、日常习惯、工具、持续项目、工作上下文,以及明确要求记住的内容。
不要记住临时意图、一次性任务、助手动作、实现细节或进行中状态。
不确定时,少存。
15. 场景:Honcho 综合用户画像和当前上下文
Honcho provider 的目标不是简单保存一条条记忆,而是通过多轮 dialectic prompts 形成对用户的综合理解。它通常会根据是否已有基础上下文,选择不同的第一轮 prompt,然后再做 gap analysis 和 reconciliation。
通俗例子:
新会话里,用户只说:继续写内存系统文档。
如果 Honcho 没有足够缓存,它会先问“这个人是谁”;如果已有基础上下文,它会更关注“当前 session 相关的用户上下文”。这样模型拿到的不是一堆原始历史,而是更聚合的用户画像或当前工作背景。
15.1 冷启动时的 Honcho prompt
英文原文:
Who is this person? What are their preferences, goals, and working style? Focus on facts that would help an AI assistant be immediately useful.
中文对照:
这个人是谁?他们的偏好、目标和工作风格是什么?请关注能让 AI 助手立刻更有用的事实。
15.2 已有基础上下文时的 Honcho prompt
英文原文:
Given what's been discussed in this session so far, what context about this user is most relevant to the current conversation? Prioritize active context over biographical facts.
中文对照:
基于本 session 目前讨论过的内容,关于这个用户的哪些上下文对当前对话最相关?优先考虑当前活跃上下文,而不是传记式事实。
15.3 第二轮 gap analysis prompt
英文原文:
Given this initial assessment:
{prior}
What gaps remain in your understanding that would help going forward? Synthesize what you actually know about the user's current state and immediate needs, grounded in evidence from recent sessions.
中文对照:
基于这个初步评估:
{prior}
为了后续更有帮助,你对用户的理解还缺什么?请基于最近 sessions 的证据,综合你实际知道的用户当前状态和即时需求。
15.4 第三轮 reconciliation prompt
英文原文:
Prior passes produced:
Pass 1:
{pass_1}
Pass 2:
{pass_2}
Do these assessments cohere? Reconcile any contradictions and produce a final, concise synthesis of what matters most for the current conversation.
中文对照:
前几轮产生了:
第 1 轮:
{pass_1}
第 2 轮:
{pass_2}
这些评估是否一致?请调和任何矛盾,并生成一个最终的、简洁的综合结论,说明当前对话最重要的内容。
16. 完整链路回放
会话 A:
用户说“以后你分析 Agent 项目,都按入口循环、提示词、工具、持久化、跨会话讲。”
模型看到 MEMORY_GUIDANCE + memory 工具 description。
模型判断这是长期用户偏好。
模型生成 memory(add, target=user)。
Agent 执行 memory 工具,写入 $HERMES_HOME/memories/USER.md。
会话 B:
新 Agent 启动。
load_from_disk() 读取 USER.md / MEMORY.md。
生成 frozen snapshot。
system prompt 注入 USER PROFILE / MEMORY。
用户只说“继续分析 provider”,模型也能沿用旧偏好。
会话 C:
用户说“以后 tool description 和参数说明也要完整给英文和中文。”
模型判断这是长期偏好更新。
模型生成 memory(replace, target=user)。
Agent 更新 USER.md。
会话 D:
用户问“之前 FTS5 怎么解释?”
模型看到 SESSION_SEARCH_GUIDANCE + session_search 工具 description。
模型判断这是历史会话回溯。
模型调用 session_search。
session_search 搜索历史 transcript 并摘要。
会话 E:
用户说“继续写那篇内存系统文档。”
Hermes 在 API call 前调用 MemoryManager.prefetch_all(original_user_message)。
外部 provider 返回相关长期记忆文本。
Hermes 用 build_memory_context_block 包成 <memory-context>。
这段召回内容临时追加到当前 user message。
模型看到它并参考,但这不是模型发起的 tool call。
会话 F:
用户新增一个长期偏好,但 USER.md 已接近字符上限。
模型先尝试 memory(add, target=user)。
memory tool 返回超限错误,提示 Replace or remove existing entries first。
模型改用 memory(replace, target=user),把两条旧偏好合并成一条更紧凑的新 entry。
这就是 Hermes Agent 的内存设计:少量长期事实进入 USER.md / MEMORY.md,历史过程交给 session_search,更大的语义记忆交给外部 provider。
更多推荐

所有评论(0)