fischer-agentkit/docs/plans/2026-06-05-006-refactor-age...

25 KiB
Raw Blame History

status date origin
active 2026-06-05 docs/brainstorms/2026-06-05-agentkit-architecture-gap-analysis-requirements.md

AgentKit v2 Phase 2: 架构完善实施计划

类型: refactor
文件: docs/plans/2026-06-05-006-refactor-agentkit-v2-phase2-plan.md
深度: Deep — 跨模块改造,涉及安全、异步、流式、进化 4 个层面


问题框架

AgentKit v2 Phase 1 已实现 12 个核心模块、535 个测试通过,但存在 4 个关键缺口使其无法被称为"生产就绪的标准 Agent 框架"

  1. 服务化安全缺失 — 无认证、无限流、CORS 配置不当、SSRF 风险
  2. 异步任务占位符 — 任务状态查询返回 placeholder同步阻塞调用
  3. 流式输出不支持 — 长时间 ReAct 循环无中间进展反馈
  4. Evolution 未集成 — 自我进化代码完整但未接入 Agent 生命周期

本计划按 B → D → C → A 顺序补齐这 4 个缺口。(需求来源见 origin 文档)


架构总览

                    +------------------------+
                    |    User / Consumer     |
                    +-----------+------------+
                                |
                    +-----------v------------+
                    |   AgentKit Server      |
                    |   [Auth + Rate Limit]  |  ← Phase B 新增
                    +-----------+------------+
                                |
                    +-----------v------------+
                    |   Task Manager         |
                    |   [Async + Streaming]  |  ← Phase D + C 新增
                    +-----------+------------+
                                |
          +----------+----------+----------+----------+
          |          |          |          |          |
   +------v---+ +---v----+ +---v----+ +---v----+     |
   | ReAct    | | Skill  | |Quality | | Intent |     |
   | [Stream] | | System | | Gate   | | Router |     |
   +----+-----+ +--------+ +--------+ +--------+     |
        |                                          |
   +----v------------------------------------------v----+
   |              ConfigDrivenAgent / BaseAgent          |
   |              [+ Evolution Hooks]                     |  ← Phase A 新增
   +------+---------+---------+---------+---------+------+
          |          |         |         |         |
   +------v---+ +---v----+ +---v----+ +---v----+ +---v----+
   | LLM      | | Tool   | | Memory | | MCP    | |Pipeline|
   | [Stream] | | System | | System | | Bridge | |Engine  |
   +----------+ +--------+ +--------+ +--------+ +--------+

