Files
sanguo_moziplus_v2/docs/design/v3.0-router-refactor.md
T
2026-05-21 10:57:41 +08:00

5.6 KiB
Raw Blame History

v3.0 Router 重构方案:去掉独立 LLM,改用 Gateway spawn Agent

日期: 2026-05-21 状态: 方案待确认 影响文件: router.py, dispatcher.py, main.py, config/default.yaml


问题

当前 RouterLLMDriver)用独立的 OpenAI() 客户端直接调 zhipu API 做路由决策。 这违反设计文档 architecture-v2.6.md 的核心原则:

系统只有两种 LLM 调用方式,都通过 Gateway

  1. L3 run agentopenclaw agent --agent <id>spawn 完整 Agent
  2. L2 spawn subopenclaw agent --agent <id> --session-id <uuid>,轻量一次性

独立 OpenAI() 不属于任何一层,是设计之外的野路子。

具体问题

  1. 凭据管理:需要单独维护 api_base/api_key,和 Gateway 配置重复
  2. 不走 Gateway:无法利用 Gateway 的模型路由、fallback、计费
  3. 设计不一致:设计文档三层模型(L1/L2/L3),Router 不在其中
  4. 可靠性差:凭据为空时静默 fallback,不报错

方案:Router 改为"能力匹配 + spawn 庞统兜底"

核心思路

Router 有两种路由方式:

  • 确定性路由(能力匹配、retry、handoff)→ 保留,纯 L1 逻辑,不调 LLM
  • 模糊路由(首次分配、不确定场景)→ 不再调独立 LLM,改为 spawn 庞统让庞统决定

路由决策流程(改后)

任务进入 Router.route()
  │
  ├─ 快速路径1: 本地 action → daemon
  ├─ 快速路径2: retry → 原执行者
  ├─ Mode B: Agent handoff (next_capability) → 能力匹配
  ├─ 快速路径3: 生命周期流转 → 能力匹配
  ├─ 快速路径4: 有 assignee → 直接分
  │
  └─ 模糊场景(以上都不匹配)
      │
      → 返回 RouteDecision(agent_id="pangtong-fujunshi", mode="delegate")
        庞统被 spawn 后,读取黑板任务信息,自己决定分配给谁
        庞统通过 API 回写 assignee → ticker 下一轮 spawn 实际执行者

改动清单

1. 删除 LLMDriver 类(router.py

整个 LLMDriver 类删除,约 120 行。Router 的 route() 方法末尾:

# 当前(Mode A: 独立 LLM 调用)
if self.llm_driver:
    decision = self.llm_driver.route(...)
    ...

# 改后(委托庞统)
return RouteDecision(
    agent_id=self.FALLBACK_AGENT,  # "pangtong-fujunshi"
    reason="Uncertain routing, delegate to coordinator",
    mode="delegate",
    confidence=0.0,
)

2. AgentRouter.__init__ 去掉 llm_driver 参数

def __init__(self, agent_profiles, counter=None):  # 删 llm_driver

3. Dispatcher 增加 delegate 模式处理

mode="delegate" 时,spawn 庞统并传入"请分配此任务"的 prompt

# dispatcher.py decide() 中
if decision.mode == "delegate":
    return {
        "level": DispatchLevel.FULL_AGENT,
        "agent_id": "pangtong-fujunshi",
        "reason": decision.reason,
        "mode": "delegate",  # 标记,用于构建不同 prompt
    }

_build_spawn_message 中为 delegate 模式生成专门的 prompt

if mode == "delegate":
    return f"""你是任务协调员。请分析以下任务,决定最合适的执行者。

## 任务信息
- ID: {task.id}
- 标题: {task.title}
- 描述: {task.description}
- 类型: {task.task_type}

## 操作
1. 分析任务需求
2. 选择最合适的 Agent(从你已知的团队中)
3. 通过 API 回写分配结果:
   curl -X POST {api}/tasks/{task.id}/status -d '{{"status":"claimed","assignee":"<agent_id>"}}'
4. 如果你自己能做,直接认领执行
"""

4. main.py 去掉 LLMDriver 初始化

# 删掉 routing_config / llm_driver 的整个初始化块(~10行)
# Router 构造不再传 llm_driver
router = AgentRouter(
    agent_profiles=agent_profiles,
    counter=counter,
)

5. config/default.yaml 去掉 routing 节

# 删掉整个 routing: 节(model/api_base/api_key/timeout/...
# 确定性路由的能力匹配不依赖配置
# 模糊路由由庞统决策,不需要配置

改动前后对比

场景 改前 改后
retry 原执行者(确定性) 不变
Agent handoff 能力匹配(确定性) 不变
生命周期 review 能力匹配(确定性) 不变
有 assignee 直接分(确定性) 不变
首次分配/模糊 独立 LLM 调用 spawn 庞统决策

影响

  • 删代码~130 行(LLMDriver + routing config
  • 改代码~30 行(Router.route 末尾 + Dispatcher._build_spawn_message
  • config:删 routing 节
  • 行为变化:模糊场景从"1-2秒 LLM 返回"变成"spawn 庞统 → 庞统思考 → 回写",多 30-60 秒但更准确
  • 优点:不再需要维护独立 LLM 凭据,所有 AI 调用统一走 Gateway

风险

  1. 庞统成为单点:所有模糊路由都走庞统,如果庞统繁忙会被跳过(counter 限制)
    • 缓解:庞统 max_concurrent=3,且 delegate 模式是轻量决策不是重活
  2. 速度变慢:独立 LLM 1-2s vs spawn 庞统 30-60s
    • 评估:首次分配本来就不用急,准确比快重要
  3. 确定性路由覆盖不到的场景:如果能力匹配足够好,大部分场景不需要庞统
    • 评估:对。实际运行中大部分任务要么有 assignee 要么有 task_type 可匹配

实施步骤

  1. 删 LLMDriver + router.py 清理
  2. main.py 去掉 llm_driver 初始化
  3. Dispatcher 增加 delegate 模式 prompt
  4. config/default.yaml 删 routing 节
  5. 发司马懿评审
  6. 评审通过后部署