SuperAPI AI 工具集

agent-memory-implementation

智能体与模型

查看项目

更新于 10-16 03:52

技能介绍

用途

该技能用于把混乱或过度膨胀的 MEMORY.md 重构为 Claude Code autoDream 服务内部使用的两层记忆架构,目标是让始终加载的索引保持精简,同时让更深层的知识可以按需访问。

两层架构

Claude Code 的记忆系统(services/autoDream/)使用如下结构:

  • MEMORY.md:第一层,始终加载,仅含指针的索引,最多约 200 行。
  • 主题文件(topic-file.md 等):第二层,领域知识,在相关时加载。

第一层 MEMORY.md 索引会被加载进每次对话,必须保持在约 200 行以内(超过 200 行的部分会被截断)。每个条目是一行指针,格式为 - [Title](file.md) — one-line hook,不含正文内容,只含指针。Claude 通过扫描它来决定加载什么。

第二层主题文件包含实际知识,当指针显示相关时由 Claude 按需加载,长度不限。每个文件带有 YAML frontmatter,包含 name、description 和 type。

没有归档层:autoDream 系统不维护 archive 目录。过时、被取代或相互矛盾的记忆会被删除或就地更正(见 consolidationPrompt.ts 第 3–4 阶段)。记忆目录始终是当前事实,而不是历史日志。

Claude Code 如何自动写入记忆

理解自动提取流水线有助于按系统期望的方式重构文件。

提取用的 fork 代理

在每次查询循环结束时(模型返回最终响应且没有待处理工具调用时),Claude Code 会通过 services/extractMemories/extractMemories.ts 中的 executeExtractMemories() 在后台启动一个 fork 代理。该代理会:

  • 接收最近 N 条用户/助手消息作为上下文;
  • 扫描记忆目录中的现有文件(只读 frontmatter,description 字段是主要信号);
  • 判断本次对话中哪些内容值得保存;
  • 在记忆目录内写入或更新 .md 文件,然后更新 MEMORY.md。

该 fork 共享父对话的 prompt 缓存(相同工具列表、相同系统提示前缀、相同缓存键),因此额外 token 成本接近于零。

互斥:如果主代理在对话期间已经写入记忆目录(例如用户说“记住这个”),fork 代理会检测到并跳过,不会重复写入。

轮次预算:硬上限为 5 轮。代理被要求在第 1 轮批量执行所有读取,在第 2 轮批量执行所有写入,不交错进行。

提取代理的提示词(参考:services/extractMemories/prompts.ts)

提示词由 buildExtractAutoOnlyPrompt() 分四部分组装:

第一部分——角色 + 工具约束 + 效率策略(硬编码):

You are now acting as the memory extraction subagent.
Analyze the most recent ~{N} messages above and use them to update
your persistent memory systems.

Available tools: Read, Grep, Glob, read-only Bash (ls/find/cat/stat/
wc/head/tail), and Edit/Write for paths inside the memory directory
only. Bash rm is not permitted.

Turn budget strategy:
  turn 1 — issue all Read calls in parallel for every file you might update
  turn 2 — issue all Write/Edit calls in parallel

You MUST only use content from the last ~{N} messages.
Do not grep source files, read code to confirm patterns, or run git commands.

第二部分——现有记忆清单(动态注入):

## Existing memory files

- [feedback] feedback_testing.md: no DB mocks in integration tests
- [user] user_role.md: user is a PM learning the codebase
- ...

Check this list before writing — update an existing file rather than
creating a duplicate.

该清单由 scanMemoryFiles() 扫描每个文件的 frontmatter 生成。frontmatter 中的 description 字段就是这行清单内容;如果它含糊不清,代理就无法判断应该更新文件还是新建文件。

第三部分——四种记忆类型 + 不应保存的内容(与系统提示共享):

使用与主代理系统提示中相同的常量(TYPES_SECTION_INDIVIDUAL、WHAT_NOT_TO_SAVE_SECTION),来自 memdir/memoryTypes.ts。单一事实来源——提取代理使用与主代理相同的标准。

第四部分——如何保存(两步写入规范):

