Claude Code记忆系统深扒底层文件解析!!!——从.claude目录看Agent记忆架构

发布时间:2026/10/3 16:42:07
Claude Code记忆系统深扒底层文件解析!!!——从.claude目录看Agent记忆架构 1. 从一次「它怎么还记得」的困惑说起Claude Code 记忆架构到底存了什么你连续几天用 Claude Code 改同一个项目第一天跟它说「这个仓库统一用 pnpm别用 npm」第三天新开一个会话它居然还是照做。这时候大多数人会冒出一个念头它到底把我说的哪句话写进了磁盘存在哪个文件我能不能自己翻出来看我一开始也以为 Claude Code 背后挂了个向量数据库每次对话做一次语义检索把相关记忆捞出来塞进上下文。真去翻~/.claude/目录之后才发现它的记忆架构比想象中朴素得多也清晰得多——没有黑盒检索全是你能直接cat出来的纯文本和 JSONL。这套设计对想搞 Agent 记忆架构的人来说参考价值反而更高因为它把「什么进上下文、什么落磁盘、什么只增不删」这几件事拆得明明白白。先把结论摆前面Claude Code 的记忆分三层各管各的层级存储位置LLM 能直接检索吗会话结束后上下文窗口内存messages[]直接看到清空持久化记忆memory/MEMORY.md 四类 md索引注入按需加载保留完整转录history.jsonlprojects/*.jsonl不能新会话不加载保留但不回灌理解这张表你就理解了 Claude Code 记忆系统的全部骨架。第一层是「正在聊的」第二层是「跨会话要记住的」第三层是「留档备查但默认不读的」。很多人把第三层误当成记忆其实它更像日志——写得很全但新会话不会主动去翻。这篇会带你从.claude目录出发把CLAUDE.md、MEMORY.md、history.jsonl、projects/xxx.jsonl这几个底层文件的字段逐个拆开再给一套可复制的目录结构和验证记忆读写行为的操作步骤。适合谁看正在用 Claude Code 做长期项目的人、想自己设计 Agent 记忆持久化方案的开发者、以及被「compact 之后旧对话去哪了」困扰过的人。顺带说一句如果你还没开始用 Claude Code或者想先低成本验证模型行为再决定要不要深入可以先用 TaoToken 的模型对话快速试一轮地址是 https://taotoken.net/api 配合接入文档 https://taotoken.net/api-keys 拿 Key 就能跑不用一上来就折腾本地环境。2. 前置准备TaoToken 接入与 Claude Code 环境打通在深扒文件之前得先让 Claude Code 能正常跑起来否则你连一个projects/xxx.jsonl都生成不出来。这一节讲清楚两件事怎么拿到可用的 API Key以及怎么把 Claude Code 指向正确的 Base URL。先说 TaoToken 这边。它的定位是给 Claude Code、Cline、Codex 这类编码 Agent 提供统一的模型接入入口你不需要在本地维护一堆供应商配置。拿 Key 的路径很直接打开 https://taotoken.net/api-keys 登录后在控制台创建 API Key复制出来形如sk-xxxxxxxx的字符串。这个 Key 后面要填进 Claude Code 的环境变量或配置文件里。如果你只是想先验证模型能不能正常对话不想动 Claude Code那用模型对话页面最省事https://taotoken.net/api 。输入一句话看它回不回确认 Key 有效、额度正常再往下走。接下来是 Claude Code 侧的配置。Claude Code 读取配置的优先级大致是环境变量 项目级.claude/settings.json 全局~/.claude/settings.json。最省心的做法是设两个环境变量让所有会话都生效export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的Key把这两行写进~/.zshrc或~/.bashrcsource一下再启动claude就能连上。注意 Base URL 这里不要带任何查询参数保持干净的https://taotoken.net/api即可。如果你更习惯用配置文件而不是环境变量可以在~/.claude/settings.json里写{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的Key } }这里有个坑要提前说settings.json是 JSON 格式不能写注释末尾不能有多余逗号否则 Claude Code 启动时会静默忽略整个文件你会以为配置没生效其实是解析失败了。改完文件后建议用python -m json.tool ~/.claude/settings.json校验一下语法。环境通了之后随便在一个项目目录里跑一次claude问它一句话比如「列出当前目录的文件」让它产生一轮真实对话。这一步的目的是生成projects/xxx.jsonl后面解析字段要用到。如果你连这一步都跑不通先别急着看记忆架构回到排障那节对照报错处理。配置完成后你的~/.claude/目录会开始积累文件。第一次跑可能只有settings.json和history.jsonl多聊几轮、多开几个项目projects/下的目录才会丰富起来。理解记忆架构的前提是你手里有真实的文件可以对照所以这一步别跳过。3. 可复制配置.claude 目录结构与 CLAUDE.md / MEMORY.md 字段解析这一节是全文的核心我们把.claude目录摊开逐个文件讲清楚它存什么、字段什么含义、什么时候被读写。先看完整的目录结构你可以直接对照自己的机器~/.claude/ ├── CLAUDE.md # 全局硬指令每次会话无条件全量加载 ├── settings.json # 权限、钩子、模型、env 配置 ├── history.jsonl # 跨会话用户输入索引只增不删 ├── stats-cache.json # 使用统计缓存 ├── projects/ │ └── -你的项目路径编码-/ │ ├── memory/ │ │ ├── MEMORY.md # 记忆索引每次会话注入 │ │ ├── feedback_autonomous_permission.md │ │ ├── project_learn_claude_code.md │ │ ├── reference_csdn_writer.md │ │ └── study_plan_langchain4j.md │ └── session-uuid.jsonl # 完整会话转录 ├── sessions/ # 会话元数据 ├── session-env/ # 会话环境变量 ├── plans/ # Plan 模式产出 ├── tasks/ # Task 系统持久化 ├── file-history/ # 文件编辑历史用于 undo ├── skills/ # 自定义 Skill ├── plugins/ # 插件系统 ├── cache/ # 远程数据缓存 ├── backups/ # 设置自动备份 └── paste-cache/ # 粘贴内容去重重点看CLAUDE.md和memory/这两块它们是「跨会话记忆」的全部来源。CLAUDE.md是硬指令层。它和MEMORY.md最大的区别在于加载方式CLAUDE.md每次会话无条件全量塞进系统提示不管当前问题相不相关MEMORY.md只是把索引注入具体内容按需加载。所以CLAUDE.md里应该放「必须遵守的规则」比如「所有回答用中文」「提交信息用 conventional commits 格式」「不要自动执行 git push」。放太多背景知识进去会白白吃掉上下文预算。memory/MEMORY.md是索引文件不是记忆内容本身。它长这样- [用户偏好中文回答](feedback_use_chinese.md) - [ThoughtCoding 学习项目](project_thoughtcoding.md) - [CSDN 文章写作规范](reference_csdn_writer.md)每一行是一个指针指向同目录下的一个 md 文件。LLM 看到索引后判断哪些跟当前问题相关再按需读取对应文件。索引超过 200 行会被截断所以别往里堆太多条目。四种记忆类型按文件名前缀区分这个约定很重要决定了 LLM 怎么理解这条记忆的性质前缀存什么举例user_用户身份、技能水平、偏好「Java 开发者偏好中文回答」feedback_行为纠正、工作方式偏好「不确定时先问不要乱搜」project_项目背景、进度、目标「正在学习 ThoughtCoding」reference_外部资源位置「CSDN 写作规范和发布流程」单个记忆文件的格式没有强约束但实践下来最有效的是「一句话结论 简短背景」。比如feedback_autonomous_permission.md里写「执行破坏性命令前必须先确认不要自动 rm」比写一大段解释更容易被 LLM 稳定遵守。这里给一个可以直接复制的settings.json片段把 env 和权限一起配好{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的Key }, permissions: { allow: [Read, Glob, Grep], ask: [Bash] } }注意permissions里的allow和ask是数组写错类型会导致整个配置失效。改完记得校验 JSON 语法。如果你用的是 Cline 或 Codex 这类同样支持自定义 Base URL 的工具配置逻辑一致三件套永远是 Base URL Key Model ID。以 Codex 的auth.json为例结构大致是{ OPENAI_API_KEY: sk-你的Key, OPENAI_BASE_URL: https://taotoken.net/api }Model ID 按你实际要用的模型填别照抄别人的不同模型在编码任务上的表现差异很大。想先对比再决定可以用模型对话页面快速试几个https://taotoken.net/api 。4. 验证记忆读写history.jsonl 与 projects/xxx.jsonl 字段实测配置好了文件也在积累接下来最关键的一步是验证「记忆到底什么时候写、写进哪个文件」。这一节给你可复制的命令和字段解析让你亲眼看到读写行为。先看history.jsonl。它的位置是~/.claude/history.jsonl每行一条 JSON只存用户输入不存 AI 回复{display:hello,timestamp:1776417590819,sessionId:66f1b428-...}字段含义很直白display是你输入的原文timestamp是毫秒时间戳sessionId标识属于哪个会话。它跨所有会话累积实时追加只增不删。你可以用这条命令看最近 5 条tail -n 5 ~/.claude/history.jsonl | python -m json.tool --json-lines再看projects/xxx.jsonl这是完整转录位置在~/.claude/projects/路径编码/session-uuid.jsonl。路径编码是把项目绝对路径里的/换成-比如/Users/me/code/demo会变成-Users-me-code-demo。每条消息完整记录{type:user,message:{role:user,content:帮我写代码},sessionId:...,timestamp:...} {type:assistant,message:{role:assistant,content:[{type:text,text:...}]},sessionId:...,timestamp:...}type区分 user / assistantmessage.content里 assistant 的响应是数组结构可能包含 text、tool_use、thinking 等多种块。用户输入、AI 回复、工具调用、thinking 过程全在里面是完整对话的每一帧。两者的关系打个比方history.jsonl是你看过的电影片名列表projects/xxx.jsonl是整部电影每一帧画面。现在做验证实验。第一步开一个新会话问一句话然后立刻不要等会话结束去看 JSONLls -lt ~/.claude/projects/-你的项目路径编码-/ | head tail -n 3 ~/.claude/projects/-你的项目路径编码-/*.jsonl你会看到刚才那一轮对话已经在文件里了时间戳就是当时的。这说明对话是实时落盘的不是等 compact 或会话结束才写。第二步验证 compact 的行为。找一个行数较多的会话文件记下当前行数wc -l ~/.claude/projects/-你的项目路径编码-/session-uuid.jsonl然后在会话里执行/compact再数一次行数。实测下来压缩后行数只会变多不会变少。新增的行包括系统重载CLAUDE.md tools skills、压缩摘要作为 user 消息注入、以及/compact命令本身和重新挂载的附件。原始对话一行没删。第三步验证记忆索引的注入。在memory/MEMORY.md里加一行指针新开一个会话问一个跟这条记忆相关的问题观察它是否按需读取了对应文件。这一步能让你直观感受到「索引注入 按需加载」和「全量加载」的区别。把这三步跑完你对 Claude Code 记忆读写的时机就有了实感对话实时写 JSONLcompact 只追加摘要不改磁盘记忆索引每次会话注入但内容按需加载。5. 常见报错排查401、local proxy failed、reading choices、OAuth 对照处理配置和验证过程中最容易卡在几个固定报错上这一节按真实报错逐条给排查路径。401 Unauthorized。最常见的原因是 Key 没生效或写错了。先确认环境变量真的被读到了echo $ANTHROPIC_API_KEY echo $ANTHROPIC_BASE_URL如果输出为空说明source没执行或者写错了文件。如果 Key 有值但还是 401检查是不是复制时带了空格或换行重新从 https://taotoken.net/api-keys 复制一次。还有一种情况是settings.json里的 env 和环境变量冲突Claude Code 的优先级可能导致你以为生效的其实没生效建议只保留一处配置。local proxy failed。这个报错通常出现在 Base URL 填错或网络不通时。先确认 URL 是https://taotoken.net/api不要多加路径或参数。然后用 curl 直接测一下连通性curl -s -o /dev/null -w %{http_code} https://taotoken.net/api返回 4xx 说明能连通但请求格式不对返回超时或连接失败说明网络层有问题。注意不要在任何配置里引入本地代理端口那会引入额外变量排查起来更麻烦。reading choices 相关报错。这类报错一般出现在响应体解析阶段说明返回的 JSON 结构跟客户端预期不一致。常见原因是 Model ID 填错或者 Base URL 指向了一个不兼容 Anthropic 消息格式的端点。确认你用的 Model ID 是实际可用的别照抄文档里的示例值。如果换了 Model ID 还是报错用模型对话页面单独测一次同一个模型隔离是客户端问题还是模型问题https://taotoken.net/api 。OAuth 相关报错。Claude Code 某些版本会走 OAuth 流程如果你已经用 API Key 配置了却还弹出 OAuth 登录说明配置没被识别。检查settings.json是否语法正确、env 字段是否拼写正确。OAuth 和 API Key 两种模式不要混用选一种配到底。排查时有个通用原则先隔离变量。把问题拆成「Key 是否有效」「URL 是否可达」「Model 是否可用」「客户端配置是否被读取」四层逐层用最小命令验证比盯着一个报错猜要快得多。上面给的 curl 和 echo 命令就是干这个用的。如果排查完发现是额度或账号问题回到控制台 https://taotoken.net/console 看用量和状态。长期做编码和 Agent 任务的话Coding Plan 通常比按量更划算可以在这里了解https://taotoken.net/coding-plan 。6. 把记忆架构用起来从文件解析到 Agent 设计的落地建议扒完文件最后聊点能直接落地的。Claude Code 这套记忆架构最值得借鉴的地方是它把「硬指令」和「软记忆」彻底分开了。CLAUDE.md是无条件加载的行为约束MEMORY.md是按需加载的知识索引两者混在一起会让上下文预算失控。你自己设计 Agent 记忆时也应该先问一句这条信息是「必须每次都遵守的规则」还是「可能相关的背景」前者进硬指令层后者进索引层。第二个可借鉴的点是「转录只增不删但不回灌」。projects/xxx.jsonl存了完整对话可新会话默认不加载它。这意味着磁盘上的历史是给人和调试用的不是给模型检索用的。Claude Code 没有做 EpisodicMemory 检索——存了但不用。如果你要做真正的长期记忆 Agent这一层是需要你自己补的比如加一个检索步骤从 JSONL 里捞出相关历史再注入上下文。第三个点是 compact 的语义。它只改内存不改磁盘把前面几十轮总结成一段摘要追加在 JSONL 末尾原始对话完整保留。这个设计的好处是可回溯你随时能翻到压缩前的原文。坏处是磁盘只增不减长期项目要留意projects/目录的体积必要时手动归档。实操建议定期整理memory/MEMORY.md把过时的指针删掉索引控制在 200 行以内CLAUDE.md只放真正必须遵守的规则别当笔记本用想验证某条记忆有没有生效就新开会话问一个相关问题看它是否按需读取了对应文件。如果你还没配好环境回到第 2 节把 Base URL 和 Key 设好用 https://taotoken.net/api-keys 拿 Key接入文档在 https://taotoken.net/api 。想先验证模型行为再深入模型对话入口是 https://taotoken.net/api 。长期跑编码和 Agent 任务Coding Plan 会更省心https://taotoken.net/coding-plan 。