背景与目标描述
摘要
面向同一服务内多个 Agent 实例并行独立运行、按需创建和销毁的场景,现有 ReActAgent 虽已考虑实例隔离与资源释放,但资源管理分散、单类职责集中、配置复杂,难以统一保障资源生命周期并支撑协作演进。本次保留旧实现,新增平级的 LiteReActAgent,通过实例分层持有资源、逐层调用各自的 close(),以及能力模块独立配置与装配,提升资源隔离与释放保障、易用性和可演进性;以新增的 RunnableAgent 为公共执行接口,以上层调用方式和输入输出协议兼容为目标,逐步适配现有设施,组装与配置方式独立调整。
全文按“需求依据 → 现有差距 → 方案取舍 → 定位边界 → 架构设计 → 实现成果”的思路展开:
- **第 1 章:服务化场景与业界依据。**结合服务化场景和业界实践,说明多实例隔离与及时释放资源的需求。
- **第 2 章:现有实现的差距与问题。**分析资源管理分散、职责集中和配置复杂的问题。
- **第 3 章:方案对比与选择。**比较三种方案的优缺点,从风险与长远收益出发选择独立 Lite 实现。
- **第 4 章:新实现的定位与边界。**明确新旧实现的平级关系、上层兼容目标及配置与内部实现的边界。
- **第 5 章:架构设计。**说明资源分层持有与逐层关闭、独立装配与模块化设计。
- **第 6 章:已实现的能力。**展示已落地的资源管理和模块解耦能力,回应前述需求与设计目标。
HTML 汇报稿
1. 服务化 Agent 的场景与业界依据
1.1 我们的服务化场景:多实例共存、按需创建和销毁
在服务化部署中,Agent 实例可能根据请求、会话或任务按需创建。一个服务进程中可以同时存在多个实例,各自装配不同的工具、技能、执行扩展和运行环境,工作结束后释放实例拥有的资源,而服务和其他实例继续运行。
这一场景要求:
- 实例之间可独立装配和运行。 一个实例的资源注册、替换和关闭,不应依靠修改其他实例也在使用的全局注册项来完成。
- 资源随所有者管理。 框架明确哪些组件归 Agent 实例所有,哪些只是借用;实例结束时能够统一释放其拥有的资源。
- 实例销毁与服务退出分离。 关闭一个 Agent 不需要停止进程级运行器,也不应要求应用逐一了解所有附属组件的内部清理入口。
这里的“快建快销”描述按需创建和及时销毁的使用模式,不代表已经获得创建耗时、吞吐量或内存占用方面的性能结论。
1.2 AgentScope Java 已将隔离与生命周期管理纳入设计目标
本次对照基于 AgentScope Java v2.0.3(2026-09-07 发布),固定源码提交为 1b8e3dcd2338550ae5198bdb2a7bae56df5bf2e0。其设计意图有直接代码依据:
这两项机制分别体现了实例级注册边界和明确的实例关闭动作,为本项目的资源隔离与释放设计提供参考。对应源码及实际使用案例见附录 A。
1.3 按请求创建 Agent 有直接的生产案例与修复记录
AgentScope 官方 Issue #2321 记录了生产服务按请求创建 Agent 的实际案例。使用方发现资源泄漏后反馈,社区已通过 PR #2322 完成修复,相关修复已列入 v2.0.1 发布记录。
这里引用该案例,是为了说明按请求创建和关闭 Agent 有实际使用需求,实例隔离与资源及时释放需要明确的设计和实现保障。
1.4 多个框架共同处理隔离与生命周期问题
- AutoGen 的状态管理教程 明确以无状态 Web 端点为场景,演示保存状态、创建新 Agent、加载状态后继续对话。
- Google ADK 的 Python Live 会话文档 采用启动时复用 Agent、Runner 和 SessionService,为会话分别创建运行配置及请求队列,并在结束时关闭队列。
据此可以归纳:**不同请求、任务或会话的可变状态需要隔离,共享组件与自有资源需要明确生命周期,是多个 Agent 框架共同处理的服务化问题。**具体方案可以是短生命周期 Agent,也可以是复用 Agent 并隔离调用状态;本项目根据部署场景,选择按需创建和关闭的 Lite Agent 实例作为能力与资源管理单元。
2. SDK 当前 ReActAgent 的差距与问题
**现有设计已考虑实例级隔离与资源及时释放,但实现上管理分散,难以统一确保隔离与资源释放;ReActAgent 单类职责集中、配置复杂,协作与演进困难。**旧体系已提供 owner 级工具隔离、共享工具保留、实例 Rail 以及注册/注销配对等机制,也有直接测试表达这些要求。当前资源登记、查找、注销和关闭尚未形成统一的实例资源管理边界,既需要补齐清理流程,也需要调整资源身份与相关组件的责任划分。
2.1 实例能力依赖全局资源体系
BaseAgent 会为每个对象创建 AbilityManager,但该管理器中的实例清单并不意味着具体能力资源也归属该对象。
以工具为例,AbilityManager.addAbility(...) 将具体工具注册到 Runner.resourceMgr(),执行时又通过该资源管理器查找工具。Runner 持有静态的 GLOBAL_RUNNER,因此这条能力运行链实际依赖进程级共享资源体系。即使应用直接调用 Agent 的 invoke(...),也不会因此绕过工具内部的全局资源查找。
这使 Agent 实例持有的能力清单,与具体资源的保存位置、隔离方式和释放责任分属不同层次。
2.2 基于标识的隔离不能完整表达对象实例隔离
旧体系已有隔离机制,但不同能力的隔离方式不统一:
- 有状态工具使用
工具名_ownerId 作为注册键,ownerId 来自 AgentCard ID。
- 无状态工具保留原始资源 ID,并按既有规则共享已注册资源。
- 默认回调和普通 Rail 使用全局回调框架,事件键由
agentId + event 构成。
- 实例 Rail 另有独立的注册入口和回调框架。
因此,不同 Agent ID 可以获得部分命名空间隔离,但同一业务 Agent ID 对应的多个 Java 对象实例,并不自然拥有各自独立的注册空间。这些实例的工具更新、查找和删除可能作用于同一注册键。
全局共享本身可以是合理选择。这里的差距是:共享、实例独占和资源所有权没有通过统一的实例装配合同明确表达,使用者需要额外管理资源标识、注册顺序与清理范围。
2.3 附属资源清理没有随 Agent 生命周期闭合
本次分支与 develop 的共同基线 27cba573 中,BaseAgent 尚无统一 close() 合同;当前分支新增了默认空实现,旧 ReActAgent 没有覆盖该方法。因此,当前旧执行路线仍未组织统一的实例关闭链。
旧体系存在 AbilityManager.teardownTools()、回调清理和 Rail 注销等手工入口,但这些操作没有被组织为统一的 Agent 关闭流程。此外,移除资源注册记录与关闭资源本身并不等价:普通工具管理器的 removeTool() 只移除注册项,不执行工具的关闭协议。
这意味着应用需要额外协调:
- 哪些工具或回调注册属于当前实例;
- 哪些注册项可以删除,哪些资源仍由其他实例使用;
- 注销之后,还需要关闭哪些附属资源;
- 某项关闭失败时,如何继续清理剩余资源。
单独丢弃 Agent 引用或调用其 close(),无法完成上述责任。对于持续创建和销毁实例的服务,这种分散的清理方式增加了资源残留和误清理共享注册项的风险。进程级 Runner 的退出流程也不能作为单个 Agent 实例的销毁方案。
上述结论说明的是资源归属和生命周期合同的结构性缺口,不将其等同于已经通过压力测试复现的内存泄漏。
2.4 职责集中与能力耦合扩大迭代成本
旧 ReActAgent.java 当前约 2500 行,除 ReAct 调度之外,还汇集工具执行适配、Skill 激活判断、Rail 接入、多种中断恢复协议、流输出和模型重试等逻辑。例如,识别 read_file、解析工具返回内容、比较文件路径并决定是否激活 Skill,都直接位于该类中。
能力细节的变化持续增加主类的修改原因和回归范围。随着工具、技能、提示词策略和执行扩展持续增加,如果各项能力都依赖同一大类的内部状态和流程,后续每项迭代都需要理解并验证越来越多的组合关系。
2.5 职责耦合增加多人协同开发成本
工具、Skill、提示词、执行扩展等能力集中在同一主类中,使不同开发者的需求容易涉及同一文件和相邻执行流程,增加合并冲突及修改相互影响的风险。
同时,模块边界不清会让代码审查和问题定位需要同时理解多项能力,难以按职责分配开发与维护责任。一个局部变更也可能需要其他能力的负责人参与联合验证,扩大协作和回归成本。
这些是职责集中和内部耦合带来的协作影响,不作为已经量化的冲突率或开发效率结论。对应的模块职责与独立演进设计见第 5 章。
2.6 弱类型与配置入口重叠增加使用成本
旧体系中,同一行为可能受多个配置来源影响。例如,模型既可以直接注入,也可以由 Agent 根据配置创建;模型配置同时存在顶层字段与嵌套对象,部分入口只修改其中一层,最终请求又可能由 Agent 配置覆盖模型名。调用方需要理解这些同步、覆盖和重建规则才能确定最终行为。
此外,部分执行输入、工具结果与中断恢复数据依赖 Object、Map 及字符串字段约定,调用方需要理解隐含的数据结构和状态含义;错误较难在编译期发现。配置入口与弱类型控制数据叠加,进一步增加使用和排查成本。
建议的方案
3. 三种实现方案对比与选择
3.1 补齐差距需要重构资源管理和模块边界
现有 ReActAgent 已提供模型注入、Rail、ContextProcessor 等扩展机制。对于不改变资源归属和运行合同的局部需求,这些机制仍然有价值。
在每个活跃实例使用唯一 Agent ID、共享依赖由外部管理、关闭前结束在途调用等约束下,将现有工具清理与 Rail 注销组织为统一流程,可以改善资源登记残留问题。旧体系也可以通过渐进重构继续完善。
要完整支持本次场景,并持续解决职责集中和能力耦合问题,必须调整以下结构:
- **资源归属与查找:**明确工具和执行扩展属于哪个实例、从哪里获取,以及共享资源与实例独占资源各由谁管理。
- **生命周期:**将资源持有、注册、注销和关闭组织到明确的所有权链中,同时与会话状态的保存和恢复分离。
- **模块职责与协作:**将集中在主类中的能力按职责拆分,通过明确接口协作,使各模块能够独立开发、验证和演进。
因此,**补齐这些差距需要对相关组件及其协作方式进行架构重构。**仅在外层追加清理调用,无法同时改变内部资源查找与所有权规则;仅拆分文件,也不能消除模块之间对内部状态和执行细节的耦合。
3.2 调用与输出可以保持稳定,组装和配置合同必须调整
公共执行合同描述调用方提交什么输入、如何调用 Agent,以及如何理解结果和流事件。这些合同可以通过 RunnableAgent 和统一的数据边界保持兼容,不必随内部资源管理与模块拆分一同改变。
组装与配置则直接决定 Agent 如何获得能力、如何组合模块,以及资源由谁持有和释放。前述重构要求在这些入口或其内部映射中表达新的责任:
| 重构要求 |
组装与配置需要表达的内容 |
| 从全局资源查找转向实例明确持有能力 |
工具与执行扩展来自哪些组件,在哪个实例中可见。 |
| 以所有权组织资源释放 |
依赖是借用还是由实例拥有,谁负责关闭,以及共享资源的管理边界。 |
| 从主类集中能力转向模块组合 |
装配哪些模块、采用何种实现、如何配置,以及模块依赖与协作顺序。 |
**因此,新实现的组装与配置语义、责任划分必须随架构重构调整,而 Agent 的公共调用与输出协议可以保持稳定。**这也是允许 Lite 独立定义配置与装配方式,同时承诺对上层执行兼容的依据。
旧配置方法的部分签名和使用形式仍可以通过适配保留,但需要明确它们如何映射到新的组装合同;如果继续保留旧全局查找、注册和回调行为,还需要维护相应的兼容策略。保留入口形式不会自动消除这些语义差异及其维护成本。
3.3 既有组装规则已经形成兼容约束
本次调整超出了保持行为不变的内部整理。以下既有规则有代码和直接测试依据:
| 既有行为合同 |
实例模型的目标规则 |
直接替换的兼容影响 |
| 当前 AbilityManager 未登记的工具,仍可以按名称从全局资源管理器查找并执行。 |
工具来源由实例显式装配的 Provider 和能力目录决定。 |
依赖全局工具回退的调用将不再成立;保留旧行为需要独立的解析策略或兼容适配。 |
有状态工具使用 工具名_ownerId 登记,默认 owner 来自 AgentCard ID,并允许刷新同一个资源键。 |
同一业务 Agent 的不同运行实例分别持有能力,注册、查找和释放均对应具体实例。 |
直接改变资源键或查找范围,会影响依赖既有 ID 规则的注册、查询和替换方式。 |
| 全局回调先于实例回调执行,两者共享可修改的上下文。 |
实例装配决定自身的执行扩展。 |
取消全局链会改变原有订阅者的执行与上下文修改效果;兼容需要保留桥接、执行顺序及注销边界。 |
上述合同分别由 AbilityManagerTest 的 executeFallsBackToResourceManagerByNameWhenAbilityIsUnregistered、addAbilityQualifiesStatefulToolAndTeardownRemovesOnlyOwnedInstance,以及 AgentCallbackManagerTest 的 executeRunsGlobalBeforeInstanceAndSharesContext 表达,代码链接见附录 B。保留方法签名,并不等于保留这些运行行为。
共享资源也需要独立的所有权规则。旧测试明确要求 stateless 工具不随某个 owner 的 teardown 一并删除;新体系同样允许共享基础组件,但必须区分借用与拥有,不能把装配关系一律解释为关闭责任。
3.4 三条改造路线及其长期成本
在需要重构的前提下,方案选择的重点是:**新的组装、配置和资源管理合同在哪里承载,如何处理与旧合同的兼容关系。**三条路线都可以将公共调用与输出协议作为稳定边界,其区别在于内部架构及组装合同的迁移方式。
| 方案 |
优点 |
缺点 |
| 方案1:直接重构旧 ReActAgent |
建立一致的实例管理与模块组合规则,集中维护一套 Agent 实现。 |
需要迁移或适配依赖旧配置、注册、解析和回调语义的调用方,迁移和回归风险较高。 |
| 方案2:旧 ReActAgent 同时支持新旧模式 |
保留旧行为,同时提供新的实例管理与模块组合方式,使用方可以逐步迁移。 |
需要长期维护两套合同的映射、混用规则、优先级及关闭责任,并验证对应的组合行为。 |
| √ 方案3:独立实现 LiteReActAgent |
旧入口维持既有运行方式,Lite 采用新的实例管理与模块组合规则,围绕公共执行协议独立演进。 |
增加两套 Agent 并存的维护责任,迁入 Lite 需要适配新的配置与能力装配合同。 |
同类双模式可以使用策略对象或适配层组织,并不必然产生大量散落的条件分支,也不必然复制两套主循环。但工具可见性、资源身份、共享方式和关闭责任仍存在两套语义;后续涉及这些边界的能力,都需要考虑兼容策略和组合验证。这些责任无法仅靠拆分文件或整理内部实现消除。
3.5 本次选择:以独立入口划定兼容与演进边界
**综合风险与长远收益,本次选择方案3:保留旧用法,支持 Lite 独立演进。**具体边界如下:
- 保持旧 ReActAgent 的执行路线独立,避免将新的能力运行合同直接施加给既有调用方。
- 在
com.openjiuwen.core.singleagent.lite 中建立独立的装配与执行路线。
- 按需复用 SP2 的 Model、ContextEngine、Session、消息等基础组件,对需要调整的配套能力在 Lite 中重新组织实现,明确实例资源管理责任。
- 让调用方根据场景明确选择使用 Lite,并通过新的组件合同接入能力。
独立入口使新实例合同无需在每个相关能力中同时承载旧的隐式全局行为,降低新场景演进时反复协调两套运行规则的需要。其代价仍是两条 Agent 执行链并存:通用修复需要逐项判断是否同步,共用基础组件的修改需要检查两侧影响,调用方迁入 Lite 也需要适配新的使用合同。
**多实例隔离与生命周期是本次需求的主因;兼容约束和长期演进成本,解释了为什么选择独立 Lite 来实现这一目标。**独立实现同时为正交模块的职责划分、独立演进和按需组合建立边界,避免后续能力持续堆积到主类中。这是一项明确承担并存成本的架构取舍,不以“旧体系技术上无法修复”或“兼容性与可演进性必然只能二选一”为前提。
4. 新实现的定位与边界
4.1 兼容承诺限定在公共调用方式与输入输出
ReActAgent 与 LiteReActAgent 都直接继承 BaseAgent;BaseAgent 实现 Core 公共接口 RunnableAgent。Lite 是同一 SDK 中的平级 Agent 实现,但这种类型关系还不足以证明调用兼容。本次明确以下对外边界:
| 层面 |
目标合同 |
| Agent 定位与调用方式 |
与现有 ReActAgent 保持平级,以 RunnableAgent 为公共执行抽象,提供兼容的普通和流式调用方式;创建、配置及装配接口另行定义。 |
| 调用输入 |
与既有公共 Agent 调用合同保持一致,包括输入结构、字段含义和会话标识的传递规则;上层不应因选择 Lite 而改用一套专用调用协议。 |
| 调用输出 |
与既有公共 Agent 调用合同保持一致,包括返回结构、状态与结果含义,以及适用的流式输出和中断恢复表达。这里的一致指数据合同,不指不同 Agent 必须生成相同的业务答案。 |
| 底层资源与能力 |
按需复用、组合或重构,以符合实例隔离和资源所有权要求;不承诺旧 Tool、Skill、Rail、Callback 或其他内部能力可以与 Lite 直接互换。 |
| 配置方式 |
不承诺 Lite 的配置、创建和装配方式与旧 ReActAgent 一致。 |
| 内部实现 |
不承诺执行组织、能力管理器、资源保存位置或生命周期实现与旧 ReActAgent 一致。 |
内部可以采用专用强类型对象,但应由 Agent 或 SDK 的统一调用边界完成必要转换,避免要求各个上层调用方分别理解 Lite 的内部类型。具体能力范围另行约定;某项能力纳入 Lite 后,其对外表达应遵循公共合同。其他 Agent 是否采用同一模块装配方式、底层能力是否相互复用,不属于上述公共输入输出一致性承诺。
当前 Lite 已复用 Core 的 Model、ContextEngine、Session、消息和流封装。这是当前实现的复用事实,不扩大为所有底层能力必须通用的承诺。
4.2 Runner 同时暴露上层调用入口与下层资源服务
现有 Runner 是进程级运行设施的统一入口,同一个类暴露了两种与 Agent 有关的职责:
| Runner 的职责 |
与 Agent 的关系 |
当前调用路径 |
runAgent/runAgentStreaming |
Agent 的可选上层运行入口:准备 Agent 和 Session,再调用 Agent 自己的执行方法。 |
应用 → Runner 运行入口 → Agent.invoke/stream。 |
resourceMgr 及全局回调等服务入口 |
旧 Agent 内部使用的资源服务:保存、查找和管理执行所需的资源。 |
旧 ReActAgent → AbilityManager → Runner.resourceMgr → Tool。 |
所以,即使应用直接调用旧 Agent、没有使用 Runner.runAgent,工具执行仍可能依赖 Runner 暴露的全局资源服务。按职责看,前者位于 Agent 上层,后者是旧 Agent 向下依赖的设施;同一个 Runner 入口同时包含这两种角色。
**Lite 当前由应用直接调用 Lite.invoke/stream:模型调用使用已装配的 Model;工具调用由 LiteAbilityManager 通过已装配的 LiteToolProvider 获取工具并统一执行。**主执行链不调用 Runner 的 Agent 调度入口,工具解析也不查询 Runner.resourceMgr。该结论限定于已核对的执行与工具路径,不扩展为所有间接 Core 依赖均不存在共享状态。
Lite 继承 BaseAgent,使现有 Runner 的基础派发分支具备调用它的静态条件;这只说明可选接入条件,不说明当前 Lite 已使用 Runner,也不把使用 Runner 作为 Lite 的运行前置要求。
4.3 上层执行依赖 RunnableAgent,创建与能力装配独立
**上层设施的执行路径应逐步依赖 RunnableAgent,复用已有任务调度、会话传递、结果消费和流式转发逻辑。**当前部分设施依赖旧 ReActAgent、BaseAgent 或反射调用,这是需要处理的现状耦合,不是上层必须长期绑定某一种 Agent 实现的理由。
RunnableAgent 已提供 getCard/invoke/stream/close,可作为最小公共执行合同。按以下职责划分推进:
| 职责 |
目标依赖与边界 |
| 执行 Agent |
接收已装配的 RunnableAgent 或返回该接口的 provider,使用公共输入输出合同;不通过强制转换回旧 ReActAgent 执行。 |
| 创建、配置和能力装配 |
由工厂、装配组件或明确的能力适配接口负责;旧体系和 Lite 可以采用不同实现。 |
| 编排与专门成员行为 |
调度和结果处理继续复用;工具委派、成员通信、任务取消、记忆和工作区等按职责提供独立适配。 |
| 实例生命周期 |
明确接入对象是借用还是由设施拥有;由所有者调用 close,不能将每次执行结束或单次任务取消自动等同于销毁实例。 |
保持 RunnableAgent 的执行职责,不把旧 AbilityManager、配置、Rail、Skill、workspace 或所有成员控制方法集中加入该接口。以 Hierarchical Tools 和 Handoff 为例,其工具注入依赖应通过独立装配边界处理,执行部分仍可以收敛到 RunnableAgent。
AgentTeam 的 MemberRuntime 可以在内部使用 RunnableAgent 执行,但仍需提供 steer、abort、中断处理及成员环境等专门合同。成员适配层与公共执行接口各负其责。
接口统一还必须落实第 4.1 节的数据合同,在公共入口验证会话识别、普通调用和流式派发;不要求 Lite 为此恢复对全局工具资源的隐式依赖。本节确定上层设施的演进方向。
4.4 兼容面覆盖多种上层入口,按实际依赖分别验收
上层设施不止 Runner。根据当前直接调用链,兼容性分析还应覆盖以下入口:
| 上层入口 |
当前边界 |
演进方向 |
| 应用直接调用、Runner 及其远程/子进程入口 |
公共 invoke/stream、输入输出、会话与传输协议;部分入口仍要求 BaseAgent,而非 RunnableAgent。 |
注册、实例解析和公共执行派发逐步支持 RunnableAgent,保留既有入口合同。 |
| Workflow ReAct 组件 |
消费 Agent 结果及流输出,但当前固定创建旧 ReActAgent。 |
接收已装配的 RunnableAgent,复用工作流调度与结果处理,分离构建和配置。 |
| 既有扩展装配设施、CLI、子 Agent 与 TaskLoop |
既有执行回调,也有固定 DeepAgent/旧 ReActAgent 的装配和控制路径。 |
执行目标或回调适配面向 RunnableAgent;旧创建、工具、Rail 与任务控制职责独立。 |
| Core 多 Agent 编排 |
基础 TeamRuntime 与 Handoff、Hierarchical Tools、Supervisor 的能力依赖不同。 |
基础运行与成员执行面向 RunnableAgent;委派工具和通信能力通过独立装配或适配接入。 |
| AgentTeam |
MemberRuntime 除流式调用外还要求控制、记忆与工作区等合同。 |
成员适配层使用 RunnableAgent 执行,并提供其余成员合同。 |
| 评测与训练等调用方 |
基础推理调用与 Rail 采集、训练操作及具体 Agent 工厂混合。 |
推理执行面向 RunnableAgent,其余训练与采集能力分别集成。 |
**上层位置不等于只依赖输入输出。**公共执行协议的一致性承诺应覆盖这些设施对该协议的消费,但不推导为它们的旧配置、工具注入或专门成员合同已能直接使用 Lite。需要逐项区分公共调用兼容与完整设施接入,避免将两者混写成“所有上层设施无缝兼容”。
当前 RunnableAgent 的输入与结果类型仍是 Object;不同团队还有自己的结果协议。因此,“一致”应落实为可互换执行场景下的具体数据与行为合同,并在上层成员边界完成必要映射。尤其要验证完成模块装配后实际交付的执行对象,不能只凭 BaseAgent 继承关系作结论。
详细入口、代码依据与验收维度见 《Lite Agent 的上层入口与兼容边界清单》。该清单记录当前静态接入条件和差距,不代表已经完成这些设施的适配,也不自动扩大本次实现范围。
4.5 保留旧入口,分批收敛公共执行路径
后续入口改造将保留已有构造和配置入口,使其继续按原有方式创建旧 ReActAgent,并按需新增接收已装配 RunnableAgent 或 provider 的入口,让不同 Agent 实现共享上层执行逻辑。兼容性验收覆盖旧入口的行为、已编译调用方适用的公共 API 兼容要求,以及新入口的普通调用、流式调用和生命周期。
具体推进顺序优先考虑只依赖执行合同的路径,再按需要拆出混合在上层设施中的能力装配和成员控制。每个入口分别确定改动范围和验收条件,不要求一次改造全部设施,也不将尚未完成的上层接入列为本次已交付能力。
配套改造依照已确认方向形成具体设计;既有 Core 的修改仍遵守最小通用扩展点或问题修复的准入条件,扩展点不包含 Lite 专有配置与能力语义。复用既有上层执行逻辑的具体方案需明确依赖、模块职责与资源所有权,不通过共享可变状态绕过实例隔离。
4.6 边界与非目标
- Lite 与旧 ReActAgent 保持平级,对外调用方式和输入输出以既有公共 Agent 合同为兼容目标;SDK 使用者的配置、装配及旧 Tool、Rail、Callback、Skill 接入方式不承诺相同。
- 上层执行路径以 RunnableAgent 为统一依赖方向,通过分离创建、配置和专门能力职责复用现有设施;逐项适配、分批验收,不宣称现有所有入口已完成接入。
- Lite 仍继承 BaseAgent 并复用 Core 基础设施;实例资源管理的改进不意味着消除所有旧基类或共享基础设施依赖。
- 多个独立实例共存与同一实例的线程安全是不同问题。当前 Lite 不承诺同一实例的并发调用、并发关闭或装配热切换安全。
- 资源按声明的所有权释放,不承诺关闭所有外部依赖,也不提供跨多次装配的事务式回滚。
- 新体系为后续能力组合提供基础,不将尚未交付的 Long Horizon、Notepad 或完整上下文压缩恢复写作本次已解决的问题。
- 合并请求应单列 BaseAgent 等公共 API 的实际调整及兼容影响;旧 ReActAgent 执行路线独立,不代表整批改动没有公共 API 变化。
5. 架构设计:资源隔离与释放、Agent 装配与模块化
5.1 以实例装配明确能力和资源归属
Lite 将工具提供与执行的职责统一收拢到实例级 LiteAbilityManager,由 DefaultLiteAbilityManager 实现,并在工具提供侧引入 Provider 模式。管理器统一组织工具目录、查找、执行及资源管理,不再通过旧 AbilityManager 将工具注册到全局 Runner 后再查找执行。拦截器、事件监听器和独立 Skill 模块也按照具体 Agent 实例进行装配和管理。
各能力模块通过明确的扩展接口接入工具、技能、提示词片段和执行扩展,并在装配时声明自身的资源与所有权。Agent 按场景选择模块并组成完整执行能力,模块的内部实现与生命周期责任保持清晰边界。
资源归属区分如下:
| 对象 |
生命周期原则 |
| Agent 拥有的 Provider、Skill、执行扩展和 AgentResource |
按各自所有权合同纳入实例关闭链。 |
| 外部装配的 Model、ContextEngine 等基础组件 |
装配不等于转移关闭责任,继续由其所有者管理。 |
| Session 中的会话历史和可恢复状态 |
按 Session 持久化合同保留,不因关闭 Agent 实例而一并删除。 |
5.2 关闭沿所有权逐层传递,各资源负责自身释放
LiteReActAgent.close() 组织自有执行扩展、Skill 模块、工具管理器和支持关闭的运行环境的关闭。工具管理器分别持有 Provider 与独立登记的自有资源,先关闭 Provider,再关闭登记资源;Skill 模块和执行扩展模块分别关闭自己持有的下级组件。各组件和资源通过自身的 close() 实现具体释放,Agent 负责组织关闭责任的传递。
装配阶段登记的模块资源同样纳入最终执行对象的关闭责任。关闭流程处理重复关闭,并在某项关闭失败后继续尝试剩余清理、聚合异常;模块负责释放自己拥有的下级资源。
由此,应用可以围绕一个明确的实例生命周期单元组织创建、使用和关闭,减少对全局资源注册规则以及各组件内部清理入口的依赖。
5.3 五层架构分工,六个能力模块通过明确接口协作
**Lite 将原先集中于 ReActAgent 的职责划分为多个相互正交的能力模块,使每个模块围绕一项明确职责独立实现、验证和演进。**这里的正交是指职责尽量不重叠、内部状态互不侵入,必要协作通过显式接口和约定的执行顺序完成。模块之间可以有必要依赖,但不依赖彼此的私有实现细节。
整体架构按以下五层组织:
| 层次 |
职责 |
| 01 上层兼容 |
以新增的 RunnableAgent 作为公共执行接口,不同 Agent 实现对上层提供统一调用合同;具体入口逐步适配。 |
| 02 独立装配 |
区分主循环配置与各能力模块独立配置与装载,配置归属组件,按需组成 Agent 实例。 |
| 03 核心循环 |
ReAct 主循环组织推理、行动、观察和终止判断,通过接口协调已装配能力。 |
| 04 能力模块 |
将工具、Skill、系统提示词、上下文管理、执行拦截与监听、流式输出划分为六个职责模块。 |
| 05 底层复用 |
按需复用 Tool / Model / PromptSection / ContextEngine / Session 等组件,必要时通过封装或转换接入。 |
其中,六个能力模块的职责如下:
| 模块职责 |
负责的行为与边界 |
| 工具管理与执行模块 |
收拢工具提供与执行职责,在提供侧通过 Provider 接入工具来源,统一管理目录、查找、执行及工具相关资源。 |
| Skill 模块 |
将技能索引、激活、内容和资源访问、状态管理等 Skill 相关实现收拢到模块内部,对外通过工具 Provider 和提示词片段参与执行。 |
| 系统提示词模块 |
管理独立提示词片段,按优先级结合当前调用上下文生成系统提示词。 |
| 上下文管理模块 |
组织消息、处理器及状态,通过已装配的 ContextEngine 为模型调用构建上下文。 |
| 执行拦截与监听模块 |
按执行阶段组织拦截链并分发事件给监听器,按约定顺序协作。 |
| 流式输出模块 |
集中组织模型、工具过程和最终结果的流事件,维护流输出协议。 |
每个模块同时明确所拥有的状态和资源,避免模块化之后仍依靠全局可变状态耦合。资源所有权是本章生命周期管理与模块化设计共同遵守的边界。
5.4 通过独立演进、扩展和插拔提升持续迭代能力
- **可独立演进:**模块在保持公共合同的前提下调整内部实现,主要影响限制在自身及明确的直接依赖;能够独立理解和测试,降低每次迭代的理解成本与回归范围。
- **可扩展:**新增能力优先通过已有扩展接口增加模块实现;新增工具来源、技能来源或提示词策略,不必持续向主执行类追加对应的专用逻辑。
- **可插拔:**在实例装配阶段,按场景选择、组合或替换满足同一合同的模块;可选能力不装配时,核心执行不应依赖其具体实现。
- **组合规则明确:**需要顺序、共享上下文或相互协作的模块,显式声明其依赖、作用范围和生命周期,避免靠隐式注册顺序或访问其他模块内部状态形成耦合。
例如,替换一个技能来源时,变化应落在技能获取模块及其装配位置;调整提示词组织策略时,工具执行和公共输出协议不应跟随修改。是否允许某种模块组合,由接口合同与组合验证决定。
这些原则使后续能力能够持续加入、替换和完善,系统性提升 ReActAgent 的可持续迭代能力。文档以模块职责、扩展合同和所有权说明架构,具体装配机制只是实现这些原则的一种方式。
5.5 配套设计:主循环与能力模块分别配置,内部类型明确
配置与装配分为主循环配置、各能力模块独立配置与装载两部分。主循环配置管理迭代上限、模型调用重试等参数;各能力模块管理自身设置,按需装载。Lite 通过 assemble(Model)、assemble(ContextEngine) 等入口接收已配置的基础组件,将组件配置责任归回组件本身。同时,为调用输入、工具结果、挂起恢复和迭代结果引入专用类型,减少核心控制逻辑对 Object、Map 和字符串约定的依赖。
组件分别负责自身配置,Agent 负责组合已配置组件;内部采用专用类型,公共执行边界应承担第 4.1 节约定的输入输出协议转换责任。这些改进服务于模块独立演进和 SDK 使用体验,不构成另建 ReActAgent 的独立主因。
6. LiteReActAgent 已实现的能力
本章沿第 5 章的两条设计主线,说明当前已经落地的机制及其作用:**实例资源隔离与释放,以及模块解耦与持续演进。**实现位置见附录 B,以下测试名称用于定位已有测试源码表达的行为,本次文档整理未重新运行测试。
6.1 Agent 资源分层持有,逐层各自销毁
1. 资源管理由分散登记转为实例分层持有。
以工具为例,旧体系将实例能力清单、全局资源登记与释放责任分置不同位置;Lite 则由 Agent 持有实例级 AbilityManager,再由管理器分别持有 Provider 与独立登记的自有资源。工具目录及工具实例通过已装配的 Provider 获取,工具运行链不再依靠旧 AbilityManager 向全局 Runner 注册后查找。拦截器、事件监听器和独立 Skill 模块也围绕具体 Agent 装配。能力来源及作用范围因此落实到实例持有的组件上,为多个实例分别选择能力提供明确边界。
直接依据:能力管理测试(LiteAbilityManagerTest)、工具运行测试(LiteReActAgentToolRuntimeTest)、执行扩展测试(LiteAgentExtensionsTest)。
2. 关闭责任逐层传递,各资源实现自己的 close()。
关闭关系为:**Agent.close() 发起实例关闭 → 组件.close() 调用所持资源的关闭入口 → 资源.close() 实现自身释放逻辑。**具体清理逻辑归属各资源,Agent 组织关闭责任的传递。借用的 Model、ContextEngine 等处于实例自有资源的关闭链之外,仍由外部所有者管理。
关闭流程同时处理重复关闭,某项清理失败后继续尝试其他清理并聚合异常。应用通过实例的关闭入口发起资源释放,并接收清理失败的汇总信息,减少逐一调用附属组件清理接口的负担。
直接依据:关闭顺序与失败聚合测试(LiteReActAgentSuspensionTest)、自有资源关闭测试(LiteProviderAssemblyTest)。
补充生命周期边界:关闭实例自有资源不删除按 Session 合同保存的会话状态,状态持久化与实例资源释放分别负责。会话保留并非 Lite 相对旧 ReActAgent 的新增特性。
Lite 在调用结束时保存上下文,按 Session 保存技能激活及待恢复工具调用状态,并区分自建会话清理与外部会话管理。恢复会话状态并重新装配依赖后,新 Agent 实例可以继续之前挂起的工具调用。这样,延续任务依靠可恢复的会话状态,应用无需为了保留任务进度而持续持有同一个 Agent 对象。
直接依据:上下文持久化测试(LiteReActAgentContextPersistenceTest)、技能管理测试(AgentSkillFrameTest)、挂起恢复测试(LiteReActAgentSuspensionTest)。
本节的实现重点是:资源由实例分层持有,关闭沿所有权逐层传递,每个资源负责实现自己的 close()。
6.2 按职责拆分模块,支撑独立演进
当前 Lite 已形成“主循环与能力模块分别配置、按需装配、能力模块各负其责、主循环协调执行”的整体组织方式。其落地成果从配置归属、六个模块的职责边界,以及扩展与协同开发三个方面说明。
1. 主循环配置与各能力模块独立配置、装载分责。
| 配置与装配部分 |
当前入口与责任 |
| 主循环配置 |
通过 configure(ReActAgentConfig) 设置迭代上限、模型调用重试等运行参数。 |
| 各能力模块独立配置与装载 |
Skill 通过 configSkillFrame(Consumer<AgentSkillFrameConfig>) 设置资源导出目录;工具 Provider、技能对象、提示词片段、拦截器和监听器通过对应的 assemble(...) 入口加入实例,上下文处理器通过有序列表装配。模块按职责采用各自的配置入口,按需装载。 |
Model、ContextEngine 等底层组件在外部完成配置,再通过 assemble(Model)、assemble(ContextEngine) 传入。模型和上下文的配置责任归回各自组件,Skill 等能力的专门设置归回模块,Agent 的装配入口负责将它们组合为具体实例。当前实现要求显式装配 Model 和 ContextEngine;调整 Agent 配置不会据此重新创建或替换这些组件。配置什么、装配什么以及由哪个模块解释配置,具有明确的职责落点。
直接依据:模型装配测试(LiteReActAgentModelAssemblyTest)、上下文装配测试(LiteReActAgentContextAssemblyTest)、技能管理测试(AgentSkillFrameTest)。
2. 主循环协调六个能力模块,将相关实现收拢到模块内部。
核心循环由 LiteReActAgent 组织推理、工具调用、结果观察以及继续或终止判断,通过接口协调已装配模块。Tool、Model、PromptSection、ContextEngine、Session 等属于按需复用的底层组件,其中 Model 提供普通和流式推理能力。
| 能力模块 |
主要实现 |
职责与协作方式 |
| 工具管理与执行模块 |
LiteAbilityManager、DefaultLiteAbilityManager、LiteToolProvider |
**统一收拢工具提供与执行职责。**提供侧引入 Provider 模式,接入不同工具来源;管理器组织目录刷新、工具查找、参数解析、执行和结果汇总,并管理 Provider 及自有资源的关闭。 |
| Skill 模块 |
skill 包、AgentSkillFrame 及其配套类型 |
**将 Skill 相关实现收拢到独立模块内部。**负责技能索引、激活、内容与资源访问、会话状态、渐进披露及生命周期;通过模块内的工具 Provider 和提示词片段接入 Agent,具体工具调用仍交由 AbilityManager 统一执行。 |
| 系统提示词模块 |
ContextAwareSystemPromptBuilder、ContextAwarePromptSection |
管理命名片段、优先级和当前调用上下文渲染,统一组织系统提示词;各能力通过片段贡献内容。 |
| 上下文管理模块 |
ContextEngine、ModelContext、Context Processor |
复用 Core 上下文能力,通过显式装配引擎和处理器组织消息、上下文窗口及状态保存,向模型调用提供输入。 |
| 执行拦截与监听模块 |
LiteAgentExtensions、拦截器与事件监听接口 |
管理调用、轮次、模型和工具四类执行阶段的拦截链与监听器,组织可选行为的执行顺序和生命周期。 |
| 流式输出模块 |
SessionStreamWriter、LiteToolStreamWriter |
集中生成模型、工具过程及最终结果流事件,管理流序号与载荷组织,为执行模块和工具提供写出入口。 |
这种划分将工具提供与执行集中到 AbilityManager 及其提供机制,将技能实现集中到 Skill 模块,将提示词、执行扩展和流事件组织集中到各自组件。模块通过明确接口协作,为独立实现、测试和按场景装配提供边界;新增工具来源、技能内容或执行扩展,有各自的接入位置。
直接测试依据按模块分布:
- 主执行与工具管理:执行合同测试(
LiteReActAgentParityTest)、工具运行测试(LiteReActAgentToolRuntimeTest)。
- Skill 与提示词:技能集成测试(
LiteAgentSkillIntegrationTest)、提示词构建测试(ContextAwareSystemPromptBuilderTest)、提示词集成测试(LiteReActAgentContextAwarePromptTest)。
- 执行扩展:执行扩展测试(
LiteAgentExtensionsTest)、拦截器集成测试(LiteReActAgentInterceptorTest)。
- 流写出:流写出测试(
SessionStreamWriterTest)、Agent 流输出测试(LiteReActAgentSessionStreamWriterTest)。
3. 能力扩展与协同开发有明确落点。
- **配置归所属组件。**模块解释自身配置,Agent 按场景装载所需能力。
- **扩展通过明确接口接入。**工具来源、Skill、提示词片段、拦截器和监听器分别在对应模块接入;扩展遵守接口、执行顺序和所有权合同。
- **开发与验证围绕模块展开。**相关实现和直接测试集中在职责模块中,减少不同能力持续集中修改同一主类的需要,便于分别开发、审查和回归。
这些实现为模块独立演进建立了边界。以职责边界降低耦合,让能力扩展与协同开发有明确落点,是本次模块化的主要成果。
附录 A:AgentScope Java 的设计与实践依据
本附录汇总第 1 章引用的三项依据,分别对应实例注册边界、实例关闭入口和按请求创建的实际使用案例。
| 关注点 |
AgentScope Java 的设计或实践依据 |
| 工具注册按实例隔离 |
Builder 通过 Toolkit.copy() 创建 Agent 自己的工具注册容器和工具组状态,各实例独立维护注册清单。Builder、注册表复制。 |
| 明确的实例关闭入口 |
Agent 提供 close() 方法,供使用方在实例使用结束后显式调用。关闭实现。 |
| 按请求创建 Agent 的实际案例 |
使用方在生产服务中按请求创建 Agent,发现资源泄漏后反馈,社区已完成修复。Issue #2321、PR #2322。 |
附录 B:SP2 代码依据
以下按类型和方法列出实现与测试依据,可在 SP2 源码中按名称检索。
| 论据 |
代码位置 |
| 进程级共享 Runner 与资源管理器 |
Runner.java:GLOBAL_RUNNER、resourceMgr()。 |
| 工具标识、全局注册、查找及手工注销 |
AbilityManager.java:qualifyToolId()、addAbility(ToolCard, Tool)、lookupTool()、teardownTools()。 |
| 全局与实例回调并存、按 Agent ID 构造事件键 |
AgentCallbackManager.java:registerRail()、registerInstanceRail()、getAgentEvent()、clear()。 |
| 工具身份、共享生命周期与全局回退的既有合同 |
AbilityManagerTest.java:addAbilityQualifiesStatefulToolAndTeardownRemovesOnlyOwnedInstance()、addAbilityKeepsStatelessToolIdAndDoesNotTeardownSharedInstance()、executeFallsBackToResourceManagerByNameWhenAbilityIsUnregistered()。 |
| 全局回调先于实例回调,且共享上下文 |
AgentCallbackManagerTest.java:executeRunsGlobalBeforeInstanceAndSharesContext()。 |
| 实例 Rail 隔离及注册/注销生命周期 |
BaseAgentInstanceRailTest.java:registerAndUnregisterManageLifecycleAndCallbacks()、sameCardIdAgentsKeepInstanceRailsSeparate()。 |
| 同一 SDK 中的公共执行合同 |
RunnableAgent.java:getCard()、invoke()、stream()、close();LiteReActAgentParityTest.java:liteIsAnIndependentBaseAndRunnableAgent()。 |
| 当前 Lite 专用输入输出及最终流载荷 |
LiteReActAgentInputs.java、AgentAnswer.java、SessionStreamWriter.java:请求/恢复对象、结果对象及 writeAnswer();旧输入和结果直接对照 ReActAgent 的 invoke() 与最终答案构造。 |
| Runner 普通/流式派发及会话识别 |
Runner.java:runAgent()、runAgentStreaming()、prepareAgent()、invokeDuckTypedAgent()、asStringObjectMap()。 |
| 编排中的旧工具装配依赖 |
HierarchicalToolsTeam.java:委派工具注入时调用 parent.getAbilityManager();ContainerAgent.java:injectToolsOnce()。 |
| 旧 ReActAgent 未组织实例关闭链 |
BaseAgent.java:当前分支新增默认空实现 close();ReActAgent.java:未覆盖该方法。 |
| 注销工具不等于关闭工具 |
ToolManager.java:removeTool()。 |
| Lite 的工具提供、执行与资源释放 |
LiteAbilityManager.java、DefaultLiteAbilityManager.java:addProvider()、refreshToolCatalog()、execute()、ownResource() 及 close()。 |
| 工具与技能模块的职责边界 |
LiteToolProvider.java:工具发现、提供与关闭;AgentSkillFrame.java:技能管理、会话状态访问及生命周期。 |
| 提示词组成与执行扩展边界 |
ContextAwarePromptSection.java:独立片段渲染及优先级;LiteAgentExtensions.java:调用、轮次、模型和工具阶段的扩展与监听。 |
| Lite 的配置、能力装配与实例关闭 |
LiteReActAgent.java:configure()、各 assemble(...) 方法、configSkillFrame() 和 close();AgentSkillFrameConfig.java:模块局部的资源导出目录配置。 |
| 配套优化涉及的旧配置和职责耦合 |
ReActAgentConfig.java:模型配置入口;ReActAgent.java:getLlm()、doRailedModelCall()、activateSkillsLoadedByToolCalls()。 |
涉及到的对外API
测试验证
测试验证
围绕“服务化多实例隔离、资源及时释放、易用性与可演进性”开展验证,采用单元测试、组件集成测试、服务场景测试、性能与稳定性测试相结合的方式。验证对象为 GitCode 仓库 hw_makeit/agent-core-java 中 dev-0.1.14-SP2 分支的最终待合入提交,并对 develop 原有 ReActAgent 的相关行为进行回归。本节为验证方案,具体执行范围、结果和数据在合入前补充,不将已有测试源码等同于测试已经通过。
1. 功能与架构验证
| 验证方向 |
测试方法 |
预期结果 |
| 多实例独立运行 |
在同一进程内创建多个 Agent,分别装配工具、Skill、提示词、上下文处理器、拦截器和监听器,使用独立 Session 交错、并行执行任务;覆盖相同业务 Agent ID、相同工具名的不同实例,并在 A 的调用间隙刷新其目录。 |
各实例只使用自身装配的能力及明确借用的组件,工具目录、调用参数、事件和结果不串用;A 的目录变化不影响 B,A 完成调用并关闭后,B 仍能正常执行。 |
| 资源分层持有与关闭 |
用可记录关闭次数、顺序和资源状态的测试组件构造 Agent、能力模块及下级资源的所有权关系,从 Agent 的 close() 发起关闭。 |
关闭按“Agent → 组件 → 自有资源”逐层传递;各资源通过自身 close() 完成释放,Provider 与独立登记资源均被覆盖,不遗漏下级自有资源。 |
| 自有与借用资源的边界 |
多个实例借用合同允许共享使用的 Model、ContextEngine 等组件,同时分别持有自己的资源;并行测试所用共享组件须支持该并行使用方式。实例调用结束后依次关闭,最后由外部所有者关闭共享组件。 |
实例关闭只释放自有资源,不误关借用组件,不影响其他实例;共享组件由外部所有者按其合同关闭。 |
| 独立配置与装配 |
分别修改主循环参数和能力模块配置,覆盖最小装配、可选能力组合、缺少必要组件及无效配置;通过公开接口装配 Model、ContextEngine 和模块。 |
配置在所属职责内生效;修改 Agent 配置不会隐式重建或替换已装配基础组件;缺少必要依赖时按合同给出明确错误。 |
| 六个能力模块协作 |
分别验证工具管理与执行、Skill、系统提示词、上下文管理、执行拦截与监听、流式输出,再组合执行完整 ReAct 流程。 |
工具目录、查找和执行一致;Skill 索引、激活与内容访问正确;提示词按优先级结合上下文渲染;上下文处理器顺序正确;拦截与监听按阶段生效;流事件的顺序、关联标识及结束语义符合合同。 |
| 易用性与扩展边界 |
用最小使用示例完成创建、配置、装配、调用和关闭;通过公开扩展接口新增一种工具来源、提示词片段或执行监听器,并验证组合行为。 |
示例可编译、可运行,配置与所有权清晰;合同支持的扩展无需修改主循环或访问其他模块私有状态,新增模块可独立测试。 |
| RunnableAgent 执行接口 |
对实际交付的执行对象验证普通调用、流式调用和 close(),检查接口类型及本次公共 API 调整。 |
当前实现的执行与生命周期合同通过验证;输入输出数据协议另行验收,不仅凭继承关系或方法签名判定完整兼容。 |
| 公共输入输出协议 |
随对应适配批次,对照旧 ReActAgent 验证输入字段、会话标识、结果结构、流事件、错误和适用的挂起恢复表达;复用既有结果消费者检查输出。 |
本批声明可互换的场景满足约定的数据与行为合同,转换在公共边界完成;当前 Lite 专用输入输出的测试不能代替公共协议兼容验收。 |
| 旧入口与状态回归 |
运行旧 ReActAgent 的相关配置、工具注册与查找、共享工具保留、回调和实例 Rail 测试;回归适用的 Session 持久化与恢复行为。 |
旧构造、配置和执行路线保持既有行为;实例资源释放不误删按 Session 合同保留的状态。会话保留作为回归边界验证,不作为新增特性。 |
Runner、Workflow、多 Agent 编排和 AgentTeam 按本次实际改造的入口分别执行集成验证。涉及工具注入、成员控制或专用协议的入口,需同时验证对应适配层;尚未纳入本次合入的上层接入单列为后续验收项,不写成已兼容。基础组件按其合同复用,PromptSection 经封装转换后的片段内容、优先级和渲染行为纳入适用的组合测试。
2. 可靠性与异常场景验证
- **重复关闭:**对提供幂等关闭合同的 Agent 和组件顺序重复调用
close(),检查下级资源的关闭动作不会被重复触发;资源自身的关闭行为按其合同单独验证,不将顺序重复关闭推导为并发关闭安全。
- **关闭失败:**分别在 Provider、Skill、执行扩展及登记资源的关闭阶段注入异常,检查其余清理仍会继续尝试,失败信息能够汇总返回;单项关闭失败不得被误报为所有资源释放成功,再次调用实例
close() 也不应被理解为自动重试失败资源。
- **装配失败:**覆盖 Provider 初始化、工具目录加载和模块装配失败,检查失败对象不会作为可用能力发布;已接管资源与未转移所有权资源分别按既定合同清理,不留下半初始化的可调用状态。
- **执行失败与重试:**注入模型异常、工具异常、无效工具结果、拦截器异常和流写出失败,检查错误传播、重试次数、事件顺序及最终执行状态;重试不得导致重复注册或跨实例状态污染。
- **超时、取消与流中断:**对本次支持超时或取消的调用路径,使用可控阻塞组件验证结束信号、后续事件和资源清理。请求结束后,由实际资源所有者执行约定的清理;不把单次请求取消自动等同于销毁 Agent,也不假设任意工具都可被强制中断。
- **并行实例与交错生命周期:**让多个独立实例分别执行创建、调用和关闭,验证某个实例异常或销毁不会中断其他实例;测试多个实例并行,不将同一实例的并发调用、调用中并发关闭或运行时热装配扩展为本次承诺。
采用故障注入、关闭计数器、事件记录和可控同步点验证顺序与边界,避免仅依赖日志人工判断或固定休眠。资源所有权断言应覆盖正常关闭和异常关闭两类路径。
3. 性能与资源稳定性验证
在固定 JDK、JVM 参数、CPU、内存、组件配置及 Session 保留策略的环境中执行测试。先用确定性模型响应和本地工具隔离模型网络延迟,测量框架开销;再用实际模型和工具执行代表性服务场景,分别报告两类结果。
| 场景 |
执行方式 |
观测与判定 |
| 创建与销毁开销 |
对最小装配和代表性完整装配分别预热,重复测量创建、装配及 close()。 |
记录耗时 P50/P95/P99、对象分配和 CPU 开销,识别资源数量增加后的成本变化。 |
| 并行实例负载 |
建议从 1、10、50、100 个独立实例逐级加压,按目标服务规模调整;使用相同输入、模型响应和工具负载重复测量。 |
记录吞吐量、错误率、调用延迟、流式首事件延迟及关闭耗时;检查是否出现实例间等待、异常争用或非预期退化。 |
| 反复创建和关闭 |
建议至少执行 10,000 次完整生命周期,并进行不少于 30 分钟的持续运行;混合正常调用、工具失败及关闭失败场景,按预期峰值扩大规模。 |
跟踪存活实例、资源计数、连接、线程、文件句柄、堆内存和 GC 趋势;正常关闭后的自有资源计数归零,失败注入产生的残留单独记录并按测试资源合同兜底清理。 |
| 长时间资源占用 |
分阶段采集对象直方图或堆快照,区分自有资源、共享组件、缓存和 Session 持久化数据。 |
在缓存预热、任务结束并经过合理回收观察窗口后,不应存在已结束实例及其自有资源随循环次数持续增长的引用链;不要求 JVM 立即归还全部进程内存。 |
| 旧能力性能回归 |
对新旧实现共有的代表性功能保持等价配置,比较合入前后的旧入口表现,并单独记录 Lite 的开销。 |
性能阈值在测试前依据基线波动和目标服务要求确定;报告逐项给出对比与原因,不以模型响应波动或代码行数减少代替性能结论。 |
重复测量时保留预热条件、样本量和异常样本说明。持续资源增长、可复现泄漏或未解释的性能退化必须定位后再判断是否满足合入条件。
4. 安全与隔离边界验证
- **能力访问隔离:**在 A、B 实例装配不同工具及同名工具,尝试通过 A 调用仅属于 B 的工具;同时在旧全局资源体系登记同名工具,验证 Lite 不会隐式回退到全局资源或其他实例的目录。
- **数据隔离:**为独立实例和会话设置可识别的测试标记,检查工具参数、上下文、提示词、Skill 状态、监听事件、结果与错误信息,确保不会带出其他实例或会话的非共享数据;按合同显式共享的组件单独检查。
- **非法输入与副作用:**覆盖未知工具名、非法参数结构、缺失或重复调用标识、重复资源标识、资源类型不匹配及关闭后登记。检查失败发生在约定边界,非法调用不会执行非预期工具或污染其他实例,被拒绝的资源登记不会误关原资源或擅自接管被拒绝对象。
- **资源清理范围:**在资源导出或文件清理涉及本次改动的场景中,使用隔离的临时目录验证关闭与清理范围,确保不会删除其他实例或外部所有者的文件及资源。
- **本次改动的安全检查:**检查新增配置、日志与异常处理不会额外暴露模型凭据或其他实例数据;如本次引入或升级依赖,按项目既有流程检查相关依赖风险。
本节验证 SDK 所提供的访问、数据与所有权边界;实例级隔离不等同于对任意第三方工具代码提供进程级安全沙箱。
5. 测试基础与执行安排
已有测试可作为补充用例和回归的基础,包括:
- 工具与资源生命周期:
LiteAbilityManagerTest、LiteProviderAssemblyTest、LiteReActAgentSuspensionTest。
- 配置、装配与执行:
LiteReActAgentModelAssemblyTest、LiteReActAgentContextAssemblyTest、LiteReActAgentToolRuntimeTest、LiteReActAgentParityTest。
- Skill 与提示词:
AgentSkillFrameTest、LiteAgentSkillIntegrationTest、ContextAwareSystemPromptBuilderTest、LiteReActAgentContextAwarePromptTest。
- 执行扩展与流输出:
LiteAgentExtensionsTest、LiteReActAgentInterceptorTest、SessionStreamWriterTest、LiteReActAgentSessionStreamWriterTest。
- 旧入口、资源合同与状态回归:
ReActAgentTest、ReActAgentReactiveTest、ReActAgentConfigTest、ReActAgentToolLifecycleStreamTest、AbilityManagerTest、AgentCallbackManagerTest、BaseAgentInstanceRailTest、LiteReActAgentContextPersistenceTest。
先将上述验证点与已有用例逐项对应,补齐没有覆盖的多实例组合、异常路径和边界用例,再按以下顺序执行:
- **模块级确定性测试:**使用可控 Model、Provider、Skill 和资源替身验证功能、失败及关闭合同;需要固定调用顺序的场景由测试替身控制。
- **集成与回归测试:**在 SP2 项目中执行相关测试,再执行项目级
mvn test 或带覆盖率报告的 mvn -Pcoverage verify,检查直接受影响的旧入口及公共 API 行为。默认排除的 system-test 用例需另行组织执行并单独记录,不能将默认 Maven 结果作为系统测试已经覆盖的依据。
- **服务场景与真实组件验证:**覆盖本次纳入范围的普通、流式和适用的恢复场景。真实模型用例只描述工作目标与环境,不通过提示词强制预设工具轨迹;模型未自然覆盖的分支由确定性测试补充。
- **性能、稳定性与安全验证:**执行上述负载与负向场景,记录指标和资源趋势;按最终候选提交生成报告,合入后通过 CI 和代表性场景确认结果。
6. 合入验收与结果记录
- 本次声明交付的能力都有对应测试,功能、异常和生命周期关键路径通过;新增改动及直接影响范围的回归无未解决失败。
- 多实例测试无能力串用、数据串用或跨实例误关闭;正常生命周期无可复现的自有资源泄漏;关闭失败可观测,其他资源清理会继续尝试。
- 本次纳入的公共调用场景满足约定协议,旧入口行为保持兼容;未完成的上层适配明确列出,不作为已交付能力。
- 性能结果满足测试前确认的阈值,资源稳定性测试无未解释的持续增长;本次改动相关的安全问题完成处理。
- 归档最终提交号、测试环境、执行命令、通过/失败/跳过数量、关键用例与覆盖情况、性能数据、资源趋势及遗留事项。未执行项说明原因与影响,不能只凭测试总通过率或覆盖率百分比判定充分验证。
期望的反馈时间
抄送的人员名单
其他补充信息
感谢你的贡献🎉!openJiuwen 核心团队每周举办一次 RFC 评审会,虽然大部分 RFC 都可在线上进行讨论,但你也可以自愿报名预约时段,参与 RFC 的线上研讨。
在你提交新issue之前
背景与目标描述
摘要
面向同一服务内多个 Agent 实例并行独立运行、按需创建和销毁的场景,现有 ReActAgent 虽已考虑实例隔离与资源释放,但资源管理分散、单类职责集中、配置复杂,难以统一保障资源生命周期并支撑协作演进。本次保留旧实现,新增平级的 LiteReActAgent,通过实例分层持有资源、逐层调用各自的 close(),以及能力模块独立配置与装配,提升资源隔离与释放保障、易用性和可演进性;以新增的 RunnableAgent 为公共执行接口,以上层调用方式和输入输出协议兼容为目标,逐步适配现有设施,组装与配置方式独立调整。
全文按“需求依据 → 现有差距 → 方案取舍 → 定位边界 → 架构设计 → 实现成果”的思路展开:
HTML 汇报稿
1. 服务化 Agent 的场景与业界依据
1.1 我们的服务化场景:多实例共存、按需创建和销毁
在服务化部署中,Agent 实例可能根据请求、会话或任务按需创建。一个服务进程中可以同时存在多个实例,各自装配不同的工具、技能、执行扩展和运行环境,工作结束后释放实例拥有的资源,而服务和其他实例继续运行。
这一场景要求:
这里的“快建快销”描述按需创建和及时销毁的使用模式,不代表已经获得创建耗时、吞吐量或内存占用方面的性能结论。
1.2 AgentScope Java 已将隔离与生命周期管理纳入设计目标
本次对照基于 AgentScope Java v2.0.3(2026-09-07 发布),固定源码提交为
1b8e3dcd2338550ae5198bdb2a7bae56df5bf2e0。其设计意图有直接代码依据:这两项机制分别体现了实例级注册边界和明确的实例关闭动作,为本项目的资源隔离与释放设计提供参考。对应源码及实际使用案例见附录 A。
1.3 按请求创建 Agent 有直接的生产案例与修复记录
AgentScope 官方 Issue #2321 记录了生产服务按请求创建 Agent 的实际案例。使用方发现资源泄漏后反馈,社区已通过 PR #2322 完成修复,相关修复已列入 v2.0.1 发布记录。
这里引用该案例,是为了说明按请求创建和关闭 Agent 有实际使用需求,实例隔离与资源及时释放需要明确的设计和实现保障。
1.4 多个框架共同处理隔离与生命周期问题
据此可以归纳:**不同请求、任务或会话的可变状态需要隔离,共享组件与自有资源需要明确生命周期,是多个 Agent 框架共同处理的服务化问题。**具体方案可以是短生命周期 Agent,也可以是复用 Agent 并隔离调用状态;本项目根据部署场景,选择按需创建和关闭的 Lite Agent 实例作为能力与资源管理单元。
2. SDK 当前 ReActAgent 的差距与问题
**现有设计已考虑实例级隔离与资源及时释放,但实现上管理分散,难以统一确保隔离与资源释放;ReActAgent 单类职责集中、配置复杂,协作与演进困难。**旧体系已提供 owner 级工具隔离、共享工具保留、实例 Rail 以及注册/注销配对等机制,也有直接测试表达这些要求。当前资源登记、查找、注销和关闭尚未形成统一的实例资源管理边界,既需要补齐清理流程,也需要调整资源身份与相关组件的责任划分。
2.1 实例能力依赖全局资源体系
BaseAgent会为每个对象创建AbilityManager,但该管理器中的实例清单并不意味着具体能力资源也归属该对象。以工具为例,
AbilityManager.addAbility(...)将具体工具注册到Runner.resourceMgr(),执行时又通过该资源管理器查找工具。Runner持有静态的GLOBAL_RUNNER,因此这条能力运行链实际依赖进程级共享资源体系。即使应用直接调用 Agent 的invoke(...),也不会因此绕过工具内部的全局资源查找。这使 Agent 实例持有的能力清单,与具体资源的保存位置、隔离方式和释放责任分属不同层次。
2.2 基于标识的隔离不能完整表达对象实例隔离
旧体系已有隔离机制,但不同能力的隔离方式不统一:
工具名_ownerId作为注册键,ownerId来自 AgentCard ID。agentId + event构成。因此,不同 Agent ID 可以获得部分命名空间隔离,但同一业务 Agent ID 对应的多个 Java 对象实例,并不自然拥有各自独立的注册空间。这些实例的工具更新、查找和删除可能作用于同一注册键。
全局共享本身可以是合理选择。这里的差距是:共享、实例独占和资源所有权没有通过统一的实例装配合同明确表达,使用者需要额外管理资源标识、注册顺序与清理范围。
2.3 附属资源清理没有随 Agent 生命周期闭合
本次分支与
develop的共同基线27cba573中,BaseAgent尚无统一close()合同;当前分支新增了默认空实现,旧 ReActAgent 没有覆盖该方法。因此,当前旧执行路线仍未组织统一的实例关闭链。旧体系存在
AbilityManager.teardownTools()、回调清理和 Rail 注销等手工入口,但这些操作没有被组织为统一的 Agent 关闭流程。此外,移除资源注册记录与关闭资源本身并不等价:普通工具管理器的removeTool()只移除注册项,不执行工具的关闭协议。这意味着应用需要额外协调:
单独丢弃 Agent 引用或调用其
close(),无法完成上述责任。对于持续创建和销毁实例的服务,这种分散的清理方式增加了资源残留和误清理共享注册项的风险。进程级 Runner 的退出流程也不能作为单个 Agent 实例的销毁方案。上述结论说明的是资源归属和生命周期合同的结构性缺口,不将其等同于已经通过压力测试复现的内存泄漏。
2.4 职责集中与能力耦合扩大迭代成本
旧
ReActAgent.java当前约 2500 行,除 ReAct 调度之外,还汇集工具执行适配、Skill 激活判断、Rail 接入、多种中断恢复协议、流输出和模型重试等逻辑。例如,识别read_file、解析工具返回内容、比较文件路径并决定是否激活 Skill,都直接位于该类中。能力细节的变化持续增加主类的修改原因和回归范围。随着工具、技能、提示词策略和执行扩展持续增加,如果各项能力都依赖同一大类的内部状态和流程,后续每项迭代都需要理解并验证越来越多的组合关系。
2.5 职责耦合增加多人协同开发成本
工具、Skill、提示词、执行扩展等能力集中在同一主类中,使不同开发者的需求容易涉及同一文件和相邻执行流程,增加合并冲突及修改相互影响的风险。
同时,模块边界不清会让代码审查和问题定位需要同时理解多项能力,难以按职责分配开发与维护责任。一个局部变更也可能需要其他能力的负责人参与联合验证,扩大协作和回归成本。
这些是职责集中和内部耦合带来的协作影响,不作为已经量化的冲突率或开发效率结论。对应的模块职责与独立演进设计见第 5 章。
2.6 弱类型与配置入口重叠增加使用成本
旧体系中,同一行为可能受多个配置来源影响。例如,模型既可以直接注入,也可以由 Agent 根据配置创建;模型配置同时存在顶层字段与嵌套对象,部分入口只修改其中一层,最终请求又可能由 Agent 配置覆盖模型名。调用方需要理解这些同步、覆盖和重建规则才能确定最终行为。
此外,部分执行输入、工具结果与中断恢复数据依赖 Object、Map 及字符串字段约定,调用方需要理解隐含的数据结构和状态含义;错误较难在编译期发现。配置入口与弱类型控制数据叠加,进一步增加使用和排查成本。
建议的方案
3. 三种实现方案对比与选择
3.1 补齐差距需要重构资源管理和模块边界
现有 ReActAgent 已提供模型注入、Rail、ContextProcessor 等扩展机制。对于不改变资源归属和运行合同的局部需求,这些机制仍然有价值。
在每个活跃实例使用唯一 Agent ID、共享依赖由外部管理、关闭前结束在途调用等约束下,将现有工具清理与 Rail 注销组织为统一流程,可以改善资源登记残留问题。旧体系也可以通过渐进重构继续完善。
要完整支持本次场景,并持续解决职责集中和能力耦合问题,必须调整以下结构:
因此,**补齐这些差距需要对相关组件及其协作方式进行架构重构。**仅在外层追加清理调用,无法同时改变内部资源查找与所有权规则;仅拆分文件,也不能消除模块之间对内部状态和执行细节的耦合。
3.2 调用与输出可以保持稳定,组装和配置合同必须调整
公共执行合同描述调用方提交什么输入、如何调用 Agent,以及如何理解结果和流事件。这些合同可以通过 RunnableAgent 和统一的数据边界保持兼容,不必随内部资源管理与模块拆分一同改变。
组装与配置则直接决定 Agent 如何获得能力、如何组合模块,以及资源由谁持有和释放。前述重构要求在这些入口或其内部映射中表达新的责任:
**因此,新实现的组装与配置语义、责任划分必须随架构重构调整,而 Agent 的公共调用与输出协议可以保持稳定。**这也是允许 Lite 独立定义配置与装配方式,同时承诺对上层执行兼容的依据。
旧配置方法的部分签名和使用形式仍可以通过适配保留,但需要明确它们如何映射到新的组装合同;如果继续保留旧全局查找、注册和回调行为,还需要维护相应的兼容策略。保留入口形式不会自动消除这些语义差异及其维护成本。
3.3 既有组装规则已经形成兼容约束
本次调整超出了保持行为不变的内部整理。以下既有规则有代码和直接测试依据:
工具名_ownerId登记,默认 owner 来自 AgentCard ID,并允许刷新同一个资源键。上述合同分别由
AbilityManagerTest的executeFallsBackToResourceManagerByNameWhenAbilityIsUnregistered、addAbilityQualifiesStatefulToolAndTeardownRemovesOnlyOwnedInstance,以及AgentCallbackManagerTest的executeRunsGlobalBeforeInstanceAndSharesContext表达,代码链接见附录 B。保留方法签名,并不等于保留这些运行行为。共享资源也需要独立的所有权规则。旧测试明确要求 stateless 工具不随某个 owner 的 teardown 一并删除;新体系同样允许共享基础组件,但必须区分借用与拥有,不能把装配关系一律解释为关闭责任。
3.4 三条改造路线及其长期成本
在需要重构的前提下,方案选择的重点是:**新的组装、配置和资源管理合同在哪里承载,如何处理与旧合同的兼容关系。**三条路线都可以将公共调用与输出协议作为稳定边界,其区别在于内部架构及组装合同的迁移方式。
同类双模式可以使用策略对象或适配层组织,并不必然产生大量散落的条件分支,也不必然复制两套主循环。但工具可见性、资源身份、共享方式和关闭责任仍存在两套语义;后续涉及这些边界的能力,都需要考虑兼容策略和组合验证。这些责任无法仅靠拆分文件或整理内部实现消除。
3.5 本次选择:以独立入口划定兼容与演进边界
**综合风险与长远收益,本次选择方案3:保留旧用法,支持 Lite 独立演进。**具体边界如下:
com.openjiuwen.core.singleagent.lite中建立独立的装配与执行路线。独立入口使新实例合同无需在每个相关能力中同时承载旧的隐式全局行为,降低新场景演进时反复协调两套运行规则的需要。其代价仍是两条 Agent 执行链并存:通用修复需要逐项判断是否同步,共用基础组件的修改需要检查两侧影响,调用方迁入 Lite 也需要适配新的使用合同。
**多实例隔离与生命周期是本次需求的主因;兼容约束和长期演进成本,解释了为什么选择独立 Lite 来实现这一目标。**独立实现同时为正交模块的职责划分、独立演进和按需组合建立边界,避免后续能力持续堆积到主类中。这是一项明确承担并存成本的架构取舍,不以“旧体系技术上无法修复”或“兼容性与可演进性必然只能二选一”为前提。
4. 新实现的定位与边界
4.1 兼容承诺限定在公共调用方式与输入输出
ReActAgent与LiteReActAgent都直接继承BaseAgent;BaseAgent实现 Core 公共接口RunnableAgent。Lite 是同一 SDK 中的平级 Agent 实现,但这种类型关系还不足以证明调用兼容。本次明确以下对外边界:内部可以采用专用强类型对象,但应由 Agent 或 SDK 的统一调用边界完成必要转换,避免要求各个上层调用方分别理解 Lite 的内部类型。具体能力范围另行约定;某项能力纳入 Lite 后,其对外表达应遵循公共合同。其他 Agent 是否采用同一模块装配方式、底层能力是否相互复用,不属于上述公共输入输出一致性承诺。
当前 Lite 已复用 Core 的 Model、ContextEngine、Session、消息和流封装。这是当前实现的复用事实,不扩大为所有底层能力必须通用的承诺。
4.2 Runner 同时暴露上层调用入口与下层资源服务
现有 Runner 是进程级运行设施的统一入口,同一个类暴露了两种与 Agent 有关的职责:
runAgent/runAgentStreamingresourceMgr及全局回调等服务入口所以,即使应用直接调用旧 Agent、没有使用
Runner.runAgent,工具执行仍可能依赖 Runner 暴露的全局资源服务。按职责看,前者位于 Agent 上层,后者是旧 Agent 向下依赖的设施;同一个 Runner 入口同时包含这两种角色。**Lite 当前由应用直接调用 Lite.invoke/stream:模型调用使用已装配的 Model;工具调用由 LiteAbilityManager 通过已装配的 LiteToolProvider 获取工具并统一执行。**主执行链不调用 Runner 的 Agent 调度入口,工具解析也不查询 Runner.resourceMgr。该结论限定于已核对的执行与工具路径,不扩展为所有间接 Core 依赖均不存在共享状态。
Lite 继承 BaseAgent,使现有 Runner 的基础派发分支具备调用它的静态条件;这只说明可选接入条件,不说明当前 Lite 已使用 Runner,也不把使用 Runner 作为 Lite 的运行前置要求。
4.3 上层执行依赖 RunnableAgent,创建与能力装配独立
**上层设施的执行路径应逐步依赖 RunnableAgent,复用已有任务调度、会话传递、结果消费和流式转发逻辑。**当前部分设施依赖旧 ReActAgent、BaseAgent 或反射调用,这是需要处理的现状耦合,不是上层必须长期绑定某一种 Agent 实现的理由。
RunnableAgent 已提供
getCard/invoke/stream/close,可作为最小公共执行合同。按以下职责划分推进:保持 RunnableAgent 的执行职责,不把旧 AbilityManager、配置、Rail、Skill、workspace 或所有成员控制方法集中加入该接口。以 Hierarchical Tools 和 Handoff 为例,其工具注入依赖应通过独立装配边界处理,执行部分仍可以收敛到 RunnableAgent。
AgentTeam 的 MemberRuntime 可以在内部使用 RunnableAgent 执行,但仍需提供 steer、abort、中断处理及成员环境等专门合同。成员适配层与公共执行接口各负其责。
接口统一还必须落实第 4.1 节的数据合同,在公共入口验证会话识别、普通调用和流式派发;不要求 Lite 为此恢复对全局工具资源的隐式依赖。本节确定上层设施的演进方向。
4.4 兼容面覆盖多种上层入口,按实际依赖分别验收
上层设施不止 Runner。根据当前直接调用链,兼容性分析还应覆盖以下入口:
**上层位置不等于只依赖输入输出。**公共执行协议的一致性承诺应覆盖这些设施对该协议的消费,但不推导为它们的旧配置、工具注入或专门成员合同已能直接使用 Lite。需要逐项区分公共调用兼容与完整设施接入,避免将两者混写成“所有上层设施无缝兼容”。
当前 RunnableAgent 的输入与结果类型仍是 Object;不同团队还有自己的结果协议。因此,“一致”应落实为可互换执行场景下的具体数据与行为合同,并在上层成员边界完成必要映射。尤其要验证完成模块装配后实际交付的执行对象,不能只凭 BaseAgent 继承关系作结论。
详细入口、代码依据与验收维度见 《Lite Agent 的上层入口与兼容边界清单》。该清单记录当前静态接入条件和差距,不代表已经完成这些设施的适配,也不自动扩大本次实现范围。
4.5 保留旧入口,分批收敛公共执行路径
后续入口改造将保留已有构造和配置入口,使其继续按原有方式创建旧 ReActAgent,并按需新增接收已装配 RunnableAgent 或 provider 的入口,让不同 Agent 实现共享上层执行逻辑。兼容性验收覆盖旧入口的行为、已编译调用方适用的公共 API 兼容要求,以及新入口的普通调用、流式调用和生命周期。
具体推进顺序优先考虑只依赖执行合同的路径,再按需要拆出混合在上层设施中的能力装配和成员控制。每个入口分别确定改动范围和验收条件,不要求一次改造全部设施,也不将尚未完成的上层接入列为本次已交付能力。
配套改造依照已确认方向形成具体设计;既有 Core 的修改仍遵守最小通用扩展点或问题修复的准入条件,扩展点不包含 Lite 专有配置与能力语义。复用既有上层执行逻辑的具体方案需明确依赖、模块职责与资源所有权,不通过共享可变状态绕过实例隔离。
4.6 边界与非目标
5. 架构设计:资源隔离与释放、Agent 装配与模块化
5.1 以实例装配明确能力和资源归属
Lite 将工具提供与执行的职责统一收拢到实例级
LiteAbilityManager,由DefaultLiteAbilityManager实现,并在工具提供侧引入 Provider 模式。管理器统一组织工具目录、查找、执行及资源管理,不再通过旧AbilityManager将工具注册到全局 Runner 后再查找执行。拦截器、事件监听器和独立 Skill 模块也按照具体 Agent 实例进行装配和管理。各能力模块通过明确的扩展接口接入工具、技能、提示词片段和执行扩展,并在装配时声明自身的资源与所有权。Agent 按场景选择模块并组成完整执行能力,模块的内部实现与生命周期责任保持清晰边界。
资源归属区分如下:
5.2 关闭沿所有权逐层传递,各资源负责自身释放
LiteReActAgent.close()组织自有执行扩展、Skill 模块、工具管理器和支持关闭的运行环境的关闭。工具管理器分别持有 Provider 与独立登记的自有资源,先关闭 Provider,再关闭登记资源;Skill 模块和执行扩展模块分别关闭自己持有的下级组件。各组件和资源通过自身的close()实现具体释放,Agent 负责组织关闭责任的传递。装配阶段登记的模块资源同样纳入最终执行对象的关闭责任。关闭流程处理重复关闭,并在某项关闭失败后继续尝试剩余清理、聚合异常;模块负责释放自己拥有的下级资源。
由此,应用可以围绕一个明确的实例生命周期单元组织创建、使用和关闭,减少对全局资源注册规则以及各组件内部清理入口的依赖。
5.3 五层架构分工,六个能力模块通过明确接口协作
**Lite 将原先集中于 ReActAgent 的职责划分为多个相互正交的能力模块,使每个模块围绕一项明确职责独立实现、验证和演进。**这里的正交是指职责尽量不重叠、内部状态互不侵入,必要协作通过显式接口和约定的执行顺序完成。模块之间可以有必要依赖,但不依赖彼此的私有实现细节。
整体架构按以下五层组织:
其中,六个能力模块的职责如下:
每个模块同时明确所拥有的状态和资源,避免模块化之后仍依靠全局可变状态耦合。资源所有权是本章生命周期管理与模块化设计共同遵守的边界。
5.4 通过独立演进、扩展和插拔提升持续迭代能力
例如,替换一个技能来源时,变化应落在技能获取模块及其装配位置;调整提示词组织策略时,工具执行和公共输出协议不应跟随修改。是否允许某种模块组合,由接口合同与组合验证决定。
这些原则使后续能力能够持续加入、替换和完善,系统性提升 ReActAgent 的可持续迭代能力。文档以模块职责、扩展合同和所有权说明架构,具体装配机制只是实现这些原则的一种方式。
5.5 配套设计:主循环与能力模块分别配置,内部类型明确
配置与装配分为主循环配置、各能力模块独立配置与装载两部分。主循环配置管理迭代上限、模型调用重试等参数;各能力模块管理自身设置,按需装载。Lite 通过
assemble(Model)、assemble(ContextEngine)等入口接收已配置的基础组件,将组件配置责任归回组件本身。同时,为调用输入、工具结果、挂起恢复和迭代结果引入专用类型,减少核心控制逻辑对Object、Map 和字符串约定的依赖。组件分别负责自身配置,Agent 负责组合已配置组件;内部采用专用类型,公共执行边界应承担第 4.1 节约定的输入输出协议转换责任。这些改进服务于模块独立演进和 SDK 使用体验,不构成另建 ReActAgent 的独立主因。
6. LiteReActAgent 已实现的能力
本章沿第 5 章的两条设计主线,说明当前已经落地的机制及其作用:**实例资源隔离与释放,以及模块解耦与持续演进。**实现位置见附录 B,以下测试名称用于定位已有测试源码表达的行为,本次文档整理未重新运行测试。
6.1 Agent 资源分层持有,逐层各自销毁
1. 资源管理由分散登记转为实例分层持有。
以工具为例,旧体系将实例能力清单、全局资源登记与释放责任分置不同位置;Lite 则由 Agent 持有实例级 AbilityManager,再由管理器分别持有 Provider 与独立登记的自有资源。工具目录及工具实例通过已装配的 Provider 获取,工具运行链不再依靠旧 AbilityManager 向全局 Runner 注册后查找。拦截器、事件监听器和独立 Skill 模块也围绕具体 Agent 装配。能力来源及作用范围因此落实到实例持有的组件上,为多个实例分别选择能力提供明确边界。
直接依据:能力管理测试(
LiteAbilityManagerTest)、工具运行测试(LiteReActAgentToolRuntimeTest)、执行扩展测试(LiteAgentExtensionsTest)。2. 关闭责任逐层传递,各资源实现自己的 close()。
关闭关系为:**Agent.close() 发起实例关闭 → 组件.close() 调用所持资源的关闭入口 → 资源.close() 实现自身释放逻辑。**具体清理逻辑归属各资源,Agent 组织关闭责任的传递。借用的 Model、ContextEngine 等处于实例自有资源的关闭链之外,仍由外部所有者管理。
关闭流程同时处理重复关闭,某项清理失败后继续尝试其他清理并聚合异常。应用通过实例的关闭入口发起资源释放,并接收清理失败的汇总信息,减少逐一调用附属组件清理接口的负担。
直接依据:关闭顺序与失败聚合测试(
LiteReActAgentSuspensionTest)、自有资源关闭测试(LiteProviderAssemblyTest)。补充生命周期边界:关闭实例自有资源不删除按 Session 合同保存的会话状态,状态持久化与实例资源释放分别负责。会话保留并非 Lite 相对旧 ReActAgent 的新增特性。
Lite 在调用结束时保存上下文,按 Session 保存技能激活及待恢复工具调用状态,并区分自建会话清理与外部会话管理。恢复会话状态并重新装配依赖后,新 Agent 实例可以继续之前挂起的工具调用。这样,延续任务依靠可恢复的会话状态,应用无需为了保留任务进度而持续持有同一个 Agent 对象。
直接依据:上下文持久化测试(
LiteReActAgentContextPersistenceTest)、技能管理测试(AgentSkillFrameTest)、挂起恢复测试(LiteReActAgentSuspensionTest)。本节的实现重点是:资源由实例分层持有,关闭沿所有权逐层传递,每个资源负责实现自己的 close()。
6.2 按职责拆分模块,支撑独立演进
当前 Lite 已形成“主循环与能力模块分别配置、按需装配、能力模块各负其责、主循环协调执行”的整体组织方式。其落地成果从配置归属、六个模块的职责边界,以及扩展与协同开发三个方面说明。
1. 主循环配置与各能力模块独立配置、装载分责。
configure(ReActAgentConfig)设置迭代上限、模型调用重试等运行参数。configSkillFrame(Consumer<AgentSkillFrameConfig>)设置资源导出目录;工具 Provider、技能对象、提示词片段、拦截器和监听器通过对应的assemble(...)入口加入实例,上下文处理器通过有序列表装配。模块按职责采用各自的配置入口,按需装载。Model、ContextEngine 等底层组件在外部完成配置,再通过
assemble(Model)、assemble(ContextEngine)传入。模型和上下文的配置责任归回各自组件,Skill 等能力的专门设置归回模块,Agent 的装配入口负责将它们组合为具体实例。当前实现要求显式装配 Model 和 ContextEngine;调整 Agent 配置不会据此重新创建或替换这些组件。配置什么、装配什么以及由哪个模块解释配置,具有明确的职责落点。直接依据:模型装配测试(
LiteReActAgentModelAssemblyTest)、上下文装配测试(LiteReActAgentContextAssemblyTest)、技能管理测试(AgentSkillFrameTest)。2. 主循环协调六个能力模块,将相关实现收拢到模块内部。
核心循环由
LiteReActAgent组织推理、工具调用、结果观察以及继续或终止判断,通过接口协调已装配模块。Tool、Model、PromptSection、ContextEngine、Session 等属于按需复用的底层组件,其中 Model 提供普通和流式推理能力。LiteAbilityManager、DefaultLiteAbilityManager、LiteToolProviderskill包、AgentSkillFrame及其配套类型ContextAwareSystemPromptBuilder、ContextAwarePromptSectionContextEngine、ModelContext、Context ProcessorLiteAgentExtensions、拦截器与事件监听接口SessionStreamWriter、LiteToolStreamWriter这种划分将工具提供与执行集中到 AbilityManager 及其提供机制,将技能实现集中到 Skill 模块,将提示词、执行扩展和流事件组织集中到各自组件。模块通过明确接口协作,为独立实现、测试和按场景装配提供边界;新增工具来源、技能内容或执行扩展,有各自的接入位置。
直接测试依据按模块分布:
LiteReActAgentParityTest)、工具运行测试(LiteReActAgentToolRuntimeTest)。LiteAgentSkillIntegrationTest)、提示词构建测试(ContextAwareSystemPromptBuilderTest)、提示词集成测试(LiteReActAgentContextAwarePromptTest)。LiteAgentExtensionsTest)、拦截器集成测试(LiteReActAgentInterceptorTest)。SessionStreamWriterTest)、Agent 流输出测试(LiteReActAgentSessionStreamWriterTest)。3. 能力扩展与协同开发有明确落点。
这些实现为模块独立演进建立了边界。以职责边界降低耦合,让能力扩展与协同开发有明确落点,是本次模块化的主要成果。
附录 A:AgentScope Java 的设计与实践依据
本附录汇总第 1 章引用的三项依据,分别对应实例注册边界、实例关闭入口和按请求创建的实际使用案例。
Toolkit.copy()创建 Agent 自己的工具注册容器和工具组状态,各实例独立维护注册清单。Builder、注册表复制。close()方法,供使用方在实例使用结束后显式调用。关闭实现。附录 B:SP2 代码依据
以下按类型和方法列出实现与测试依据,可在 SP2 源码中按名称检索。
Runner.java:GLOBAL_RUNNER、resourceMgr()。AbilityManager.java:qualifyToolId()、addAbility(ToolCard, Tool)、lookupTool()、teardownTools()。AgentCallbackManager.java:registerRail()、registerInstanceRail()、getAgentEvent()、clear()。AbilityManagerTest.java:addAbilityQualifiesStatefulToolAndTeardownRemovesOnlyOwnedInstance()、addAbilityKeepsStatelessToolIdAndDoesNotTeardownSharedInstance()、executeFallsBackToResourceManagerByNameWhenAbilityIsUnregistered()。AgentCallbackManagerTest.java:executeRunsGlobalBeforeInstanceAndSharesContext()。BaseAgentInstanceRailTest.java:registerAndUnregisterManageLifecycleAndCallbacks()、sameCardIdAgentsKeepInstanceRailsSeparate()。RunnableAgent.java:getCard()、invoke()、stream()、close();LiteReActAgentParityTest.java:liteIsAnIndependentBaseAndRunnableAgent()。LiteReActAgentInputs.java、AgentAnswer.java、SessionStreamWriter.java:请求/恢复对象、结果对象及writeAnswer();旧输入和结果直接对照 ReActAgent 的invoke()与最终答案构造。Runner.java:runAgent()、runAgentStreaming()、prepareAgent()、invokeDuckTypedAgent()、asStringObjectMap()。HierarchicalToolsTeam.java:委派工具注入时调用parent.getAbilityManager();ContainerAgent.java:injectToolsOnce()。BaseAgent.java:当前分支新增默认空实现close();ReActAgent.java:未覆盖该方法。ToolManager.java:removeTool()。LiteAbilityManager.java、DefaultLiteAbilityManager.java:addProvider()、refreshToolCatalog()、execute()、ownResource()及close()。LiteToolProvider.java:工具发现、提供与关闭;AgentSkillFrame.java:技能管理、会话状态访问及生命周期。ContextAwarePromptSection.java:独立片段渲染及优先级;LiteAgentExtensions.java:调用、轮次、模型和工具阶段的扩展与监听。LiteReActAgent.java:configure()、各assemble(...)方法、configSkillFrame()和close();AgentSkillFrameConfig.java:模块局部的资源导出目录配置。ReActAgentConfig.java:模型配置入口;ReActAgent.java:getLlm()、doRailedModelCall()、activateSkillsLoadedByToolCalls()。涉及到的对外API
测试验证
测试验证
围绕“服务化多实例隔离、资源及时释放、易用性与可演进性”开展验证,采用单元测试、组件集成测试、服务场景测试、性能与稳定性测试相结合的方式。验证对象为 GitCode 仓库
hw_makeit/agent-core-java中dev-0.1.14-SP2分支的最终待合入提交,并对develop原有 ReActAgent 的相关行为进行回归。本节为验证方案,具体执行范围、结果和数据在合入前补充,不将已有测试源码等同于测试已经通过。1. 功能与架构验证
close()发起关闭。close()完成释放,Provider 与独立登记资源均被覆盖,不遗漏下级自有资源。close(),检查接口类型及本次公共 API 调整。Runner、Workflow、多 Agent 编排和 AgentTeam 按本次实际改造的入口分别执行集成验证。涉及工具注入、成员控制或专用协议的入口,需同时验证对应适配层;尚未纳入本次合入的上层接入单列为后续验收项,不写成已兼容。基础组件按其合同复用,PromptSection 经封装转换后的片段内容、优先级和渲染行为纳入适用的组合测试。
2. 可靠性与异常场景验证
close(),检查下级资源的关闭动作不会被重复触发;资源自身的关闭行为按其合同单独验证,不将顺序重复关闭推导为并发关闭安全。close()也不应被理解为自动重试失败资源。采用故障注入、关闭计数器、事件记录和可控同步点验证顺序与边界,避免仅依赖日志人工判断或固定休眠。资源所有权断言应覆盖正常关闭和异常关闭两类路径。
3. 性能与资源稳定性验证
在固定 JDK、JVM 参数、CPU、内存、组件配置及 Session 保留策略的环境中执行测试。先用确定性模型响应和本地工具隔离模型网络延迟,测量框架开销;再用实际模型和工具执行代表性服务场景,分别报告两类结果。
close()。重复测量时保留预热条件、样本量和异常样本说明。持续资源增长、可复现泄漏或未解释的性能退化必须定位后再判断是否满足合入条件。
4. 安全与隔离边界验证
本节验证 SDK 所提供的访问、数据与所有权边界;实例级隔离不等同于对任意第三方工具代码提供进程级安全沙箱。
5. 测试基础与执行安排
已有测试可作为补充用例和回归的基础,包括:
LiteAbilityManagerTest、LiteProviderAssemblyTest、LiteReActAgentSuspensionTest。LiteReActAgentModelAssemblyTest、LiteReActAgentContextAssemblyTest、LiteReActAgentToolRuntimeTest、LiteReActAgentParityTest。AgentSkillFrameTest、LiteAgentSkillIntegrationTest、ContextAwareSystemPromptBuilderTest、LiteReActAgentContextAwarePromptTest。LiteAgentExtensionsTest、LiteReActAgentInterceptorTest、SessionStreamWriterTest、LiteReActAgentSessionStreamWriterTest。ReActAgentTest、ReActAgentReactiveTest、ReActAgentConfigTest、ReActAgentToolLifecycleStreamTest、AbilityManagerTest、AgentCallbackManagerTest、BaseAgentInstanceRailTest、LiteReActAgentContextPersistenceTest。先将上述验证点与已有用例逐项对应,补齐没有覆盖的多实例组合、异常路径和边界用例,再按以下顺序执行:
mvn test或带覆盖率报告的mvn -Pcoverage verify,检查直接受影响的旧入口及公共 API 行为。默认排除的system-test用例需另行组织执行并单独记录,不能将默认 Maven 结果作为系统测试已经覆盖的依据。6. 合入验收与结果记录
期望的反馈时间
抄送的人员名单
其他补充信息
感谢你的贡献🎉!openJiuwen 核心团队每周举办一次 RFC 评审会,虽然大部分 RFC 都可在线上进行讨论,但你也可以自愿报名预约时段,参与 RFC 的线上研讨。
在你提交新issue之前