Step 1 — write topic file with frontmatter:
  ---
  name: <slug>
  description: <one-line summary — used for relevance matching>
  type: user | feedback | project | reference
  ---

Step 2 — add one pointer line to MEMORY.md:
  - [Title](file.md) — one-line hook

对重构的启示

description 是关键字段——提取代理(去重检查)和相关度评分器(读取时选择)都会使用它。像“notes”这样含糊的 description 会让两者都无法正常工作。应让它足够具体,能够回答“如果用户问到 X,这个文件是否相关?”

frontmatter 的 type 决定归档方式——提取代理使用类型分类法来决定适用哪些标准。类型错误(或没有类型)的文件在未来的更新中会被错误处理。

MEMORY.md 的指针钩子很重要——破折号后的钩子文本是 Claude 用来决定是否加载完整文件的依据。只写“misc notes”的钩子会浪费这个位置。

记忆类型定义

阅读 references/memory-type-definitions.md 可获取 memdir/memoryTypes.ts 中的逐字 XML——四种类型规范(user、feedback、project、reference)和排除列表。在决定从对话中提取什么以及为每条记忆分配哪种类型时加载它。

重构流程

第 1 步——审计现有内容

读取 MEMORY.md 和同一目录下的所有记忆文件。编目:

  • MEMORY.md 的总行数;
  • 哪些条目是纯指针(好)与含内联内容(需要提取);
  • 哪些主题文件已变得臃肿(超过 200 行)并应拆分;
  • 哪些条目明显过时、被取代或相互矛盾。

第 2 步——对每个条目分类

对每块内容决定其层级:

内容类型 层级
通用事实、始终相关的规则 L1 指针 → L2 文件
项目特定决策、当前约束 L1 指针 → L2 文件
历史性的“我们为什么做 X”上下文 压缩进相关 L2 文件或删除
被取代的方法 删除
相互矛盾的事实 删除或就地更正
逐步实现细节 删除(代码就是记录)

第 3 步——重构

对于 MEMORY.md:

  • 只保留指针行(每个记忆文件一行);
  • 格式:- [Descriptive Title](filename.md) — one-line hook(什么使它相关?);
  • 总行数保持在 200 行以内;
  • 如有帮助,可用简短的分节标题对相关指针分组(例如 ## Architecture、## User preferences);
  • 移除已删除文件的条目。

对于主题文件:

  • 每个文件获得正确的 frontmatter:
---
name: <topic name>
description: <one-line — used to judge relevance in future conversations>
type: user | feedback | project | reference
---
  • feedback 类型:先写规则,然后是 Why: 和 How to apply: 行;
  • project 类型:先写事实/决策,然后是 Why: 和 How to apply:;
  • 将近重复的文件(同一主题、角度略有不同)合并为一个;
  • 将相对日期转换为绝对日期(“last week” → “2026-03-15”)。

第 4 步——验证

重构后检查:

  • MEMORY.md 是否在 200 行以内?
  • MEMORY.md 中的每个指针是否都指向存在的文件?
  • 每个主题文件是否都有有效的 frontmatter?
  • MEMORY.md 中是否没有直接内容(只有指针)?
  • 是否没有重复或近重复的主题文件?

第 5 步——报告

告知用户:

  • MEMORY.md 重构前后的行数;
  • 创建/合并/删除了多少主题文件;
  • 发现的任何矛盾及其解决方式。

常见反模式

  • 索引臃肿——MEMORY.md 里是成段内容而不是指针。应提取到主题文件。
  • 单个巨型文件——所有内容都堆在一个 memories.md 中。应按主题拆分。
  • 缺少 frontmatter——主题文件没有 name/description/type。应补上——description 帮助 Claude 决定是否加载该文件。
  • 过时事实——记忆说“using postgres 14”,但代码库显示 16。应就地修正。
  • 时间衰减——“We decided last week to use X”。应转换为绝对日期,并核实该决策是否仍然成立。
  • 索引中的历史上下文——旧决策或“我们为什么做 X”弄乱了 MEMORY.md。要么把理由压缩进相关主题文件的 Why: 行,要么在不再相关时删除。