5 种 AI 对话数据格式全解析

本文面向:想统一管理多个 AI 编程工具对话数据的开发者。

预计阅读时间:10 分钟

最终效果:理解 Claude Code、Codex、Cursor、Trae、Copilot 五种对话格式的结构、优劣与解析陷阱,明白为什么需要统一抽象层。

当你用 Claude Code 写了一下午代码、用 Cursor 调了半天 bug、用 Copilot 补全了一堆函数之后,你的对话数据散落在三种完全不同的文件格式里。如果你想把这些对话统一管理------导入、搜索、总结------你需要先理解每种格式的结构、优缺点和解析陷阱。

本文深入分析 ChatCrystal 支持的 5 种 AI 对话数据格式。

一、Claude Code:JSONL 文件

文件位置: ~/.claude/projects/ 目录下,按项目路径组织

文件格式: JSONL(JSON Lines),每行一个 JSON 对象

Claude Code 的对话记录是最"朴素"的格式。每个 JSONL 文件代表一次会话,每行是一个消息对象,包含 role(user/assistant)、content(文本内容)、type 等字段。

结构示例:

jsonl 复制代码
{"type":"user","message":{"role":"user","content":"帮我写一个 Fastify 插件..."}}
{"type":"assistant","message":{"role":"assistant","content":"好的,这是一个 Fastify 插件的模板..."}}
{"type":"tool_use","message":{"role":"assistant","content":[{"type":"tool_use","name":"write_file","input":{...}}]}}
{"type":"tool_result","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"...","content":"文件已写入"}]}}

解析难点:

  1. 系统标签污染。 Claude Code 的消息内容中经常混入 <system-reminder><command-name> 等 XML 标签。这些标签是 UI 渲染用的,对内容理解没有帮助,反而会干扰 LLM 的摘要生成。ChatCrystal 的 sanitizeContent() 函数会正则匹配并移除这些标签。

  2. 工具调用的嵌套结构。 assistant 消息的 content 有时不是纯字符串,而是一个数组,包含 tool_usetext 类型的混合。解析时需要递归处理。

  3. 连续工具消息的合并。 一个工具调用通常涉及三条消息:assistant 发起 tool_use、user 返回 tool_result、assistant 继续回复。这三条在语义上是一个整体,解析时需要把它们合并为一个"工具调用组"。

优势: 格式简单、可读性好、文件天然按会话分割、不需要额外依赖即可解析。

劣势: 没有元数据头(项目名、开始时间等需要从文件路径推断)、没有内置的索引机制。

二、Codex CLI:事件流 JSONL

文件位置: ~/.codex/sessions/ 目录下

文件格式: JSONL 事件流,每个 JSON 对象是一个事件

Codex CLI 的对话格式和 Claude Code 的 JSONL 有本质区别。它不是直接存储消息,而是存储事件流------一系列带时间戳的操作事件。

核心事件类型:

  • session_meta:会话创建,包含初始配置
  • event_msg:用户输入消息
  • response_item:AI 响应片段(可以是文本、工具调用、推理过程)
  • function_call:工具执行的调用和返回

解析难点:

  1. 对话需要"重建"。 和 Claude Code 的直接消息列表不同,Codex 的对话需要从事件流中重建。你需要遍历所有事件,把 event_msgresponse_item 按时间顺序组装成对话流。

  2. 响应碎片化。 AI 的回复不是一个完整的消息,而是多个 response_item 事件的拼接。有些是文本片段,有些是工具调用,有些是推理过程(chain of thought)。你需要把它们按类型分组,再组装成可读的对话。

  3. 事件顺序依赖时间戳。 如果时间戳精度不够,或者存在时钟回退,事件的顺序可能错乱。ChatCrystal 的解析器会做容错处理。

优势: 事件流保留了完整的操作历史(包括工具调用的输入输出),适合做审计和回放。

劣势: 解析复杂度高、文件体积大(每个事件都带完整元数据)、对话重建需要额外逻辑。

三、Cursor:SQLite 数据库

文件位置: Cursor 的 workspaceStorageglobalStorage 目录下的 state.vscdb

文件格式: SQLite 数据库,键值对存储

Cursor 没有使用文件系统来存储对话,而是用了 VS Code 的状态存储机制------一个 SQLite 数据库文件 state.vscdb。对话数据以键值对的形式存在数据库中。

数据结构:

  • Composer 元数据: 键名类似 composer.composerData,存储所有对话的 ID、标题、创建时间等元信息
  • Bubble 数据: 键名格式为 bubbleId:{composerId}:{bubbleId},存储每条消息的内容,包括用户输入和 AI 回复
  • 工具调用数据: 工具调用的输入输出单独存储在特定的键下

解析难点:

  1. 键值对的间接引用。 对话元数据和消息内容分开存储。你需要先读取元数据获取对话列表和消息 ID,再逐个查询消息内容。这种间接引用模式在数据量大时会产生大量查询。

  2. Blob 数据的编码。 某些值可能是二进制大对象(Blob)而非纯文本,需要判断类型并做相应解码。

  3. 数据库锁定。 如果 Cursor 正在运行,数据库文件可能被锁定。ChatCrystal 的 Cursor 适配器会在检测到锁定时给出提示,建议关闭 Cursor 后再导入。

  4. 数据量膨胀。 Cursor 会在同一个 state.vscdb 里存储远超对话的数据------设置、扩展状态、工作区配置等。一个典型的工作区数据库可能有数百 MB,但对话数据只占很小的比例。

优势: 结构化存储、支持复杂查询(SQL)、单文件管理所有状态。

劣势: 解析依赖 SQLite 库(ChatCrystal 用 sql.js WASM 避免原生依赖)、需要处理数据库锁定、数据模型复杂。

四、Trae:SQLite 数据库(变体)

文件位置: Trae 的 workspaceStorage 目录下的 state.vscdb

文件格式: SQLite 数据库,键值对存储

Trae 基于 VS Code 架构,数据存储方式和 Cursor 类似,但对话的数据模型有显著差异。

数据结构:

Trae 的对话数据存储在 memento/icube-ai-agent-storage 这个键下。每条记录代表一个 Agent 任务(AgentTask),包含:

  • taskId:任务唯一标识
  • taskTitle:任务标题
  • agentTaskContent:一个 JSON 数组,包含任务中所有消息
  • 每条消息有 rolecontentcontentType 等字段

解析难点:

  1. Agent 任务 vs 普通对话。 Trae 的对话模型是"任务制"而非"会话制"。一个任务可能包含多轮对话,但所有消息打包在 agentTaskContent 字段中。这和 Claude Code 的"一个文件一次会话"有本质区别。

  2. 内容类型的多样性。 contentType 不只有纯文本------还有代码块、工具输出、图片描述等。解析时需要按类型分别处理。

  3. 响应内容的提取。 Agent 的回复不是直接存储在 content 里,而是嵌套在特定的响应结构中。ChatCrystal 的 Trae 适配器会提取 content 字段中的文本内容,过滤掉结构化的元数据。

优势: 和 Cursor 类似,结构化存储、SQL 可查询。

劣势: 数据模型更复杂(嵌套 JSON 数组)、Agent 任务的粒度比会话更粗、某些字段的文档缺失需要逆向工程。

五、GitHub Copilot:JSONL 会话快照

文件位置: VS Code 的 workspaceStorage/<id>/chatSessionsglobalStorage/emptyWindowChatSessions

文件格式: JSONL,每行一个会话快照

Copilot 的数据格式相对规整。每个 JSONL 文件包含多个会话快照,每个快照是一个完整的对话记录。

数据结构:

每个快照以 kind:0 标记为完整会话快照,包含:

  • requests:用户请求列表,每条包含 message(用户输入)、timestampresponse(AI 响应数组)等。注意 response 是嵌套在每个 request 对象内部的字段,而非独立的顶层数组。

解析难点:

  1. 响应类型的多样性。 每个 request 内的 response 数组包含多种类型的条目(textthinkingtoolInvocationSerialized 等),需要按 kind 字段分别处理,提取有意义的文本内容。

  2. 会话快照的增量更新。 一个 JSONL 文件中可能包含同一会话的多个版本(每次保存都是完整快照)。解析时需要去重,只保留最新版本。

  3. 多窗口会话的分离。 Copilot 分 workspaceStorageglobalStorage 两个位置存储对话。工作区对话在各自的工作区目录下,全局对话(没有打开工作区时的对话)在 emptyWindowChatSessions 中。完整的导入需要扫描两个位置。

优势: 格式规整、数据结构清晰、JSONL 易于逐行解析。

劣势: 快照式存储导致文件体积冗余(同一个会话的多个版本)、响应类型多样需要分类处理。

格式对比总结

特性 Claude Code Codex CLI Cursor Trae Copilot
文件格式 JSONL JSONL SQLite KV SQLite KV JSONL
对话粒度 会话 事件流 Composer 对话 Agent 任务 会话快照
解析复杂度 中高 中低
外部依赖 sql.js sql.js
元数据丰富度
工具调用记录
增量更新支持 天然支持 天然支持 需查询 需查询 需去重

为什么格式统一很重要

5 种格式、5 种解析逻辑、5 种数据模型。如果每个工具都只能管理自己的对话,你最终会得到 5 个孤岛。

ChatCrystal 的 SourceAdapter 插件架构正是为了解决这个问题。每个适配器负责一种格式的解析,输出标准化的 ConversationMessage 类型。上层的导入服务、摘要服务、搜索服务不需要关心数据来自哪个工具------对它们来说,所有对话都是一样的。

这种抽象的价值在搜索时最为明显。当你搜"数据库连接池"时,搜索结果横跨所有 5 种工具的对话。你在 Claude Code 里讨论的架构设计、在 Cursor 里调试的连接泄漏、在 Copilot 里写的连接池代码,都被统一索引和检索。

这才是个人知识管理应有的样子------不被工具割裂


项目地址:github.com/ZengLiangYi/ChatCrystal

如有疑问欢迎在 GitHub Issues 或私信交流,很乐意解答。

相关推荐
东方佑1 小时前
递归创世:条件随机、自指递归与分形——一个贯穿真实世界、自然语言和大型语言模型的统一原理
人工智能·语言模型·自然语言处理
Python私教2 小时前
AI 代理只会在本地打转?我用 MCP 给它接上手脚,3 步接通第一个外部服务
agent·ai编程·mcp
jinxindeep3 小时前
CVPR26最佳论文提名:NitroGen,面向通用游戏智能体的 视觉-动作基础模型
人工智能·游戏
小雨下雨的雨7 小时前
井字棋AI机器人实现详解 - Minimax算法实战-鸿蒙PC Electron框架完成
前端·人工智能·算法·华为·electron·鸿蒙
我没胡说八道9 小时前
高校论文AI检测优化工具对比研究与实测分析(2026)
人工智能·深度学习·机器学习·计算机视觉·aigc·论文
秦亚伟9 小时前
AI浪潮重塑融资租赁行业新格局
人工智能
love530love10 小时前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
元启数宇10 小时前
喷淋AI布点实战:8小时人工布点→20分钟自动出图
人工智能
哈哈,柳暗花明10 小时前
人工智能专业术语详解(H)
人工智能·专业术语