Profile 与 User Memory 边界
Profile/MCP/Memory Bank 基础:MCP 记忆集成层 Claude Code 记忆机制:精读: Claude Code 记忆系统 Codex 记忆机制:精读: Codex 记忆系统 Coding Agent 横评:Coding Agent 记忆横评
调研元信息
| 项目 | 值 |
|---|---|
| 调研日期 | 2026-06-22 |
| 涉及研究轴 | C(Profile 层)为主 |
| 前置阅读 | deep-dive-mcp-memory-bridge.md Profile 对比章节 |
| 证据等级 | [源码] [文档] [社区] 混合 |
一句话定位
Profile(CLAUDE.md / AGENTS.md / .cursor/rules)是开发者写给 Agent 的行为规范,User Memory 是Agent 自己从对话中学到的知识——两者在概念上清晰,在实践中经常混淆,而 Memory Bank 社区模式更是刻意模糊了这条边界 [社区]。
记忆类型标注
| 类型 | 涉及 | 说明 |
|---|---|---|
| Working | 否 | 不涉及 session 上下文 |
| Profile | 核心 | CLAUDE.md / AGENTS.md / Rules |
| User | 核心 | memdir / Codex memories / Cursor Memories |
| External | 间接 | Memory Bank 用 Profile 模拟 External |
日常类比
Profile 就像一个公司的员工手册——写着”代码用 4 空格缩进”“所有 API 必须有错误处理”“先写测试再写实现”。这是规范,不会因为你做了某件事就自动更新。
User Memory 则像你的个人工作笔记——”张三偏好 TypeScript”“这个项目的数据库用 PostgreSQL”“上次那个 bug 的根因是连接池泄漏”。这是从工作经验中提炼的知识,会随着交互自动积累。
混淆场景:如果你把”上次那个 bug 的根因”写进员工手册(Profile),下次换了新人也能看到——但员工手册会越来越厚,而且”上次那个 bug”的上下文可能已经过时。这就是 Memory Bank 模式的根本问题。
概念模型:Profile ≠ User Memory
flowchart TB
subgraph profile["Profile(行为规范)"]
direction TB
P1["写入者:人工<br/>更新频率:低<br/>内容:'应该怎么做'"]
P2["CLAUDE.md<br/>AGENTS.md<br/>.cursor/rules<br/>CONVENTIONS.md"]
end
subgraph user_mem["User Memory(学到的知识)"]
direction TB
U1["写入者:Agent/系统<br/>更新频率:高<br/>内容:'学到了什么'"]
U2["memdir<br/>~/.codex/memories/<br/>Cursor Memories"]
end
subgraph confusion["混淆地带"]
direction TB
C1["Memory Bank<br/>用 Profile 文件模拟 User Memory"]
C2["在 CLAUDE.md 写 'remember to...'<br/>期望被 extractMemories 提取"]
end
profile --> AGENT[Agent]
user_mem --> AGENT
confusion -.->|"不推荐"| AGENT
三个经典误区
误区 1:把动态知识写进 Profile
错误做法:在 CLAUDE.md 里写 “当前正在重构 auth 模块,注意 JWT 过期时间改为 1 小时”。
问题:Profile 文件通常受版本控制,所有团队成员共享。”当前正在重构 auth 模块”是临时状态,重构完成后这句话就过时了——但如果没人记得删掉它,Agent 会一直以为 auth 模块在重构中 [社区]。
正确做法:这类信息应该在 User Memory(如 Claude Code 的 memdir)中自然存在,并通过 staleness 机制在过期后自动降权。Claude Code 的 memoryAge 模块就是为此设计的——超过 1 天的记忆会被自动加上 <system-reminder> 提示模型注意时效 [源码]。
误区 2:期望 Profile 内容被 extractMemories 提取
错误做法:在 CLAUDE.md 写 “remember that this project uses pnpm not npm”,然后期望 extractMemories 把它存到 memdir。
问题:Claude Code 的 extractMemories 明确将 “CLAUDE.md 已有的内容”列为不应保存的信息——因为 Profile 已经在 system prompt 中了,重复存到 memdir 是浪费 [源码]。
正确做法:CLAUDE.md 负责规范(”用 pnpm”),memdir 负责上下文(”上次用户试过 npm 遇到了 peer dependency 冲突”)。
误区 3:Memory Bank 就是 User Memory
错误做法:认为用 Memory Bank 文件(activeContext.md、progress.md 等)就等于有了 User Memory。
问题:Memory Bank 的三个根本缺陷——无嵌入/无语义检索(全量注入)、无冲突合并(多 session 竞态)、人工触发(遗忘=丢失)——使它在本质上仍然是 Profile 的变种,只是内容更动态而已 [社区]。
对照:Claude Code 的 memdir 有 Sonnet 语义检索、hasMemoryWritesSince 竞态保护、自动触发的 extractMemories hook——这些都是 Memory Bank 缺失的基础设施。
AGENTS.md 发现链深度分析
Codex 的 AGENTS.md 发现链在 agents_md.rs 中实现,是 Profile 系统中设计最精巧的链式机制 [源码]:
发现流程:
- 从 cwd 向上逐级查找
.git(或其他项目根标记),确定项目根 - 从项目根到 cwd 路径上的每一级目录,按优先级查找:
AGENTS.override.md→AGENTS.md→ fallback(如CLAUDE.md) - 用户级 instructions 排最前,各级内容用
--- project-doc ---分隔符拼接
设计亮点:AGENTS.override.md 类似 .env.local——可以 gitignore,不影响团队配置。这解决了 Profile 系统的一个痛点:个人偏好(如”我用 vim keybinding”)不应该提交到团队 repo,但又需要 Agent 知道。
与 CLAUDE.md 的差异:CLAUDE.md 虽然也支持链式发现和 CLAUDE.local.md 本地覆盖,但其路径布局更复杂(全局 / 项目根 / .claude/ / 子目录 / local),而 AGENTS.md 的设计更简洁——只有三层优先级,且作为 30+ 工具的联合标准有更广的兼容性 [源码]。
Cursor Rules 四种 Apply 模式
详细对比见 bridge 篇
Cursor 的 .cursor/rules/*.mdc 提供了最灵活的条件注入策略,四种模式形成了从”始终注入”到”按需注入”的完整光谱 [文档]:
flowchart LR
ALWAYS["Always Apply<br/>始终注入<br/>= CLAUDE.md"] --> GLOBS["Globs<br/>文件匹配注入<br/>= 无对应"]
GLOBS --> DESC["Description<br/>Agent 自判注入<br/>≈ findRelevantMemories"]
DESC --> MANUAL["Manual<br/>@引用<br/>= 无对应"]
关键观察:Description 模式让 Agent 读规则描述后自行判断是否拉入上下文——这在概念上接近 Claude Code 的 findRelevantMemories(用 LLM 判断相关性),只是作用对象不同(Cursor 判断的是规则,Claude Code 判断的是记忆文件) [文档]。
边界判断决策树
面对一条新信息,应该放在 Profile 还是 User Memory?
flowchart TB
START[新信息] --> Q1{是否跨 session 有用?}
Q1 -->|否| DAILY[放 daily/<br/>(会话内用完即弃)]
Q1 -->|是| Q2{是否所有团队成员<br/>都应遵守?}
Q2 -->|是| Q3{是否变化频率低?<br/>(月级别以上)}
Q3 -->|是| PROFILE["Profile<br/>CLAUDE.md / AGENTS.md / Rules"]
Q3 -->|否| ISSUE["考虑拆分:<br/>稳定部分 → Profile<br/>动态部分 → User Memory"]
Q2 -->|否| Q4{是否可从代码/环境推导?}
Q4 -->|是| SKIP["不保存<br/>(extractMemories 也会跳过)"]
Q4 -->|否| USER_MEM["User Memory<br/>memdir / Codex memories"]
各 Agent 的 Profile-Memory 边界实践
| Agent | Profile 和 User Memory 的代码级边界 | 是否有防重复机制 |
|---|---|---|
| Claude Code | extractMemories 明确排除 CLAUDE.md 已有内容 [源码] |
是——主代理写过记忆时提取代理跳过 |
| Codex | Phase1 过滤 AGENTS.md 指令和 developer 消息 [源码] |
是——Phase2 consolidation 做去重合并 |
| OpenClaw | flush prompt 标注 MEMORY.md/SOUL.md 为只读 [源码] |
部分——dreaming 晋升时有评分 |
| Cursor | Memories 记录编程偏好,Rules 记录项目规范 [文档] |
不确定 |
| Cline/Aider | 无 User Memory,不存在边界问题 | 不适用 |
Memory Bank:权宜之计的教训
Memory Bank 模式的存在和演变为整个 Profile-Memory 边界讨论提供了一个真实案例 [社区]:
起因:Cursor 1.0 之前没有 User Memory,Cline 至今没有。开发者需要跨 session 持久化项目上下文,于是用 Profile 文件来模拟。
结果:6 个 markdown 文件(projectBrief → progress)形成了一个类似 Wiki 的结构,但继承了 Profile 的所有缺陷——无检索、无冲突合并、人工触发。
教训:
- 需求是真实的——跨 session 持久化是刚需,Coding Agent 不能忽视
- Profile 不是正确的容器——静态文件 + 全量注入无法扩展
- MCP 是正确方向——让 Cline 接入 supermemory 或 DB-Agent-Memory 的 MCP Server,可以获得 Memory Bank 缺失的所有能力(检索、自动提取、冲突处理)
局限性
- AGENTS.md 源码分析基于 Codex 仓库:其他采用 AGENTS.md 标准的 30+ 工具可能有不同实现
[源码]。 - Cursor Memories Beta 内部机制不透明:云端实现细节无法验证
[文档]。 - Memory Bank 分析基于社区文档和 Cline 源码:不同社区变体可能有差异
[社区]。
证据等级汇总
| 论点 | 证据等级 |
|---|---|
| extractMemories 排除 CLAUDE.md 内容 | [源码] deep-dive-claude-code-memory.md |
| AGENTS.md 发现链实现 | [源码] agents_md.rs |
| Cursor Rules 四种 apply 模式 | [文档] cursor.com/docs |
| Memory Bank 社区模式分析 | [社区] + [源码] Cline |
| Codex Phase1 过滤 AGENTS.md | [源码] deep-dive-codex-memory.md |
| 三个经典误区 | [源码][社区] 推导 |