上一篇我们深入探讨了 Hermes Agent 的 Skills 技能系统,掌握了如何通过技能市场、本地技能、版本锁定等方式让 Agent 具备专业领域能力。技能让 Agent 从"通用助手"进化为"领域专家",但还有一个关键能力尚未触及——**记忆**。

Memory 持久记忆 —— 跨会话记忆、Memory 工具、用户画像与环境偏好

简介

上一篇我们深入探讨了 Hermes Agent 的 Skills 技能系统,掌握了如何通过技能市场、本地技能、版本锁定等方式让 Agent 具备专业领域能力。技能让 Agent 从"通用助手"进化为"领域专家",但还有一个关键能力尚未触及——记忆

想象一下这些场景:

  • 你上周告诉 Agent 你的项目使用 TypeScript 5.x + React 18,今天新开会话时它又问你"项目用什么技术栈?"
  • 你习惯把编辑器主题设为 Monokai,每次开新会话都要重新说一遍
  • 你上次让 Agent 写了一个数据库迁移脚本,这次想回顾但完全找不到当时的对话记录
  • 你对 Agent 说"用老样子的方式",但它根本不知道"老样子"是什么

这些问题都指向同一个核心能力:持久记忆。没有记忆的 Agent,就像每次见面都完全失忆的朋友——无论你之前说过多少次,它每次都像第一次认识你。

本文将带你全面掌握 Hermes Agent 的 Memory 系统:

  • 跨会话记忆:记忆如何在不同会话间持久化
  • Memory 工具:存储、查询、更新记忆的操作接口
  • 用户画像:自动构建和维护用户偏好档案
  • 环境偏好:项目配置、编码风格、工具链偏好的记忆

核心目标:让 Agent 真正"记住你",而不是每次从零开始。

目录

Memory 系统架构

什么是 Memory?

Hermes Agent 的 Memory 系统是一个多层次的持久化记忆框架,允许 Agent 在不同会话之间保留关键信息。它不是简单地把所有对话都存下来——那样会淹没在噪音中——而是有策略地提取、存储、检索有价值的信息。

text
Memory 系统架构:
├── 🧠 记忆存储层
│   ├── 短期记忆(当前会话)
│   ├── 长期记忆(跨会话持久化)
│   └── 语义记忆(向量化存储)
│
├── 🔧 记忆工具层
│   ├── memory_write(写入记忆)
│   ├── memory_read(读取记忆)
│   ├── memory_search(搜索记忆)
│   ├── memory_update(更新记忆)
│   └── memory_delete(删除记忆)
│
├── 👤 用户画像层
│   ├── 技术偏好
│   ├── 编码风格
│   ├── 沟通偏好
│   └── 项目上下文
│
└── 🌍 环境配置层
    ├── 编辑器偏好
    ├── 终端设置
    ├── 构建工具配置
    └── 部署习惯

记忆的三种类型

类型 持久性 范围 示例
短期记忆 会话内 当前对话上下文 刚才讨论的变量名
长期记忆 永久 跨所有会话 用户的技术栈偏好
语义记忆 永久 可模糊检索 "上次讨论的数据库优化方案"

记忆的层次结构

1. 会话级记忆(Session Memory)

会话级记忆是当前对话的上下文窗口,这是所有 LLM 交互的基础能力。但它有容量限制,当对话过长时,最早的信息会被"挤出"上下文窗口。

python
# 会话记忆的局限性
session_memory = {
    "max_tokens": 128000,  # 上下文窗口上限
    "current_tokens": 125000,  # 接近上限
    "strategy": "rolling_window",  # 滚动窗口策略
    "risk": "最早的信息即将丢失"
}

2. 用户级记忆(User Memory)

用户级记忆是跨会话持久的,绑定到用户身份。无论何时开启新会话,这些记忆都可用。

