
此项目的功能
AI Coding Assistant Data Extraction 会收集本地存储的多个编码助手对话,并将其写入统一的 JSONL 格式。它适用于备份聊天记录、进行个人数据分析、准备微调数据,或在应用清除本地数据库前保存对话。
该工具包会自动发现 macOS、Linux 和 Windows 上的存储位置。它无需第三方 Python 依赖即可读取 JSONL 文件、JSON 会话文件、Markdown 转录文件、SQLite 数据库和嵌套 JSON 存储树。
支持的来源
该项目目前支持以下工具:
- Claude Code:位于
~/.claude/projects/下的 JSONL 会话文件。 - Codex CLI:位于
~/.codex/sessions/下的 JSONL rollout 文件。 - Cursor:全局存储和工作区存储中的 SQLite
state.vscdb文件。 - Windsurf:使用尽力而为的启发式方法解析 SQLite 存储。
- Trae:使用尽力而为的启发式方法解析 SQLite 和 JSONL 存储。
- Continue:
~/.continue/sessions/中的 JSON 文件。 - Gemini CLI:位于
~/.gemini/tmp/下的 JSON 聊天文件。 - OpenCode:JSON 会话、消息和分段树。
- Cline 和 Roo Code:由编辑器扩展存储的 JSON 任务文件夹。
- Aider:项目目录中名为
.aider.chat.history.md的 Markdown 转录文件。
安装和设置
克隆或下载代码仓库,然后从项目根目录运行脚本。提取器仅使用 Python 标准库。需要 Python 3.9 或更高版本,建议使用 Python 3.10 或更高版本。
python --version
核心提取器无需创建虚拟环境或安装依赖。开始提取前,请确保已在计算机上使用过相关的 AI 编码工具,以便本地存在对话文件或数据库。
运行首次提取
如需使用交互式流程,请在不带参数的情况下运行主脚本。脚本会显示编号菜单,让你选择要提取的来源。
python extract.py
如需在不显示提示的情况下提取所有支持的来源,请使用 --all。
python extract.py --all
你也可以使用逗号分隔的列表选择特定来源。来源 ID 会显示在代码仓库的来源表中,也可以通过 --list 查看。
python extract.py --sources cursor,claude_code,aider
如需查看发现了哪些安装,但不提取任何对话,请运行:
python extract.py --list
在支持该命令的系统上,随附的 shell 快捷脚本可以执行所有来源的提取:
./extract_all.sh
选择输出和搜索路径
默认情况下,带时间戳的 JSONL 文件会写入 ./extracted_data。使用 --output-dir 可以选择其他目标目录。
python extract.py --all --output-dir ./chat-backup
大多数工具使用位置固定的应用数据目录,因此提取器会自动搜索常见的操作系统路径。Aider 则不同:它会在每个项目目录中存储一个 Markdown 转录文件,而不是使用集中式应用数据目录。
当你的项目或应用数据位于常规位置之外时,可以使用一个或多个 --search-path 选项。
python extract.py --sources aider \
--search-path ~/client-work \
--search-path /mnt/data/repos
对于其他受支持工具的非标准安装,额外的搜索路径同样有用。
将对话合并到一个文件
通常,每个选定的来源都会获得一个单独的带时间戳输出文件。添加 --merge 后,所有提取的对话还会被连接到 all_conversations.jsonl 中。
python extract.py --all --merge
典型的输出目录可能包含以下文件:
extracted_data/
├── claude_code_conversations_20260816_143022.jsonl
├── cursor_conversations_20260816_143022.jsonl
├── aider_conversations_20260816_143022.jsonl
├── cline_conversations_20260816_143022.jsonl
└── all_conversations.jsonl
了解标准化格式
输出文件中的每一行代表一个对话。通用结构包括 messages 数组、source 标识符和 session_id。其他字段取决于原始工具记录的内容。
{
"messages": [
{
"role": "user",
"content": "如何修复这个 TypeScript 错误?",
"code_context": [
{
"file": "/Users/you/project/index.ts",
"code": "const x: string = 123;"
}
],
"timestamp": "2026-01-16T14:30:22Z"
},
{
"role": "assistant",
"content": "这是因为将一个数字赋值给了字符串类型。",
"tool_use": [
{
"name": "edit_file",
"input": {"path": "src/index.ts"}
}
],
"timestamp": "2026-01-16T14:30:25Z"
}
],
"source": "cursor-composer",
"session_id": "c1a2b3...",
"project_path": "/Users/you/project",
"name": "修复 TypeScript 类型错误",
"created_at": 1705414222000
}
如果来源存储了 code_context、令牌使用量、项目路径、时间戳、工具调用和差异等信息,输出中也会包含相应字段。可以始终依赖的字段是 messages、source 和 session_id。
提取工作原理
- 程序会检测操作系统,并构建可能的数据根目录列表,其中包括
Application Support、.config、.local/share、%APPDATA%和%LOCALAPPDATA%等位置。 - 每个来源都会在这些根目录中搜索其已知的文件夹和文件名。
- 相应的读取器会加载 JSONL、JSON、SQLite、Markdown 或嵌套 JSON 存储。
- 提取器会将发现的记录规范化为共享的消息结构。
- 带时间戳的 JSONL 文件会写入输出目录。
SQLite 数据库以只读方式打开,有助于避免阻塞正在运行的编辑器。读取器彼此隔离,因此损坏或被锁定的文件只会产生部分结果,不会中止整个提取过程。
处理未公开的存储格式
Cursor、Windsurf 和 Trae 没有公开稳定的存储架构。Cursor 提取器明确支持多种已知结构,包括工作区 ItemTable 聊天数据、内联编写器数据,以及拆分存储的 bubbleId 编写器数据。
Windsurf 和 Trae 在 extractors/common.py 中使用通用启发式方法。它会搜索与聊天相关的键,并遍历解析后的 JSON,查找类似于由角色和文本组成的消息对的对象。这种方法有意采用尽力而为的策略。如果未来应用更新改变了存储结构,可能需要更新相应的 KEY_HINTS 值。
将输出用于训练数据
可以使用 Hugging Face 的 datasets 库加载规范化后的 JSONL 文件。以下示例会加载所有提取的文件,保留包含助手消息的对话,并使用分词器的聊天模板进行格式化。
from datasets import load_dataset
dataset = load_dataset(
"json",
data_files="extracted_data/*.jsonl",
split="train"
)
dataset = dataset.filter(
lambda x: any(m["role"] == "assistant" for m in x["messages"])
)
def format_chat(example):
return {
"text": tokenizer.apply_chat_template(
example["messages"],
tokenize=False
)
}
dataset = dataset.map(format_chat)
请根据模型的要求进一步检查和转换记录。不同来源可能包含不同的可选字段,因此训练流程应主要依赖共享的消息结构。
为提取器添加新来源
每个来源提取器都遵循一个由两个函数组成的小型接口。复制 continue_ext.py 即可获得一个简单的起点。
DISPLAY_NAME = "My Tool"
SOURCE_ID = "my_tool"
def find_installations(extra_paths: list[Path] | None = None) -> list[Path]:
"""返回值得扫描的目录或文件。"""
def extract(installations: list[Path]) -> list[dict]:
"""返回规范化的对话字典。"""
创建模块后,将其注册到 extract.py 中的 REGISTRY 列表。共享读取器和通用启发式方法位于 extractors/common.py 中。
保护敏感的对话数据
本地聊天历史可能包含 API 密钥、专有代码、个人路径、客户信息和工具输入。在共享提取文件或将其用于训练前,请先进行审核。
- 扫描输出中的机密信息。
- 仔细检查
code_context和tool_use字段。 - 不要将
extracted_data/提交到公共代码仓库。 - 将敏感备份保存在加密存储中。
pip install detect-secrets --break-system-packages
detect-secrets scan extracted_data/*.jsonl
项目已在 .gitignore 中包含 extracted_data/,但在发布任何内容前,你仍应核实代码仓库和备份实践。
故障排除
未找到安装
工具可能尚未安装、没有保存的聊天历史,或使用了非标准位置。先运行 --list,然后通过 --search-path 提供相关目录。你也可以检查来源提取器中的 SEARCH_DIRS 或 APP_DIR_NAMES 常量。
Cursor 或 Windsurf 报告数据库已锁定
提取器使用只读 SQLite 连接,因此正在运行的应用通常不会阻塞提取。如果错误仍然存在,请关闭应用后再次运行提取。
Windsurf 或 Trae 提取不到任何对话
使用 --list 确认是否找到了应用目录。如果已找到但没有提取出聊天记录,请检查相关的 state.vscdb 键,并在相应提取器的 KEY_HINTS 中添加匹配模式。
结论
AI Coding Assistant Data Extraction 提供了一种无需依赖项的方式,可跨多种存储格式和操作系统保存并规范化本地编程对话。首先运行 python extract.py --list,选择所需来源,检查生成的 JSONL 中是否包含敏感信息,然后将规范化记录用于备份、分析或经过谨慎准备的训练流程。
此工具包旨在处理安装在你自己计算机上的 AI 工具数据。你需要负责确认自己拥有提取数据的权利、保护敏感信息、遵守各工具的条款,并在共享或使用结果进行训练前扫描机密信息。
