- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
导读
ContextWindow是 openJiuwen agent-core-java(openJiuwen Core 的 Java 版本)上下文子系统中"发往模型推理端的最终窗口对象",它聚合系统消息、上下文消息、工具定义与统计快照,是ContextEngine与ModelContext产出的最终推理输入载体。本文以 ContextWindow.md 为骨架,结合源码实现、配置项与测试用例,完整讲解其字段语义、Builder 用法、窗口裁剪规则、处理器拦截链路、统计口径以及它在 ReActAgent、LLM 事件处理器与 Ascend KV Cache 亲和调度中的实际调用方式。读完你将能在自己的 Agent 会话中正确构造、读取与扩展推理上下文窗口。
一、ContextWindow 在上下文子系统中的定位
在 openJiuwen 的上下文架构中,ContextEngine是统一入口,负责按sessionId + "_" + contextId的池键创建或复用ModelContext(见 ContextEngine.java),并统一通过ModelContext#getContextWindow()契约产出推理窗口(见 ModelContext.java)。
ContextWindow正是这条调用链的终点产物:
ContextEngine -> ModelContext(SessionModelContext) -> ContextProcessor 链路 -> ContextWindow -> 模型调用- 会话中的历史消息由
messageBuffer管理,getContextWindow()负责按窗口大小 / 对话轮数裁剪; - 注册的
ContextProcessor处理器(如RoundLevelCompressor、MessageOffloader、ToolResultBudgetProcessor等,预注册清单见 ContextEngine.java)可以在窗口产出前后介入改造; - 最终
ContextWindow通过getMessages()/getToolList()输出,成为model.invoke()的输入。
类本身定义于 ContextWindow.java,其 Javadoc 明确说明它是对 Python 版openjiuwen/core/context_engine/base.py中ContextWindow的镜像实现,字段序列化后可被会话状态保存与恢复。
二、字段语义与默认值
ContextWindow持有四类数据,默认值均为空集合或全新统计对象:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
systemMessages | List<BaseMessage> | [] | 应固定放在最终消息列表开头的系统级消息(如系统提示词)。 |
contextMessages | List<BaseMessage> | [] | 已按窗口大小、对话轮数或处理器规则裁剪后的上下文消息。 |
tools | List<ToolInfo> | [] | 当前轮可供模型调用的工具定义。 |
statistic | ContextStats | new ContextStats() | 当前窗口的统计快照(消息数、轮次、token 用量等)。 |
一个值得注意的实现细节:防御性拷贝贯穿始终。所有 getter(getSystemMessages、getContextMessages、getTools)都返回new ArrayList<>(...),所有 setter 与 Builder 方法也会先判空再拷贝(ContextWindow.java),避免调用方直接持有内部列表引用、破坏窗口不可变性,也避免null传入时污染内部状态。
三、核心方法:getMessages 与 getToolList
public List<BaseMessage> getMessages()
按systemMessages + contextMessages的顺序拼接出最终消息列表(ContextWindow.java):
public List<BaseMessage> getMessages() { List<BaseMessage> messages = new ArrayList<>(systemMessages); messages.addAll(contextMessages); return messages; }系统消息必须位于消息列表最前,这是保证模型正确理解系统指令的前提。测试用例 ContextWindowTest.java 对此做了显式验证:system 消息在 index 0,随后是 user、assistant 消息。
public List<ToolInfo> getToolList()
返回当前窗口持有的工具定义列表。源码中它是getTools()的兼容别名(ContextWindow.java):
/** Compatibility alias for {@link #getTools()}. */ public List<ToolInfo> getToolList() { return getTools(); }原文档特别指出:虽然类设计上兼容 Lombok@Data风格,但上下文子系统内部统一通过显式的getToolList()读取工具列表,以保证行为一致、可审计。测试 ContextWindowTest.java 验证了getToolList()能正确返回 builder 注入的工具。
四、Builder 构造与空值保护
ContextWindow同时提供全参构造函数与静态builder()(ContextWindow.java)。Builder 与 setter 对null入参的处理完全一致:统一回退为空ArrayList或全新ContextStats,因此即使调用方漏传某个字段,也不会产生NullPointerException。
ContextWindow window = ContextWindow.builder() .systemMessages(List.of(new SystemMessage("You are helpful"))) .contextMessages(List.of(new UserMessage("Hello"), new AssistantMessage("Hi"))) .tools(toolList) .statistic(ContextStats.builder().totalMessages(3).build()) .build(); List<BaseMessage> messages = window.getMessages(); // system 在前 List<ToolInfo> tools = window.getToolList();ContextWindowTest的testDefaults用例(ContextWindowTest.java)验证了默认 builder 产出的三个列表均为非空(assertNotNull)且为空集合(isEmpty),保证下游遍历安全。
类还重写了equals/hashCode,基于四个字段做深度比较(ContextWindow.java),便于窗口在 KV Cache 命中判断、会话状态对比等场景下做值相等性比较。
五、窗口从何而来:SessionModelContext 的裁剪与产出
ContextWindow通常不是手动 new 出来的,而是通过SessionModelContext#getContextWindow()自动产出(SessionModelContext.java)。该方法签名如下:
CompletionStage<ContextWindow> getContextWindow(List<BaseMessage> systemMessages, List<ToolInfo> tools, Integer windowSize, Integer dialogueRound, Map<String, Object> kwargs);参数校验
windowSize与dialogueRound若传入且<= 0,直接抛出CONTEXT_EXECUTION_ERROR,保证裁剪逻辑的输入合法;kwargs中的compression_trigger(默认"passive")会传递给处理器链路,标识本次窗口产出的触发方式;kwargs中的model参与 KV Cache 释放与模型上下文窗口 token 上限的解析。
裁剪规则(getWindowMessages)
窗口裁剪的核心逻辑在 SessionModelContext.java:
- 取缓冲区全部上下文消息;
- 若指定
dialogueRound,通过findLastNDialogueRound只保留最近 N 轮对话(默认轮数来自defaultDialogueRound,即配置default_window_round_num); - 若指定
windowSize,则从系统消息和上下文消息尾部各取一段,保证"最近优先":系统消息最多占windowSize的头部,剩余配额分配给上下文消息。
这种"尾部裁剪"策略与对话场景直觉一致——最新的消息优先级最高,过期的早期消息被丢弃,从而在固定窗口下保留最有价值的信息。
处理器链路
窗口产出后,SessionModelContext会遍历已注册处理器(SessionModelContext.java):
- 先调用
processor.triggerGetContextWindow(...)判断是否满足触发条件; - 满足条件则调用
processor.onGetContextWindow(...)对窗口进行压缩、卸载等改造,并用返回的contextWindow替换原窗口; - 处理器抛出的异常会被捕获并记录压缩状态后继续(与 Python 版"处理器失败不阻断主流程"的行为保持一致);
- 全程通过
emitCompressionState输出压缩状态事件,便于可观测。
处理器基类 ContextProcessor.java 默认实现均为透传(onGetContextWindow原样返回窗口),具体处理器可覆写实现压缩、卸载等逻辑。
产出后的窗口修正与统计
处理器链路结束后,validateAndFixContextWindow(SessionModelContext.java)会做一次"卫生检查":如果上下文消息以孤立ToolMessage开头(前面没有对应的 assistant 工具调用),则截断丢弃这些头部消息,避免模型收到无上下文的工具回包。
最后通过statContextWindow(SessionModelContext.java)统计消息数、各角色消息数、对话轮数与 token 用量,写入window.setStatistic(...),再返回给调用方。
六、statistic 快照:ContextStats 字段全解
ContextWindow.statistic的类型是ContextStats(ContextStats.java),它是一份覆盖消息与工具用量的统计快照,字段如下:
| 字段 | 说明 |
|---|---|
totalMessages | 当前统计范围内的消息总数。 |
totalTokens | 累计 token 总数(含工具 token)。 |
totalDialogues | 由对话轮次识别逻辑计算出的轮次数。 |
systemMessages/userMessages/assistantMessages/toolMessages | 各角色消息数。 |
tools | 注入窗口的ToolInfo数量。 |
systemMessageTokens/userMessageTokens/assistantMessageTokens/toolMessageTokens | 各角色消息的累计 token。 |
toolTokens | 工具定义本身的 token 数。 |
统计口径从源码可以确认:statContextWindow遍历getMessages()与getTools(),按角色累加消息数与 token(SessionModelContext.java);工具 token 在未启用专用ToolTokenCounterPort时,按"名称 + 描述 + 参数 JSON"的文本长度除以 4 估算(SessionModelContext.java)。
窗口的 token 上限解析由resolveContextMax(SessionModelContext.java)完成,优先级为:显式contextWindowTokens(配置context_window_tokens)→ 按模型名查modelContextWindowTokens(配置model_context_window_tokens,也可通过 OpenRouter 拉取)→ 内置模型默认表 → 全局兜底值。
七、实际调用场景:从 ReActAgent 到 LLM 事件处理器
ReActAgent 的每轮推理输入
在 ReActAgent.java 中,每轮模型调用前都会产出新窗口:
ContextWindow contextWindow = ctx.getContext().getContextWindow( List.of(new SystemMessage(promptBuilder.build())), tools, null, // windowSize,走默认配置 null, // dialogueRound,走默认配置 contextWindowKwargs // 启用 KV 释放时携带 "model" ).toCompletableFuture().join(); List<BaseMessage> messages = contextWindow.getMessages(); tools = contextWindow.getTools(); modelInputs.setMessages(new ArrayList<>(messages)); modelInputs.setTools(new ArrayList<>(tools));窗口的getMessages()/getTools()结果直接被灌入ModelInvokeOptions,作为model.invoke()的输入。当启用 KV cache 释放(enable_kv_cache_release)且当前 LLM 支持时,kwargs会携带model字段,供窗口产出后进行 KV cache 释放决策。
LLM 事件处理器
LlmEventHandler.java 同样通过context.getContextWindow(systemMessages, tools, null, null, Map.of("model", model))获取窗口,再以contextWindow.getTools()和contextWindow.getMessages()构造ModelInvokeOptions调用模型。
工作流组件按轮数截取历史
QuestionerDirectReplyHandler.java 展示了dialogueRound参数的实战用法:通过config.getChatHistoryMaxRounds()作为dialogueRound传入,只取最近 N 轮对话作为聊天历史,且保证历史末尾是 user 消息。
八、与 KV Cache 亲和调度的联动
窗口对象还参与 Ascend KV Cache 亲和调度。KVCacheModelCallHook.handleContextWindowChange(KVCacheModelCallHook.java)会把上一轮窗口与当前窗口做 diff,通过KVCacheManager.firstChangedDecision定位发生变更的消息/工具区间,再对llm.evictKvc(...)发起半开区间驱逐,保证缓存前缀有效。这也解释了为什么ReActAgent会用lastAffinityWindows按 session 记住上一轮的ContextWindow(ReActAgent.java):窗口对象本身成为 KV 缓存一致性判断的数据基础。
九、测试验证与使用建议
测试覆盖
ContextWindowTest.java 提供了三个关键用例,可作为行为契约参考:
testDefaults:builder 默认产出的三个列表非空且为空,防止 NPE;testGetMessages:拼接后 system 消息保持在前,顺序为 system → user → assistant;testGetToolList:工具列表可经兼容别名正确读取。
使用建议
- 不要绕过
ModelContext#getContextWindow()手动拼窗口:会话历史的裁剪、处理器压缩、孤立 ToolMessage 修正、统计快照都在这一路径中完成,直接手拼会丢失这些保障; - 善用
dialogueRound/windowSize:分别从"轮数"和"消息条数"两个维度控制窗口大小,二者为 null 时回退到ContextEngineConfig的default_window_round_num与default_window_message_num; - 通过
getMessages()而非内部字段读取最终消息:它保证了系统消息在前的顺序语义,也是 KV 缓存 diff 与统计口径的统一入口。
十、相关资源索引
- API 文档:ContextWindow.md、ContextStats.md、ContextEngine.md
- 源码实现:ContextWindow.java、ContextStats.java、SessionModelContext.java、ContextEngine.java
- 测试用例:ContextWindowTest.java
- 调用示例:ReActAgent.java、LlmEventHandler.java
- 配置入口:ContextEngineConfig.java(
default_window_message_num、default_window_round_num、context_window_tokens、model_context_window_tokens等)
- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- Agent 工作流
- RAG
- MCP Clients
- 强化学习
【免费下载链接】agent-core-java
openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。
相关推荐
openJiuwen agent-core 上下文引擎 ModelContext 接口与 ContextWindow 构建深度指南
openJiuwen agent core 上下文引擎 ModelContext 接口与 ContextWindow 构建深度指南 本指南以 openjiuwe
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习ok-ww 鸣潮自动化完整指南:日常一条龙、刷 4C 声骸到自动战斗如何跑通
ok ww 鸣潮自动化完整指南:日常一条龙、刷 4C 声骸到自动战斗如何跑通 ok ww 是一款面向《鸣潮》的开源自动化程序,靠截屏图像识别加模拟点击按键,把登
GUI 自动化计算机视觉RPA人工智能Open Model Zoo核心组件深度解析:从模型架构到推理引擎
Open Model Zoo核心组件深度解析:从模型架构到推理引擎 Open Model Zoo作为Intel® OpenVINO™工具包的重要组成部分,提供了
人工智能深度学习计算机视觉模型评测NLP语音
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考