想象一下,你是一位叫小明的程序员,正和Claude Code CLI一起排查一个诡异的线上Bug。你们像侦探搭档一样,你一句"我怀疑是缓存问题",它一句"看看Redis的TTL设置",来回几十轮对话,终于揪出了元凶------一个藏在第三方库里的时间戳溢出。
小明激动得拍大腿:"这段推理太精彩了!必须存下来当团队教材!" 于是,他在终端里敲下:
bash
/export --format markdown --output bug_solving_journey.md
瞬间,一份排版精美的Markdown文档就生成了,里面清晰记录了你们所有的对话、代码片段、甚至中间的工具调用结果。
这就是Claude Code CLI中 /export 命令的魔法------把会话中的智慧结晶,变成可分享、可复用的永久文档。
作为资深Claude Code CLI架构师,我将带你从小白视角 ,用一个有趣的故事 + 精确的时序图 + 核心代码伪实现,彻底搞懂/export的原理 和最佳用法。
🧙 故事:/export 背后的"三兄弟"
Claude Code CLI就像一个聪明的"对话工厂",而/export命令背后站着三位角色:
- 📋 记事本老伯(Session Manager) :负责记住你和AI说的每一句话、AI的每一次回答、甚至中间调用的工具(比如搜索代码、读取文件)。所有对话都像录像带一样,按时间顺序锁在他胸口的"会话保险箱"里。
- 🎨 排版大师(Formatter) :精通各种"文件语言"------Markdown、JSON、纯文本......他能把老伯那堆原始对话数据,按照你想要的风格"装修"成漂亮的文档。
- 💾 快递员小哥(File Writer) :最后一步,他把排版大师做好的文档,安全送到你指定的文件路径。如果路径冲突,他还会贴心地问"要覆盖吗?还是换个名字?"
你每次敲下/export,这三个角色就会默契地合作,流程大致如下:
🔧 原理深扒:从代码看"三兄弟"的真功夫
下面我们打开"工厂的监控录像",看看代码层面具体怎么实现。虽然是伪代码,但逻辑与真实Claude Code CLI高度一致。
1. 命令注册 ------ 告诉CLI:"我能处理 /export"
typescript
// 在命令注册中心
cli.registerCommand({
name: 'export',
description: '导出当前会话内容到文件',
options: [
{ flag: '--format', type: 'string', default: 'markdown', choices: ['markdown', 'json', 'text'] },
{ flag: '--output', type: 'string', required: true, help: '输出文件路径' },
{ flag: '--include-system', type: 'boolean', default: false, help: '是否包含系统提示' }
],
handler: exportHandler // 用户敲/export时,调用这个函数
});
2. 核心处理函数 exportHandler ------ 调度三兄弟
typescript
async function exportHandler(args: any, context: RuntimeContext) {
// 1. 从"记事本老伯"那里拿到当前会话的所有消息
const session = context.sessionManager.getCurrentSession();
const messages = session.getAllMessages(); // 包含时间戳、角色、内容、工具调用等
// 2. 根据用户选择的格式,叫对应的"排版大师"
let formattedContent: string;
switch (args.format) {
case 'markdown':
formattedContent = markdownFormatter(messages, args.includeSystem);
break;
case 'json':
formattedContent = jsonFormatter(messages, args.includeSystem);
break;
default:
formattedContent = textFormatter(messages, args.includeSystem);
}
// 3. "快递员小哥"写文件
const filePath = path.resolve(args.output);
const writer = new FileWriter({ overwrite: args.force || false });
const result = await writer.write(filePath, formattedContent);
// 4. 给用户反馈
console.log(`✅ ${result.messageCount} 条消息已导出至 ${filePath} (${result.bytesWritten} bytes)`);
}
3. 排版大师(Markdown版)------ 把对话变成优雅文档
typescript
function markdownFormatter(messages: Message[], includeSystem: boolean): string {
let md = `# Claude Code 会话导出\n**生成时间**: ${new Date().toISOString()}\n\n`;
for (const msg of messages) {
// 跳过系统消息(除非用户要求包含)
if (msg.role === 'system' && !includeSystem) continue;
// 根据角色添加Markdown风格
switch (msg.role) {
case 'user':
md += `## 👤 用户\n\n${msg.content}\n\n`;
break;
case 'assistant':
md += `## 🤖 Claude\n\n${msg.content}\n\n`;
// 如果助手调用了工具,把工具调用细节也以代码块展示
if (msg.toolCalls?.length) {
md += `**使用的工具**:\n```json\n${JSON.stringify(msg.toolCalls, null, 2)}\n```\n\n`;
}
break;
case 'tool':
md += `**🔧 工具结果** (${msg.toolName}):\n```\n${msg.content}\n```\n\n`;
break;
}
}
return md;
}
4. 快递员小哥 ------ 处理文件写入的细节
typescript
class FileWriter {
constructor(private options: { overwrite: boolean }) {}
async write(filePath: string, content: string): Promise<WriteResult> {
// 检查目录是否存在,不存在则创建
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
await fs.mkdir(dir, { recursive: true });
}
// 如果文件已存在且不允许覆盖,报错
if (fs.existsSync(filePath) && !this.options.overwrite) {
throw new Error(`文件 ${filePath} 已存在,使用 --force 覆盖或更换路径`);
}
// 异步写入
await fs.writeFile(filePath, content, 'utf-8');
const stats = await fs.stat(filePath);
return {
bytesWritten: stats.size,
messageCount: content.split('\n').filter(l => l.includes('## ')).length // 粗略统计
};
}
}
🧭 最佳用法:小白的"四板斧"
光知道原理还不够,关键是怎么用出花来。结合真实开发场景,我总结四个最佳实践:
1️⃣ 导出为Markdown,分享给团队(最常用)
bash
/export --format markdown --output docs/session_2025-04-08.md
什么时候用:解决完一个复杂问题后,把推理过程发给同事参考。Markdown在GitLab/GitHub上渲染完美,代码高亮自动保留。
2️⃣ 导出为JSON,做自动化分析
bash
/export --format json --output ./logs/chat.json --include-system
什么时候用:你想写脚本统计自己和AI的对话习惯(比如最常问哪类问题),或者把对话导入另一个AI进行二次训练。JSON结构化最方便解析。
3️⃣ 导出纯文本,快速复制到邮件或Notion
bash
/export --format text --output conversation.txt
什么时候用:你只需要对话文字,不需要任何格式折腾。纯文本文件小、兼容性最好。
4️⃣ 选择性导出(进阶技巧)------ 用"标签"做过滤器
虽然基础/export不支持直接按标签过滤,但聪明的你可以配合会话分支实现:
bash
# 先给某段关键对话打标签(伪命令,真实CLI可用/checkpoint)
/checkpoint bug_investigation
# 然后导出特定标签后的所有消息
/export --from checkpoint bug_investigation --format markdown --output final_report.md
(注:实际Claude Code CLI中可用/resume切换会话,再/export,效果一样)
⚠️ 三个坑,小白千万别踩
- 坑1:忘记
--output,命令报错
/export必须指定输出路径,因为AI不知道你想把文件存哪里。正确:/export --output myfile.md - 坑2:覆盖重要文件
默认情况下,如果文件已存在,/export会拒绝覆盖。想强制覆盖加--force,但建议先确认。 - 坑3:导出包含敏感信息
你的对话里可能藏有API密钥、内部IP、密码等。导出后别忘了审查一下,或者用--exclude(如果CLI支持)过滤掉包含敏感词的消息。
🎬 结尾:故事里的"破案笔记"诞生了
回到小明身上,他敲完/export --format markdown bug_solving_journey.md后,打开文件看到的是:
markdown
# Claude Code 会话导出
**生成时间**: 2025-04-08T14:32:00.000Z
## 👤 用户
我怀疑是Redis缓存的TTL设置有问题,你看这段代码:...
[代码块]
## 🤖 Claude
你说得对,TTL设置成了3600秒,但业务逻辑里...建议改成600秒并增加乱序处理...
**使用的工具**:
```json
[{"name": "read_file", "args": {"path": "src/cache/redis.go"}}]
🔧 工具结果 (read_file)
... 文件内容 ...
text
他把这份文档扔到团队群里,新人看完直呼"比任何教科书都生动"。而小明微微一笑,心想:"这不过是`/export`的日常操作罢了。"
现在,你也能像小明一样,把和AI的每一次精彩对话都变成永恒的财富。**记住:智慧需要被记录,而`/export`就是你的录音笔。**