关键技术决策(复用 origin 文档 KTD1-KTD5

决策 选择 理由
认证方案 API Key非 JWT/OAuth 服务间调用API Key 足够简单有效
速率限制 内存计数器(非 Redis 单实例足够,后续可升级
异步存储 Redis + 内存降级 已有 Redis 依赖
流式协议 SSE非 WebSocket 单向推送足够HTTP 兼容性好
Evolution 可选集成 通过 YAML evolution.enabled 控制

高层次技术设计

中间件链Phase B

Request → CORS Middleware → API Key Auth → Rate Limiter → Route Handler
                                          ↓ 401          ↓ 429
                                    Unauthorized     Too Many Requests

异步任务流Phase D

POST /tasks → 生成 task_id → 存入 TaskStore(PENDING)
                          → 后台 asyncio.create_task() 执行
                          → 更新 TaskStore(RUNNING → COMPLETED/FAILED)
                          → 返回 {"task_id": "...", "status": "PENDING"}

GET /tasks/{id} → 查询 TaskStore → 返回真实状态
GET /tasks/{id}/result → 查询 TaskStore → 返回结果或 404

流式输出流Phase C

POST /tasks/stream → SSE endpoint
                  → 后台执行任务
                  → 每步发出事件:
                    event: step
                    data: {"type": "think|act|observe", "step": 1, "content": "..."}
                  → 完成时发出:
                    event: done
                    data: {"status": "completed", "output": {...}}

Evolution 生命周期钩子Phase A

BaseAgent.execute():
  on_task_start()
  handle_task()
  quality_gate → retry
  on_task_complete()
  └─→ [NEW] evolve_after_task()  ← EvolutionMixin
        └─→ Reflector.reflect()
        └─→ PromptOptimizer.optimize() [if suggestions]
        └─→ ABTester.evaluate() [if optimized]
        └─→ EvolutionStore.apply/rollback()

输出结构

src/agentkit/
├── server/
│   ├── middleware.py           # NEW: Auth + Rate Limit 中间件
│   ├── task_store.py           # NEW: 任务状态存储
│   ├── routes/
│   │   └── streaming.py       # NEW: SSE 流式端点
│   ├── app.py                 # MODIFIED: 注册中间件
│   ├── client.py              # MODIFIED: 添加流式 + 异步方法
│   └── routes/
│       └── tasks.py           # MODIFIED: 异步任务 + 状态查询
├── core/
│   ├── base.py                # MODIFIED: 集成 Evolution
│   ├── dispatcher.py          # MODIFIED: Callback URL 验证
│   ├── config_driven.py       # MODIFIED: handler 白名单 + evolution 配置
│   └── protocol.py            # MODIFIED: 新增 TaskState 枚举
├── llm/
│   ├── gateway.py             # MODIFIED: 新增 stream() 方法
│   └── providers/
│       └── openai.py          # MODIFIED: 支持 stream=True
├── skills/
│   └── base.py                # MODIFIED: 添加 evolution 配置
├── core/
│   └── react.py               # MODIFIED: 新增 execute_streaming()
└── evolution/                  # 现有代码,无需修改

Implementation Units

U1. CORS 修复 + API Key 认证中间件

Goal: 修复 CORS 配置冲突,添加 API Key 认证保护所有 API 端点(健康检查除外)。

Requirements: R1, R3

Dependencies: 无

Files:

  • Create: src/agentkit/server/middleware.py
  • Modify: src/agentkit/server/app.py
  • Test: tests/unit/test_server_middleware.py

Approach:

  1. 新建 middleware.py,实现 APIKeyAuthMiddlewareStarlette middleware 接口)
  2. 从环境变量 AGENTKIT_API_KEY 读取密钥,未设置时跳过认证(开发模式)
  3. 验证 X-API-Key 请求头,不匹配时返回 401
  4. 白名单路径:/api/v1/health 不需要认证
  5. 修改 app.py
    • 移除 allow_credentials=True(与 allow_origins=["*"] 冲突)
    • 添加 app.add_middleware(APIKeyAuthMiddleware)
  6. create_app() 中添加 api_key: str | None = None 参数,允许程序化配置

Patterns to follow: Starlette BaseHTTPMiddleware 模式,参考 FastAPI 中间件文档

Test scenarios:

  • 无 API Key 访问受保护端点 → 401 Unauthorized
  • 错误 API Key → 401 Unauthorized
  • 正确 API Key → 200 OK
  • 健康检查端点无需 API Key → 200 OK
  • AGENTKIT_API_KEY 未设置时 → 跳过认证(开发模式)
  • 程序化传入 api_key 参数 → 使用传入的值

Verification: pytest tests/unit/test_server_middleware.py -v 全部通过,现有测试不受影响


U2. 速率限制中间件

Goal: 添加基于固定窗口的速率限制,防止 LLM 成本耗尽。

Requirements: R2

Dependencies: U1中间件基础设施

Files:

  • Modify: src/agentkit/server/middleware.py
  • Test: tests/unit/test_server_middleware.py(追加)

Approach:

  1. middleware.py 中实现 RateLimiter
  2. 使用 time.time() + defaultdict(list) 实现固定窗口计数器
  3. 默认限制60 requests/minute通过环境变量 AGENTKIT_RATE_LIMIT_PER_MINUTE 配置
  4. 基于请求 IPrequest.client.host)或 API Key 进行独立计数
  5. 超过限制时返回 429 Too Many Requests响应头包含 Retry-After
  6. app.py 中注册速率限制中间件(在 Auth 之后)

Test scenarios:

  • 请求在限制内 → 正常通过
  • 超过限制 → 429 Too Many Requests
  • Retry-After 响应头正确设置
  • 不同 IP 独立计数
  • 时间窗口过后计数器重置
  • 可配置 rate_limit_per_minute

Verification: 新增测试通过,不影响现有路由测试


U3. Callback URL SSRF 防护

Goal: 验证 TaskDispatcher 的 callback URL防止 SSRF 攻击。

Requirements: R4

Dependencies: 无

Files:

  • Modify: src/agentkit/core/dispatcher.py
  • Test: tests/unit/test_dispatcher.py(追加)

