Skip to content

[Feature]: MiddlewareBase#activePoints() 应改为抽象方法——参与集只认显式声明 #3576

Open

Description

@xzxiaoshan

现状

// MiddlewareBase —— 未覆写即参与全部扩展点(含未来新增的点)
default Set<ExtensionPoint> activePoints() {
    return EnumSet.allOf(ExtensionPoint.class);
}
// ReActAgent#groupMiddlewares —— null 折算为全集
Objects.requireNonNullElse(mw.activePoints(), EnumSet.allOf(...));

javadoc 约定 null 视为全集、空集表示全点不参与。不覆写、返回 null、显式返回集合三种写法中,前两种语义相同——"没说"与"明确要全部"不可区分。 六个现有扩展点的 default 实现均为直通或 no-op,默认参与只是空转,因此问题一直未暴露。

问题

  1. 参与集合不是可靠判据。 middlewaresAt(point) 返回的成员里混着大量被默认卷入、在该点没有任何逻辑的中间件;任何按参与集合决策的框架能力(激活标志、观测短路、按点统计)拿到的都是被污染的集合。
  2. 开发者被默认卷入新增的扩展点。 未覆写 activePoints() 的中间件在新点上线后自动参与,无意图也无告警;想精确表达需在覆写 hook 之外再罗列清单,双重记账,漏写即静默失效。
  3. 副作用型扩展点不可用。 设想一个激活即改变全局行为的扩展点:例如终局输出审查钩子,要求回答在审查裁决前不得进入公共事件流——激活即牺牲逐 token 流式。激活判定取 !middlewaresAt(point).isEmpty() 时,链上任何一个带默认 activePoints() 的中间件都会点亮它,与该点毫无关系的 agent 全体受影响。任何"激活即全局生效"的未来能力都会撞上同样的问题。

原则:参与必须是意图的表达,不能是缺省的结果。

方案

activePoints() 去掉 default,改为抽象方法;参与集只认显式返回的集合。

// 现状
default Set<ExtensionPoint> activePoints() {
    return EnumSet.allOf(ExtensionPoint.class);
}

// 改为
/**
 * 参与集的唯一来源。空集 = 保留注册、全点不参与;null = 编程错误,
 * 构建期抛出;覆写 hook 而未声明对应点 = 永不调用。
 */
Set<ExtensionPoint> activePoints();
activePoints() 返回 参与集
未实现 编译失败
null 构建期 fail-fast
空集合 无(保留注册)
具体集合(含显式 allOf(...)) 恰好这些点

配套:groupMiddlewares 删除 null→全集折算;javadoc 重写,并确立新增扩展点的评审原则——副作用型激活必须显式注册,不能默认参与。

迁移影响(直观且代价很小)

对升级框架的开发者影响很小:未覆写 activePoints() 的中间件升级后编译报错,直接定位到要修改的类;补一个方法返回自己实现的点集合即可——一行 EnumSet.of(...),想维持原行为则显式 allOf(...)。方法语义单一(声明激活的点),无理解成本,顺手即可完成。

其余:已显式覆写的中间件不变;预编译的第三方中间件 jar 需随升级重编译(否则运行期 AbstractMethodError);middlewaresAt() 只含显式声明者,属公开 API 行为变化。属 source + binary 破坏性变更,不需要过渡版本或废弃周期——编译错误即迁移信号 (合理无隐患)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions