跳到主要内容
AI教程

使用 fast-jev-compaction 保留完整的 Claude Code 上下文

了解如何将 fast-jev-compaction 安装并用作 npm 库或 Claude Code 插件。本教程介绍其基于 Jev 的决策机制、配置选项、自定义传输支持、失败行为,以及如何在逐字保留重要文本的同时安全缩减过长的对话记录。

使用 fast-jev-compaction 保留完整的 Claude Code 上下文

fast-jev-compaction 的作用

fast-jev-compaction 是一个 npm 库和 Claude Code 插件,用于缩减较长的代理记录,而不是将其改写成摘要。它会请求 Jev 模型为旧的工具调用和工具结果评分,然后根据可配置的阈值保留、截断或移除这些内容。

用户和助手文本会逐字保留,并维持原始顺序。只有工具调用及其匹配的结果会被列为移除候选。这样可以避免传统摘要方式丢失精确的约束、文件路径、命令和错误消息。

代码仓库同时包含 src/ 下的可复用程序包,以及 hooks/ 和 .claude-plugin/ 下的 Claude Code 函数钩子插件。

压缩工作原理

  1. 每个 tool_use 都会通过 tool_use_id 与其 tool_result 配对。

  2. 第一条消息和最新的 preserveRecentMessages 条消息中的调用会被固定,因此不会被修改。

  3. 完整对话会按从旧到新的顺序提供给 Jev。在此决策状态中,工具结果内容会被替换为类似 ok, 4213 chars (omitted) 的简短说明,而工具输入和文本仍然可用。

  4. 对于每个未固定的调用,Jev 会回答两个问题:是否仍然需要知道该调用,以及是否必须逐字保留完整结果。

  5. 返回的概率会与 keepThreshold 进行比较。

  6. 系统会重建记录,且不会留下无对应调用的结果。

决策结果

  • 如果结果评分达到阈值,则保留调用和完整结果。

  • 如果只有调用评分达到阈值,则保留调用,并将结果截短为前 truncateHeadChars 个字符,后面附加说明。

  • 如果两个评分都未达到阈值,则同时移除调用及其结果。

变为空的消息会被移除。不需要修改的消息会以原对象返回。

将较大历史记录放入 Jev 请求

决策状态默认上限为预计 25000 个 token。如果原始状态过大,库会逐步缩短展示给 Jev 的内容。它会截断工具输入,使用开头和结尾缩略长文本,折叠旧消息,将旧调用压缩为单行记录,省略没有旧调用的消息,并将连续的仅含旧调用的消息合并。

这些转换只会影响用于评分的状态,不会影响最终记录中保留的文本。如果状态仍然无法放入请求,压缩会抛出错误。

问题也会被分成多个批次,以确保每个“状态加问题”的请求都低于 maxRequestTokens,其默认值为 30000。请求会并发运行,随后合并其决策。

安装 npm 库

安装程序包,并通过环境变量提供 TypeSafe API 密钥:

npm install fast-jev-compaction
export TYPESAFE_API_KEY=...

不要提交 API 密钥,也不要将其直接写入源文件。

默认客户端会读取 process.env.TYPESAFE_API_KEY。调用 API 时,也可以提供 apiKey 选项。

压缩记录

导入 compactMessages,准备记录,并传入与默认值不同的选项:

import {
  compactMessages,
  reductionRatio,
  type Message,
} from 'fast-jev-compaction';

const transcript: Message[] = [
  {
    role: 'user',
    text: 'Fix the failing test. Never edit src/generated.',
    toolUses: [],
  },
  {
    role: 'assistant',
    text: '',
    toolUses: [
      {
        tool_use_id: 'toolu_1',
        tool: 'Read',
        input: { file_path: 'src/a.ts' },
      },
    ],
  },
  {
    role: 'user',
    text: '',
    toolUses: [],
    toolResults: [
      { tool_use_id: 'toolu_1', text: '…file contents…' },
    ],
  },
];

const result = await compactMessages(transcript, {
  preserveRecentMessages: 4,
});

console.log(result.messages);
console.log(result.decisions);
console.log(result.stats);

导出的 Message 类型是 Claude Code 的 SessionMessage 子集,因此可以直接将 Claude Code 会话记录传递给该程序包。

检查压缩是否值得

程序包导出了 reductionRatio,应用可以利用它来决定是否使用压缩后的历史记录:

const result = await compactMessages(transcript);

if (reductionRatio(result) < 0.25) {
  // Keep the original transcript or use another fallback.
} else {
  // Continue with result.messages.
}

结果统计包括压缩前后的消息数和字符数、按原因分组的决策计数、预计状态大小、使用的适配阶段,以及 Jev 请求的数量。

配置压缩行为

主要选项包括:

  • apiKey:TypeSafe API 密钥。默认为 TYPESAFE_API_KEY。

  • model:Jev 模型名称。默认为 jev-latest。

  • baseUrl:System One 端点。默认为 https://api.typesafe.ai/v1/systemone。

  • fetch:可注入的 fetch 实现,尤其适用于测试。

  • goal:包含在状态中的当前任务描述。默认使用最近三条用户提示。

  • keepThreshold:保留调用或完整结果所需的最低概率。默认为 0.5。

  • preserveRecentMessages:不可修改的最新消息数量。默认为 6;第一条消息也始终保留。

  • maxStateTokens:决策状态的估算令牌上限。默认为 25000。

  • maxRequestTokens:单次请求中状态加问题的估算上限。默认为 30000。

  • truncateHeadChars:结果被截断时保留的开头字符数。默认为 300。