Approach:

  1. dispatcher.py 中添加 _validate_callback_url(url: str) -> bool 函数
  2. 使用 urllib.parse.urlparse 解析 URL
  3. 校验规则:
    • 协议必须是 httphttps
    • 主机不能是内网 IP127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1
    • 主机不能是 localhost
  4. _trigger_callback() 中调用验证,无效 URL 记录 warning 并跳过
  5. socket.gethostbyname() 做 try/except 防止 DNS 解析失败崩溃

Test scenarios:

  • 合法公网 URLhttps://example.com/callback)→ 验证通过
  • localhost URL → 拒绝
  • 127.0.0.1 URL → 拒绝
  • 10.x.x.x 内网 URL → 拒绝
  • 192.168.x.x 内网 URL → 拒绝
  • ftp:// 协议 → 拒绝
  • file:// 协议 → 拒绝
  • 无效 URL 格式 → 拒绝

Verification: 新增测试通过,现有 dispatcher 测试不受影响


U4. custom_handler 模块前缀白名单

Goal: 为 ConfigDrivenAgent._import_handler() 添加模块前缀白名单,防止任意代码执行。

Requirements: R4安全加固补充

Dependencies: 无

Files:

  • Modify: src/agentkit/core/config_driven.py
  • Test: tests/unit/test_config_driven.py(追加)

Approach:

  1. ConfigDrivenAgent 类中添加 _ALLOWED_HANDLER_PREFIXES = ("agentkit.", "app.agent_framework.")
  2. _import_handler() 开头添加前缀校验
  3. 不在白名单中的路径抛出 ConfigValidationError
  4. 参考 QualityGate._import_validator() 的白名单实现模式

Test scenarios:

  • agentkit.xxx.handler → 允许
  • app.agent_framework.handlers.xxx → 允许
  • os.system → 拒绝ConfigValidationError
  • subprocess.run → 拒绝
  • 空路径 → 拒绝

Verification: 新增测试通过


U5. 任务状态存储

Goal: 实现任务状态存储,支持 Redis 和内存两种后端。

Requirements: R5, R7

Dependencies: 无

Files:

  • Create: src/agentkit/server/task_store.py
  • Test: tests/unit/test_task_store.py

Approach:

  1. 定义 TaskState 枚举:PENDING, RUNNING, COMPLETED, FAILED
  2. 定义 TaskRecord dataclasstask_id, state, input_data, output_data, error_message, created_at, updated_at, started_at
  3. 定义 TaskStore ABCcreate(), update(), get(), list_tasks(), cleanup()
  4. 实现 InMemoryTaskStore:使用 dict + asyncio.Lock 保证线程安全
  5. 实现 RedisTaskStore:使用 Redis hash 存储TTL 24 小时自动清理
  6. 提供 create_task_store(redis_url: str | None = None) -> TaskStore 工厂函数
  7. Redis 不可用时自动降级到 InMemory

Patterns to follow: 参考 WorkingMemory 的 Redis 模式和 UsageTracker 的内存模式

Test scenarios:

  • InMemoryTaskStore: create → get 返回正确记录
  • InMemoryTaskStore: update 状态从 PENDING → RUNNING → COMPLETED
  • InMemoryTaskStore: get 不存在的 task_id 返回 None
  • InMemoryTaskStore: list_tasks 返回所有记录
  • InMemoryTaskStore: 并发安全asyncio.Lock
  • RedisTaskStore: create → get 返回正确记录skip if no Redis
  • 工厂函数: Redis 可用时返回 RedisTaskStore
  • 工厂函数: Redis 不可用时降级到 InMemoryTaskStore

Verification: pytest tests/unit/test_task_store.py -v 全部通过


U6. 异步任务执行

Goal: POST /api/v1/tasks 改为异步提交100ms 内返回 task_id。

Requirements: R5, R6

Dependencies: U5

Files:

  • Modify: src/agentkit/server/routes/tasks.py
  • Test: tests/unit/test_server_routes.py(更新现有测试)
  • Test: tests/integration/test_server_e2e.py(更新)

