AI Coding JSONL 里的系统标签噪音如何过滤

本文面向:想了解 Claude Code 数据格式细节的开发者,或在解析 JSONL 时遇到问题的人。 预计阅读时间:6 分钟


问题

Claude Code 的 JSONL 文件里,每行是一个 JSON 对象。但不是每一行都是有用的对话内容。大量系统生成的噪音混在里面,如果不过滤,生成的笔记质量会很差。

JSONL 里都有什么

一个典型的 Claude Code JSONL 文件里,你可能看到这些类型的消息:

类型 是否有用 说明
user ✅ 有用 用户输入
assistant ✅ 有用 AI 回复
system ❌ 噪音 系统消息(api_error、compact_boundary 等)
file-history-snapshot ❌ 噪音 文件历史快照
progress / agent_progress ❌ 噪音 进度信息
tool_use ❌ 噪音 工具调用流式片段
tool_result ❌ 噪音 工具结果流式片段
thinking ❌ 噪音 思考过程流式片段
text ❌ 噪音 文本流式片段
无 uuid 的行 ❌ 噪音 流式传输的中间状态

有用的只有 userassistant 类型的完整消息(有 uuid)。

ChatCrystal 的过滤逻辑

typescript 复制代码
const SKIP_TYPES = new Set([
  'file-history-snapshot',
  'last-prompt',
  'progress',
  'agent_progress',
  'hook_progress',
  'queue-operation',
  'message',      // streaming delta
  'tool_use',     // streaming tool delta
  'tool_result',  // streaming tool result delta
  'thinking',     // streaming thinking delta
  'text',         // streaming text delta
  'tool_reference',
]);

function isRelevantMessage(line: RawMessage): boolean {
  if (!line.uuid) return false;           // 过滤流式片段
  if (line.type && SKIP_TYPES.has(line.type)) return false;
  if (line.type === 'system') return false;
  return ['user', 'assistant'].includes(line.type ?? '');
}

判断流程:

sql 复制代码
有 uuid?
  → 否:跳过(流式片段)
  → 是:类型在 SKIP_TYPES 里?
    → 是:跳过
    → 否:是 system?
      → 是:跳过
      → 否:是 user 或 assistant?
        → 是:保留
        → 否:跳过

消息内容的清理

即使保留下来的 userassistant 消息,内容里也可能夹杂系统标签。ChatCrystal 会自动清除:

会被清除的标签

xml 复制代码
<system-reminder>系统提醒内容</system-reminder>
<command-name>/help</command-name>
<command-message>执行命令</command-message>
<command-args>--flag value</command-args>
<local-command-stdout>命令输出</local-command-stdout>
<local-command-caveat>注意事项</local-command-caveat>

清理代码

typescript 复制代码
function sanitizeContent(text: string): string {
  let result = text;
  result = result.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, '');
  result = result.replace(/<command-name>[^<]*<\/command-name>/g, '');
  result = result.replace(/<command-message>[^<]*<\/command-message>/g, '');
  result = result.replace(/<command-args>[^<]*<\/command-args>/g, '');
  result = result.replace(/<local-command-stdout>[^<]*<\/local-command-stdout>/g, '');
  result = result.replace(/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g, '');
  return result.trim();
}

不过滤会怎样

如果不过滤噪音,LLM 生成摘要时会收到大量无关内容:

  • <system-reminder> 里的系统指令会干扰摘要判断
  • 流式 delta 片段会产生重复内容
  • file-history-snapshot 会让摘要变成文件变更日志
  • tool_use / tool_result 片段会让摘要充斥工具调用细节

最终生成的笔记标题可能是「system-reminder: you are Claude...」而不是「修复登录 bug」。

为什么 Claude Code 要存这些噪音

这些噪音对 Claude Code 本身是有用的:

  • 流式 delta --- 实时显示 AI 回复
  • system-reminder --- 维护对话上下文
  • tool_use/result --- 记录工具调用链
  • file-history-snapshot --- 支持撤销操作

但对「从对话中提取知识」这个目标来说,这些都是噪音。


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

相关推荐
小蠢驴打代码1 小时前
记忆库能通过测试,不等于回答值得信:Coding Agent Memory 的两层评估设计
github·ai编程
喂你一颗橘子糖1 小时前
我用 Codex 跑长任务:快照、Loop 和单线写入,解决三个失控问题
ai编程
李剑一2 小时前
瑞幸也AI上了?我用AI命令行帮我点了一杯咖啡,但是我花了不止一杯咖啡钱
aigc·openai·ai编程
leoZ2312 小时前
记忆系统与 Agent 定制完全指南(六):Agent 编排与调度
ai编程
Ai拆代码的曹操3 小时前
opencode CLI 源码拆解:yargs + effectCmd 双层架构如何管理 20+ 子命令
架构·ai编程·opencode·源码拆解
AINative软件工程3 小时前
LLM 应用的熔断降级工程实践:Circuit Breaker 不只是重试的升级版
后端·llm·ai编程
倔强的石头_11 小时前
不想每次都从头解释:我用 Doubao-Seed-Evolving 做了一个「稿件接力站」
ai编程
大模型码小白13 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
-XWB-15 小时前
【LLM】Agent Planning 完全指南:8 种纯 LLM 范式 + 8 种混合规划模式详解(二)
人工智能·经验分享·aigc·学习方法·ai编程
沉默王二15 小时前
腾讯一面,我霸气反问:“你说你们在做Agent项目,说说 SubAgent、Plan 模式、Skill 调用这些你们都是怎么做的?”面试官一直在擦汗。。
面试·agent·ai编程