Claude Code 如何恢复一段会话

一段 Claude Code 会话做到一半,关掉终端,之后再运行 claude --continue,通常还能接着做。终端里的旧消息会重新出现,能恢复的 agent 配置、Git worktree 等工作状态也会一并带回来。

这看起来像是"把日志重新读一遍",但真正的恢复分成两步:Claude Code 先从本地记录中重建一段可以继续操作的会话;等你输入新消息后,它才整理下一次发给模型的上下文。claude --resume <session-id> 走的是同一条主线,只是选择了指定会话。

下面沿着这条路径,看看会话是怎样被找到、重建并重新投入使用的:

先从 Claude Code 如何找到会话说起。

选择要恢复的会话

Claude Code 提供三个常用入口:

入口 用途
claude --continue 继续当前项目最近的一次会话
claude --resume <id 或名称> 返回指定会话;不带参数时打开选择器
/resume 在当前 Claude Code 中切换会话

会话按项目保存,所以"最近"指当前项目里的最近会话。选择器也可以扩展到同一仓库的其他 worktree,或者机器上的其他项目。

--continue--resume 在启动时恢复会话;/resume 在当前进程中切换会话。它们的入口不同,后面读取日志和恢复消息的步骤基本一致。

从 JSONL 中重建对话

JSONL(JSON Lines)是一种按行保存 JSON 数据的文本格式。每一行都是一条独立的 JSON 记录,因此程序可以在会话运行过程中不断向文件末尾追加新内容。

Claude Code 通常把每段会话保存为一份 JSONL 文件,默认位于 ~/.claude/projects/<项目目录>/<session-id>.jsonl。文件名中的 session-id 用来标识这段会话。

会话中的消息、工具调用和状态变化都会陆续写入这份文件。每行最外层的 typeJSONL 记录类型 ,用于告诉 Claude Code 该怎样读取和恢复这条记录。它不是对 AI 消息内容的分类,也不能简单理解成"user 是人说的话,assistant 是 AI 的文字回答"。

对于 userassistant 记录,内部还会有 message.role。两者通常与顶层 type 同名,但表达的是模型交互的方向:user 表示送入模型的一侧,assistant 表示模型返回的一侧。消息里具体装了什么,还要继续看 message.content

因此,看到顶层 type: "user" 时,还不能判断它是不是用户亲自输入。内部是 text,可能是用户消息;内部是 tool_result,就是工具返回给模型的结果。

读取 JSONL 后,Claude Code 会把可恢复的对话记录整理进内存中的 messageList。一次工具调用通常会形成四条记录:用户提出问题,模型发起 tool_use,工具以 tool_result 返回结果,模型再继续回答。界面上看起来像模型连续完成了"调用工具"和"给出结论",但 JSONL 中的两条 assistant 记录之间还有一条保存工具结果的 user 记录。

这类记录主要依靠下面两个字段连接:

字段 用途
uuid 标识当前消息
parentUuid 指向逻辑上的上一条消息,不一定是 JSONL 中紧邻的上一行

除了 userassistant,JSONL 还会保存会话控制与辅助记录。它们不会作为普通的用户消息或模型回答显示,主要用于恢复控制状态、会话信息、运行方式和工作环境。

type 记录的内容 恢复时的作用
system Claude Code 写入的运行时控制记录 根据 subtype 恢复对应的会话控制状态
summary 用于会话列表展示的简短概述 帮助识别会话,不作为普通对话内容恢复
custom-title 用户设置的会话标题 恢复会话列表中的标题
tag 用户给会话添加的标签 用于筛选和查找会话
agent-name agent 的显示名称 恢复会话列表和终端中的名称
agent-setting 当前会话使用的 agent 类型或名称 查找并重新应用对应的 agent 配置
mode 会话的运行模式 恢复相应的运行方式
worktree-state worktree 的名称、路径和分支等信息 worktree 仍存在时,重新进入原来的工作目录
file-history-snapshot 某个消息节点对应的文件备份索引 重建文件历史,供 rewind 恢复文件内容
pr-link 会话关联的 PR 信息 恢复会话与 PR 的关联关系

一条 worktree 状态记录如下:

这些记录通常通过 sessionId 归属到会话,再按 type 交给对应的恢复逻辑处理。system 记录可能参与 parentUuid 消息链;标题、标签和 worktree 等元数据通常不参与消息链。

正常对话通常只有一条路线。分叉通常出现在用户使用 /rewind 回到较早的消息,然后重新输入内容时。

这份会话日志采用追加写入:新消息产生后直接写到文件末尾,不需要每次都重写整个会话。这样写入更简单,即使中途退出,通常也不会影响前面已经保存的记录;消息的 uuid 也可以保持不变。