const result = await compactMessages(transcript, {
  goal: 'Fix the test without editing generated files',
  keepThreshold: 0.6,
  preserveRecentMessages: 8,
  truncateHeadChars: 500,
});

更高的 keepThreshold 要求更高的保留概率,因此可能会移除更多工具活动。由于概率并不能证明删除是安全的,请根据具有代表性的记录评估阈值变更。

使用自定义 Jev 传输

如果内置的 TypeSafe 客户端不适合你的环境,可以实现导出的 JevAsker 接口。该接口要求提供 ask(state, questions) 方法。然后调用 compact(messages, asker, options),而不是 compactMessages。

该软件包还导出用于构造 HTTP 请求正文的 buildJevRequest,以及用于验证响应的 parseJevResponse。此外还提供更底层的构建模块,适用于更专业的集成:

  • collectToolCalls 将调用与其结果配对。

  • fitState 在配置的大小上限内准备状态。

  • batchCalls 将问题分配到多个请求中。

  • decideCall 将分数转换为保留、截断或移除决策。

  • applyDecisions 重建消息历史。

安装 Claude Code 插件

该插件要求 Claude Code 2.1.274 或更高版本。函数钩子目前处于早期访问阶段,因此请在 Claude Code 运行的所有环境中启用它们。例如,将环境设置添加到 ~/.claude/settings.json:

{
  "env": {
    "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1",
    "TYPESAFE_API_KEY": "<your key>"
  }
}

将仓库添加为插件市场并安装插件:

claude plugin marketplace add tamaratran/fast-jev-compaction
claude plugin install fast-jev-compaction@fast-jev-compaction

安装程序会提示你设置阈值和 truncateHeadChars 等选项。API 密钥选项保持默认值,即可使用环境变量中的 TYPESAFE_API_KEY。

重启 Claude Code,或运行:

/reload-plugins

激活后,/compact 和自动压缩都会通过 Jev 钩子。替换成功后会显示类似 fast-jev-compaction: kept N/M messages, no summary (...) 的提示。如果 Jev 失败或压缩幅度不足,钩子会回退到 Claude Code 内置的摘要功能。

直接从检出目录运行插件

你可以在不发布或安装插件的情况下测试仓库:

CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir .

请在仓库根目录运行此命令。

高级使用技巧

保护当前工作

当最近的工具输出可能会被再次使用时,请增加 preserveRecentMessages。这些消息中的调用会被固定,无法移除或截断。

提供准确的目标

默认目标取自最近三条用户提示。对于较长或任务不断变化的会话,明确设置 goal 可以让 Jev 更清楚地了解当前任务。

使用统计数据定义回退策略

请检查 result.stats 和 reductionRatio(result),不要自动接受每个压缩结果。短会话可能无法实现足够的压缩,因而不值得替换原始记录。

规划错误处理

当 Jev 失败、返回格式错误的数据、遗漏必需键,或收到无法在状态限制内完成适配的历史记录时,压缩会抛出异常。请在库调用外层添加错误处理,并在必要时保留原始记录或调用其他压缩策略。Claude Code 钩子已经会回退到其内置摘要功能。

了解请求成本

每个问题批次都会重复发送完整的已适配状态。因此,接近状态上限的历史记录可能需要为每个小问题组分别发送一个大型请求。调整限制时,请查看 result.stats 中的请求数量。

在不进行网络调用的情况下测试

仓库的单元测试使用虚假的 Jev 实现,从不连接 TypeSafe。在应用测试中,自定义 JevAsker 或注入的 fetch 实现也可以采用相同的方法。

开发命令

在仓库中工作时,请安装依赖并运行可用的检查:

npm install
npm run typecheck
npm test
npm run build
npm run validate:plugin
TYPESAFE_API_KEY="$(cat ~/.typesafe_key)" npm run demo

demo 命令会执行实时网络检查。仓库还包含一个位于 demo/JevDemo 下的 macOS SwiftUI 动画。它使用预先准备的对话记录演示压缩过程,不会调用 API:

demo/JevDemo/build.sh

在应用中按空格键即可重新播放动画。

重要限制

  • 只能移除或截断工具调用及其结果。文本消息在输出中保持不变。

  • Token 数量是根据字符模式估算的,并非通过分词器计算。

  • Jev 的概率并不能保证某个结果可以安全删除,但在必要时,助手可以重新运行已移除的工具调用。

  • 每个请求批次都会重复发送完整状态,因此对于接近配置上限的历史记录,成本可能会增加。

结论

fast-jev-compaction 通过保留用户和助手文本、仅选择性清理过时的工具活动,为有损对话摘要提供了另一种方案。使用 npm API 进行应用级控制,使用 Claude Code 插件实现自动集成,并利用所提供的阈值、保留设置、统计信息和回退行为,根据你的工作流调整压缩策略。