yaml
# 用户级记忆示例
user_memory:
  user_id: "hermes-user-001"
  profile:
    name: "开发者"
    primary_language: "Python"
    secondary_language: "TypeScript"
    editor: "Neovim"
    terminal: "WezTerm"
    shell: "zsh"
  preferences:
    code_style: "black"  # Python 格式化
    linter: "ruff"
    test_framework: "pytest"
    commit_style: "conventional_commits"
  projects:
    - name: "ai-agent-blog"
      path: "~/ai-agent-blog"
      stack: ["markdown", "nodejs"]
    - name: "ml-pipeline"
      path: "~/projects/ml-pipeline"
      stack: ["python", "pytorch", "fastapi"]

3. 项目级记忆(Project Memory)

项目级记忆绑定到特定项目目录,任何访问该项目的会话都能读取。

yaml
# .hermes/memory.yaml - 项目级记忆
project:
  name: "my-web-app"
  language: "TypeScript"
  framework: "Next.js 14"
  database: "PostgreSQL"
  orm: "Prisma"
  testing:
    unit: "Vitest"
    e2e: "Playwright"
  conventions:
    naming: "camelCase"
    imports: "absolute"
    styling: "tailwind"
    state_management: "zustand"
  deployment:
    platform: "Vercel"
    ci: "GitHub Actions"
  notes:
    - "API 使用 /api/v2/ 前缀"
    - "数据库迁移使用 prisma migrate"
    - "组件使用 Server Components 优先"

Memory 工具详解

memory_write:写入记忆

text
用户:记住我的偏好——我习惯用 Prettier 做代码格式化,
     tab 宽度设为 2,使用单引号,末尾不加分号。

Agent:[调用 memory_write]

参数:
  key: "coding_preferences.formatting"
  value:
    tool: "prettier"
    tab_width: 2
    single_quote: true
    semi: false
  scope: "user"  # user | project | session
  ttl: null  # null = 永久

Agent:✅ 已记住你的代码格式化偏好:Prettier,
       2 空格缩进,单引号,末尾不加分号。

代码示例:

python
# Memory 工具调用示例
memory_write(
    key="coding_preferences.formatting",
    value={
        "tool": "prettier",
        "tab_width": 2,
        "single_quote": True,
        "semi": False,
        "trailing_comma": "es5"
    },
    scope="user",
    metadata={
        "source": "explicit_user_input",
        "confidence": 1.0,
        "timestamp": "2025-05-20T10:30:00Z"
    }
)

memory_read:读取记忆

text
用户:我的格式化偏好是什么?

Agent:[调用 memory_read]

参数:
  key: "coding_preferences.formatting"

Agent:[读取记忆]
  → tool: prettier
  → tab_width: 2single_quote: truesemi: false

Agent:你的格式化偏好是:使用 Prettier,2 空格缩进,
       单引号,末尾不加分号。

memory_search:搜索记忆

text
用户:我之前说过关于数据库的事情吗?

Agent:[调用 memory_search]

参数:
  query: "数据库"
  scope: "user"
  limit: 5

Agent:[语义搜索返回结果]
  1. "使用 PostgreSQL 作为主数据库" (2025-04-15)
  2. "ORM 偏好 Prisma" (2025-04-15)
  3. "数据库迁移习惯手动写 SQL" (2025-05-02)

Agent:关于数据库,你之前提到过:
  1. 使用 PostgreSQL 作为主数据库
  2. ORM 偏好 Prisma
  3. 数据库迁移习惯手动写 SQL

memory_update:更新记忆

text
用户:改一下,现在我用双引号了,分号也加上。

Agent:[调用 memory_update]

参数:
  key: "coding_preferences.formatting"
  value:
    single_quote: false  # 覆盖
    semi: true  # 覆盖
    # 其他字段保持不变

Agent:✅ 已更新:现在使用双引号,末尾加分号。

memory_delete:删除记忆

text
用户:忘了我之前说的数据库迁移习惯。

Agent:[调用 memory_delete]

参数:
  key: "coding_preferences.db_migration"