Approach:

  1. tasks.py 中注入 TaskStore(通过 req.app.state.task_store
  2. app.pycreate_app() 中初始化 task_store 并设置到 app.state
  3. 修改 submit_task 路由:
    • 生成 task_id,创建 TaskRecord(PENDING) 存入 TaskStore
    • 使用 asyncio.create_task() 后台执行任务
    • 立即返回 {"task_id": task_id, "status": "PENDING"}
  4. 后台任务逻辑:
    • 更新 TaskStore 为 RUNNING
    • 执行 agent.execute(task)
    • 更新 TaskStore 为 COMPLETED/FAILED存储 output_data
    • 运行 quality gate 和 output standardizer存储结果
  5. 添加可选参数 sync: bool = False,当 sync=true 时保持原有同步行为

Test scenarios:

  • 提交任务 → 100ms 内返回 task_id + PENDING
  • 后台任务执行 → TaskStore 状态变为 COMPLETED
  • 后台任务失败 → TaskStore 状态变为 FAILED
  • sync=true 参数 → 同步执行(原有行为)
  • 输入验证失败 → 400/413 错误(同步返回)

Verification: 路由测试通过E2E 测试验证异步行为


U7. 任务状态查询 + 结果获取

Goal: GET /api/v1/tasks/{task_id} 返回真实状态,新增结果获取端点。

Requirements: R6, R7

Dependencies: U5, U6

Files:

  • Modify: src/agentkit/server/routes/tasks.py
  • Test: tests/unit/test_server_routes.py(追加)

Approach:

  1. 修改 get_task_status 路由:
    • 从 TaskStore 查询 task_id
    • 返回 {"task_id": ..., "status": "...", "created_at": "...", "updated_at": "..."}
    • 不存在时返回 404
  2. 新增 GET /api/v1/tasks/{task_id}/result 路由:
    • 从 TaskStore 查询 task_id
    • 如果状态是 COMPLETED → 返回完整结果(含 quality_result, standard_output
    • 如果状态是 PENDING/RUNNING → 返回 202 Accepted + {"status": "..."}
    • 如果状态是 FAILED → 返回错误信息
    • 不存在时返回 404

Test scenarios:

  • 查询存在的 task_id → 返回正确状态
  • 查询不存在的 task_id → 404
  • PENDING 状态查询结果 → 202 Accepted
  • COMPLETED 状态查询结果 → 返回完整输出
  • FAILED 状态查询结果 → 返回错误信息

Verification: 路由测试通过


U8. LLM Gateway 流式支持

Goal: LLM Gateway 支持 streaming 模式,逐 chunk 返回 LLM 响应。

Requirements: R8

Dependencies: 无

Files:

  • Modify: src/agentkit/llm/gateway.py
  • Modify: src/agentkit/llm/protocol.py
  • Modify: src/agentkit/llm/providers/openai.py
  • Test: tests/unit/test_llm_gateway.py(追加)
  • Test: tests/unit/test_llm_provider.py(追加)

Approach:

  1. protocol.py 中添加 LLMStreamChunk dataclass
    • content: str(增量文本)
    • tool_calls: list[ToolCall] | None
    • finish_reason: str | Nonestop, tool_calls, length
    • usage: TokenUsage | None(仅在最后一个 chunk 有值)
  2. LLMProvider ABC 中添加 stream() 抽象方法:
    • async def stream(request: LLMRequest) -> AsyncIterator[LLMStreamChunk]
  3. OpenAICompatibleProvider 中实现 stream()
    • 使用 httpx.AsyncClient.stream() 发送请求
    • 解析 SSE 格式响应(data: {...} 行)
    • yield LLMStreamChunk 对象
  4. LLMGateway 中添加 stream() 方法:
    • 解析模型别名和 provider
    • 调用 provider 的 stream() 方法
    • 转发 chunk

Patterns to follow: OpenAI Python SDK 的 streaming 模式,response.iter_lines() 解析 SSE

Test scenarios:

  • OpenAICompatibleProvider.stream() 逐 chunk yield 内容
  • 最后一个 chunk 包含 usage 信息
  • finish_reason 为 stop 时流结束
  • finish_reason 为 tool_calls 时包含 tool_calls 信息
  • LLMGateway.stream() 正确转发 chunk
  • 网络错误时抛出 LLMProviderError

Verification: 新增流式测试通过


U9. ReAct Engine 事件流

Goal: ReAct Engine 支持 streaming 事件输出,实时推送 Think/Act/Observe 进展。

Requirements: R9

Dependencies: U8

Files:

  • Modify: src/agentkit/core/react.py
  • Modify: src/agentkit/core/protocol.py
  • Test: tests/unit/test_react_engine.py(追加)

Approach:

  1. protocol.py 中添加 ReActEvent dataclass
    • event_type: strthink_start, think_end, tool_call, tool_result, final_answer
    • step: int
    • data: dict(事件具体数据)
    • timestamp: datetime
  2. ReActEngine 中添加 execute_streaming() 方法:
    • 参数与 execute() 相同,返回 AsyncIterator[ReActEvent]
    • Think 前 yield think_start 事件
    • 调用 LLM stream 后 yield think_end 事件
    • 每个工具调用 yield tool_call 事件
    • 工具执行完成后 yield tool_result 事件
    • 最终答案 yield final_answer 事件
  3. 保持原有 execute() 方法不变(向后兼容)

Test scenarios:

  • execute_streaming() 按顺序 yield 事件
  • Think → Act → Observe 事件顺序正确
  • 最终 yield final_answer 事件
  • 事件中包含 step 编号和 timestamp
  • 工具调用失败时 yield tool_result含 error
  • 与 execute() 结果一致(同一输入产生相同输出)

Verification: 新增流式测试通过


U10. SSE 流式端点 + Client SDK

Goal: Server 提供 SSE 流式端点Client SDK 支持流式消费。

Requirements: R10

Dependencies: U8, U9

Files:

  • Create: src/agentkit/server/routes/streaming.py
  • Modify: src/agentkit/server/app.py
  • Modify: src/agentkit/server/client.py
  • Test: tests/unit/test_streaming_routes.py
  • Test: tests/unit/test_client_streaming.py

Approach:

  1. 新建 streaming.py,实现 POST /api/v1/tasks/stream 端点:
    • 使用 StreamingResponse + text/event-stream content type
    • 后台执行任务,调用 react_engine.execute_streaming()
    • 每个 ReActEvent 序列化为 SSE 格式:event: <type>\ndata: <json>\n\n
    • 完成后发送 event: done\ndata: <json>\n\n
  2. app.py 中注册 streaming router
  3. client.py 中添加 submit_task_streaming() 方法:
    • 使用 httpx.AsyncClient.stream() 消费 SSE
    • yield ReActEvent 对象
    • 支持 async iterator 协议

Patterns to follow: Starlette EventSourceResponseStreamingResponse,参考 FastAPI SSE 文档

Test scenarios:

  • SSE 端点返回 text/event-stream content type
  • 事件按 Think → Act → Observe → done 顺序
  • 每个事件包含正确的 event type 和 JSON data
  • Client SDK 消费 SSE 流
  • Client SDK 正确解析 ReActEvent
  • 任务失败时发送 error 事件

Verification: 流式路由和客户端测试通过


U11. Evolution 生命周期钩子集成

Goal: 将 EvolutionMixin 集成到 BaseAgent任务完成后自动触发进化流程。

Requirements: R11

Dependencies: 无

Files:

  • Modify: src/agentkit/core/base.py
  • Modify: src/agentkit/evolution/lifecycle.py
  • Test: tests/unit/test_evolution_lifecycle.py(更新)
  • Test: tests/unit/test_base_agent_v2.py(追加)

Approach:

  1. BaseAgent 中添加 Evolution 相关属性:
    • _reflector: Reflector | None
    • _prompt_optimizer: PromptOptimizer | None
    • _ab_tester: ABTester | None
    • _evolution_store: EvolutionStore | None
    • _evolution_enabled: bool = False
  2. BaseAgent 中添加 use_evolution() 方法:
    • 接受 reflector, prompt_optimizer, ab_tester, evolution_store 参数
    • 设置所有 Evolution 组件
    • 设置 _evolution_enabled = True
  3. 修改 BaseAgent.execute() 方法:
    • on_task_complete() 之后,如果 _evolution_enabled 为 True
      • 调用 EvolutionMixin.evolve_after_task(task, result)(非阻塞,asyncio.create_task()
  4. EvolutionMixin.evolve_after_task() 中添加开关检查:
    • 如果任何组件为 None跳过对应步骤并记录 debug 日志

Patterns to follow: 参考 use_tool(), use_memory() 的插件注入模式

Test scenarios:

  • evolution_enabled=False → 不触发进化流程
  • evolution_enabled=True → evolve_after_task 被调用
  • Reflector 为 None → 跳过反思
  • 完整流程Reflect → Optimize → AB Test → Apply
  • 进化流程非阻塞(不阻塞 execute 返回)
  • EvolutionMixin 混入 ConfigDrivenAgent 正常工作

Verification: Evolution 集成测试通过,现有测试不受影响


U12. Evolution 配置化

Goal: Agent 可通过 YAML 配置启用/禁用 Evolution 功能。

Requirements: R12

Dependencies: U11

Files:

  • Modify: src/agentkit/core/config_driven.py
  • Modify: src/agentkit/skills/base.py
  • Test: tests/unit/test_config_driven.py(追加)
  • Test: tests/unit/test_skill_config.py(追加)

Approach:

  1. AgentConfig 中添加 evolution: dict[str, Any] | None 字段
  2. 定义 EvolutionConfig dataclass
    • enabled: bool = False
    • reflect_after_task: bool = True
    • ab_test_threshold: float = 0.95
    • max_optimization_rounds: int = 3
  3. SkillConfig 中继承 evolution 配置
  4. 修改 ConfigDrivenAgent.__init__()
    • 从 config.evolution 解析 EvolutionConfig
    • 如果 evolution.enabled = True,自动创建默认组件并调用 use_evolution()
    • 默认组件Reflector启发式评分、PromptOptimizer、ABTester、EvolutionStore内存模式
  5. YAML 配置示例文档化

Test scenarios:

  • YAML 中 evolution.enabled=true → Agent 自动启用进化
  • YAML 中 evolution.enabled=false → Agent 不启用进化
  • YAML 中无 evolution 字段 → 默认不启用
  • EvolutionConfig 字段默认值正确
  • SkillConfig 继承 evolution 配置

Verification: 配置化测试通过


范围和边界

包含

  • Phase B服务化安全R1-R4→ U1-U4
  • Phase D异步任务R5-R7→ U5-U7
  • Phase C流式输出R8-R10→ U8-U10
  • Phase AEvolution 集成R11-R12→ U11-U12

不包含

  • GEO 项目的任何改动
  • 新的 LLM Provider 实现
  • 前端 UI 开发
  • 生产环境部署配置K8s、Prometheus 等)
  • pgvector 向量检索实现

推迟到后续工作

  • WebSocket 推送(当前使用 SSE
  • Redis 滑动窗口速率限制(当前使用内存计数器)
  • Anthropic/Google 原生 Provider
  • Evolution 的分布式 A/B 测试
  • 任务优先级队列

风险和缓解

风险 影响 缓解
流式输出改动大 ReAct Engine 需要重构 保持原有同步接口不变,新增 streaming 接口
异步任务需要 Redis 测试环境可能没有 Redis InMemoryTaskStore 降级方案
API Key 认证破坏现有测试 测试需要传递 API Key 测试环境不设置 AGENTKIT_API_KEY跳过认证
Evolution 集成后 Agent 变慢 反思和优化增加延迟 异步执行asyncio.create_task可配置关闭
SSE 端点与现有同步端点冲突 路由冲突 使用不同路径 /tasks/stream

测试策略

  • TDD 原则:每个单元先写测试,再写实现
  • 测试覆盖目标:总测试数 600+(当前 535
  • 分层测试
    • 单元测试mock 外部依赖,验证逻辑
    • 集成测试:使用真实 Redis/PostgreSQLdocker-compose.test.yml
    • E2E 测试:验证完整链路
  • 回归保护:每次修改后运行全量测试

执行顺序

Phase B安全              Phase D异步任务           Phase C流式输出           Phase AEvolution
┌─────┐                    ┌─────┐                      ┌─────┐                      ┌─────┐
│ U1  │                    │ U5  │                      │ U8  │                      │ U11 │
│ Auth│                    │Store│                      │LLM  │                      │Hooks│
└──┬──┘                    └──┬──┘                      └──┬──┘                      └──┬──┘
   │                         └──┬──┘                      └──┬──┘                      └──┬──┘
┌──▼──┐                       ┌▼────┐                     ┌─▼───┐                     ┌──▼──┐
│ U2  │                       │ U6  │                     │ U9  │                     │ U12 │
│Rate │                       │Async│                     │React│                     │Config│
└─────┘                       └──┬──┘                     └──┬──┘                     └─────┘
                                 └──┬──┘                     └──┬──┘
                               ┌────▼────┐                 ┌───▼────┐
                               │ U7      │                 │ U10    │
                               │Status   │                 │SSE+SDK │
                               └─────────┘                 └────────┘

可并行U3 + U4无依赖可与任何单元并行