第4章:模块职责划分:业务逻辑层、编排层、基础设施层的异常职责边界

4.1 边界定义

在Agent系统中,异常处理并非由单一模块完成,而是由三个核心层各司其职、协同闭环。边界划分的核心原则是:异常由产生的源头就近捕获,由拥有恢复信息最丰富的层处理,跨层传递时保持语义不丢失。

层次 核心职责 异常范围 处理模式
业务逻辑层 业务规则验证、状态转换、意图判定 输入校验失败、业务规则冲突、状态机非法跳转 本地重试 → 补偿事务 → 返回业务错误码
编排层 流程调度、任务编排、资源分配、链路追踪 子任务超时、依赖断裂、编排逻辑死锁 降级链路 → 超时熔断 → 回滚至编排检查点
基础设施层 网络通信、存储I/O、外部API调用、资源计量 连接池耗尽、磁盘满、第三方API限流、序列化失败 指数退避重试 → 快速失败 → 上报度量指标
关键契约: 业务逻辑层不得直接处理基础设施层的连接超时异常;编排层不得在编排脚本中写入硬编码的退避算法。层次间通过异常适配器进行错误码与上下文的转换,保持信任边界的完整性。

4.2 分层职责详述

4.2.1 业务逻辑层

  • 输入校验: 对用户输入的Agent指令、参数、上下文进行业务规则校验。校验失败直接返回BusinessValidationError,不向下传递。
  • 状态机保护: 当Agent状态(如“待处理→执行中→完成”)发生非法跳转时,产生StateTransitionException,并触发状态回滚。
  • 补偿事务: 当业务逻辑内的部分步骤失败时,业务逻辑层自行执行补偿(如撤销已完成的子步骤),补偿失败再上报编排层。

4.2.2 编排层

  • 流程健康度检测: 监控每个子任务的预期完成时间,超时后判断是等待还是降级。
  • 熔断与降级: 当某个下游依赖连续失败超过阈值(如5次),编排层自动切断该依赖调用,执行预设的降级逻辑(如返回缓存结果或模拟响应)。
  • 检查点回滚: 维护流程执行的历史快照,异常不可恢复时回滚至最近的检查点,保证状态一致性。

4.2.3 基础设施层

  • 资源隔离: 连接池超时、线程池耗尽等异常应在该层内部完成隔离,不泄露资源句柄。
  • 重试策略: 支持可配置的指数退避重试(如初始间隔1s,倍率2,最大重试3次),超过次数后直接向编排层返回ResourceExhaustedError。
  • 度量上报: 记录每次失败的类型、频率、流量,供监控系统用于自动弹性和扩缩容决策。
避坑提示: 基础设施层不要自行“消化”异常并返回成功。例如,不能把写入数据库失败后静默返回"OK",这会导致编排层和业务逻辑层产生幻读,引发级联数据不一致。

4.3 数据流/控制流/信任链路

下图描述了当一次Agent任务执行过程中,异常在三个层次间的典型传播路径与信任边界。

异常在三个层次间的传播与信任链路 业务逻辑层 输入校验异常捕获 状态机非法跳转 补偿事务执行 编排层 超时检测与降级决策 熔断器状态维护 检查点回滚触发 基础设施层 连接池/线程池隔离 指数退避重试 失败度量上报 正常调用 正常调用 ResourceExhaustedError 编排异常上报 信任边界 说明:虚线为异常上报路径,实线为正常业务调用路径。 每层仅向上传递自身可处理的异常语义,不跨层“泄漏”实现细节。
信任链路要点: 基础设施层信任编排层不会在短时间内发送太多请求导致过载(编排层负责入口限流);编排层信任业务逻辑层不会产生无限循环的子任务(业务逻辑层负责循环检测)。异常边界明确后,每层只需守住自己的契约,调试时能快速定位肇事层。

4.4 选型权衡

选型维度 方案A:向上抛原始异常 方案B:本层封装为业务异常 方案C:本层静默消化
调试成本 低,保留完整stack trace 中,需解析封装后的上下文 高,异常丢失难以根因定位
层间耦合 高,上层需理解下层异常细节 低,通过错误码/合约解耦 极低,但隐藏了故障
恢复能力 强,上层可针对性制定恢复策略 中,基于错误码触发通用恢复 无,本层已放弃恢复
适用场景 开发环境或内部调用链路短的Agent 生产环境、多团队协作的编排系统 非关键路径、可容忍偶发失败的日志/指标
选型决策建议: 生产系统推荐方案B,因为它结合了可恢复性与低耦合。方案A可用于开发阶段的断言验证;方案C仅限基础设施层内对“可自愈的瞬间失败”(如偶尔的网络抖动的第一次重试)使用。

4.5 风险点

  • 责任链过长: 异常每经过一层都被添加一次包装上下文,最终错误消息膨胀,上层难以提取原始根因。应每层只追加一个关键字段,不要复制整个trace。
  • 降级黑盒: 编排层执行降级后,业务逻辑层可能不知道实际响应是降级产生的,导致基于降级数据做出错误业务决策。降级响应中必须附带 x-agent-retryable: true 头。
  • 资源泄露闭环: 基础设施层发生连接池异常时,若编排层同时发起了降级操作,新的降级路径可能又试图建立新的连接,导致连接池无法恢复。需要引入“熔断后隔离窗口”机制。

4.6 落地步骤

  1. 步骤1:定义三层之间的异常合约 — 明确错误码前缀(如 BIZ_、ORCH_、INFRA_)和每个错误的payload结构。
  2. 步骤2:为每层添加异常适配器 — 将原始异常转换为合约定义的格式。
  3. 步骤3:配置链路超时和重试参数 — 在编排层设置每个子任务的超时阈值,在基础设施层设置连接池的最大等待时间。
  4. 步骤4:安装熔断器与度量探针 — 在编排层关键路径上插入熔断器,在基础设施层所有外部调用处插入失败计数器。
  5. 步骤5:集成测试异常场景 — 编写故障注入测试,验证每个异常类型是否在正确的层被捕获且不泄漏。
代码示例:异常适配器核心结构
// 编排层适配器示例
public class OrchestrationExceptionAdapter {
    public static OrchestrationError adapt(InfraException ex) {
        return new OrchestrationError(
            ErrorCode.ORCH_INFRA_DOWN,
            "基础设施资源不可用: " + ex.getResourceType(),
            ex.getCause(),
            ex.isRetryable()
        );
    }
}

4.7 验收标准

验收项 验收方法 指标
异常不跨层泄漏 故障注入后检查上层收到的异常类是否属于合约定义 接收到的外部异常类名不包含下层实现类
降级路径可识别 模拟下游故障,检查降级响应中是否包含 x-agent-retryable 头 100%的降级响应携带该头
熔断后恢复时间 连续注入10次失败后等待熔断窗口,再注入成功请求 熔断窗口内失败直接快速失败,窗口后正常恢复
检查点回滚完整性 在编排脚本中途注入异常,验证状态是否回滚至上一个检查点 回滚后状态与检查点完全一致
验收自动化: 建议将上述验收标准写成Pytest或JUnit的混沌测试用例,每次CI/CD构建时自动运行,确保边界契约未被破坏。任何对异常处理代码的修改都必须通过所有验收用例才能合并。