Agent:✅ 已删除关于数据库迁移习惯的记忆。

用户画像系统

自动画像构建

Hermes Agent 不仅能被动接受记忆写入,还能主动从对话中提取用户画像信息:

python
# Agent 自动提取用户画像的流程
class UserProfileExtractor:
    """从对话中自动提取用户偏好"""

    def extract(self, conversation):
        patterns = {
            "tech_stack": [
                r"我用 (?:的是)?([\w\s\.]+)",
                r"项目用 (?:的是)?([\w\s\.]+)",
                r"习惯用 (?:的是)?([\w\s\.]+)"
            ],
            "editor": [
                r"(?:编辑器|IDE).*(?:VS ?Code|Vim|Neovim|IDEA|WebStorm)",
                r"(?:用|使用).*(?:VS ?Code|Vim|Neovim)"
            ],
            "style": [
                r"(?:喜欢|偏好).*(?:2|4)\s*空格",
                r"(?:喜欢|偏好).*(?:单引号|双引号)"
            ]
        }

        # 提取并写入记忆
        for category, regex_list in patterns.items():
            for regex in regex_list:
                matches = re.finditer(regex, conversation, re.IGNORECASE)
                for match in matches:
                    self.write_to_memory(category, match.group(1))

画像数据结构

yaml
# 完整的用户画像
user_profile:
  identity:
    name: "开发者"
    timezone: "Asia/Shanghai"
    language: "zh-CN"

  tech_preferences:
    languages:
      - name: "Python"
        level: "expert"
        version: "3.12"
        frameworks: ["FastAPI", "Django"]
      - name: "TypeScript"
        level: "proficient"
        version: "5.x"
        frameworks: ["React", "Next.js"]
      - name: "Go"
        level: "intermediate"
        frameworks: ["Gin"]

    tools:
      editor: "Neovim"
      terminal: "WezTerm"
      shell: "zsh"
      package_manager: "uv"  # Python
      frontend_pm: "pnpm"

    formatting:
      python: "ruff format"
      typescript: "prettier"
      tab_width: 2
      line_length: 88

    testing:
      python: "pytest"
      typescript: "vitest"

    logging:
      level: "INFO"
      format: "json"

  communication:
    language: "中文"
    detail_level: "detailed"  # brief | detailed | verbose
    code_comment_language: "zh"  # 代码注释用中文
    error_explanation: "chinese_with_english_terms"

  learned_behaviors:
    - pattern: "用户倾向于先解释思路,再给代码"
      frequency: 85
      confidence: 0.92
    - pattern: "用户对错误信息很敏感,喜欢详细的错误分析"
      frequency: 78
      confidence: 0.88

画像应用场景

text
场景 1:新会话自动加载画像
═══════════════════════════════════════
Agent:[会话启动]
  → 读取用户画像
  → 检测到 primary_language = Python
  → 检测到 editor = Neovim
  → 检测到 detail_level = detailed

  Agent 自动调整:
  - 使用 Python 示例代码
  - 提及 Neovim 相关配置
  - 提供详细的解释

──────────────────────────────────────

场景 2:智能推荐
═══════════════════════════════════════
用户:这个项目该怎么测试?

Agent:[查询画像]
  → testing.python = "pytest"

Agent:根据你的偏好,我推荐使用 pytest。
       你的项目使用 FastAPI,可以配合 httpx 做异步测试:

       ```python
       import pytest
       from httpx import AsyncClient

       @pytest.mark.asyncio
       async def test_read_main():
           async with AsyncClient(app=app, base_url="http://test") as ac:
               response = await ac.get("/")
               assert response.status_code == 200
       ```

       需要我帮你配置 pytest.ini 和 conftest.py 吗?

环境偏好记忆

编辑器偏好

