【learn-claude-code】S06ContextCompact - 上下文压缩:上下文会满,你需要腾出空间
核心理念“上下文会满你需要腾出空间” – 三层压缩策略实现无限会话。源码https://github.com/xiayongchao/learn-claude-code-4j/blob/main/src/main/java/org/jc/agents/S06ContextCompact.java原版https://github.com/shareAI-lab/learn-claude-code上篇S05SkillLoading - 技能加载上篇回顾上篇文章我们实现了 SkillLoader按需加载专业知识避免上下文膨胀。问题Agent 工作越久messages 数组越大。每次工具调用的结果都永久留在上下文里直到超出模型的上下文窗口上限。Claude Code 的解决方案三层压缩策略让无限会话成为可能。解决方案三层压缩LLM 调用前 | v --- Layer 1: microCompact (每次调用前) | | 替换旧的 tool_result 为占位符 --- | token 超过阈值? v --- Layer 2: autoCompact (自动) | | 保存会话记录 总结 重建上下文 --- | 模型调用 compact 工具? v --- Layer 3: manual compact (手动) | | 用户或模型主动触发压缩 ---Java 实现详解1. 压缩触发条件privatestaticfinalStringSYSTEM你是运行在 Commons.CWD 工作目录下的编程智能体请使用工具完成各项任务;privatestaticfinalintTHRESHOLD3000;// token 阈值2. Token 估算混合文本计算publicstaticintestimateTokens(Stringtext){if(textnull||text.isBlank()){return0;}doubletokenCount0;for(inti0;itext.length();i){charctext.charAt(i);// 中文每个字符 1 tokenif(Character.UnicodeScript.of(c)Character.UnicodeScript.HAN){tokenCount;}else{// 英文/数字/符号每 4 个字符 ≈ 1 tokentokenCount0.25;}}return(int)Math.ceil(tokenCount);}3. Layer 1microCompact - 微观压缩每次 LLM 调用前执行将旧的 tool_result 替换为占位符privatestaticfinalintKEEP_RECENT3;// 保留最近 3 条publicstaticvoidmicroCompact(ListChatCompletionMessageParammessages){// 1. 收集所有 tool 消息ListChatCompletionMessageParamtoolMessagesnewArrayList();for(ChatCompletionMessageParammessage:messages){if(message.isTool()){toolMessages.add(message);}}if(toolMessages.size()KEEP_RECENT){return;// 不足 3 条无需压缩}// 2. 建立 tool_call_id - tool_name 映射MapString,StringtoolNameMapnewHashMap();for(ChatCompletionMessageParammessage:messages){if(!message.isAssistant())continue;// ... 遍历 tool_calls 建立映射}// 3. 替换旧的 tool_result 为占位符ListChatCompletionMessageParamtoClearMessagesCommons.getFirstN(toolMessages,KEEP_RECENT);for(ChatCompletionMessageParammessage:toClearMessages){// 保留最近 3 条其余替换为// [上一步: 已使用 readFile]StringplaceholderString.format([上一步: 已使用 %s],toolName);// ... 构建新消息}}效果file content of pom.xml... (5000 chars)→[上一步: 已使用 readFile]4. Layer 2autoCompact - 自动压缩当 token 超过阈值时执行publicstaticvoidautoCompact(ListChatCompletionMessageParammessages){try{// 1. 保存完整会话记录到磁盘PathtranscriptDirPathPaths.get(Commons.TRANSCRIPT_DIR);Files.createDirectories(transcriptDirPath);StringtimestampString.valueOf(System.currentTimeMillis()/1000);PathtranscriptPathtranscriptDirPath.resolve(transcript_timestamp.jsonl);ListStringlinesnewArrayList();for(ChatCompletionMessageParammsg:messages){lines.add(Messages.toStandardJson(msg));}Files.write(transcriptPath,lines);System.out.println([会话记录已保存: transcriptPath]);// 2. 让 LLM 总结对话Stringprompt对本次对话进行连贯总结需包含1已完成事项2当前所处状态3达成的关键决策。请保持总结简洁保留关键细节。\nconversationText;ChatCompletionCreateParamsparamsChatCompletionCreateParams.builder().model(qwen3.5-plus).messages(List.of(ChatCompletionMessageParam.ofUser(ChatCompletionUserMessageParam.builder().content(prompt).build()))).maxCompletionTokens(2000).build();ChatCompletionchatCompletionCommons.getClient().chat().completions().create(params);StringsummaryCommons.getAssistantText(chatCompletion.choices().get(0).message().toParam());// 3. 重建上下文只保留 2 条消息messages.clear();messages.add(ChatCompletionMessageParam.ofUser(ChatCompletionUserMessageParam.builder().content([对话已压缩。会话记录transcriptPath]\n\nsummary).build()));messages.add(ChatCompletionMessageParam.ofAssistant(ChatCompletionAssistantMessageParam.builder().content(我已获取总结中的上下文继续执行).build()));}catch(Exceptione){// 异常处理}}5. agentLoop 集成三层压缩publicstaticvoidagentLoop(ListChatCompletionMessageParammessages){while(true){// Layer 1: 每次调用前微观压缩Compacts.microCompact(messages);// Layer 2: token 超过阈值则自动压缩if(Tokens.countDialogTokens(messages)THRESHOLD){System.out.println([已触发自动压缩]);Compacts.autoCompact(messages);}// 正常 LLM 调用...ChatCompletionchatCompletionCommons.getClient().chat().completions().create(params);messages.add(ChatCompletionMessageParam.ofAssistant(message.toParam()));// ... 工具执行 ...// Layer 3: 手动压缩通过 compact 工具触发if(manualCompact){System.out.println([手动压缩]);Compacts.autoCompact(messages);}}}6. compact 工具TOOL_HANDLERS.put(compact,args-已请求手动压缩);// 模型调用 compact 工具时设置标记for(ChatCompletionMessageToolCalltoolCall:toolCalls){if(Tools.isCompactTool(toolCall)){manualCompacttrue;continue;// 不执行只标记}// ... 其他工具}三层压缩对比层级触发条件作用粒度Layer 1: microCompact每次调用前替换旧结果为占位符消息级Layer 2: autoCompacttoken 3000保存记录 总结会话级Layer 3: manual模型调用 compact 工具同 autoCompact手动触发压缩效果示意压缩前 (假设 500 条消息): User: 读取所有 Java 文件... Assistant: 我来读取... Tool: readFile pom.xml 返回 2000 字符... Tool: readFile App.java 返回 3000 字符... Tool: readFile Service.java 返回 2500 字符... ... (更多工具调用) 压缩后 (2 条消息): User: [对话已压缩。会话记录: transcript_123456.jsonl] 总结已完成读取 pom.xml(App 配置)、App.java(主类)、Service.java(业务逻辑)... Assistant: 我已获取总结中的上下文继续执行相对 s05 的变更组件s05s06压缩无三层压缩策略Token 估算无Tokens.estimateTokens()会话持久化无transcript_*.jsonlcompact 工具无手动触发压缩试试看逐一读取 agents/ 目录下的每个 java 文件持续读取文件直到压缩功能自动触发使用 compact 工具手动压缩对话核心要义“Context will fill up; you need a way to make room”上下文有限但会话可以无限设计原则微观压缩保留关键信息去除冗余细节自动压缩阈值触发无感知清理手动压缩用户/模型主动控制会话持久化压缩前保存保留完整历史
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2481886.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!