因此,rewind 只是改变"接下来从哪里继续",并不会删除已经发生的对话。新消息会追加到文件末尾,再通过 parentUuid 指向较早的消息,新旧两条路线也就同时留在了 JSONL 中。

下面是一个按真实字段精简的例子。为了方便阅读,省略了会话 ID、时间戳等无关字段:

前四行是一条完整的对话:用户先要求修复登录问题,随后决定改用 OAuth。接着,用户通过 /rewind 回到 a1 之后,把要求改成"只修密码登录"。因此,第五行虽然写在文件末尾,它的 parentUuid 仍然是 a1

这 6 行记录实际形成了两条路线:

假设本次要从 a3 继续,Claude Code 会沿着 parentUuid 向前查找:

text 复制代码
a3 → u3 → a1 → u1

再把顺序反过来,重建结果就是下面这 4 条按正常阅读顺序排列的消息:

text 复制代码
修复登录失败
→ 我先检查鉴权流程
→ 先不改方案,只修密码登录
→ 问题出在密码校验逻辑

a3 回溯并反转后,Claude Code 得到这次需要恢复的对话历史。它会先用这组消息恢复终端中的会话;等用户继续输入,再以此为基础准备下一次模型请求。

这个重建过程不会生成新的 JSONL,也不会重新生成摘要。磁盘上仍然保留 6 条记录,只是 u2a2 属于 OAuth 路线,不在当前消息链中。按这条路线恢复时,它们会被跳过,但仍会留在文件中占用空间。

如果对话之前已经压缩

压缩通常发生在会话运行期间,而不是恢复时。较早的对话被压缩后,Claude Code 会把压缩边界和已经生成的摘要也写入 JSONL。

假设压缩前的对话是:

text 复制代码
u1 → a1 → u2 → a2

压缩完成后,文件末尾会增加一条压缩边界 B 和一条摘要消息 S。这里的 S 不是前文用于会话列表展示的顶层 type: summary 记录,而是参与当前消息链的压缩结果。下面是按真实字段精简后的例子:

压缩边界中的几个字段分别表示:

字段 含义
subtype: compact_boundary 这不是普通系统消息,而是一次压缩的分界点
parentUuid: null 新的对话链从这里开始,不再沿父引用读取更早的原始消息
logicalParentUuid: a2 记录压缩前最后处理到 a2,但重建消息链时不会沿它向前查找
compactMetadata 保存压缩是自动还是手动触发,以及压缩前的大致 token 数
isCompactSummary: true 表示 S 是对早期对话的摘要,不是用户新输入的问题

摘要消息 SparentUuid 指向压缩边界 B。后续对话再从 S 继续:

text 复制代码
原始消息:u1 → a1 → u2 → a2

当前路线:B → S → u3 → a3

旧消息仍可能留在 JSONL 中,但已经不在当前路线里。

恢复时,Claude Code 从 a3 沿 parentUuid 向前查找,只会得到:

text 复制代码
B → S → u3 → a3

压缩边界是内部标记,不会作为普通聊天内容发给模型。因此,后续真正用于准备模型请求的是:

text 复制代码
早期对话摘要 S
→ 压缩后的新消息 u3、a3
→ 用户接下来输入的新消息

这个过程不会重新调用模型生成摘要,而是直接复用 JSONL 中已经保存的摘要。

恢复消息和工作状态

重建出对话历史后,还要处理上次没有正常结束的回合。例如:

  • 用户的问题已经写入日志,但回答还没开始:保留用户的问题,并补上不显示给用户的内部占位消息,让对话仍然保持一问一答的结构。
  • Claude Code 发出了工具调用,但工具还没有返回结果:移除这次未完成的工具调用,避免恢复出一段无法继续的消息。
  • 工具已经返回结果,但最终回答还没生成:加入一条不显示给用户的"继续处理"消息,标记这个回合是在中途停止的。

这些处理不会自动重跑工具,而是把消息整理成可以继续对话的结构。

除了消息,Claude Code 还会恢复"工作状态"。这里的工作状态,是指没有直接写在聊天正文里,但会影响接下来在哪个环境、以什么方式继续工作的记录。它不是整个进程的快照,也不会恢复一个已经停止的命令。

这些工作状态的相关记录也保存在当前会话的 JSONL 中。下面的例子只保留了与说明有关的字段:

恢复时,Claude Code 会把消息和状态记录分开处理:消息按照 parentUuid 重建,状态则按各自的类型读取,再写回当前进程。

