openJiuwen agent-core 上下文引擎 CurrentRoundCompressor:当前轮工作压缩器的配置、原理与实战

📅 发布时间:2026/10/9 5:06:32
openJiuwen agent-core 上下文引擎 CurrentRoundCompressor:当前轮工作压缩器的配置、原理与实战
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习【免费下载链接】agent-coreopenJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力项目地址https://gitcode.com/openJiuwen/agent-core点击查看免费下载导读本文讲解 openJiuwen agent-core 上下文引擎Context Engine中的当前轮压缩处理器CurrentRoundCompressor当上下文 Token 数达到上下文容量的一定比例时它调用 LLM 把本轮内已完成的工作最后一次真实用户消息之后的推理、工具调用、工具结果等压缩成一条memory_block_current摘要消息而用户请求本身保持原样不动。读完本文你将掌握该处理器的全部配置参数、触发判定逻辑、压缩产物结构、错误重试机制并能直接写出可运行的最小接入示例。一、它解决什么问题长任务中的本轮失控在工具型 Agent 的长任务中上下文膨胀往往发生在当前这一轮用户发出一条请求后Agent 连续进行多轮思考 → 工具调用 → 工具结果的循环例如反复读取文件、执行命令、查看测试输出。这些中间过程消息数量巨大但其中大量信息如大段文件内容、冗长的命令输出在被消费过后已不再需要以原始形态占据上下文。CurrentRoundCompressor的定位正是针对这一场景只压缩本轮产生的工作消息即最后一次真实用户消息last real user message之后产生的所有推理、工具调用与工具结果用户请求永不压缩最后一次真实用户消息及其之前的内容构成保留前缀preserved prefix作为任务的意图锚点原样保留压缩产物是可恢复的检查点摘要消息不是简单的对话总结而是能让下一个模型实例继续执行当前任务的执行状态快照execution state snapshot。从源码结构看该处理器位于 forked/compressor/current_round_compressor.py与DialogueCompressor对话历史压缩、RoundLevelCompressor整轮级全上下文压缩等同属压缩处理器家族但分工不同CurrentRoundCompressor只处理最新用户消息之后的活跃工作区。二、配置类 CurrentRoundCompressorConfig7 个参数全解配置类CurrentRoundCompressorConfig继承自PrefixCompactProcessorConfig定义见 forked/compressor/base.py两者结合共提供以下核心参数参数类型默认值取值范围作用trigger_context_ratiofloat0.8(0, 1)上下文 Token 数达到上下文容量 × 该比例时触发压缩min_target_context_ratiofloat0.1[0, 1)可压缩消息的 Token 数低于上下文容量 × 该比例时跳过压缩防止收益过小keep_recent_messagesint0≥ 0本轮末尾保留不压缩的最近消息条数modelModelRequestConfig | NoneNone—执行压缩所用的模型请求配置model_clientModelClientConfig | NoneNone—执行压缩所用的模型服务配置provider、api_base、api_key 等enable_compression_dumpboolFalse—是否把每次真实压缩调用请求 压缩后上下文落盘用于离线分析compression_dump_dirstr | NoneNone—压缩落盘文件的目录为None时使用默认目录参数约束与行为要点源码 current_round_compressor.py 中的 pydantic 校验trigger_context_ratio必须严格大于 0、小于 1gt0.0, lt1.0min_target_context_ratio允许 0、小于 1ge0.0, lt1.0keep_recent_messages非负。model与model_client必须同时配置否则处理器永远不会触发压缩——在 base.py 中只有两者都非None时才会构造Model与CompressionExecutortrigger_get_context_window首先就会因执行器缺失而直接返回False。工具边界保护keep_recent_messages指定的保留边界会被自动向后扩展保证工具调用AssistantMessage.tool_calls与它的工具结果ToolMessage永不分离。这一逻辑由adjust_keep_recent_for_tool_boundaries实现base.py它从尾部保护区内收集所有工具结果 ID再向前扫描对应的工具调用消息把起始边界移动到最早的关联调用之前。基类还提供enable_kv_cache_affinity默认False由 ReActAgent 场景的 ContextProcessorRail 推导直接使用处理器时需显式开启与compression_recall_config回忆归档配置从ContextEngineConfig继承旧版enable_recall等字段会被_reject_legacy_recall_config校验器拒绝并提示迁移。三、工作原理三段式 Span 划分与触发判定3.1 把消息流切成三段CurrentRoundCompressor的核心是_build_span方法current_round_compressor.py它把整条上下文切成PrefixCompactSpan三段preserved_prefix保留前缀[0, last_user_index 1)即最后一次真实用户消息及其之前的全部内容——永远不压缩messages_to_compress待压缩区(last_user_index, split_index)即本轮内用户消息之后、保留尾之前的活跃工作消息protected_tail保护尾部末尾effective_keep条最近消息经过工具边界修正。其中真实用户消息的判定在 base.py只认UserMessage且内容不以内部前缀开头——内部前缀集合INTERNAL_USER_PREFIXES包括system-reminder、memory_block_current、memory_block_dialogue、memory_block_round、memory_block_session、recovered_context、[STATE_REINJECTION]等见 support/util.py这些用户角色消息实际承载的是内部状态不能当作真实用户输入。3.2 两段式触发判定在上下文窗口物化get_context_window阶段处理器按trigger → on两段式工作接口定义见 forked/base.pytrigger_get_context_windowbase.py计算整窗 Token 数优先使用模型上报的 usage否则用 token_counter 统计消息 工具若未达到context_max × trigger_context_ratio的绝对阈值 → 不触发构建 span若没有可压缩消息 → 不触发计算待压缩区 Token 数若低于context_max × min_target_context_ratio→ 跳过记录target_below_min全部通过才返回True。on_get_context_windowbase.py真正执行压缩成功后把context_window.context_messages与context内的消息替换为压缩后序列并返回携带compact_summary的ContextEvent。3.3 压缩产物memory_block_current结构压缩成功后原消息被替换为一条UserMessage内容包裹在memory_block_current.../memory_block_current中标记常量定义于 current_round_compressor.py消息包装逻辑见 base.pymemory_block_current meaning This is a compressed summary of work already performed after the latest user request. ... /meaning conflict_policy Newer raw messages, fresh tool results, and the latest user instructions override this summary. /conflict_policy summary ...LLM 生成的执行状态快照... /summary /memory_block_current处理器类属性还定义了压缩摘要的语义契约current_round_compressor.py摘要不是新的用户请求而是已完成的推理、工具调用、代码变更、测试结果与后续步骤的恢复依据较新的原始消息、新鲜的工具结果与最新的用户指令优先于摘要。reinject_builder_names [plan_mode, plan, task_status, todo, skills, read_file]表明压缩后还会尝试把计划模式、计划、任务状态、待办、技能与文件读取等关键状态以状态重注入消息的形式补回上下文_build_compacted_messagesbase.py。3.4 压缩提示词面向可恢复性而非省 Token处理器使用内置提示词CURRENT_COMPACT_PROMPT定义见 prompts/prompts.py。该提示词的核心设计值得关注输出硬约束纯文本、禁止任何工具调用、输出必须恰好包含coverage_check与state_snapshot两个 XML 块角色定位执行状态压缩助手Execution State Compression Assistant目标是让另一个模型实例能以最小的重复劳动继续当前工作而不是总结对话不追求最省 Token而是追求执行连续性maximize execution continuity within the available token budgetstate_snapshot内部有 11 个固定小节Active Task、Constraints and Preferences、Completed Work in This Active Segment、Current Work and Active State、Immediate Resume Point、Pending Tasks and Next Useful Step、Key Facts/Decisions/Evidence/Fixes、Files/Code Areas/Artifacts、Blockers/Risks/Verification、Critical Context、Relevant Files Structure安全要求删除敏感信息API Key、Token、口令等。压缩响应还会经过_extract_state_snapshot_or_raw解析base.py若响应内容包含state_snapshot.../state_snapshot块则提取其内容作为摘要否则使用完整原始文本。四、完整可运行示例继承原文档并补充注释以下示例完整继承自关联文档并补充了关键注释。它演示了如何构建模型配置与处理器配置、如何通过forked.activate()注册处理器、如何用名称引用处理器并创建上下文。 import os import asyncio from openjiuwen.core.context_engine import ContextEngine, ContextEngineConfig from openjiuwen.core.context_engine.processor import forked from openjiuwen.core.context_engine.processor.forked.compressor.current_round_compressor import ( ... CurrentRoundCompressor, ... CurrentRoundCompressorConfig, ... ) from openjiuwen.core.foundation.llm import ( ... UserMessage, ... AssistantMessage, ... ToolMessage, ... ModelRequestConfig, ... ModelClientConfig, ... ) # 1. 通过环境变量准备模型服务参数按需替换为真实值 API_BASE os.getenv(API_BASE, your api base) API_KEY os.getenv(API_KEY, your api key) MODEL_NAME os.getenv(MODEL_NAME, gpt-4o-mini) MODEL_PROVIDER os.getenv(MODEL_PROVIDER, OpenAI) async def main(): ... # 2. 配置压缩用的模型model 与 model_client 必须同时配置否则永不触发 ... model_config ModelRequestConfig(modelMODEL_NAME) ... model_client_config ModelClientConfig( ... client_providerMODEL_PROVIDER, ... api_baseAPI_BASE, ... api_keyAPI_KEY, ... ) ... # 3. 配置当前轮压缩器上下文 80% 时触发末尾保留 2 条最近消息 ... compressor_config CurrentRoundCompressorConfig( ... trigger_context_ratio0.8, ... keep_recent_messages2, ... modelmodel_config, ... model_clientmodel_client_config, ... ) ... forked.activate() # 注册处理器使其可以被按名称引用 ... engine_config ContextEngineConfig(default_window_message_num100) ... engine ContextEngine(engine_config) ... ctx await engine.create_context( ... demo_ctx, ... None, ... history_messages[], ... processors[(CurrentRoundCompressor, compressor_config)], ... ) ... # 4. 注入一条用户消息 一轮工具调用 → 工具结果的活跃工作 ... await ctx.add_messages([ ... UserMessage(contentHelp me fix this error), ... AssistantMessage(content, tool_calls[{id: 1, name: read_file, type: function, arguments: {}}]), ... ToolMessage(contentfile content ..., tool_call_id1), ... AssistantMessage(contentLocated the problem, fixing it now.), ... ]) ... # 5. 尚未达到 trigger_context_ratio0.8因此不触发压缩返回原始消息数 ... return len(ctx.get_messages()) asyncio.run(main()) 4示例输出说明上面输出4是压缩未触发时的原始消息数。当上下文达到触发阈值后用户请求保持完整1 条除末尾keep_recent_messages示例中为 2之外的本轮消息被替换为 1 条memory_block_current摘要因此get_messages()变为1 条用户消息 1 条摘要 keep_recent_messages 条最近消息。五、源码级纵深错误分类、重试与观测5.1 压缩调用的错误分类与重试压缩模型调用由CompressionExecutor封装compression_executor.py异常通过classify_compression_error归入 8 类CompressionErrorKindcontext_overflow、rate_limit、authentication、timeout、server_unstable、api_request_error、unknown等依据错误文本关键词与 HTTP 状态码识别如 413 判为上下文溢出、429 判为限流、401/403 判为鉴权失败、500/502/503/504 判为服务不稳定。_invoke_compression_with_retriesbase.py实现了两套恢复策略上下文溢出CONTEXT_OVERFLOW预算收缩重试当压缩请求自身超出模型上下文时依次尝试(0.85, 0.65, 0.5)三档预算比例_CONTEXT_OVERFLOW_RETRY_BUDGET_RATIOS把更多待压缩消息移入保护尾部、缩小送入压缩模型的窗口后重试预算耗尽则放弃本次压缩保留原上下文瞬时错误限流/超时/服务不稳定/未知退避重试最多重试 2 次退避延迟按0.05s × 2^(n-1)指数增长_TRANSIENT_COMPRESSION_MAX_RETRIES 2、_TRANSIENT_COMPRESSION_RETRY_BASE_DELAY_SECONDS 0.05。压缩失败不会破坏主 Agent 上下文——on_get_context_window返回None时原窗口保持不变这正是压缩是尽力而为的优化这一设计原则的体现。5.2 压缩收益校验与回滚即使压缩成功_has_compression_benefitbase.py还会比较压缩前后 Token 数只有new_tokens original_tokens时才真正替换上下文否则放弃新结果若已写入回忆归档还会触发归档回滚_delete_compression_archive。这防止了压缩后反而更大的负收益情况。5.3 可观测性压缩落盘Compression Dump开启enable_compression_dumpTrue后每次真实压缩调用会把完整工件落盘_dump_compression_artifactbase.py包含发给压缩模型的prompt与request、原始消息、三段 span、压缩摘要、压缩后消息、usage 统计等可用于离线分析压缩效果。落盘实现采用延迟导入避免循环依赖见 compression_dump.py。同时trigger_get_context_window与on_get_context_window全程通过_write_context_debug记录threshold_check、span_built、compression_retry等调试事件便于定位为什么没压缩。5.4 与 ReActAgent 的模型切换协同基类提供rebind_modelbase.py当主 Agent 在运行时切换模型时可把压缩执行器重绑到当前活跃模型上避免压缩器一直使用过时配置。该机制从源码看是为 ReActAgent 动态换模型场景设计的扩展点。六、测试验证与接入建议6.1 测试覆盖单元测试见 tests/unit_tests/core/context_engine/test_current_round_compressor.py覆盖了关键行为用 mock 模型响应验证大消息超过阈值后触发压缩通过ContextEngine.create_context以processors[(CurrentRoundCompressor, compressor_config)]方式注册处理器使用长度型 token counter 模拟 Token 计数验证触发判定逻辑验证压缩目标是最后一条 UserMessage 之后的 Assistant/Tool 消息这一核心语义。6.2 接入与调参建议首次接入先保持trigger_context_ratio0.8与keep_recent_messages0默认值用示例中的最小代码验证管道连通降低触发门槛若任务中工具结果普遍较长、希望更早压缩可将trigger_context_ratio下调例如0.6注意该值必须大于 0 小于 1保护最近信息若希望最近几条助手回复/工具结果不被压缩设置keep_recent_messages2~4工具边界会自动保护成对消息防止无意义压缩min_target_context_ratio默认0.1可压内容太少时会自动跳过压缩前自查确认model与model_client均正确配置——这是最容易被忽略的永不触发原因生产排障开启enable_compression_dumpTrue并设置compression_dump_dir结合调试日志分析每次压缩的收益与失败原因注意容量来源触发阈值基于上下文容量context_max计算该容量由resolve_context_max根据模型与上下文配置解析base.py实际部署时应确保上下文容量配置与所选模型一致。关联阅读ContextProcessor 基类说明、同族的 DialogueCompressor 与 RoundLevelCompressor 可构成当前轮 历史对话 整轮的完整压缩策略组合。赞分享人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习【免费下载链接】agent-coreopenJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力项目地址https://gitcode.com/openJiuwen/agent-core点击查看免费下载相关推荐openJiuwen agent-core 上下文引擎 ModelContext 接口与 ContextWindow 构建深度指南openJiuwen agent core 上下文引擎 ModelContext 接口与 ContextWindow 构建深度指南 本指南以 openjiuwe人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen context_engine 全解析Agent 上下文存储、窗口构建与压缩处理实战指南openJiuwen context_engine 全解析Agent 上下文存储、窗口构建与压缩处理实战指南 导读 openjiuwen.core.conte人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习ok-ww 鸣潮自动化完整指南日常一条龙、刷 4C 声骸到自动战斗如何跑通ok ww 鸣潮自动化完整指南日常一条龙、刷 4C 声骸到自动战斗如何跑通 ok ww 是一款面向《鸣潮》的开源自动化程序靠截屏图像识别加模拟点击按键把登GUI 自动化计算机视觉RPA人工智能上一篇京东抢购助手3分钟快速上手告别手动抢购烦恼下一篇N_m3u8DL-RE流媒体下载器5大核心技术深度解析与实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考