想象一下,你是一位名叫“小克”的 AI 编程助手,每天要跟无数开发者聊天。每个对话都是一本魔法日记——里面写满了代码、思考、报错和解决方案。但问题来了:如果用户说“刚才那个 bug 我们再看看”,你该怎么办?难道要失忆吗?
当然不!/resume 就是你的时光回溯魔法。它让你像翻书一样,找到之前的某本日记,打开那一页,然后接着写下去。
📖 实现原理:三件魔法神器
1. 会话存档器(Session Archiver)
每次对话,小克都会悄悄把所有消息、上下文、文件快照(如果有)保存成一个 JSON 文件。就像一个自动写日记的魔法羽毛笔。
// 简化的会话保存逻辑
interface Message {
role: 'user' | 'assistant' | 'system';
content: string;
timestamp: number;
// 附带的技术元数据
toolCalls?: ToolCall[];
fileSnapshots?: Record<string, string>;
}
interface Session {
id: string; // 例如 "sess_20240315_143022"
title: string; // 自动生成或用户自定义
messages: Message[];
cwd: string; // 工作目录
createdAt: number;
lastActiveAt: number;
// 支持分支!就像 git 的 commit
parentSessionId?: string; // 从哪个会话恢复来的
branchName?: string;
}
class SessionArchiver {
private storageDir = '~/.claude/sessions';
async save(session: Session): Promise<void> {
const filePath = `${this.storageDir}/${session.id}.json`;
await fs.writeJson(filePath, session);
}
async list(): Promise<SessionMeta[]> {
const files = await fs.readdir(this.storageDir);
return files
.filter(f => f.endsWith('.json'))
.map(f => fs.readJson(`${this.storageDir}/${f}`))
.sort((a,b) => b.lastActiveAt - a.lastActiveAt);
}
async load(id: string): Promise<Session> {
return fs.readJson(`${this.storageDir}/${id}.json`);
}
}
2. 记忆编织机(Context Weaver)
当你执行 /resume 并选择一个旧会话,小克不会简单地把历史消息“倒带”重放。它会重建整个心理状态:
- 加载所有历史消息(包括 assistant 之前的回复)。
- 重新注入当时的环境变量、工作目录。
- 如果涉及文件编辑,恢复文件快照(或依赖 git diff 重建心智模型)。
class ContextWeaver {
async weave(session: Session): Promise<ClaudeContext> {
// 1. 构建消息数组(完整历史)
const messages = session.messages.map(m => ({
role: m.role,
content: m.content
}));
// 2. 恢复文件状态(可选)
if (session.fileSnapshots) {
await this.restoreFileSnapshots(session.fileSnapshots);
}
// 3. 注入系统提示:“你正在恢复 2024-03-15 的会话,以下是之前的对话...”
const systemPrompt = this.buildSystemPrompt(session);
return { messages, systemPrompt, cwd: session.cwd };
}
private buildSystemPrompt(session: Session): string {
return `你正在恢复一个旧会话(ID: ${session.id},最后活跃于 ${new Date(session.lastActiveAt)})。
以下是该会话的历史消息。请接着这个上下文继续回答,就像刚才还在聊天一样。
如果用户询问之前的内容,你可以引用历史。`;
}
}
3. 分支魔法(Branching)
Claude Code CLI 最酷的功能之一:会话分支。假如你从一个旧会话恢复,然后聊了新的内容,系统会创建一个新会话,但标记 parentSessionId 指向旧的。这样你就有了一棵对话树——就像平行宇宙!
# 示例会话树
sess_001 (初始对话)
├─ sess_002 (从 001 /resume 后继续)
└─ sess_003 (又从 001 /resume,但走了另一条路)
这让你可以回到某个决策点,尝试不同的 AI 建议,而不丢失任何分支。
⏱️ 时序图:/resume 的完整调用过程
🧙 最佳用法:小克给你的六条锦囊
1. 给会话起个好名字
不要默认用 会话 2024-03-15 14:30:22。用 /title 命令改名,比如“支付接口幂等性设计”。以后 /resume 一眼就能找到。
2. 频繁保存关键节点
遇到复杂 bug 或设计决策前,手动触发 /save(如果有)或直接 /resume 后再 /branch。分支就是你的“存档点”。
3. 利用恢复来“热启动”
早上上班,直接 /resume 昨天的会话,不用重新描述项目背景。省下 10 分钟上下文 token。
4. 清理无用会话
用 /sessions prune(如果支持)或手动删除 ~/.claude/sessions/ 下的旧文件。否则会像衣柜一样爆满。
5. 恢复后验证环境
如果之前你让 AI 改了 config.js,恢复会话时,Claude Code 不会自动撤销文件修改。建议在恢复后手动 git diff 确认状态。或者使用内置的文件快照功能(如果开启)。
6. 分支实验
遇到不确定的方案:
当前会话: “方案A 用 Redis”
/resume 回到选择前的会话
然后说 “试试方案B 用 Memcached”
这样你就有两个分支,可以分别对比 AI 的建议。
🎯 真实代码示例:手动实现一个极简版 /resume
假设你正在写一个自己的 CLI 工具,想模拟这个行为:
#!/usr/bin/env python3
import json, os, sys
from datetime import datetime
from pathlib import Path
SESSIONS_DIR = Path.home() / ".my_cli_sessions"
SESSIONS_DIR.mkdir(exist_ok=True)
class SessionManager:
def __init__(self):
self.current_session = None
self.messages = []
def new_session(self, title=None):
sess_id = f"sess_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
title = title or f"会话 {sess_id}"
self.current_session = {"id": sess_id, "title": title, "messages": []}
self.messages = []
self._save()
return sess_id
def _save(self):
if self.current_session:
path = SESSIONS_DIR / f"{self.current_session['id']}.json"
with open(path, 'w') as f:
json.dump(self.current_session, f, indent=2)
def list_sessions(self):
sessions = []
for p in SESSIONS_DIR.glob("*.json"):
with open(p) as f:
data = json.load(f)
sessions.append((data['id'], data['title'], len(data['messages'])))
return sessions
def resume(self, sess_id):
path = SESSIONS_DIR / f"{sess_id}.json"
if not path.exists():
print("会话不存在")
return False
with open(path) as f:
self.current_session = json.load(f)
self.messages = self.current_session['messages']
print(f"✅ 已恢复 '{self.current_session['title']}',共 {len(self.messages)} 条消息")
# 打印最后几条历史作为上下文提醒
for msg in self.messages[-3:]:
print(f"[{msg['role']}]: {msg['content'][:50]}...")
return True
def add_message(self, role, content):
msg = {"role": role, "content": content, "timestamp": datetime.now().isoformat()}
self.messages.append(msg)
if self.current_session:
self.current_session['messages'] = self.messages
self.current_session['lastActiveAt'] = datetime.now().isoformat()
self._save()
def chat_loop(self):
if not self.current_session:
self.new_session()
print("进入对话模式 (输入 /resume 列出会话, /exit 退出)")
while True:
user_input = input("\n> ")
if user_input == "/exit":
break
elif user_input == "/resume":
sessions = self.list_sessions()
print("\n可恢复的会话:")
for idx, (sid, title, cnt) in enumerate(sessions):
print(f"{idx+1}. {title} ({cnt}条消息) [{sid}]")
choice = input("请输入编号: ")
try:
chosen = sessions[int(choice)-1][0]
self.resume(chosen)
except:
print("无效选择")
continue
# 正常消息
self.add_message("user", user_input)
# 这里本该调用 AI API,我们模拟 AI 回复
ai_reply = f"小克收到: {user_input} (基于 {len(self.messages)} 条历史)"
print(f"🤖 {ai_reply}")
self.add_message("assistant", ai_reply)
if __name__ == "__main__":
sm = SessionManager()
sm.chat_loop()
运行一下:
$ python mini_resume.py
进入对话模式 (输入 /resume 列出会话, /exit 退出)
> 帮我写个排序算法
🤖 小克收到: 帮我写个排序算法 (基于 2 条历史)
> /resume
可恢复的会话:
1. 会话 sess_20240315_151022 (2条消息) [sess_20240315_151022]
请输入编号: 1
✅ 已恢复 '会话 sess_20240315_151022',共 2 条消息
[user]: 帮我写个排序算法...
[assistant]: 小克收到: 帮我写个排序算法...
🌟 总结:为什么要爱 /resume
- 省 token:不用重复喂上下文,Claude 直接“记起来”。
- 省时间:不用重新描述项目结构、报错信息。
- 可回溯:犯错后可以回到之前的某个状态,重新尝试。
- 分支探索:并行试验多个 AI 方案,互不干扰。
现在,你已经是 /resume 的魔法学徒了。快去 Claude Code CLI 里输入 /resume,看看你之前留下的那些“日记本”吧!📓✨