Expand the batch auto-import V2 spec and TDD plan with stability requirements, result state persistence, and result page design. Add a dedicated architecture document for run state, APIs, pages, and UI field layout, and sync the execution board to the new V2 scope.
17 KiB
V2 技术架构 — Batch Auto-Import
日期:2026-05-22 状态:设计中 关联文档:
docs/2026-05-21-BATCH_AUTO_IMPORT_SPEC.mddocs/2026-05-21-BATCH_AUTO_IMPORT_TDD_PLAN.mddocs/EXECUTION_BOARD.md
1. 文档目标
这份文档回答 4 个问题:
- V2 在系统里由哪些组件组成
- 运行状态如何持久化,如何保证导入任务更稳定
- 结果页到底展示什么,字段如何组织
- 后续实现时,后端、存储、页面应该如何分工
这份文档不重复 SPEC 的产品动机,也不替代 TDD plan 的编码顺序。它只负责把 V2 的技术结构和结果页设计讲清楚。
2. 设计目标
V2 必须同时满足这 5 个目标:
-
稳定导入
- 单条 URL + key 的 probe / provision / confirm / validate 全过程可控
- 批量导入时,单条失败不应让整批状态丢失
-
状态可恢复
- 控制面重启后,历史 run 和 item 结果仍可查看
- 对 transient 失败要有明确 retry 轨迹
-
模型纠错
- 人工填写的模型名不是最终事实
- 必须基于 key 实探结果自动归一化、匹配、推荐
-
兼容分流
- 对国产模型 / 第三方 OpenAI-compatible 上游,必须记录 capability profile
- 后续 routing、确认逻辑、warning 解释都依赖 profile
-
结果可视
- 不再只靠 CLI 和日志
- 控制面必须提供 run 列表和 run 详情页
3. 非目标
这版架构明确不做:
- 多 key 自动负载均衡
- 高级调度系统
- 实时 WebSocket 推送
- 复杂前端工作台
- 自动价格发现与自动调价
- 宿主数据库直连或宿主 DB 读写
4. 逻辑组件
V2 在控制面内部拆成 6 个逻辑层:
operator input
↓
batch import orchestrator
├── probe layer
├── capability profiler
├── provision adapter
├── confirmation engine
├── validation engine
└── run state store
↓
result projection
↓
HTTP API / result pages / CLI output
4.1 Probe Layer
职责:
- 调用 upstream
/v1/models - 探测
/v1/chat/completions - 探测
/v1/responses - 探测
/v1/messages - 抽取原始模型列表
- 计算模型归一化结果
输入:
base_urlapi_keyrequested_models(可选)
输出:
raw_modelsnormalized_modelsresolved_smoke_modelcapability_profileprobe_summary
4.2 Provision Adapter
职责:
- 计算
provider_id - 查找或创建目标 channel
- patch
model_mapping - patch
model_pricing - 创建或更新 account
- 绑定 provider 资源关系
输入:
normalized_modelscapability_profileresolved_smoke_model
输出:
channel_idaccount_idprovider_idmanaged_resources
4.3 Confirmation Engine
职责:
- 处理宿主异步探测窗口
- 处理首次
403 probe race - 处理首次
503 no available accounts - 决定
confirmation_status
输出状态:
confirmed_activeconfirmed_warningconfirmed_broken
4.4 Validation Engine
职责:
- 使用托管 key 对宿主 gateway 真实发起
/v1/chat/completions - 决定最终
access_status - 将 validation 结果写入结果页投影
4.5 Run State Store
职责:
- 持久化 run 和 item 的阶段状态
- 持久化 retry、warning、错误阶段
- 为结果页提供可直接读取的数据源
4.6 Result Projection
职责:
- 将低层运行状态整理成运营和开发都能直接看的摘要
- 生成 run 列表统计
- 生成 item 详情视图
- 不暴露内部实现噪音
5. 运行时状态模型
5.1 Run 级状态
ImportRun.state
runningcompletedcompleted_with_warningsfailedcancelled
ImportRun 核心字段:
| 字段 | 含义 |
|---|---|
run_id |
一次批量导入任务的主键 |
mode |
strict / partial |
access_mode |
subscription / self_service |
total_items |
总条目数 |
completed_items |
已完成条目数 |
active_items |
最终 active 条目数 |
degraded_items |
最终 degraded 条目数 |
broken_items |
最终 broken 条目数 |
state |
run 总状态 |
started_at |
开始时间 |
updated_at |
最近更新时间 |
finished_at |
完成时间 |
5.2 Item 级状态
ImportRunItem.current_stage
probeprovisionconfirmvalidatedone
ImportRunItem.stage_status
discoveredprovisionedconfirmingconfirmed_activeconfirmed_warningconfirmed_broken
ImportRunItem 核心字段:
| 字段 | 含义 |
|---|---|
item_id |
单条导入记录 ID |
base_url |
当前导入目标 URL |
provider_id |
自动生成的 provider 标识 |
requested_models |
人工请求模型名 |
raw_models |
upstream 原始模型列表 |
normalized_models |
归一化后模型列表 |
resolved_smoke_model |
最终用于 smoke 的模型 |
capability_profile_json |
能力画像 |
channel_id |
宿主 channel |
account_id |
宿主 account |
confirmation_status |
确认状态 |
access_status |
最终访问状态 |
retry_count |
当前总重试次数 |
advisory_messages |
warning / advisory 列表 |
last_error_stage |
最近错误发生阶段 |
last_error |
最近错误文本 |
created_at |
创建时间 |
updated_at |
更新时间 |
6. 状态库设计
推荐在控制面 SQLite 中新增两张表:
6.1 import_runs
id TEXT PRIMARY KEY
mode TEXT NOT NULL
access_mode TEXT NOT NULL
state TEXT NOT NULL
total_items INTEGER NOT NULL
completed_items INTEGER NOT NULL
active_items INTEGER NOT NULL
degraded_items INTEGER NOT NULL
broken_items INTEGER NOT NULL
started_at DATETIME NOT NULL
updated_at DATETIME NOT NULL
finished_at DATETIME NULL
索引:
idx_import_runs_started_atidx_import_runs_state
6.2 import_run_items
id TEXT PRIMARY KEY
run_id TEXT NOT NULL
base_url TEXT NOT NULL
provider_id TEXT NOT NULL
current_stage TEXT NOT NULL
stage_status TEXT NOT NULL
requested_models_json TEXT NOT NULL
raw_models_json TEXT NOT NULL
normalized_models_json TEXT NOT NULL
resolved_smoke_model TEXT NOT NULL
capability_profile_json TEXT NOT NULL
channel_id INTEGER NULL
account_id INTEGER NULL
confirmation_status TEXT NOT NULL
access_status TEXT NOT NULL
retry_count INTEGER NOT NULL
advisory_messages_json TEXT NOT NULL
last_error_stage TEXT NULL
last_error TEXT NULL
created_at DATETIME NOT NULL
updated_at DATETIME NOT NULL
索引:
idx_import_run_items_run_ididx_import_run_items_provider_ididx_import_run_items_stage_statusidx_import_run_items_access_status
约束:
- 所有页面和 API 只读这两张控制面表
- 不直接读宿主数据库
- 宿主状态变化要通过控制面自己的确认与验证结果回写
7. 稳定性机制
7.1 阶段落盘
每个 item 每完成一个阶段都立刻落盘:
- probe 完成后写
discovered - provision 完成后写
provisioned - confirm 开始写
confirming - confirm/validate 结束后写
confirmed_*
这样做的价值:
- 进程中断后不丢历史轨迹
- 页面可以显示“卡在哪一阶段”
- 后续如果支持 resume,有阶段边界可用
7.2 Advisory 与 Blocking 分离
V2 必须显式区分:
- blocking error
- 真正阻止继续执行
- advisory
- 不阻止完成,但需要展示原因
典型 advisory:
- 第三方 upstream 首次
403 Forbiddenprobe race - 首次
503 no available accounts但重试后恢复 /responses不支持,但/chat/completions可用
7.3 Retry Policy
不是所有失败都重试。
建议策略:
| 错误类型 | 处理 |
|---|---|
401/403 unauthorized |
不重试,直接失败 |
首次 403 probe race |
advisory,等待异步确认,再测 |
429 rate_limit |
记录 warning,可选限次重试 |
首次 503 no available accounts |
短时重试 |
502/503 upstream unreachable |
按策略有限重试 |
每次 retry 都必须写入:
retry_countlast_error_stagelast_error- 最近 retry 时间
7.4 Restart Safety
控制面重启后至少保证:
- 历史 run 列表还能查看
- 历史 item 详情还能查看
- 若 run 在中途停止,页面能看到“最后停在什么阶段”
V2 第一阶段可以不做自动 resume,但必须让“失败现场可见”。
8. 结果页设计
V2 最少提供两个页面:
/batch-import/runs/batch-import/runs/{run_id}
8.1 批次列表页
页面目标:
- 快速看最近有哪些导入批次
- 快速判断哪一批成功、哪一批有 warning、哪一批失败
页面结构
页面标题:Batch Import Runs
[筛选区]
- 状态筛选:all / running / completed / warning / failed
- access_mode 筛选:all / subscription / self_service
- 时间范围
- 关键字搜索:run_id / provider_id / base_url
[列表表格]
- Run ID
- Started At
- Finished At
- Mode
- Access Mode
- Total
- Active
- Degraded
- Broken
- State
- Actions
字段布局
| 列 | 说明 |
|---|---|
Run ID |
可点击进入详情 |
Started At |
开始时间 |
Finished At |
完成时间,运行中为空 |
Mode |
strict / partial |
Access Mode |
subscription / self_service |
Total |
item 总数 |
Active |
绿色数值 |
Degraded |
黄色数值 |
Broken |
红色数值 |
State |
run 总状态 badge |
Actions |
查看详情 |
状态表现
running:蓝色 badgecompleted:绿色 badgecompleted_with_warnings:黄色 badgefailed:红色 badgecancelled:灰色 badge
8.2 批次详情页
页面目标:
- 快速回答“这批次具体哪条 URL 出了什么问题”
- 能看到模型纠错、compatibility、warning 和 retry 轨迹
页面结构
页面标题:Batch Import Run Detail
[头部摘要卡]
- Run ID
- State
- Started At / Finished At
- Mode / Access Mode
- Total / Active / Degraded / Broken
[Item 列表表格]
- Item ID
- Base URL
- Provider ID
- Requested Models
- Resolved Smoke Model
- Current Stage
- Confirmation Status
- Access Status
- Retry Count
- Last Error Stage
- Last Error
- Actions
[点击某个 Item 后展开侧栏/详情区]
- URL 与 provider 基础信息
- 模型纠错结果
- capability profile 摘要
- channel/account 资源绑定
- advisory messages
- retry timeline
- 原始错误与最终结论
Item 表格字段
| 列 | 说明 |
|---|---|
Item ID |
单条记录标识 |
Base URL |
当前 upstream |
Provider ID |
自动生成 provider |
Requested Models |
人工输入 |
Resolved Smoke Model |
最终 smoke 模型 |
Current Stage |
probe/provision/confirm/validate/done |
Confirmation Status |
confirmed_active/warning/broken |
Access Status |
active/degraded/broken |
Retry Count |
已重试次数 |
Last Error Stage |
最近错误阶段 |
Last Error |
最近错误摘要 |
Item 详情区字段
-
基础信息
base_urlprovider_idchannel_idaccount_id
-
模型信息
requested_modelsraw_modelsnormalized_modelsresolved_smoke_modelrecommended_models(如果发生纠错)
-
兼容能力摘要
supports_openai_modelssupports_openai_chat_completionssupports_openai_responsessupports_anthropic_messagesmodel_id_styleknown_advisories
-
确认与访问结果
confirmation_statusprobe_okaccess_statusretry_countlast_error_stagelast_error
-
说明区
- warning 为什么是 warning
- broken 为什么是 broken
- 这个 item 是否建议人工介入
8.3 页面交互原则
- 默认先显示摘要,不先展示原始 JSON
- 详情区优先显示“结论”和“原因”
- 原始 capability profile / 模型列表可以折叠查看
- warning 要能解释成一句人能读懂的话
示例:
-
responses_unsupported_but_chat_ok- 页面说明:
该上游不支持 /v1/responses,系统已自动回退到 /v1/chat/completions
- 页面说明:
-
initial_probe_race_expected- 页面说明:
账号创建后宿主异步探测尚未稳定,首次 /test 结果已按 advisory 处理
- 页面说明:
9. API 设计
9.1 列表 API
GET /api/batch-import/runs
返回结构:
{
"runs": [
{
"run_id": "batch-20260522-001",
"state": "completed_with_warnings",
"mode": "partial",
"access_mode": "subscription",
"total_items": 12,
"active_items": 9,
"degraded_items": 2,
"broken_items": 1,
"started_at": "2026-05-22T10:00:00+08:00",
"finished_at": "2026-05-22T10:02:12+08:00"
}
]
}
9.2 详情 API
GET /api/batch-import/runs/{run_id}
返回:
- run summary
- count summary
- recent warnings
9.3 Item 列表 API
GET /api/batch-import/runs/{run_id}/items
支持筛选:
stage_statusaccess_statusprovider_idhas_warning
9.4 Item 详情 API
GET /api/batch-import/runs/{run_id}/items/{item_id}
返回:
- item 全量详情
- capability profile
- advisory
- retry trail
10. 后端模块映射
建议模块划分:
internal/batch/run_state.go
职责:
- run / item 状态仓储接口
- run summary 聚合
- 状态投影基础函数
internal/batch/status_projection.go
职责:
- 将底层字段转换成页面友好的摘要
- 统一 warning 文案
- 统一 badge / state 映射
internal/app/http_batch_import.go
职责:
- run 列表 API
- run 详情 API
- item 列表 API
- item 详情 API
internal/app/http_batch_runs.go
职责:
- 渲染最小结果页
- 不关心 probe/provision 细节
- 只依赖 projection 层输出
11. 页面草图
11.1 列表页草图
+----------------------------------------------------------------------------------+
| Batch Import Runs |
+----------------------------------------------------------------------------------+
| Status: [all v] Access Mode: [all v] Search: [__________________________] |
+----------------------------------------------------------------------------------+
| Run ID | State | Total | Active | Degraded | Broken | Started At |
| batch-20260522-001 | warning | 12 | 9 | 2 | 1 | 10:00:00 |
| batch-20260522-002 | running | 4 | 1 | 0 | 0 | 10:05:13 |
+----------------------------------------------------------------------------------+
11.2 详情页草图
+----------------------------------------------------------------------------------+
| Batch Import Run: batch-20260522-001 |
+----------------------------------------------------------------------------------+
| State: completed_with_warnings Mode: partial Access: subscription |
| Total: 12 Active: 9 Degraded: 2 Broken: 1 |
+----------------------------------------------------------------------------------+
| Items |
+----------------------------------------------------------------------------------+
| URL | Provider | Stage | Confirm | Access | Retry | ... |
| api.deepseek.com | deepseek | done | warning | active | 1 | ... |
| api.53hk.cn/v1 | minimax | done | active | active | 0 | ... |
+----------------------------------------------------------------------------------+
| Selected Item Detail |
+----------------------------------------------------------------------------------+
| Requested Models: [minimax-m27-highspeed] |
| Resolved Smoke Model: MiniMax-M2.7-highspeed |
| Capability: responses=false, chat=true, messages=false |
| Advisory: 首次 /test 403 已按异步 probe race 处理 |
| Last Error Stage: confirm |
| Last Error: API returned 403: Forbidden |
+----------------------------------------------------------------------------------+
12. 实施建议
按最小可落地顺序做:
- 先实现
run_state表与 repo - 再让 batch service 在每阶段写入状态
- 再做 API
- 最后做最小页面
不要先做页面再补状态库。否则页面会重新依赖日志和运行态对象,后面还得推倒重来。
13. 验收标准
这份架构落地后,至少应满足:
- 导入过程中可以查询到 run 和 item 状态
- 导入完成后可以通过页面复盘每个 item 的结果
- 页面可以看出模型纠错是否发生
- 页面可以看出 capability profile 的关键摘要
- warning 和 broken 有可读解释
- 控制面重启后,历史结果仍可查看
- 页面和 API 只依赖控制面状态库,不依赖宿主数据库