Claude对话机制深度解析:为什么越聊越懂你?每句话都要读完整上下文吗?
先说几个核心判断。这个问题拆开看,其实涉及两套完全不同的机制:一套回答“上下文怎么装得下”,另一套回答“记忆是怎么延续的”。很多用户把这两件事混为一谈了,其实背后的实现逻辑完全是两码事。
一、每句话都要读整个上下文吗?——答案是“是,但也不完全是”
要理解这个看似矛盾的说法,得先搞明白 Claude API 最根本的工作方式。
1.1 LLM 天生“无状态”
Claude 的 API 是纯 HTTP 调用,每次调用之间它不记事儿。你每次敲回车,发生的事情是这样的:claude.exe 把 messages[] 数组完整打包,POST 给 API,API 返回一段新文本,然后结束。下一次你再来,claude.exe 重新打包一个新的 messages[](包含了上次的回复),再次 POST 过去。
换句话说,每一轮调用,整个 messages[] 都是完整发送的。模型确实要“读”整个上下文——到你当前消息位置为止的全部历史。
1.2 那上下文不会爆掉吗?——Compaction 自动压缩
每轮对话都往 messages[] 里追加新内容,迟早会撞上 200K token 的 context window 上限。Claude Code 的解决方案叫 Compaction(自动压缩)。从 System Prompt 里的原话来看,工作机制是这样的:
触发条件是 messages[] 的 token 数接近 context window 阈值。压缩过程分几步:先调用一个轻量模型(比如 Haiku),把 messages[] 前半部分(旧的)作为输入,生成一段摘要,概括用户的主要目标、已完成哪些步骤、哪些文件被创建/修改、当前在什么阶段。然后旧消息被替换为一条简短的 compaction summary,后半部分(最近的对话)原样保留。
举个例子:压缩前,messages[0] 是 MEMORY.md 索引,messages[1] 是 Git 状态,messages[2] 是用户的第一句话,messages[3] 是模型第一轮回复……几十轮之后,messages[20] 是用户最新的一句话。压缩后,messages[0] 还是 MEMORY.md 索引,messages[1] 还是 Git 状态,但 messages[2] 变成了 [COMPACTED: 前面的对话已摘要为一段文字...],然后 messages[3]、[4]、[5] 分别是用户最近几轮消息、模型最近几轮回复和用户最新一句话——这些是完整保留的。
所以准确的说法是:每句话确实读到“整个上下文”,但“整个上下文”不等于“全部历史”。旧的被压缩成摘要,新的原样保留——模型读到的是“摘要 + 近期全文”的组合。
这也是为什么 System Prompt 里有一条专门的指令告诉模型:“如果你看到内容看起来像是前面对话的摘要,请自然地从那个状态继续,不要重新提问。”如果不加这句话,模型看到摘要块可能会困惑:“前面细节丢了?我要不要重新问?”——这条指令就是在消除压缩带来的认知偏差。
相关配置项:autoCompactEnabled 控制是否启用自动压缩(默认开),autoCompactWindow 控制压缩触发阈值,precomputeCompactionEnabled 控制后台是否预计算压缩摘要,环境变量 DISABLE_COMPACT 可以强制关闭压缩。
二、那为什么越聊越懂你?——三重记忆机制在同时工作
上面说的是“每次调用的上下文怎么来的”,但真正让 Claude Code“越来越懂你”的,远不止 messages[] 这一个维度。实际上有三套独立的记忆机制同时在运转。
2.1 第一重记忆:System Prompt 中的动态注入
这是最隐蔽也最关键的一层。每次调用 API 前,claude.exe 会动态构建 System Prompt,往里注入 MEMORY.md(你的 .claude/projects/,相当于你的个人档案,之前跟它说的偏好、习惯、项目背景都存在这里)、gitStatus(当前仓库的 git 状态,分支、最近提交、变更文件)、currentDate(今天的日期)、CLAUDE.md(项目级别的指令文件)。
举个例子——某台机器上,System Prompt 中自动注入了渗透核心信念层文档、补天漏洞响应平台提交规范、3D 背景 + 玻璃 UI 叠加开发手册等。这些不是模型“记性好”,而是 claude.exe 在每次 API 请求时都把它们塞进了 System Prompt。模型每轮调用都能“看到”你之前沉淀下来的偏好和规则——这就是“越来越懂你”的第一重保障。
2.2 第二重记忆:对话转录的完整恢复(--resume)
当你敲 claude --resume 时,发生的不是“打开聊天记录浏览”,而是一次完整的状态重建。具体步骤是:读取 .jsonl 转录文件,提取所有 type="user" 和 type="assistant" 的消息,跳过 attachment、queue-operation、ai-title 等元事件,用提取的 messages[] 重建内存会话状态,每条消息的 role/content 原样恢复。然后重新构建 System Prompt(日期、Git 状态更新到今天),重新收集 MCP 服务工具定义(当前连接状态可能与上次不同),最后把恢复的 messages[] 加上新的 system/tools 发给模型。
关键点在于:System Prompt 和 tools[] 不存档,每轮实时构建。所以恢复后的对话既保留了完整的历史记忆,又更新了日期和工具状态。模型收到的是几乎一模一样的 messages[],体验上就是“无缝接上”。
2.3 第三重记忆:文件快照(/rewind)
还有一个独立于对话记忆的系统——file-history,存放在 ~/.claude/file-history/ 目录下。每次 Claude Code 修改你的文件前,它会先创建一份快照。当你用 /rewind 回退修改时,就是从这些快照恢复。这保证了“即使模型改错了,你的代码也能回到之前的状态”——这也算是一种“记得你之前文件长什么样”的表现。
三、底层怎么承载这些记忆?——三层存储架构
上面说了“记忆了什么”,现在来说“这些东西存在哪”。Claude Code 的对话存档分了三个物理层,每层职责不同。
C:UsersHI.claude 目录下,第一层是 history.jsonl(全局索引,轻量),第二层是 projects/(完整转录,重量),第三层是 sessions/(进程注册表)。
第一层:history.jsonl——对话目录
每条记录只存用户输入文本、时间戳、项目路径和 sessionId。不存模型回复,不存 System Prompt,不存工具调用。职责很简单:敲 claude --resume 时,列出所有历史对话标题,供你选择恢复哪个。
第二层:会话转录文件——完整事件流
这是真正的重量级存储。每个 .jsonl 文件存的是完整的对话事件流。第一行是 queue-operation(消息入队),第二行是 queue-operation(消息出队),第三行是用户说的话,第四行是当时的所有 skill 定义全文,第五行是自动生成的会话标题,第六行是模型的完整回复(思考 + 文本 + 工具调用),第七行是工具执行结果,第八行是模型基于结果的下一段思考……如此反复,数百到数千行。
每条 assistant 消息都完整记录了当时的 token 消耗、思考过程和工具参数。每条消息有 uuid,通过 parentUuid 形成完整因果链。比如用户消息(aaa) → 助理回复(bbb) → 工具调用 Glob → 工具结果(ccc) → 助理回复(ddd) → 工具调用 Read → 工具结果(eee) → 助理最终回复(fff),整个链条清清楚楚。
第三层:sessions/.json——进程注册表
这是最轻的一层,只有会话元数据(pid、sessionId、cwd、启动时间、版本、状态)。作用是告诉进程管理器:哪些会话还在运行,哪些已经结束。
四、写入时机:崩溃也不丢数据
存档不是“会话结束后一次性写入”——那样进程崩了全丢。JSONL 格式天然支持追加写入。每产生一个新事件,就往文件末尾追加一行。即使进程中途崩溃,已写入的行不丢。
写入顺序就是事件发生的顺序:用户敲下“介绍一下Harness”,立即写入 user message;模型开始思考,写入 assistant + thinking;模型决定调用 Glob,写入 assistant + tool_use;Glob 返回结果,写入 tool_result;模型继续生成,写入 assistant + text_delta。整个过程是实时、追加的。
五、TTL 与自动清理:记忆也有“保质期”
存档不会无限增长。cleanupPeriodDays 配置项默认是 30 天。30 天前的对话转录文件 (.jsonl) 会被自动清理,sessions/--resume 一个月前的对话——转录文件已经被清理掉了。
相关配置项:cleanupPeriodDays 控制保留天数(默认 30,最小 1),--no-session-persistence 参数可以完全不写转录文件。
六、实际数据量
在某台机器上,从 6 月 7 日到 6 月 29 日,22 天内积累了:history.jsonl 493 KB(全局索引),sessions/ 约 1 KB(进程注册表),projects/ 目录下 100 多个文件,总计约 114 MB。其中最大单次会话 1.86 MB,大约相当于 30 万字的对话量(含模型思考、工具调用、token 统计)。
七、总结
回到标题的两个问题。
为什么 Claude Code 越聊越懂你?因为它不是靠模型的“记性”,而是靠三层机制:System Prompt 每轮注入你的偏好记忆(MEMORY.md),messages[] 携带完整对话历史,--resume 可以完整恢复会话状态。这三重保障叠加,让你感觉它“记得”越来越多关于你的事。
每句话都要读整个上下文吗?是的——LLM 是无状态的,每轮 API 调用都发送完整 messages[]。但“整个上下文”不等于“全部历史”,Compaction 会把旧对话压缩为摘要,模型实际读的是“摘要 + 近期全文”的混合。这保证了即使聊了上百轮,也不会超出 context window。
底层,这一切由三层两速的追加式事件流系统承载:实时追加保证崩溃不丢数据,后台压缩保证上下文不爆窗,TTL 清理保证磁盘不爆炸。
数据来源:Windows 11 上 Claude Code v2.1.187 的实际存储目录
