深度拆解 HermesAgent(五):记忆系统与用户建模 ------ AI Agent 如何"记住"你
系列导读 :本文是 [HermesAgent 深度拆解系列](#HermesAgent 深度拆解系列) 的第五篇。记忆是 Agent 跨会话连续性的基石。本文将深入分析 HermesAgent 的多层记忆架构、会话搜索机制,以及基于 Honcho 的辩证用户建模系统。
上一篇 :[多终端后端与 Gateway 网关](#多终端后端与 Gateway 网关) | 下一篇 :研究功能与测试体系
一、为什么记忆系统是 AI Agent 的"生死线"?
想象一下你的手机每天晚上都会重置所有数据------联系人、聊天记录、设置、照片全部清空。你还能正常使用吗?
大多数 AI Agent 目前就处于这种"每晚失忆"的状态。每次对话结束,一切归零。
HermesAgent 的 Nous Research 团队深刻理解这个问题,设计了五层记忆架构来解决这个问题。
二、五层记忆架构
┌───────────────────────────────────────────────────┐
│ 记忆金字塔 │
│ │
│ ┌───────────────┐ │
│ │ L5: 技能记忆 │ 从经验中提取的可复用技能 │
│ │ ~/.hermes/ │ │
│ │ skills/ │ │
│ ├───────────────┤ │
│ │ L4: 用户建模 │ 跨会话用户画像 │
│ │ (Honcho) │ │
│ ├───────────────┤ │
│ │ L3: Agent策展 │ Agent自主决定保存的知识 │
│ │ ~/.hermes/ │ │
│ │ memory/ │ │
│ ├───────────────┤ │
│ │ L2: 会话搜索 │ FTS5 + LLM 跨会话回忆 │
│ ├───────────────┤ │
│ │ L1: 会话记忆 │ SQLite 对话记录 │
│ │ (SessionDB) │ │
│ └───────────────┘ │
└───────────────────────────────────────────────────┘
第一层:会话记忆(SessionDB)
实现 :hermes_state.py 中的 SessionDB 类
这是最基础的记忆层------原始的对话记录。所有对话都被完整保存到 SQLite 数据库:
python
# hermes_state.py 简化示意
class SessionDB:
def __init__(self, db_path: str):
self.conn = sqlite3.connect(db_path)
self._init_tables()
self._init_fts5() # 初始化全文搜索引擎
def save_message(self, session_id: str, role: str, content: str):
"""保存一条消息"""
self.conn.execute(
"INSERT INTO messages (session_id, role, content, timestamp) VALUES (?,?,?,?)",
(session_id, role, content, time.time())
)
self.conn.commit()
def get_history(self, session_id: str, limit: int = 50) -> list[dict]:
"""获取会话历史"""
rows = self.conn.execute(
"SELECT role, content FROM messages WHERE session_id=? ORDER BY timestamp DESC LIMIT ?",
(session_id, limit)
).fetchall()
return [{"role": r[0], "content": r[1]} for r in reversed(rows)]
存储位置 :~/.hermes/sessions.db
特点:
- ✅ 完整保存所有对话
- ✅ 支持按 session_id 隔离
- ✅ 零外部依赖(SQLite 内置于 Python)
- ✅ 内置 FTS5 全文搜索
第二层:会话搜索(FTS5 + LLM 摘要)
光有保存还不够,还需要能检索。HermesAgent 使用 SQLite FTS5 实现全文搜索,再结合 LLM 做语义摘要:
python
class SessionDB:
def search_sessions(self, query: str, limit: int = 10) -> list[dict]:
"""跨会话全文搜索"""
# FTS5 全文搜索
rows = self.conn.execute("""
SELECT session_id, role, content, rank
FROM messages_fts
WHERE messages_fts MATCH ?
ORDER BY rank
LIMIT ?
""", (query, limit)).fetchall()
# LLM 语义摘要(可选)
if rows and self.auxiliary_client:
context = "\n".join([r[2] for r in rows])
summary = self.auxiliary_client.summarize(
f"用户问题: {query}\n\n相关对话:\n{context}",
max_tokens=500
)
return {"summary": summary, "sources": rows}
return rows
搜索流程:
用户: "上次我们讨论的那个部署方案是什么来着?"
│
▼
提取关键词: ["部署", "方案"]
│
▼
FTS5 搜索: MATCH '部署 方案'
│
▼
找到 5 条相关历史消息
│
▼
LLM 摘要: "你们上次讨论了三种部署方案:
1. Docker Compose(推荐)
2. Kubernetes(适合生产)
3. 裸机部署(成本最低)"
│
▼
注入当前对话上下文 → Agent 基于历史回答
第三层:Agent 策展记忆
这是 HermesAgent 最独特的设计------Agent 自己决定什么值得记住。
~/.hermes/memory/
├── long_term/ # 长期记忆文件
│ ├── project_setup.md
│ ├── deployment_prefs.md
│ └── coding_style.md
└── short_term/ # 短期记忆(近期摘要)
└── recent_context.md
策展流程:
- 定期 Nudge:系统定时向 Agent 发送"整理记忆"的提醒
- 评估价值:Agent 回顾近期交互,评估哪些信息有持久化价值
- 提取知识:将碎片化信息提炼为结构化知识
- 写入文件 :保存到
~/.hermes/memory/long_term/
python
# agent/memory_manager.py 简化示意
class MemoryManager:
async def curate_memories(self, user_id: str):
"""Agent 策展记忆"""
# 获取近期未处理的消息
recent = self.session_db.get_recent_unprocessed(user_id)
if not recent:
return
# 让 Agent 评估并提取有价值的信息
prompt = f"""
回顾以下近期对话,提取值得长期记住的信息:
{format_conversations(recent)}
请输出 JSON 格式:
{{
"memories": [
{{
"topic": "主题",
"content": "具体内容",
"importance": "high/medium/low"
}}
]
}}
"""
response = await self.llm.generate(prompt)
memories = parse_memories(response)
# 保存到长期记忆
for memory in memories:
await self.save_long_term_memory(user_id, memory)
第四层:Honcho 用户建模
集成 Honcho 辩证用户建模系统:
┌──────────────┐ ┌──────────────┐
│ 当前用户画像 │ ←→ │ 新的观察证据 │
│ (Thesis) │ │ (Antithesis) │
└──────┬───────┘ └──────┬───────┘
│ │
└──────→ 合成 ←──────┘
(Synthesis)
│
▼
┌──────────────┐
│ 更新后的用户画像│
└──────────────┘
用户画像持续深化:
第 1 次对话 → {"role": "开发者", "language": "Python"}
第 5 次对话 → {"role": "后端开发者", "language": "Python",
"framework": "FastAPI", "style": "务实"}
第 20 次对话 → {"role": "AI 方向创业者", "language": "Python",
"focus": "AI Agent", "company": "Avatime 超我科技",
"style": "务实、不喜欢过度工程化",
"working_hours": "主要在白天", ...}
第五层:技能记忆
这不是传统的"记忆",而是从经验中提取的可复用技能 。我们已在第二篇中详细分析,这里不再展开。
三、记忆上下文注入
所有层级的记忆最终都需要注入到 Agent 的系统提示词中,才能影响 Agent 的行为:
python
# agent/prompt_builder.py 简化示意
class PromptBuilder:
def build_system_prompt(self, user_id: str, platform: str) -> str:
parts = []
# 1. 基础系统提示词
parts.append(BASE_SYSTEM_PROMPT)
# 2. 用户画像(Honcho)
user_profile = self.honcho.get_user_profile(user_id)
if user_profile:
parts.append(f"\n## 关于当前用户\n{user_profile}")
# 3. 长期记忆
long_term = self.memory_manager.get_relevant_memories(user_id)
if long_term:
parts.append(f"\n## 你记住的重要信息\n{long_term}")
# 4. 活跃技能
active_skills = self.skills_manager.get_active_skills()
if active_skills:
parts.append(f"\n## 你掌握的技能\n{active_skills}")
# 5. 平台特定指令
if platform == "cli":
parts.append(CLI_SPECIFIC_INSTRUCTIONS)
elif platform == "telegram":
parts.append(TELEGRAM_SPECIFIC_INSTRUCTIONS)
return "\n".join(parts)
四、上下文压缩
随着记忆增多,上下文窗口可能不够用。HermesAgent 通过 agent/context_compressor.py 实现自动上下文压缩:
python
class ContextCompressor:
async def compress(self, messages: list[dict], max_tokens: int) -> list[dict]:
"""压缩对话历史以适应上下文窗口"""
current_tokens = estimate_tokens(messages)
if current_tokens <= max_tokens:
return messages # 不需要压缩
# 策略:保留最近的 N 条消息 + 压缩更早的消息
recent = messages[-10:] # 最近 10 条完整保留
older = messages[:-10]
if older:
# 用 LLM 压缩旧消息
summary = await self.auxiliary_client.summarize(
format_messages(older), max_tokens=500
)
compressed = [{"role": "system", "content": f"[历史对话摘要] {summary}"}]
return compressed + recent
return messages
此外还支持 Anthropic 提示词缓存 (agent/prompt_caching.py),对于重复的系统提示词部分可以利用 API 缓存减少 token 成本。
五、存储设计
5.1 文件系统布局
~/.hermes/
├── config.yaml # 用户配置
├── .env # API 密钥
├── sessions.db # SQLite 会话数据库(含 FTS5 索引)
├── memory/ # Agent 策展记忆
│ ├── short_term/
│ └── long_term/
├── skills/ # 技能文件
│ └── *.md
├── skins/ # CLI 皮肤
└── profiles/ # 多实例配置
├── work/
└── personal/
5.2 Profile 隔离
HermesAgent 支持通过 HERMES_HOME 环境变量实现完全隔离的多实例:
bash
# 工作实例
HERMES_HOME=~/.hermes/profiles/work hermes
# 个人实例
HERMES_HOME=~/.hermes/profiles/personal hermes
代码中有 119+ 处 引用 get_hermes_home() 确保路径隔离,这意味着每个 Profile 有完全独立的:
- 会话记录
- 记忆文件
- 技能
- 配置
- 用户画像
六、与 OpenClaw 记忆系统的初步对比
(完整的对比分析将在后续专题文章中展开)
| 维度 | HermesAgent | OpenClaw |
|---|---|---|
| 存储 | SQLite + 文件系统 | 多种后端(SQL/向量DB) |
| 搜索 | FTS5 + LLM 摘要 | 向量搜索 (LanceDB) |
| 用户建模 | Honcho 辩证建模 | 无显式用户建模 |
| Agent 策展 | ✅ Agent 自主决定 | ❌ 规则驱动 |
| 上下文压缩 | ✅ 自动压缩 | ✅ 自动管理 |
| 多实例隔离 | HERMES_HOME Profile | 多 Profile 支持 |
| 技能作为记忆 | ✅ 从经验提取技能 | ❌ 无技能系统 |
七、对 Avagent 的启示
1. 五层记忆是"数字分身"的基础设施
如果 Avatime 的愿景是"让每个人拥有 AI 数字分身",那记忆系统就是分身的"大脑"。HermesAgent 的五层架构提供了很好的参考框架。
2. Agent 策展 vs 规则驱动
让 Agent 自己决定"记住什么"比人类预设规则更灵活。但需要注意:
- 设置遗忘机制,防止记忆过载
- 记忆质量需要可审计(用户能查看 Agent 记住了什么)
- 提供遗忘接口(用户能让 Agent "忘记"某些事)
3. FTS5 + LLM 摘要的混合策略
零额外依赖 + 语义理解,非常适合初期快速落地。后期可以升级为向量搜索。
4. 用户建模差异化
Honcho 的辩证建模是一个亮点。Avagent 可以考虑构建更贴合"数字分身"场景的用户建模------不仅记录偏好,还要建模行为模式、思维方式、表达风格。
八、小结
HermesAgent 的记忆系统不是简单的"存取"机制,而是一个完整的"感知-记忆-回忆-策展"循环:
- 感知:从对话中提取信息
- 存储:多层级的持久化
- 回忆:FTS5 全文搜索 + LLM 语义摘要
- 策展:Agent 自主决定什么值得记住
- 建模:Honcho 持续深化用户画像
这种设计让 Agent 真正拥有了"连续性"------它不是每次都从零开始,而是带着之前的经验和对你的理解来面对每一次新的交互。
这,才是一个"数字分身"应该有的样子。
系列导航:
本文基于 HermesAgent v0.10.0 源码分析,项目持续迭代中。