diff --git a/docs/EXECUTION_BOARD.md b/docs/EXECUTION_BOARD.md index 20e85d85..a198d5c5 100644 --- a/docs/EXECUTION_BOARD.md +++ b/docs/EXECUTION_BOARD.md @@ -145,6 +145,18 @@ - 主状态库继续使用 SQLite - 路由运行态使用 Redis 或 memory backend 抽象 - 智能路由日志必须最终结构化写回插件 SQLite + - 2026-05-29 已新增 Phase 2 可开工任务单 `docs/plans/2026-05-29-phase2-intelligent-routing-closure-plan.md` + - 已把 `管理页入口 / 正式数据面入口 / route 健康视图 / 真实验收矩阵` 拆成可执行任务 + - 已明确当前 Phase 2 不是再证明“路由能跑”,而是把现有能力收敛成产品闭环: + - 管理员可维护 `logical_group -> route -> shadow_group` + - 插件存在正式数据面入口,而不只是实验 proxy + - route 的 sticky / failover / cooldown 状态可被运营查看 + - `remote43` 真验收敛成固定矩阵,而不是零散命令 + - 当前 Phase 2 的建议实施顺序是: + - `P2-T1 管理页入口` + - `P2-T2 正式数据面入口` + - `P2-T3 route 健康视图` + - `P2-T4 真实验收矩阵` - 2026-05-28 已完成 Phase 1 / `P1-T1 SQLite schema foundation` - 提交:`7f75d8a6 feat(routing): add logical group schema foundation` - 新 migration:`internal/store/migrations/0010_logical_groups_and_routes.sql` diff --git a/docs/plans/2026-05-29-phase2-intelligent-routing-closure-plan.md b/docs/plans/2026-05-29-phase2-intelligent-routing-closure-plan.md new file mode 100644 index 00000000..2e10b343 --- /dev/null +++ b/docs/plans/2026-05-29-phase2-intelligent-routing-closure-plan.md @@ -0,0 +1,423 @@ +# Phase 2 实施计划:智能路由产品闭环 + +日期:2026-05-29 + +## 目标 + +把已经跑通的路由基础设施收敛成一个可正式承载流量、可被运营使用、可被真实服务器反复验证的 **Phase 2 产品闭环**。 + +本阶段只做以下四块: + +1. 管理页入口 +2. 正式数据面入口 +3. route 健康视图 +4. 真实验收矩阵 + +本阶段完成后,必须满足: + +- 管理员可以在 UI 上维护 `logical_group -> route -> shadow_group` +- 插件存在一个正式、稳定、可审计的数据面入口,而不只是实验性质的最小 proxy API +- route 的 sticky / failover / cooldown / 最近错误状态可以被运营查看 +- 每次核心改动都可以按固定矩阵在 `remote43` 上复验,不再依赖临时手工串命令 + +本阶段**不做**: + +- 供应商帐号库存页 +- 普通用户 Portal 逻辑分组改造 +- 成本感知 / 延迟感知 / A/B 路由 +- 多公开模型同名双线路主备产品化 + +## 0. 当前基线 + +截至本计划编写时,以下基础已经存在并且做过 `remote43` 真验: + +- `logical_group / route / route_model` SQLite 持久化 +- `logical_group / route` 管理 API +- `route_decision_logs / route_failover_events / route_sticky_audit` +- `memory / redis` sticky runtime backend +- `POST /api/routing/resolve` +- `POST /api/routing/proxy/chat/completions` +- failover / cooldown / sticky rebinding +- canonical shadow provider 方案 +- `managed subscription key -> real host /v1/chat/completions = 200` + +因此 Phase 2 不是从零开始,而是把“可工作的工程链路”升级成“可持续运营的产品链路”。 + +## 1. 总体约束 + +### 技术约束 + +- 主状态库继续使用 **SQLite** +- 路由运行态继续使用 **Redis** +- 路由日志必须继续结构化落 SQLite +- 不修改宿主源码 +- 不直写宿主数据库 +- 所有 route / shadow group 行为都通过插件控制面和宿主 HTTP API 完成 + +### 质量门禁 + +每个任务完成后必须通过: + +```bash +gofmt -l . +go vet ./... +go test -cover ./internal/... +go test ./tests/integration/... -count=1 +``` + +如有前端或脚本改动,还必须通过: + +```bash +bash ./scripts/test/test_tksea_portal_assets.sh +bash ./scripts/test/test_real_host_scripts.sh +``` + +### 远端验证门禁 + +每个闭环功能完成后,必须执行: + +1. 提交代码 +2. 推送远端仓库 +3. 部署到 `remote43` +4. 验证 `http://127.0.0.1:18173/healthz` +5. 通过公网或 remote43 本机完成真实 API 验证 +6. 留下可回读证据 +7. 更新 `docs/EXECUTION_BOARD.md` + +## 2. 实施顺序 + +```text +P2-T1 管理页入口 +P2-T2 正式数据面入口 +P2-T3 route 健康视图 +P2-T4 真实验收矩阵 +``` + +说明: + +- `P2-T1` 先把控制面能力真正暴露给运营 +- `P2-T2` 把现有实验 proxy 收敛成正式数据面入口 +- `P2-T3` 再补 route 运行状态可视化 +- `P2-T4` 最后把前面三者收敛成固定验收矩阵 + +## 2.1 依赖矩阵 + +| 任务 | 依赖 | 可并行度 | 完成后解锁 | +| --- | --- | --- | --- | +| `P2-T1` | `P1-T2` | 可独立 | 运营侧能维护 logical routing | +| `P2-T2` | `P1-T3` + `P1-T4` + 已有 canonical shadow 真验 | 建议紧跟 `P2-T1` | 正式数据面接入 | +| `P2-T3` | `P1-T3` + `P1-T4` | 可与 `P2-T2` 部分交叉 | 运行状态可视化 | +| `P2-T4` | `P2-T1` + `P2-T2` + `P2-T3` | 不建议提前 | 标准化真验与回归 | + +--- + +## 3. P2-T1 管理页入口 + +## 目标闭环 + +让管理员不再只能靠 API 维护 logical routing,而是能在现有 admin portal 中完成: + +- 创建 / 编辑 `logical_group` +- 维护 `public_model` +- 创建 / 编辑 `route` +- 维护 `public_model -> shadow_model` +- 关联 `shadow_host_id / shadow_group_id` + +## 建议实现 + +优先复用现有 `deploy/tksea-portal/admin/` 结构,新增独立页面,例如: + +- `deploy/tksea-portal/admin/logical-groups.html` + +首版只做最小运营流,不做复杂图表: + +1. 左侧:`logical_group` 列表 +2. 中间:当前分组详情 +3. 右侧: + - `public_model` 列表 + - route 列表 + - route model 映射编辑器 + +## 需要对接的 API + +- `GET /api/logical-groups` +- `POST /api/logical-groups` +- `GET /api/logical-groups/{group_id}` +- `PUT /api/logical-groups/{group_id}` +- `POST /api/logical-groups/{group_id}/models` +- `GET /api/logical-groups/{group_id}/routes` +- `POST /api/logical-groups/{group_id}/routes` +- `PUT /api/logical-groups/{group_id}/routes/{route_id}` +- `GET /api/logical-groups/{group_id}/routes/{route_id}/models` +- `POST /api/logical-groups/{group_id}/routes/{route_id}/models` + +## 文件范围 + +- Add: + - `deploy/tksea-portal/admin/logical-groups.html` +- Update: + - `deploy/tksea-portal/admin/index.html` + - 如有必要补充 portal 静态资源脚本 + +## 产出清单 + +- 一个可直接访问的逻辑分组管理页 +- 至少一条从页面发起的 `create group -> create route -> add route model` 成功链路 +- 页面内保留 `shadow_host_id / shadow_group_id` 的显式展示 + +## 远端验收 + +至少完成: + +1. 登录 `/portal/admin/` +2. 打开 `logical-groups.html` +3. 创建临时 `logical_group` +4. 创建临时 route +5. 绑定一条 `public_model -> shadow_model` +6. 通过 `GET /api/logical-groups/{group_id}` 回读一致 + +--- + +## 4. P2-T2 正式数据面入口 + +## 目标闭环 + +把当前实验性质的 `POST /api/routing/proxy/chat/completions` 升级成正式、可演进的数据面入口。 + +这个入口的职责是: + +1. 接收公开模型请求 +2. 调用 `resolve` +3. 命中 sticky / failover / cooldown +4. 自动解析 `shadow_host_id / shadow_group_id / shadow_model` +5. 必要时自动供给 `managed subscription key` +6. 转发到真实 host `/v1/chat/completions` +7. 回写 route logs + +## 建议实现 + +首版不要急着做“全 OpenAI 兼容网关”,先只收敛为一个正式插件入口,例如: + +- `POST /api/routing/chat/completions` + +保留现有最小 proxy 作为内部/调试入口,但对外语义切到正式路由入口。 + +建议请求字段最少包含: + +- `logical_group_id` +- `model` +- `subject_id` +- `messages` +- `subscription_user_id` 或调用方显式 key 来源 +- `request_id`(允许外部传入,也允许服务端自动生成) + +建议响应至少包含: + +- `request_id` +- `selected_route_id` +- `shadow_host_id` +- `shadow_group_id` +- `shadow_model` +- `sticky_hit` +- `fallback_used` +- `forward.upstream_status` + +## 文件范围 + +- Update: + - `internal/app/http_api.go` + - `internal/app/route_proxy_api.go` + - 如有必要新增 `internal/app/route_gateway_api.go` +- Add tests: + - `internal/app/*_test.go` + - `tests/integration/...` 补一轮正式入口集成测试 + +## 产出清单 + +- 正式路由数据面入口 +- 与实验 proxy 明确分层的 API 语义 +- 同一 `request_id` 可串起 resolve / forward / decision log + +## 远端验收 + +至少完成: + +1. 创建临时 `logical_group / route / route_model` +2. 调正式入口发起最小 chat +3. 命中真实 canonical shadow route +4. 返回 `forward.upstream_status=200` +5. 通过 `GET /api/routing/logs/decisions` 回读该次请求 + +--- + +## 5. P2-T3 Route 健康视图 + +## 目标闭环 + +让运营能看见 route 当前是否健康,而不是只能翻日志。 + +首版关注四类状态: + +- `healthy` +- `cooldown` +- `failing` +- `disabled` + +## 建议实现 + +首版不做复杂 dashboard,只做一个列表页 + 轻量聚合 API。 + +建议新增: + +- `GET /api/routing/routes/health` +- 可选过滤: + - `logical_group_id` + - `route_id` + - `status` + +聚合数据来源: + +- `logical_group_routes.status` +- sticky runtime 中的 `routefail:{route_id}` +- sticky runtime 中的 `routecool:{route_id}` +- 最近一段时间的 `route_decision_logs` +- 最近一段时间的 `route_failover_events` + +建议返回字段: + +- `route_id` +- `logical_group_id` +- `shadow_host_id` +- `shadow_group_id` +- `priority` +- `runtime_status` +- `failure_count` +- `cooldown_until` +- `last_error_class` +- `last_selected_at` +- `last_upstream_status` +- `recent_failover_count` + +前端建议增加: + +- `deploy/tksea-portal/admin/route-health.html` + +## 文件范围 + +- Add: + - `internal/app/route_health_api.go` + - `deploy/tksea-portal/admin/route-health.html` +- Update: + - `deploy/tksea-portal/admin/index.html` + +## 产出清单 + +- 一组 route 健康聚合 API +- 一个可查看 route 运行状态的管理页 +- 至少一条 route 的 `healthy -> cooldown -> failover` 可视化回读 + +## 远端验收 + +至少完成: + +1. 先写入一条 route failure 或 cooldown +2. 打开 `route-health.html` +3. 看到该 route 状态变为 `failing` 或 `cooldown` +4. 再触发一次 resolve +5. 验证健康页和日志页一致 + +--- + +## 6. P2-T4 真实验收矩阵 + +## 目标闭环 + +把当前靠零散命令完成的真验,收敛成固定矩阵和固定证据格式。 + +## 验收矩阵 + +### 控制面 + +1. `logical_group` 创建 / 查询 / 更新 +2. route 创建 / 查询 / 更新 +3. route model 创建 / 查询 + +### 路由运行态 + +1. sticky bind +2. sticky hit +3. failure threshold failover +4. cooldown failover +5. sticky rebinding + +### 数据面 + +1. 正式入口 -> canonical shadow route -> real host chat `200` +2. `managed subscription key` 自动供给 +3. `request_id` 全链路串接 +4. route decision log 回写 + +### 管理页 + +1. `logical-groups.html` +2. `route-health.html` +3. 必要的 admin index 导航可见 + +## 建议沉淀形式 + +- 优先补充现有 acceptance / verify 脚本 +- 必要时新增: + - `scripts/acceptance/verify_route_control_plane.sh` + - `scripts/acceptance/verify_route_data_plane.sh` + - `scripts/acceptance/verify_route_health_ui.sh` + +每次真验至少输出: + +- 代码提交号 +- remote43 当前 `repo HEAD` +- request/sample IDs +- 关键 API 响应摘要 +- decision log 回读摘要 + +## 产出清单 + +- 一份标准化验收矩阵 +- 至少两条可复用脚本 +- `EXECUTION_BOARD` 中新增“P2 标准真验矩阵”记录 + +## 远端验收 + +本任务自身的验收就是: + +- 按矩阵完整跑通一次 +- 证据可复读 +- 后续任何 Phase 2 回归都可复用 + +--- + +## 7. 当前建议实施顺序 + +```text +P2-T1 管理页入口 +P2-T2 正式数据面入口 +P2-T3 Route 健康视图 +P2-T4 真实验收矩阵 +``` + +原因: + +- 先让人能配置 +- 再让流量能正式走 +- 再让状态能看见 +- 最后让整个 Phase 2 可持续回归 + +## 一句话结论 + +Phase 2 的重点已经不是“证明路由能跑”,而是把现有能力收敛成: + +- 可操作的控制面 +- 可正式承载流量的数据面 +- 可视化的 route 健康面 +- 可重复执行的真实验收矩阵 + +只有这四块完成后,插件的智能路由能力才算从“工程验证成功”进入“产品闭环可运营”。