如何管理 AI Agent 的记忆之二:让 Claude Code、Codex、OpenCode 共享同一份记忆
Posted on 五 07 8月 2026 in AI
| Abstract | 如何管理 AI Agent 的记忆之二:让 Claude Code、Codex、OpenCode 共享同一份记忆 |
|---|---|
| Authors | Walter Fan |
| Category | learning note |
| Version | v1.0 |
| Updated | 2026-08-07 |
| License | CC-BY-NC-ND 4.0 |
前几天我清理主目录,ls 一敲,愣是发现自己在维护一堆内容几乎一样的文件:
$ ls -la ~/.claude/CLAUDE.md ~/.codex/AGENTS.md ~/.config/opencode/AGENTS.md
~/.claude/CLAUDE.md # 给 Claude Code 看的个人规则
~/.codex/AGENTS.md # 给 Codex 看的,内容八成一样
~/.config/opencode/AGENTS.md # 给 OpenCode 看的,又抄了一遍
再看我这个博客仓库根目录,AGENTS.md 14KB、CLAUDE.md 12KB,俩文件内容重叠九成——就因为不同工具读不同的文件名,我把同一套约定抄了两遍。
这就是同时用多个编码 Agent 的通病:你的"记忆"被工具切成了好几份,改了这份忘了那份,三个助手越用越像三个各说各话的人。 上一篇《如何管理 AI Agent 的记忆》讲的是单个 Agent 内部怎么分层管记忆;这一篇解决的是它的孪生问题——多个工具之间,怎么共享同一份记忆。
看完你能带走一套可落地的方案,分两层:
- 静态规则(项目约定、编码规范、个人偏好):用"单一事实源 + 符号链接",一处编辑,三处生效。
- 动态长期记忆(跨会话积累的偏好、项目事实):用一个"记忆 MCP 服务",三个工具连同一个后端。
先搞清楚:三个工具各读哪份文件
想让它们共享,得先知道它们各自认哪个文件名、按什么顺序加载。这是整套方案的地基,别猜,照下面这张表来(截至 2026 年中的约定,工具更新快,落地前建议 --help 或看官方文档再核一遍):
| 工具 | 全局(个人)记忆 | 项目记忆 | 加载方式 |
|---|---|---|---|
| Claude Code | ~/.claude/CLAUDE.md |
./CLAUDE.md 或 ./.claude/CLAUDE.md |
启动时全量载入上下文 |
| Codex | ~/.codex/AGENTS.md |
项目根往下走的 AGENTS.md |
启动时构建指令链 |
| OpenCode | ~/.config/opencode/AGENTS.md |
./AGENTS.md |
启动时载入指令 |
一眼就能看出好消息和坏消息:
- 好消息:Codex 和 OpenCode 都认
AGENTS.md这个名字——这已经在慢慢变成事实标准了。 - 坏消息:Claude Code 偏偏认
CLAUDE.md。所以要三家统一,绕不开处理这个"名字不一样"的问题。
关键洞察:三个工具读的都是"磁盘上的一个文件"。
那让它们共享就简单了——只要这几个路径最终指向同一份内容就行。这正是符号链接(symlink)的用武之地。
第一层:静态规则用"单一事实源 + 符号链接"
思路和上一篇的"单一事实源"一模一样:内容只存一份,其他位置都是指向它的链接。 编辑那一份,三个工具同时生效,从此告别"抄三遍、改漏俩"。
项目级:一份 AGENTS.md,把 CLAUDE.md 链过去
在项目根目录,让 AGENTS.md 当唯一真身,CLAUDE.md 做它的软链:
# 项目根目录下
# 1) 保留 AGENTS.md 作为单一事实源(Codex / OpenCode 直接读它)
# 2) 把 CLAUDE.md 变成指向 AGENTS.md 的软链(Claude Code 也读到同一份)
ln -sf AGENTS.md CLAUDE.md
# 验证:CLAUDE.md 现在是个指向 AGENTS.md 的链接
ls -l CLAUDE.md
# CLAUDE.md -> AGENTS.md
这样三个工具在这个项目里读到的都是同一份 AGENTS.md。想改约定?只动 AGENTS.md 一个文件。
提交进 Git 前留个心眼:Git 默认会把 symlink 当"链接"存下来,同事拉下去在 macOS/Linux 上能正常还原。但 Windows 上 symlink 支持不稳,团队里有 Windows 同事的话,考虑改用下一节的"import 引用"方案,或在 CI 里生成链接。
全局级:把三个个人规则都指向一份
个人偏好(比如"提交信息用中文""别自动 push""回答简洁点")也同理。挑一个中立位置放真身,其余软链过去:
# 1) 真身放一个中立位置,比如 ~/.config/ai/AGENTS.md
mkdir -p ~/.config/ai
mv ~/.claude/CLAUDE.md ~/.config/ai/AGENTS.md # 把现有内容挪过去当真身
# 2) 三个工具的路径都软链到这份真身
ln -sf ~/.config/ai/AGENTS.md ~/.claude/CLAUDE.md
ln -sf ~/.config/ai/AGENTS.md ~/.codex/AGENTS.md
ln -sf ~/.config/ai/AGENTS.md ~/.config/opencode/AGENTS.md
# 3) 验证三条都指向同一个 inode(ls -i 看 inode 号是否相同)
ls -li ~/.claude/CLAUDE.md ~/.codex/AGENTS.md ~/.config/opencode/AGENTS.md
从此我个人的规则只有一份 ~/.config/ai/AGENTS.md,vim 一改,三个工具下次启动全生效。
不想用软链?用"import 引用"更稳
如果 symlink 让你不放心(Windows、或者团队协作),还有个更朴素的办法:每个工具的文件只写一行,把内容"引用"进来。 三个工具大多支持 @path 或 Markdown 链接式的 import:
<!-- ~/.claude/CLAUDE.md 里就写一行 -->
@~/.config/ai/AGENTS.md
<!-- ~/.codex/AGENTS.md 里也是 -->
@~/.config/ai/AGENTS.md
真身依然只有一份,三个入口文件都是"薄壳"。好处是纯文本、跨平台、Git 友好;代价是得确认你那版工具支持 import 语法(这点各家实现有差异,落地前测一下)。
小结一下静态层的取舍:
| 方案 | 优点 | 缺点 | 适合 |
|---|---|---|---|
| 符号链接 | 零配置、内容 100% 一致 | Windows 支持差、Git 需留意 | 个人、macOS/Linux |
| import 引用 | 跨平台、Git 友好 | 依赖工具支持 import 语法 | 团队、跨系统 |
| 手工同步脚本 | 最兼容 | 得记得跑、易漏 | 前两者都不行时的兜底 |
第二层:动态长期记忆用一个 MCP 服务
静态规则解决了"约定",但还有一类记忆是跑着跑着自动长出来的:用户偏好、项目事实、上次踩的坑——就是上一篇讲的那套语义/情景记忆。这类东西你没法手写进 AGENTS.md,得让工具自己写、自己读。
问题来了:Claude Code 把自动记忆写在 ~/.claude/projects/<project>/memory/ 下,Codex 和 OpenCode 各有各的地盘。这些"自动记忆"是各存各的,天然不通。
要打通,靠一个共同的"接口层"——MCP(Model Context Protocol)。这三个工具都支持接 MCP server。那思路就清晰了:
把记忆做成一个 MCP 服务,三个工具都连它。 记忆的"读"和"写"都走这个统一后端,谁写的另俩都读得到。
这正好接上一篇那个记忆库(pgvector + 重要性打分 + 去重 + 加权检索)。只要在它外面套一层 MCP,就从"单个 Agent 的私有记忆"升级成了"多工具共享的记忆服务"。
架构长这样
Claude Code Codex OpenCode
│ │ │
└──────┬──────┴─────┬──────┘
│ MCP 协议 │
▼ ▼
┌──────────────────────────┐
│ 记忆 MCP Server │
│ remember() / recall() │ ← 上一篇那套逻辑
└──────────────────────────┘
│
PostgreSQL + pgvector
(单一记忆后端,谁写都读得到)
记忆 MCP Server 的骨架
用 Python 的 MCP SDK 把上一篇的 remember() / recall() 包成两个工具(tool),代码骨架如下——注意核心逻辑直接复用,MCP 只是壳:
# memory_mcp_server.py
from mcp.server.fastmcp import FastMCP
from memory_store import remember, recall # 上一篇实现的那两个函数
mcp = FastMCP("shared-memory")
@mcp.tool()
def save_memory(user_id: str, text: str, kind: str = "semantic") -> str:
"""把一条值得长期记住的信息存进共享记忆(会自动打分+去重)。"""
remember(user_id, text, kind=kind, source="mcp")
return "ok"
@mcp.tool()
def search_memory(user_id: str, query: str, k: int = 3) -> list[str]:
"""从共享记忆里检索与 query 最相关的 top-k 条。"""
return recall(user_id, query, k=k)
if __name__ == "__main__":
mcp.run() # 默认 stdio 传输,三个工具都能连
三个工具怎么连它
各家配置文件格式略有差异,但都是"声明一个 MCP server + 启动命令"这个套路:
// Claude Code: 项目根 .mcp.json(或用 `claude mcp add` 命令)
{
"mcpServers": {
"shared-memory": {
"command": "python",
"args": ["/path/to/memory_mcp_server.py"]
}
}
}
// OpenCode: opencode.json 里的 mcp 段
{
"mcp": {
"shared-memory": {
"type": "local",
"command": ["python", "/path/to/memory_mcp_server.py"]
}
}
}
Codex 同样支持在其配置里声明 MCP server(配置键名以你手头版本的文档为准)。三个都连上之后,效果就是:
- 你在 Claude Code 里说"记住:这个项目 CI 用的是 GitLab 不是 GitHub",它调
save_memory写进共享库。 - 第二天你切到 Codex 干活,它调
search_memory检索,"想起来"了这条——尽管这条根本不是它写的。
这就是跨工具共享动态记忆的闭环。而且因为复用了上一篇那套"打分+去重+加权检索",共享的同时依然不烧 Token、不爆存储。
完整落地:一个 setup 脚本搞定静态层
静态层可以一把梭。下面这个脚本你改改路径就能跑(先备份、幂等、可重复执行):
#!/usr/bin/env bash
set -euo pipefail
# 单一事实源
SRC="$HOME/.config/ai/AGENTS.md"
mkdir -p "$(dirname "$SRC")"
# 若真身还不存在,从现有 Claude 规则迁过来(没有就建空文件)
if [[ ! -f "$SRC" ]]; then
if [[ -f "$HOME/.claude/CLAUDE.md" && ! -L "$HOME/.claude/CLAUDE.md" ]]; then
mv "$HOME/.claude/CLAUDE.md" "$SRC"
else
touch "$SRC"
fi
fi
link() { # 备份已有真文件,再建软链
local target="$1"
mkdir -p "$(dirname "$target")"
if [[ -f "$target" && ! -L "$target" ]]; then
mv "$target" "$target.bak.$(date +%s)"
echo "backed up $target"
fi
ln -sf "$SRC" "$target"
echo "linked $target -> $SRC"
}
link "$HOME/.claude/CLAUDE.md"
link "$HOME/.codex/AGENTS.md"
link "$HOME/.config/opencode/AGENTS.md"
echo "done. edit $SRC once, all three tools follow."
跑完,你以后维护记忆就只剩一件事:vim ~/.config/ai/AGENTS.md。
几个坑,提前给你避掉
我自己趟这套方案时踩到的和想到的坑,列出来省你时间:
- 别把动态记忆写进静态文件。
AGENTS.md是给人和团队看的"约定",改动要过脑子、进 Git;自动积累的偏好该走 MCP 记忆库。两者混在一起,AGENTS.md会越滚越臃肿,最后每次会话白烧一大把 Token。 - 全局 vs 项目要分清。个人偏好(回答风格、提交习惯)放全局那份;项目约定(这个 repo 的构建命令、目录结构)放项目那份。别把"我个人爱好"塞进团队仓库,也别把"项目专属规则"塞进全局。
- symlink 提交 Git 前想清楚。团队有 Windows 同事就改用 import 引用;纯个人 macOS/Linux 用软链最省事。
- MCP 记忆要做用户/项目隔离。共享后端不等于"大杂烩"——
user_id/project_id命名空间一定要带上,否则 A 项目的事实被检索进 B 项目,既影响效果也有隐私风险(这点上一篇的 checklist 里强调过)。 - 工具更新快,约定会变。
AGENTS.md正在成为跨工具事实标准,但各家加载顺序、import 语法、MCP 配置键仍在演进。落地前用小项目验一遍,别一上来就动主力仓库。
接入前可以先做一张兼容性表:工具版本、规则文件加载位置、import 或 symlink 是否支持、MCP 配置格式、失败时的错误提示。再用同一个小项目测试四种情况:新建会话、跨工具读取规则、写入一条长期记忆、修改单一事实源后重新加载。
Token 是否节省不必凭感觉判断。可以选三类相同任务,分别采用重复粘贴规则、共享静态文件、共享 MCP 记忆,记录上下文长度、工具调用次数和人工纠正次数。共享记忆的收益不只是少写几段提示词,还包括避免三个工具分别形成互相矛盾的项目事实。
收个尾:checklist
想让三个编码 Agent 共享记忆,照这张单子走:
静态规则层
- 选一个单一事实源,比如
~/.config/ai/AGENTS.md。 - 三个工具的规则路径全部软链(或 import)到它。
- 项目里让
AGENTS.md当真身、CLAUDE.md软链过去。 - 区分全局(个人偏好)和项目(团队约定),别混。
动态记忆层
- 把上一篇那套记忆库(打分+去重+加权检索)包成 MCP server。
- 三个工具都在各自配置里声明这个 MCP server。
- 记忆读写全走这个统一后端,带上
user_id/project_id隔离。
一句话:
静态规则靠"一份文件链三处",动态记忆靠"一个服务连三家"。
单一事实源,永远是治"多份不一致"的解药。
最后一句
工具会一直增多——今天是 Claude Code、Codex、OpenCode,明天可能又冒出来俩。但只要你守住一个原则:记忆只存一份,工具只是它的不同入口,那不管来几个新工具,你要做的都只是"再加一条链接、再连一次 MCP",而不是"再抄一遍规则"。
别让你的 AI 助手们,活成三个各记各账、互不通气的同事。
全文思维导图
@startmindmap
<style>
mindmapDiagram {
node {
BackgroundColor #F8F9FA
RoundCorner 10
Padding 10
FontSize 13
}
:depth(0) {
BackgroundColor #1E3A5F
FontColor white
FontSize 18
FontStyle bold
}
:depth(1) {
FontSize 15
FontStyle bold
}
:depth(2) {
FontSize 13
}
}
</style>
* 三个编码 Agent 共享记忆
** 痛点
*** 一套规则抄三份
*** 改了这个忘那个
*** 三个助手各说各话
** 各读哪份文件
*** Claude Code: CLAUDE.md
*** Codex: AGENTS.md
*** OpenCode: AGENTS.md
*** 都是磁盘上一个文件
** 静态规则层
*** 单一事实源
*** 符号链接(macOS/Linux)
*** import 引用(跨平台)
*** 全局 vs 项目分开
** 动态记忆层
*** 各工具自动记忆不互通
*** 用 MCP 做统一接口
*** 复用上一篇记忆库
*** 谁写的另俩都读得到
** 坑
*** 动态别写进静态文件
*** symlink 慎入 Git/Windows
*** MCP 记忆做用户/项目隔离
*** 工具更新快先小项目验
** 原则
*** 记忆只存一份
*** 工具是入口不是仓库
@endmindmap

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。 欢迎在我的个人网站 https://www.fanyamin.com 访问原文并评论。