跳到主要内容
AI教程

使用 Python 提取并规范化 AI 编程助手聊天记录

了解如何使用 AI 编程助手数据提取工具,从 Claude Code、Codex CLI、Cursor、Windsurf、Trae、Continue、Gemini CLI、OpenCode、Cline、Roo Code 和 Aider 中发现本地聊天记录,并将其转换为规范化 JSONL,以便备份、分析或训练。

使用 Python 提取并规范化 AI 编程助手聊天记录

此项目的功能

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。

提取工作原理

  1. 程序会检测操作系统,并构建可能的数据根目录列表,其中包括 Application Support、.config、.local/share、%APPDATA% 和 %LOCALAPPDATA% 等位置。
  2. 每个来源都会在这些根目录中搜索其已知的文件夹和文件名。
  3. 相应的读取器会加载 JSONL、JSON、SQLite、Markdown 或嵌套 JSON 存储。
  4. 提取器会将发现的记录规范化为共享的消息结构。
  5. 带时间戳的 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 密钥、专有代码、个人路径、客户信息和工具输入。在共享提取文件或将其用于训练前,请先进行审核。

  1. 扫描输出中的机密信息。
  2. 仔细检查 code_context 和 tool_use 字段。
  3. 不要将 extracted_data/ 提交到公共代码仓库。
  4. 将敏感备份保存在加密存储中。
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 工具数据。你需要负责确认自己拥有提取数据的权利、保护敏感信息、遵守各工具的条款,并在共享或使用结果进行训练前扫描机密信息。