yaml
# 编辑器配置记忆
editor_preferences:
  neovim:
    theme: "tokyonight"
    font: "JetBrainsMono Nerd Font"
    font_size: 13
    tab_size: 2
    line_numbers: "relative"
    cursor_style: "block"
    plugins:
      - "telescope.nvim"
      - "nvim-treesitter"
      - "lsp-zero.nvim"
      - "nvim-cmp"
      - "gitsigns.nvim"
    lsp_servers:
      python: "pyright"
      typescript: "typescript-language-server"
      go: "gopls"

终端偏好

yaml
# 终端配置记忆
terminal_preferences:
  emulator: "WezTerm"
  shell: "zsh"
  prompt: "starship"
  theme: "Catppuccin Mocha"
  font: "JetBrainsMono Nerd Font"
  font_size: 14
  opacity: 0.95
  keybindings:
    new_tab: "Ctrl+Shift+T"
    split_horizontal: "Ctrl+Shift+H"
    split_vertical: "Ctrl+Shift+V"
  aliases:
    - "ll = ls -la"
    - "gs = git status"
    - "gc = git commit"
    - "gp = git push"

构建和部署偏好

yaml
# 构建和部署记忆
build_deploy_preferences:
  python:
    packaging: "uv build"
    virtual_env: "uv venv"
    dependency_management: "uv sync"
    deployment: "docker + k8s"

  typescript:
    bundler: "vite"
    package_manager: "pnpm"
    deployment: "Vercel / Cloudflare Pages"

  go:
    build: "go build -ldflags='-s -w'"
    deployment: "二进制 + systemd"

  ci_cd:
    platform: "GitHub Actions"
    triggers: ["push to main", "pull_request"]
    cache: true
    notify_on_failure: true

环境偏好自动应用

python
# Agent 根据环境偏好自动调整行为
def apply_environment_preferences(self):
    """根据记忆的环境偏好调整 Agent 行为"""

    prefs = self.memory_read("environment_preferences")

    # 代码生成适配
    if prefs.get("editor") == "neovim":
        self.add_note("提示:在 Neovim 中,你可以用 :w 保存后运行")

    # 命令适配
    if prefs.get("python_packaging") == "uv":
        self.use_command("uv run", instead_of="python")
        self.use_command("uv add", instead_of="pip install")

    # 终端提示适配
    if prefs.get("shell") == "zsh":
        self.suggest_zsh_plugins()

    # 字体和显示适配
    if "Nerd Font" in prefs.get("font", ""):
        self.use_unicode_icons = True  # 可以使用图标

跨会话记忆实战

实战 1:记住项目技术栈

text
═══════════════════════════════════════
会话 A(第一次讨论)
═══════════════════════════════════════

用户:我有一个新项目,打算用 FastAPI + PostgreSQL +
     Prisma Client(Python 版),帮我想想项目结构。

Agent:[记忆写入]
  memory_write(
    key="project.new_project.stack",
    value={
        "framework": "FastAPI",
        "database": "PostgreSQL",
        "orm": "prisma-client-py",
        "created_at": "2025-05-15"
    },
    scope="user"
  )

Agent:好的,基于你的技术栈选择,我建议以下结构:
     [给出项目结构]

═══════════════════════════════════════
会话 B(3 天后,新会话)
═══════════════════════════════════════

用户:上次说的那个项目,我现在要加用户认证模块。

Agent:[自动检索记忆]
  memory_search("用户认证 项目")
  → 匹配: "new_project" (FastAPI + PostgreSQL)

Agent:你说的是那个 FastAPI + PostgreSQL 的项目对吧?
     好的,基于已有的技术栈,我推荐用 JWT + OAuth2:

     [给出与已有技术栈一致的认证方案]

实战 2:记住编码风格

text
═══════════════════════════════════════
会话 A(发现偏好)
═══════════════════════════════════════

用户:函数命名用蛇形,不要用驼峰。注释写中文。

Agent:[自动记忆]
  memory_write(
    key="coding_style.naming",
    value="snake_case",
    scope="project"
  )
  memory_write(
    key="coding_style.comment_language",
    value="zh-CN",
    scope="user"
  )

