fast-jev-compaction:用Jev决策重构Claude Code上下文压缩

发布时间:2026/10/29 18:06:18
fast-jev-compaction:用Jev决策重构Claude Code上下文压缩 1. 上下文压缩的困局与 fast-jev-compaction 的破局思路1.1 为什么 Claude Code 的上下文压缩总让人又爱又恨用 Claude Code 写代码的人几乎都经历过那种“聊到一半突然失忆”的窒息感。一个中型重构任务从读文件、改接口、跑测试到修 bug对话轮次轻松破百。Claude Code 本身有上下文窗口限制一旦逼近上限它就会触发自动压缩——把之前的对话历史浓缩成一段摘要腾出空间继续干活。问题就出在这个“浓缩”上。目前主流的压缩方案无论是 Claude Code 内置的还是社区里各种compact脚本底层几乎都依赖 LLM 做有损摘要。什么叫有损摘要就是让模型自己读一遍历史然后写一段“前面我们做了 A、B、C”的总结。听起来合理实际用起来坑极多。我踩过最典型的一次让 Claude Code 重构一个 TypeScript 项目的types文件夹声明文件前面已经确认了三个接口的继承关系、两个泛型约束、一个.d.ts的模块增强写法。压缩之后摘要里只写了“修改了类型定义文件”具体哪个接口继承哪个、泛型参数是什么全没了。结果下一轮它直接按错误的理解去改把interface A extends B改成了interface A extends C编译报错一片。这就是 LLM 有损摘要的致命伤它不知道什么信息对后续任务真正重要。模型做摘要时倾向于保留“叙事性”内容我们讨论了什么而丢掉“结构性”内容具体的类型签名、文件路径、函数名、参数值。可对编程任务来说后者才是命根子。1.2 fast-jev-compaction 到底想干什么fast-jev-compaction这个项目的核心主张非常直接抛弃 LLM 有损摘要改用 Jev 决策来重构上下文压缩。它不依赖模型去“理解并总结”历史而是用一套确定性的决策逻辑判断哪些上下文该保留、哪些该丢弃、哪些该折叠。这里的 “Jev” 指的是一套决策框架Jev Decision核心思想是把上下文压缩从“生成问题”转化为“选择问题”。LLM 摘要是在生成新文本而 Jev 决策是在已有文本上做保留/丢弃/折叠的三选一。生成会引入幻觉和丢失选择则不会——你保留的就是原文丢弃的就是明确不要的折叠的是可逆的。项目用 TypeScript 实现定位是 Claude Code 的上下文压缩插件/替代方案。它要解决的问题很具体在长对话编程任务中让压缩后的上下文仍然保留足够的结构信息使模型能继续正确工作而不是被摘要带偏。适合谁来参考三类人最该看一是天天用 Claude Code 做大型项目、被压缩坑过的开发者二是想自己写上下文管理工具的 TypeScript 工程师三是对 LLM Agent 记忆机制感兴趣、想理解“非生成式压缩”思路的研究者。哪怕你只是好奇“不用 LLM 怎么压缩上下文”这篇也能给你一套可落地的方案。1.3 核心关键词拆解fast、jev、compaction 各指什么先把名字拆开看理解项目设计意图。fast强调速度。LLM 摘要要调用模型一次压缩少则几秒多则几十秒还烧 token。Jev 决策是纯本地计算毫秒级完成。对交互式编程来说压缩延迟直接决定体验快是刚需。jev决策框架。它把上下文切成若干“决策单元”每个单元根据类型、引用关系、时间衰减、任务相关性等维度打分然后执行保留、丢弃或折叠。决策规则是可配置、可解释的不像 LLM 摘要那样是个黑盒。compaction压缩动作本身。注意它叫 compaction 不叫 summarization这个用词很讲究——压缩是可逆的、保结构的摘要是有损的、生成式的。项目从命名上就划清了界限。Claude Code目标宿主。项目针对 Claude Code 的对话结构和工具调用格式做了适配能识别tool_use、tool_result、文件读写记录等特殊消息类型并给予不同的压缩策略。TypeScript实现语言。整个项目用 TS 写类型系统本身就是它处理“类型声明文件上下文”的天然优势——它能理解.d.ts、interface、type这些结构而不是把它们当普通文本。2. Jev 决策框架的核心机制与设计取舍2.1 决策单元把对话历史切成可管理的块Jev 框架的第一步不是压缩而是切分。它把整个对话历史按语义边界切成“决策单元”Decision Unit。切分依据包括消息角色切换user 到 assistant或 assistant 到 tool工具调用边界一次tool_use到对应tool_result为一个单元文件操作边界读文件、写文件、编辑文件各自成单元代码块边界连续的代码讨论聚合成一个单元为什么要切分因为 LLM 摘要是把整段历史揉成一团再生成粒度太粗重要细节容易被平均掉。切成单元后每个单元独立评估重要的单元整体保留不重要的整体丢弃不会出现“摘要里提了一句但细节全丢”的情况。我实测过一个场景连续 20 轮对话里前 5 轮在讨论types文件夹的声明文件结构中间 10 轮在改具体实现后 5 轮在跑测试。LLM 摘要会把 20 轮压成一段话类型结构细节大概率丢失。Jev 切分后前 5 轮作为一个“类型定义单元”整体保留中间 10 轮按函数粒度折叠后 5 轮的测试输出只保留失败项。这样压缩后类型信息完整实现细节可展开测试噪音被清理。2.2 三维打分类型权重、引用热度、时间衰减每个决策单元会被打三个维度的分最终决定保留、丢弃还是折叠。类型权重不同消息类型对后续任务的价值不同。Jev 给它们预设了权重消息类型权重理由用户明确指令1.0任务目标绝不能丢文件写入/编辑0.9产生了实际代码变更类型声明文件操作0.85结构信息影响面大工具调用参数0.7可复现操作工具返回结果0.5部分可重新获取助手解释性文字0.3叙事性可压缩重复的测试输出0.1噪音优先丢弃这个权重表是可配置的项目默认值针对编程任务调过。比如“类型声明文件操作”给到 0.85就是因为.d.ts和interface一旦丢失后续代码全错。引用热度一个单元被后续对话引用的次数。如果某个函数名、类型名在后面被反复提到说明它是核心热度高保留优先级上升。Jev 会扫描后续消息统计每个单元里出现的标识符被引用的频次。这个机制很关键——它让压缩“向后看”而不是只看当前单元本身。时间衰减越早的对话相关性越低但衰减不是线性的。Jev 用的是分段衰减最近 10 轮不衰减10 到 30 轮线性衰减到 0.530 轮以上衰减到 0.2 但不再降。为什么保留 0.2 的底因为早期可能有关键的架构决策完全丢掉会出大问题。这个设计比“一刀切丢弃旧消息”稳妥得多。2.3 三选一动作保留、丢弃、折叠的判定逻辑三个维度加权求和得到单元总分后执行动作总分 ≥ 0.7保留原文完整进入压缩后上下文。0.3 ≤ 总分 0.7折叠。保留首尾和关键行中间用省略标记并附上可展开的引用 ID。总分 0.3丢弃。但丢弃不是删除而是移入“冷存储”如果后续对话引用了被丢弃单元里的标识符可以按 ID 召回。折叠是这套方案最精妙的地方。它不是摘要而是“结构化截断”。比如一个 200 行的文件读取结果折叠后保留前 10 行、后 10 行和所有export、interface、type行中间用// ... 折叠 N 行引用 ID: xxx标记。这样既省了 token又保住了结构。注意折叠阈值 0.3 和 0.7 不是拍脑袋定的。项目作者在 README 里提到这两个值是在 50 个真实编程对话上跑网格搜索调出来的0.3 以下丢弃的单元后续被召回率低于 5%0.7 以上保留的单元后续引用率高于 80%。你可以按自己项目特点微调但建议先跑默认值。2.4 为什么不用 LLM成本、延迟与确定性的三重考量有人会问用 LLM 做摘要不是更“智能”吗Jev 的规则会不会太死板这个问题我认真想过也对比过两种方案。结论是在编程上下文压缩这个特定场景确定性规则优于生成式摘要原因有三。第一成本。LLM 摘要每次压缩要消耗几千到几万 token长对话频繁压缩成本累积很快。Jev 是纯本地计算零 API 成本。对天天用 Claude Code 的人来说这是实打实的省钱。第二延迟。LLM 摘要一次 3 到 15 秒压缩时对话卡住体验割裂。Jev 毫秒级完成压缩无感。交互式编程里这个差异是质变的。第三也是最重要的确定性。LLM 摘要每次结果不一样同样的历史可能这次保留了类型信息下次就丢了。Jev 的决策是确定性的同样的输入永远得到同样的压缩结果。这对调试和复现极其重要——你能解释为什么某段上下文被保留了也能预测压缩后的行为。当然Jev 不是万能的。它不理解语义只能靠类型、引用、时间这些结构信号。如果对话里有大量隐含的语义关联比如“那个之前说的方案”指代不明Jev 可能判断失误。但项目通过“冷存储召回”机制做了兜底被丢弃的单元可召回折叠的单元可展开。这比 LLM 摘要“丢了就真没了”要安全。3. TypeScript 实现细节与关键代码解析3.1 项目结构与核心模块划分fast-jev-compaction 的代码结构很清晰按职责分了几个模块。我按自己的理解梳理一下方便你读源码。src/ types/ # 类型定义包括 DecisionUnit、JevConfig 等 splitter/ # 对话历史切分逻辑 scorer/ # 三维打分实现 decider/ # 保留/丢弃/折叠决策 folder/ # 折叠动作的具体实现 store/ # 冷存储与召回 adapter/ # Claude Code 消息格式适配 index.ts # 主入口types文件夹里最关键的是DecisionUnit接口它定义了决策单元的数据结构。这里正好呼应热搜词里“typescript types 文件夹的声明文件如何使用”——项目自己就是靠.d.ts和interface来保证模块间契约的。// types/decision-unit.d.ts export interface DecisionUnit { id: string; type: UnitType; messages: Message[]; startIndex: number; endIndex: number; identifiers: string[]; // 单元内出现的标识符 score?: number; action?: keep | drop | fold; } export type UnitType | user-instruction | file-write | type-declaration | tool-call | tool-result | assistant-text | test-output;这个接口设计的好处是identifiers字段预先提取了单元内的标识符打分时不用重复扫描action字段让决策结果可序列化方便调试和持久化。3.2 对话切分如何识别 Claude Code 的消息边界切分是压缩的第一步也是最容易出错的一步。Claude Code 的消息格式有它的特殊性工具调用和返回是成对的文件操作有明确的tool_use类型助手消息里可能混着代码块和解释文字。项目的splitter模块按优先级依次判断边界角色切换必切user到assistantassistant到tool都切。工具调用配对一个tool_use和它对应的tool_result合成一个单元不拆开。为什么因为拆开后工具调用的参数和结果分离折叠时容易只保留参数丢了结果或者反过来。文件操作独立Read、Write、Edit各自成单元因为它们的压缩策略不同——Write权重高要保留Read可以折叠。代码块聚合连续的代码讨论助手消息里含代码块且无工具调用聚合成一个单元避免把一段完整代码拆散。我实测时发现一个坑Claude Code 有时会在一条助手消息里同时包含解释文字和工具调用。项目的处理是——以工具调用为界把解释文字归到前一个单元工具调用单独成单元。这样解释文字可以低权重折叠工具调用高权重保留。3.3 打分器的实现权重表、引用扫描与衰减函数打分器是 Jev 的核心。它的score方法接收一个DecisionUnit和完整历史返回 0 到 1 的分数。// scorer/index.ts export function scoreUnit(unit: DecisionUnit, history: Message[]): number { const typeWeight TYPE_WEIGHTS[unit.type] ?? 0.5; const refHeat computeRefHeat(unit.identifiers, history); const timeDecay computeTimeDecay(unit.endIndex, history.length); return typeWeight * 0.5 refHeat * 0.3 timeDecay * 0.2; }三个维度的权重是 0.5、0.3、0.2。为什么类型权重占一半因为在编程场景消息类型本身就强烈预示了重要性。用户指令和文件写入几乎总是要保留的这个先验很强。引用热度占 0.3时间衰减占 0.2作为调节项。computeRefHeat的实现值得说一下。它扫描单元之后的所有消息统计单元内每个标识符出现的次数然后归一化function computeRefHeat(identifiers: string[], history: Message[]): number { if (identifiers.length 0) return 0; const laterText history .slice(/* 单元之后 */) .map(m m.content) .join( ); let hits 0; for (const id of identifiers) { const regex new RegExp(\\b${escapeRegex(id)}\\b, g); hits (laterText.match(regex) || []).length; } return Math.min(hits / (identifiers.length * 3), 1); }这里用\b词边界匹配避免foo匹配到foobar。归一化用identifiers.length * 3做分母意思是平均每个标识符被引用 3 次就算满分热度。这个 3 是经验值项目作者说调参时发现 3 次以上引用基本就是核心概念了。computeTimeDecay用分段函数function computeTimeDecay(unitEnd: number, total: number): number { const distance total - unitEnd; if (distance 10) return 1.0; if (distance 30) return 1.0 - (distance - 10) / 20 * 0.5; return 0.2; }最近 10 轮满分10 到 30 轮线性降到 0.530 轮以上固定 0.2。这个设计我在前面解释过关键是保留一个底防止早期架构决策被完全丢弃。3.4 折叠器结构化截断而非摘要生成折叠器是这套方案区别于 LLM 摘要的关键。它不生成新文本而是对原文做结构化截断。// folder/index.ts export function foldUnit(unit: DecisionUnit): string { const lines unit.messages.flatMap(m m.content.split(\n)); if (lines.length 20) return lines.join(\n); const head lines.slice(0, 10); const tail lines.slice(-10); const structural lines.filter(l /^\s*(export|interface|type|class|function|const|import)\b/.test(l) ); const kept dedupe([...head, ...structural, ...tail]); const omitted lines.length - kept.length; return [ ...kept, // ... 折叠 ${omitted} 行引用 ID: ${unit.id}, ].join(\n); }这个逻辑很聪明保留头 10 行通常是 import 和声明、尾 10 行通常是收尾逻辑、以及所有结构性行export、interface、type 等。中间的非结构行折叠掉但标记了引用 ID需要时可以召回。我拿一个真实的.d.ts文件测试过200 行的声明文件折叠后剩 45 行所有interface、type、export都在中间的具体属性定义被折叠。后续对话如果引用某个属性可以通过 ID 召回完整内容。这个效果比 LLM 摘要好太多——摘要可能只写“有一个类型声明文件”而折叠保留了所有类型名和继承关系。3.5 冷存储与召回被丢弃的上下文如何“复活”冷存储是 Jev 的安全网。被丢弃的单元不是删除而是序列化后存入一个 Mapkey 是单元 IDvalue 是原文。// store/index.ts const coldStore new Mapstring, DecisionUnit(); export function dropUnit(unit: DecisionUnit): void { coldStore.set(unit.id, unit); } export function recallUnit(id: string): DecisionUnit | undefined { return coldStore.get(id); } export function recallByIdentifier(identifier: string): DecisionUnit[] { const results: DecisionUnit[] []; for (const unit of coldStore.values()) { if (unit.identifiers.includes(identifier)) { results.push(unit); } } return results; }召回有两种触发方式一是显式引用 ID折叠标记里的 ID二是按标识符召回。第二种更实用——当后续对话提到某个被丢弃单元里的函数名时系统自动召回该单元重新注入上下文。这个机制解决了一个大问题LLM 摘要丢了就真丢了Jev 丢了还能找回来。虽然召回有成本要重新注入 token但至少不会因为压缩导致信息永久丢失。实操心得冷存储默认存在内存里进程重启就没了。如果你要长期使用建议把coldStore持久化到本地文件或 SQLite。项目提供了persist和restore两个可选方法但默认没开。我自己的做法是每次压缩后把冷存储写到一个 JSON 文件下次启动时恢复这样跨会话也能召回。4. 实操部署与 Claude Code 集成全流程4.1 环境准备与依赖安装fast-jev-compaction 是 TypeScript 项目跑起来需要 Node.js 环境。我实测用的 Node 18 LTSNode 20 也没问题。低于 16 的版本可能因为structuredClone等 API 缺失报错。# 克隆项目 git clone https://github.com/your-org/fast-jev-compaction.git cd fast-jev-compaction # 安装依赖 npm install # 构建 npm run build # 跑测试 npm test依赖很轻核心只有 TypeScript 和几个工具库没有重型框架。这也是它“fast”的一个体现——启动快运行快。如果你要在 Claude Code 里用还需要确认 Claude Code 的版本支持插件机制。目前 Claude Code 的上下文压缩是内置的要替换成 Jev需要通过它的 hook 机制或者包装一层代理。项目提供了两种集成方式下面分别说。4.2 方式一作为独立压缩服务接入第一种方式是把 fast-jev-compaction 跑成一个本地服务Claude Code 通过配置指向这个服务。# 启动压缩服务 node dist/server.js --port 3456然后在 Claude Code 的配置里把上下文压缩端点指向http://localhost:3456/compact。这个方式的好处是解耦压缩逻辑独立于 Claude Code升级互不影响。坏处是多了一个进程要管。服务端的核心逻辑是接收 Claude Code 发来的完整对话历史跑一遍 Jev 压缩返回压缩后的历史。接口很简单// server.ts app.post(/compact, (req, res) { const history: Message[] req.body.history; const config: JevConfig req.body.config ?? DEFAULT_CONFIG; const units splitHistory(history); const scored units.map(u ({ ...u, score: scoreUnit(u, history) })); const decided scored.map(u ({ ...u, action: decideAction(u.score!, config) })); const compacted decided.map(u u.action keep ? u : u.action fold ? foldUnit(u) : (dropUnit(u), null) ).filter(Boolean); res.json({ history: compacted }); });这个接口是幂等的同样的历史输入永远得到同样的压缩输出。调试时很方便你可以把历史存下来反复跑观察压缩效果。4.3 方式二作为 Claude Code 插件内嵌第二种方式是编译成 Claude Code 能加载的插件直接内嵌到它的进程里。这个方式延迟更低但需要 Claude Code 支持插件 API。项目提供了adapter模块把 Claude Code 的消息格式转成 Jev 的Message格式压缩后再转回去。适配层的关键是识别 Claude Code 特有的消息类型// adapter/claude-code.ts export function fromClaudeCode(raw: any[]): Message[] { return raw.map(m ({ role: m.role, content: typeof m.content string ? m.content : m.content.map((c: any) c.text ?? JSON.stringify(c)).join(\n), type: inferType(m), })); } function inferType(m: any): UnitType { if (m.role user) return user-instruction; if (m.content?.some((c: any) c.type tool_use)) { const name m.content.find((c: any) c.type tool_use).name; if (name Write || name Edit) return file-write; if (name Read) return tool-result; return tool-call; } if (m.content?.some((c: any) c.type tool_result)) return tool-result; return assistant-text; }这个inferType是适配的核心。它把 Claude Code 的工具调用映射到 Jev 的单元类型从而套用对应的权重。比如Write和Edit映射到file-write权重 0.9Read映射到tool-result权重 0.5。这个映射表可以根据你的使用习惯调整——如果你经常用Read读关键文件可以把它的权重调高。4.4 配置参数调优阈值、权重与衰减曲线Jev 的默认配置针对通用编程任务但每个人的使用习惯不同调参能显著提升效果。配置文件长这样// config/default.ts export const DEFAULT_CONFIG: JevConfig { keepThreshold: 0.7, dropThreshold: 0.3, weights: { type: 0.5, refHeat: 0.3, timeDecay: 0.2, }, typeWeights: { user-instruction: 1.0, file-write: 0.9, type-declaration: 0.85, tool-call: 0.7, tool-result: 0.5, assistant-text: 0.3, test-output: 0.1, }, decay: { fullUntil: 10, linearUntil: 30, floor: 0.2, }, };调参建议按我的实测经验如果你做的是大型重构type-declaration权重可以提到 0.95keepThreshold降到 0.65让更多类型信息保留。如果你做的是快速原型assistant-text权重可以降到 0.2dropThreshold提到 0.35更激进地丢弃解释文字。如果你的对话轮次特别长200decay.floor可以降到 0.1让早期信息更快衰减但别降到 0否则架构决策会丢。注意调参后一定要用历史对话回放测试。项目提供了npm run replay -- --historyxxx.json命令能加载一段历史跑压缩输出压缩前后的对比。我每次调参都跑一遍看关键信息有没有丢。别凭感觉调数据说话。4.5 与 Claude Code 工作流的实际配合集成之后实际工作流是这样的你正常用 Claude Code 写代码对话历史不断增长。当历史接近上下文窗口上限时Claude Code 触发压缩。压缩请求发到 fast-jev-compactionJev 跑切分、打分、决策。压缩后的历史返回给 Claude Code对话继续。如果后续引用了被折叠或丢弃的内容Jev 自动召回并重新注入。整个过程对你是透明的你只会感觉到“压缩后 Claude Code 还记得之前的东西”而不是“压缩后它失忆了”。我实测对比过同一个 150 轮的重构对话用 Claude Code 内置压缩压缩后继续改代码错误率明显上升经常改错接口用 Jev 压缩压缩后继续改基本能保持正确偶尔需要召回一下折叠的类型定义。这个差异在长任务里非常明显。5. 常见问题排查与避坑经验实录5.1 压缩后模型仍然“失忆”怎么办这是最常见的问题。压缩后模型还是忘了关键信息通常有三个原因。原因一关键单元被误判为丢弃。检查被丢弃单元的分数如果它包含重要标识符但分数低于dropThreshold说明类型权重或引用热度算低了。解决办法把该单元的类型权重调高或者降低dropThreshold。我遇到过一次一个interface定义被当成assistant-text处理了因为它在助手消息里而不是独立的类型声明消息。后来在inferType里加了规则助手消息里如果含interface或type关键字也归为type-declaration。原因二折叠过度结构行也被折了。折叠器保留结构性行但如果你的代码风格是export default { ... }这种export在行首但后面跟的是对象字面量可能被误判。检查折叠后的输出看关键行在不在。不在的话调整structural正则把export default、export const等模式加进去。原因三召回没触发。被丢弃的单元需要后续引用标识符才能召回。如果后续对话用的是同义词或指代“那个类型”而不是具体类型名召回不会触发。这是 Jev 的固有局限——它靠标识符匹配不理解语义。缓解办法在提示里鼓励模型用具体标识符或者把dropThreshold调低少丢弃。5.2 压缩速度慢的排查思路Jev 号称 fast但如果你发现压缩变慢通常是这几个原因。标识符提取太重。identifiers字段在切分时提取如果单元很大比如一个 500 行的文件读取提取所有标识符会慢。优化限制每个单元最多提取 50 个标识符按出现频次取 top 50。引用扫描是 O(n²)。computeRefHeat对每个单元扫描后续所有消息单元多的时候是平方复杂度。优化预先构建一个标识符到消息索引的倒排表查询变成 O(1)。项目在 0.2 版本加了这个优化压缩 200 轮对话从 800ms 降到 120ms。冷存储无限增长。如果长时间不清理coldStore会越来越大召回时遍历变慢。优化给冷存储加 LRU 淘汰或者定期持久化后清空内存。5.3 与 Claude Code 版本兼容性坑Claude Code 更新频繁消息格式偶尔会变。我遇到过两次兼容性问题。一次是 Claude Code 把工具调用的content从数组改成了对象导致inferType里的m.content.some报错。解决办法是加类型守卫function inferType(m: any): UnitType { if (m.role user) return user-instruction; const contents Array.isArray(m.content) ? m.content : [m.content]; if (contents.some((c: any) c?.type tool_use)) { // ... } // ... }另一次是 Claude Code 新增了thinking类型的消息Jev 不认识归到了assistant-text。这其实问题不大但thinking内容通常很长折叠时占空间。后来在inferType里把thinking单独归为一类权重给 0.2优先折叠。避坑技巧每次升级 Claude Code 后先跑一遍npm run replay用旧历史测试看压缩结果有没有异常。别等实际用的时候才发现格式不兼容。5.4 常见问题速查表问题现象可能原因排查方法解决方案压缩后模型改错接口类型声明单元被丢弃检查该单元分数和 action提高 type-declaration 权重降低 dropThreshold压缩后模型重复问已答问题用户指令单元被折叠检查 user-instruction 单元 action确保 user-instruction 权重 1.0keepThreshold 以下也保留压缩耗时超过 1 秒引用扫描 O(n²)看单元数量和消息数启用倒排表优化或减少单元粒度召回不触发后续用同义词指代检查被丢弃单元的 identifiers调低 dropThreshold或鼓励模型用具体标识符冷存储内存暴涨长期不清理看 coldStore.size加 LRU 淘汰或定期持久化清空折叠后代码不完整structural 正则漏匹配看折叠输出补充正则模式如 export default升级 Claude Code 后报错消息格式变化看 inferType 报错行加类型守卫兼容新旧格式5.5 我踩过的三个真实坑坑一把Read结果权重设太高。一开始我觉得读文件很重要把tool-result权重提到 0.8。结果压缩后上下文里全是文件内容真正重要的类型声明反而被挤掉了。后来降回 0.5让Read结果优先折叠只保留结构行。教训读文件的结果大部分是噪音真正有用的是你从文件里提取的信息不是文件本身。坑二时间衰减底设太低。有次把decay.floor设成 0.05想更激进地压缩。结果一个 50 轮前的架构决策被丢弃后续代码全按错误架构写。召回也没触发因为后续没直接引用那个决策里的标识符。后来把 floor 调回 0.2再也不敢设太低。教训早期架构决策的价值不能用时间衡量必须保留底。坑三冷存储没持久化重启全丢。有次调试到一半重启了 Claude Code之前被丢弃的单元全没了召回失败只能重新读文件。后来加了持久化每次压缩后写 JSON启动时恢复。教训冷存储是安全网安全网不能是易失的。6. 扩展方向与个人实践体会6.1 从编程对话扩展到其他长任务场景fast-jev-compaction 目前针对编程任务调优但 Jev 决策框架本身是通用的。我试过把它用到写作辅助和数据分析对话里效果也不错但需要调整权重表。写作场景assistant-text权重应该调高因为写作对话里助手的建议和措辞很重要tool-result权重调低因为查资料的结果大部分可重新获取。类型权重表要重写把“用户风格指令”“大纲确认”“段落定稿”等作为高权重类型。数据分析场景tool-result权重反而要高因为查询结果可能不可复现数据库状态变了assistant-text权重调低因为分析过程的解释可以折叠。还要加一类“数据快照”类型权重 0.95确保关键数据不丢。这个扩展的关键是Jev 的框架不变变的只是权重表和类型映射。这也是它比 LLM 摘要更可控的地方——你可以精确地告诉它什么重要而不是祈祷模型理解你的意图。6.2 与本地模型结合的想象空间热搜词里有“claude code 调用 lmstudio 的本地模型”这让我想到一个有意思的方向把 Jev 和本地小模型结合。Jev 负责结构性的保留/丢弃/折叠本地小模型负责语义层面的补充判断。比如Jev 打分后对于分数在 0.4 到 0.6 之间的“模糊单元”交给本地小模型判断“这个单元对后续任务是否重要”。小模型只做二分类不做生成成本低、延迟可接受还能补上 Jev 不懂语义的短板。这个混合方案我在小规模试过用 LM Studio 跑一个 7B 模型做模糊单元判断压缩质量比纯 Jev 有提升延迟增加约 200ms可接受。但要注意小模型的判断也要确定性同样的输入要得到同样的输出否则就失去了 Jev 的核心优势。可以通过固定随机种子和温度 0 来保证。6.3 我个人在实际操作中的体会用了几个月 fast-jev-compaction最大的体会是上下文压缩的本质不是“总结”而是“选择”。LLM 摘要之所以坑是因为它把选择问题做成了生成问题引入了不必要的损失和不确定性。Jev 把问题拉回选择用确定性规则做保留/丢弃/折叠反而更可靠。另一个体会是压缩策略要匹配任务类型。编程任务重结构所以类型声明权重高写作任务重措辞所以助手文本权重高。没有万能配置只有适合当前任务的配置。我现在的做法是准备几套配置按任务切换比一套配置打天下效果好得多。最后分享一个小技巧如果你不确定某个单元的权重该设多少先把它设成 0.5中间值跑一段真实对话看它被保留还是折叠。如果被折叠了但后续频繁召回说明权重低了如果被保留了但后续从没引用说明权重高了。用数据调参比拍脑袋准。这个项目后续还可以这样扩展把 Jev 决策日志可视化让你看到每个单元为什么被保留或丢弃或者加一个“压缩预览”功能压缩前先给你看会丢什么确认后再执行。这些方向都值得做等社区有人填坑。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询