工作状态 大概作用 之前存在哪里 恢复时怎么做
agent 设置 决定使用哪套提示词、工具范围和模型配置 JSONL 中的 agent-setting,只保存 agent 的名称或类型 在当前 settings 中找到对应 agent,并应用它现在的配置
worktree 让后续修改继续发生在原来的隔离目录和分支中,避免改错代码目录 JSONL 中的 worktree-state,保存名称、路径和分支等信息 检查目录是否存在;存在就切换过去,不存在就留在当前目录
文件读取记录 记录哪些文件已经读过,供 Edit 等工具进行编辑前校验 不单独保存,而是包含在 Read、Write、Edit 等工具消息中 扫描恢复后的消息,重新建立文件读取缓存
文件历史 保存文件在不同消息节点上的备份,执行 rewind 时可以把代码还原到当时的状态 JSONL 保存 file-history-snapshot,实际备份保存在配置目录的 file-history 按当前对话链重建快照,并重新关联对应的备份文件
会话信息 帮助用户识别和查找会话,本身不决定模型如何执行 JSONL 中的标题、标签和 agent 名称等记录 读取最后一次保存的值,恢复到会话列表和终端

从实现上看,读取阶段会先得到一个临时的恢复结果,其中包含消息、agent 设置、worktree、文件历史等数据。随后,这些数据会被分别写入消息列表、运行状态、缓存和当前工作目录:

这些数据写回后,Claude Code 得到的不是一份新的状态文件,而是一个已经恢复好运行环境的进程。模型上下文仍要等用户继续输入后再准备。

例如,上次会话使用代码审查 agent,在 fix-login worktree 中读取并修改了 src/auth.ts,随后测试工具执行到一半时终端被关闭。恢复后,Claude Code 会清理未完成的工具调用,重新进入仍然存在的 worktree,并恢复 agent、文件读取记录和文件历史,然后等待用户继续输入。

恢复是有条件的:Claude Code 会重新读取当前 settings,命令行参数可以覆盖会话中保存的设置;如果原 agent 已被删除,或者 worktree 目录已经不存在,就会退回当前可用的配置和目录。

终端里的旧消息,模型都会看到吗

不一定。会话恢复后,终端显示的是当前路线上的对话。下一次真正发给模型的内容,要等你继续输入时才开始整理。

Claude Code 会从最近一次压缩的位置接着读取历史。内容仍然太多时,较早的部分会继续被压缩,剩下的消息再转换成模型请求需要的格式。

这就会出现一种看似矛盾的情况:终端里还能翻到很早的对话,Claude 却没有接住其中某个细节。记录可能没有丢,只是那段内容没有完整进入这次请求,或者已经变成了摘要。当然,也可能是内容进了上下文,但模型没有用到它。

如果恢复后觉得前文被忘了,可以先看终端里的历史。这里已经少了一段,就回头检查会话选择、日志读取和消息链;终端记录还在,再看后续的上下文裁剪和压缩。排查时把这两层分开,就不容易绕错方向。

结语

Claude Code 的会话恢复,更像是把上次的工作重新接起来,而不是让程序回到关闭前的那一刻。JSONL 留下对话和状态记录,parentUuid 找回当前路线,仍然有效的工作状态再回到当前进程。

这套实现也提供了一个很实用的工程思路:日志不一定只是写给人看的几行字符串。JSONL 仍然是文本,但每一行都有固定结构,程序可以一边运行一边追加,也能在之后重新解析。

同一份日志还能保存多种类型的记录。对话消息、工具结果和工作状态各有自己的 type,读取时再交给不同逻辑处理。日志因此不只用于排查问题,也可以成为恢复状态的数据来源。

Claude Code 就是靠这些结构化记录把会话重新接起来。用户继续输入后,新的模型请求才会开始准备;日志保存的内容、终端恢复出的会话和模型最后收到的上下文相互关联,却不一定完全相同。

如果你觉得这篇文章有帮助,欢迎点赞、收藏,也可以关注我

相关推荐
En^_^Joy2 小时前
Django项目配置全攻略:settings配置文件
后端·python·django
就叫飞六吧3 小时前
目前App开发的主力语言和对应开发工具
ai编程
段一凡-华北理工大学4 小时前
AI推动工业智能化转型~系列文章20:工业 AI 平台架构:云-边-端协同的技术体系
人工智能·python·架构·工业平台·云-边协同
IT_陈寒5 小时前
Python线程池吞了异常还不告诉我,这谁顶得住啊
前端·人工智能·后端
CodeBlog-star5 小时前
Harness Engineering:Pi Agent 架构深度解析
人工智能·python·架构·harness工程
IT大白鼠5 小时前
OpenBao开源密钥管理系统:技术架构、核心功能与行业应用研究
架构·开源·aiops·openbao
小强库计算机毕业设计5 小时前
SpringBoot+Vue3 学生宿舍管理系统实战
java·spring boot·后端·vue·学生宿舍管理系统
小狼1835 小时前
实践6|SDD 实战:AI 写的规格被推翻了四次
后端·claude