═══════════════════════════════════════
会话 B(自动应用)
═══════════════════════════════════════

用户:写一个用户注册的函数。

Agent:[读取记忆]
  naming → snake_case
  comment_language → zh-CN

Agent:好的:

```python
def create_user(
    username: str,
    email: str,
    password: str
) -> User:
    """创建新用户

    参数:
        username: 用户名
        email: 邮箱地址
        password: 密码(会自动哈希)

    返回:
        创建好的 User 对象
    """
    # 检查用户名是否已存在
    existing = db.query(User).filter(
        User.username == username
    ).first()
    if existing:
        raise ValueError("用户名已存在")

    # 创建新用户
    user = User(
        username=username,
        email=email,
        password_hash=hash_password(password)
    )
    db.add(user)
    db.commit()
    return user
```

实战 3:记住部署习惯

text
═══════════════════════════════════════
会话 A(设定习惯)
═══════════════════════════════════════

用户:我的项目都部署到 Vercel,环境变量用 .env.local 管理。

Agent:[记忆写入]
  memory_write(
    key="deployment.preferences",
    value={
        "platform": "Vercel",
        "env_management": ".env.local",
        "env_pattern": "NEXT_PUBLIC_* for client, others for server"
    },
    scope="user"
  )

═══════════════════════════════════════
会话 B(自动适配)
═══════════════════════════════════════

用户:这个项目需要接入一个第三方 API,怎么配置密钥?

Agent:[读取记忆]
  deployment.platform → Vercel
  env_management → .env.local

Agent:根据你的部署习惯(Vercel + .env.local):

1. 开发环境 - 在 .env.local 中添加:
   ```
   THIRD_PARTY_API_KEY=your_key_here
   ```

2. 生产环境 - 在 Vercel Dashboard 中添加环境变量:
   Settings → Environment Variables → Add New

3. 代码中使用:
   ```typescript
   // 只在服务端访问
   const apiKey = process.env.THIRD_PARTY_API_KEY;
   ```

记忆的生命周期管理

记忆的创建

记忆可以通过以下方式创建:

  1. 显式写入:用户直接要求记住某些信息
  2. 自动提取:Agent 从对话中自动识别和提取
  3. 系统注入:从项目配置文件(.hermes/memory.yaml)加载

记忆的更新

yaml
# 记忆版本管理
memory_versioning:
  strategy: "append_with_timestamp"
  max_versions: 10

  example:
    key: "coding_preferences.formatting"
    versions:
      - value: {semi: false}
        timestamp: "2025-01-15"
        source: "explicit"
      - value: {semi: true}
        timestamp: "2025-05-20"
        source: "explicit"

记忆的过期

yaml
# 记忆过期策略
memory_expiry:
  default_ttl: null  # 默认永久
  rules:
    - pattern: "session_notes.*"
      ttl: "30d"  # 会话笔记 30 天后过期
    - pattern: "temporary.*"
      ttl: "7d"   # 临时记忆 7 天后过期
    - pattern: "user_profile.*"
      ttl: null   # 用户画像永久有效
    - pattern: "project_context.*"
      ttl: "90d"  # 项目上下文 90 天后刷新

  cleanup_schedule: "weekly"
  cleanup_action: "archive_then_delete"  # 先归档再删除

记忆的归档

python
# 记忆归档流程
def archive_old_memories():
    """归档过期记忆"""

    old_memories = find_expired_memories()

    for memory in old_memories:
        # 1. 移动到归档存储
        archive_store.write(memory)

        # 2. 生成归档摘要
        summary = generate_summary(memory)
        memory_write(
            key=f"archive.{memory.key}",
            value=summary,
            scope="user"
        )

        # 3. 删除原始记忆
        memory_delete(memory.key)

隐私与安全

记忆加密

yaml
# 记忆安全配置
memory_security:
  encryption:
    at_rest: "AES-256-GCM"
    in_transit: "TLS 1.3"

  access_control:
    user_memories: "user_only"  # 只有用户自己能访问
    project_memories: "project_collaborators"  # 项目协作者
    shared_memories: "configurable"  # 可配置

  sensitive_data:
    auto_detect: true
    patterns:
      - "password"
      - "api_key"
      - "token"
      - "secret"
    action: "encrypt_and_restrict"  # 加密并限制访问

记忆审计

yaml
# 记忆操作审计日志
memory_audit:
  enabled: true
  log_format:
    - timestamp
    - action  # read/write/update/delete
    - key
    - scope
    - source  # explicit/auto/system
    - user_id

  retention: "180d"
  export_format: "json"

用户控制

bash
# 用户记忆管理命令

# 查看所有记忆
hermes memory list

# 查看特定记忆
hermes memory get coding_preferences.formatting

# 导出所有记忆
hermes memory export > my-memories.yaml

# 导入记忆
hermes memory import my-memories.yaml

# 清除所有记忆(危险操作)
hermes memory clear --confirm

# 清除特定范围的记忆
hermes memory clear --scope session
hermes memory clear --scope project --path ./my-project

# 设置记忆自动过期
hermes memory set-ttl "project_notes.*" 30d

最佳实践

1. 记忆粒度控制

yaml
# ✅ 推荐:细粒度的记忆键
coding_preferences:
  formatting:
    tool: "prettier"
    tab_width: 2
  naming:
    convention: "camelCase"
  imports:
    order: "alphabetical"

# ❌ 不推荐:一个大块记忆
coding_preferences: "用 prettier,2 空格,驼峰命名,字母排序导入..."

2. 合理使用范围

范围 适用场景 示例
user 全局偏好 编辑器、语言偏好、编码风格
project 项目特定 技术栈、项目约定、API 地址
session 临时信息 本次讨论的临时方案

3. 定期审查记忆

bash
# 每周检查一次记忆
hermes memory list --sort-by=last_accessed

# 清理不常用的记忆
hermes memory prune --unused-since=90d --dry-run

4. 不要过度记忆

yaml
# ❌ 不要记忆每次对话的细节
# ✅ 只记忆有价值的结论和偏好

good_memories:
  - "用户偏好 TypeScript"
  - "项目使用 PostgreSQL"
  - "部署到 Vercel"

bad_memories:
  - "用户今天问了 5 个问题"
  - "用户下午 3 点开始会话"
  - "用户说了一个然后改主意的方案"

总结

本文全面介绍了 Hermes Agent 的 Memory 持久记忆系统:

  1. Memory 系统架构:短期记忆、长期记忆、语义记忆的三层架构
  2. 记忆工具:write、read、search、update、delete 五种核心操作
  3. 用户画像系统:自动从对话中提取偏好,构建完整的用户档案
  4. 环境偏好记忆:编辑器、终端、构建工具、部署平台的偏好记忆
  5. 跨会话记忆实战:技术栈记忆、编码风格记忆、部署习惯记忆
  6. 记忆生命周期管理:创建、更新、过期、归档的完整流程
  7. 隐私与安全:加密、访问控制、审计日志、用户控制

核心原则:

  • 记忆让 Agent 真正"认识你":不再每次从零开始
  • 有策略地记忆:记住有价值的结论,忽略噪声
  • 细粒度管理:不同范围、不同类型的记忆独立管理
  • 用户完全控制:随时查看、修改、删除记忆
  • 隐私优先:敏感数据自动检测和保护

📌 下篇预告

Session Search 对话搜索 —— 在海量历史对话中精准定位:关键词搜索、语义搜索、OR/AND 组合查询、上下文回忆。当记忆系统帮你记住了关键信息后,如何快速找到过去的完整对话?下一篇将带你掌握 Hermes Agent 的对话搜索能力,让历史对话成为你的知识宝库。