404 lines
8.4 KiB
Markdown
404 lines
8.4 KiB
Markdown
|
|
# V2 API Response Schema 细稿 — Batch Auto-Import
|
|||
|
|
|
|||
|
|
日期:2026-05-22
|
|||
|
|
关联文档:
|
|||
|
|
|
|||
|
|
- `docs/2026-05-21-BATCH_AUTO_IMPORT_SPEC.md`
|
|||
|
|
- `docs/2026-05-21-BATCH_AUTO_IMPORT_TDD_PLAN.md`
|
|||
|
|
- `docs/2026-05-22-BATCH_AUTO_IMPORT_V2_ARCHITECTURE.md`
|
|||
|
|
- `docs/openapi.yaml`
|
|||
|
|
|
|||
|
|
## 1. 目标
|
|||
|
|
|
|||
|
|
这份文档把 V2 结果 API 细化到 handler 和前端都可直接对照实现的粒度。
|
|||
|
|
|
|||
|
|
覆盖:
|
|||
|
|
|
|||
|
|
- 路由
|
|||
|
|
- query/filter
|
|||
|
|
- response schema
|
|||
|
|
- error schema
|
|||
|
|
- badge / 文案映射
|
|||
|
|
- 示例 JSON
|
|||
|
|
|
|||
|
|
## 2. 资源模型
|
|||
|
|
|
|||
|
|
V2 API 只暴露 3 层资源:
|
|||
|
|
|
|||
|
|
1. `run`
|
|||
|
|
2. `run items`
|
|||
|
|
3. `run item events`
|
|||
|
|
|
|||
|
|
不直接暴露:
|
|||
|
|
|
|||
|
|
- 宿主数据库结构
|
|||
|
|
- `import_batches` 细节
|
|||
|
|
- legacy repo 的内部实现字段
|
|||
|
|
|
|||
|
|
## 3. Endpoint 列表
|
|||
|
|
|
|||
|
|
### 3.1 创建 run
|
|||
|
|
|
|||
|
|
`POST /api/batch-import/runs`
|
|||
|
|
|
|||
|
|
作用:
|
|||
|
|
|
|||
|
|
- 创建 V2 run
|
|||
|
|
- 立即返回 `run_id`
|
|||
|
|
- 可选等待一个短暂 confirm window,但不保证全部 item 已 done
|
|||
|
|
|
|||
|
|
### 3.2 列表 runs
|
|||
|
|
|
|||
|
|
`GET /api/batch-import/runs`
|
|||
|
|
|
|||
|
|
作用:
|
|||
|
|
|
|||
|
|
- 查看最近导入批次
|
|||
|
|
- 支持状态筛选和关键词搜索
|
|||
|
|
|
|||
|
|
### 3.3 run 详情
|
|||
|
|
|
|||
|
|
`GET /api/batch-import/runs/{run_id}`
|
|||
|
|
|
|||
|
|
作用:
|
|||
|
|
|
|||
|
|
- 返回 run summary
|
|||
|
|
- 返回汇总告警摘要
|
|||
|
|
|
|||
|
|
### 3.4 item 列表
|
|||
|
|
|
|||
|
|
`GET /api/batch-import/runs/{run_id}/items`
|
|||
|
|
|
|||
|
|
作用:
|
|||
|
|
|
|||
|
|
- 展示批次内各 URL/provider 的状态
|
|||
|
|
- 支持按 stage/access/warning 过滤
|
|||
|
|
|
|||
|
|
### 3.5 item 详情
|
|||
|
|
|
|||
|
|
`GET /api/batch-import/runs/{run_id}/items/{item_id}`
|
|||
|
|
|
|||
|
|
作用:
|
|||
|
|
|
|||
|
|
- 返回一个 item 的全量投影
|
|||
|
|
- 包括 capability、模型纠错、event trail
|
|||
|
|
|
|||
|
|
## 4. Query 参数约定
|
|||
|
|
|
|||
|
|
### 4.1 `GET /api/batch-import/runs`
|
|||
|
|
|
|||
|
|
支持:
|
|||
|
|
|
|||
|
|
- `state`
|
|||
|
|
- `running`
|
|||
|
|
- `completed`
|
|||
|
|
- `completed_with_warnings`
|
|||
|
|
- `failed`
|
|||
|
|
- `cancelled`
|
|||
|
|
- `access_mode`
|
|||
|
|
- `subscription`
|
|||
|
|
- `self_service`
|
|||
|
|
- `q`
|
|||
|
|
- 搜索 `run_id / provider_id / base_url`
|
|||
|
|
- `limit`
|
|||
|
|
- `cursor`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 页面显示可以把 `completed_with_warnings` 渲染成 `warning`
|
|||
|
|
- API 不应引入第二套 `warning` 枚举
|
|||
|
|
|
|||
|
|
### 4.2 `GET /api/batch-import/runs/{run_id}/items`
|
|||
|
|
|
|||
|
|
支持:
|
|||
|
|
|
|||
|
|
- `current_stage`
|
|||
|
|
- `probe`
|
|||
|
|
- `provision`
|
|||
|
|
- `confirm`
|
|||
|
|
- `validate`
|
|||
|
|
- `done`
|
|||
|
|
- `confirmation_status`
|
|||
|
|
- `pending`
|
|||
|
|
- `confirmed`
|
|||
|
|
- `advisory`
|
|||
|
|
- `failed`
|
|||
|
|
- `access_status`
|
|||
|
|
- `unknown`
|
|||
|
|
- `active`
|
|||
|
|
- `degraded`
|
|||
|
|
- `broken`
|
|||
|
|
- `has_warning`
|
|||
|
|
- `true/false`
|
|||
|
|
- `provider_id`
|
|||
|
|
- `q`
|
|||
|
|
- 搜索 `provider_id / base_url / item_id`
|
|||
|
|
- `limit`
|
|||
|
|
- `cursor`
|
|||
|
|
|
|||
|
|
## 5. 通用错误结构
|
|||
|
|
|
|||
|
|
建议统一:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"error": {
|
|||
|
|
"code": "invalid_request",
|
|||
|
|
"message": "subscription_users is required when access_mode=subscription"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
常用 `code`:
|
|||
|
|
|
|||
|
|
- `invalid_request`
|
|||
|
|
- `not_found`
|
|||
|
|
- `conflict`
|
|||
|
|
- `internal_error`
|
|||
|
|
|
|||
|
|
## 6. 响应 Schema
|
|||
|
|
|
|||
|
|
### 6.1 `POST /api/batch-import/runs`
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"run_id": "run_20260522_0001",
|
|||
|
|
"state": "running",
|
|||
|
|
"result_page": "/batch-import/runs/run_20260522_0001",
|
|||
|
|
"total_items": 2,
|
|||
|
|
"active_items": 0,
|
|||
|
|
"degraded_items": 0,
|
|||
|
|
"broken_items": 0,
|
|||
|
|
"warning_items": 0
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
约束:
|
|||
|
|
|
|||
|
|
- 这是 `run created` 语义,不是 final result
|
|||
|
|
- `state` 初始一般是 `running`
|
|||
|
|
|
|||
|
|
### 6.2 `GET /api/batch-import/runs`
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"runs": [
|
|||
|
|
{
|
|||
|
|
"run_id": "run_20260522_0001",
|
|||
|
|
"state": "completed_with_warnings",
|
|||
|
|
"mode": "partial",
|
|||
|
|
"access_mode": "subscription",
|
|||
|
|
"total_items": 2,
|
|||
|
|
"completed_items": 2,
|
|||
|
|
"active_items": 1,
|
|||
|
|
"degraded_items": 1,
|
|||
|
|
"broken_items": 0,
|
|||
|
|
"warning_items": 1,
|
|||
|
|
"started_at": "2026-05-22T12:20:00+08:00",
|
|||
|
|
"finished_at": "2026-05-22T12:20:07+08:00"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"next_cursor": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 `GET /api/batch-import/runs/{run_id}`
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"run": {
|
|||
|
|
"run_id": "run_20260522_0001",
|
|||
|
|
"state": "completed_with_warnings",
|
|||
|
|
"mode": "partial",
|
|||
|
|
"access_mode": "subscription",
|
|||
|
|
"total_items": 2,
|
|||
|
|
"completed_items": 2,
|
|||
|
|
"active_items": 1,
|
|||
|
|
"degraded_items": 1,
|
|||
|
|
"broken_items": 0,
|
|||
|
|
"warning_items": 1,
|
|||
|
|
"started_at": "2026-05-22T12:20:00+08:00",
|
|||
|
|
"finished_at": "2026-05-22T12:20:07+08:00"
|
|||
|
|
},
|
|||
|
|
"recent_warnings": [
|
|||
|
|
"该批次包含 1 条 advisory item,建议检查 capability profile 与 retry 轨迹"
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.4 `GET /api/batch-import/runs/{run_id}/items`
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"items": [
|
|||
|
|
{
|
|||
|
|
"item_id": "item_01",
|
|||
|
|
"base_url": "https://kimi.a7m.com.cn/v1",
|
|||
|
|
"provider_id": "kimi-a7m-7d7ac291",
|
|||
|
|
"requested_models": ["kimi-k2.6"],
|
|||
|
|
"resolved_smoke_model": "kimi-k2.6",
|
|||
|
|
"current_stage": "done",
|
|||
|
|
"confirmation_status": "advisory",
|
|||
|
|
"access_status": "active",
|
|||
|
|
"retry_count": 2,
|
|||
|
|
"last_retry_at": "2026-05-22T12:20:05+08:00",
|
|||
|
|
"advisory_messages": [
|
|||
|
|
"该上游不支持 /v1/responses,系统已自动回退到 /v1/chat/completions"
|
|||
|
|
],
|
|||
|
|
"last_error_stage": "confirm",
|
|||
|
|
"last_error": "API returned 403: Forbidden"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"next_cursor": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.5 `GET /api/batch-import/runs/{run_id}/items/{item_id}`
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"item_id": "item_01",
|
|||
|
|
"base_url": "https://kimi.a7m.com.cn/v1",
|
|||
|
|
"provider_id": "kimi-a7m-7d7ac291",
|
|||
|
|
"requested_models": ["kimi-k2.6"],
|
|||
|
|
"raw_models": ["kimi-k2.6"],
|
|||
|
|
"normalized_models": ["kimi-k2.6"],
|
|||
|
|
"recommended_models": [],
|
|||
|
|
"resolved_smoke_model": "kimi-k2.6",
|
|||
|
|
"current_stage": "done",
|
|||
|
|
"confirmation_status": "advisory",
|
|||
|
|
"access_status": "active",
|
|||
|
|
"retry_count": 2,
|
|||
|
|
"last_retry_at": "2026-05-22T12:20:05+08:00",
|
|||
|
|
"channel_id": 12,
|
|||
|
|
"account_id": 4,
|
|||
|
|
"advisory_messages": [
|
|||
|
|
"该上游不支持 /v1/responses,系统已自动回退到 /v1/chat/completions"
|
|||
|
|
],
|
|||
|
|
"last_error_stage": "confirm",
|
|||
|
|
"last_error": "API returned 403: Forbidden",
|
|||
|
|
"capability_profile": {
|
|||
|
|
"transport_profile": {
|
|||
|
|
"supports_openai_models": true,
|
|||
|
|
"supports_openai_chat_completions": true,
|
|||
|
|
"supports_openai_responses": false,
|
|||
|
|
"supports_anthropic_messages": false,
|
|||
|
|
"auth_style": "bearer",
|
|||
|
|
"model_id_style": "canonical",
|
|||
|
|
"known_advisories": [
|
|||
|
|
"responses_unsupported_but_chat_ok",
|
|||
|
|
"initial_probe_race_expected"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"model_profiles": [
|
|||
|
|
{
|
|||
|
|
"raw_model_id": "kimi-k2.6",
|
|||
|
|
"normalized_model_id": "kimi-k2.6",
|
|||
|
|
"supports_stream": true,
|
|||
|
|
"supports_tools": "unknown",
|
|||
|
|
"supports_reasoning_fields": "unknown",
|
|||
|
|
"smoke_chat_ok": true
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"events": [
|
|||
|
|
{
|
|||
|
|
"event_id": "evt_01",
|
|||
|
|
"event_type": "retry_scheduled",
|
|||
|
|
"stage": "confirm",
|
|||
|
|
"attempt": 1,
|
|||
|
|
"message": "initial 503 no available accounts, retry scheduled",
|
|||
|
|
"payload_json": "{\"delay_ms\":500}",
|
|||
|
|
"created_at": "2026-05-22T12:20:04+08:00"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 7. Badge / 文案映射
|
|||
|
|
|
|||
|
|
### 7.1 Run state badge
|
|||
|
|
|
|||
|
|
| API 值 | 页面 badge |
|
|||
|
|
|---|---|
|
|||
|
|
| `running` | 蓝色 `running` |
|
|||
|
|
| `completed` | 绿色 `completed` |
|
|||
|
|
| `completed_with_warnings` | 黄色 `warning` |
|
|||
|
|
| `failed` | 红色 `failed` |
|
|||
|
|
| `cancelled` | 灰色 `cancelled` |
|
|||
|
|
|
|||
|
|
### 7.2 Confirmation badge
|
|||
|
|
|
|||
|
|
| API 值 | 页面 badge |
|
|||
|
|
|---|---|
|
|||
|
|
| `pending` | 蓝色 `pending` |
|
|||
|
|
| `confirmed` | 绿色 `confirmed` |
|
|||
|
|
| `advisory` | 黄色 `advisory` |
|
|||
|
|
| `failed` | 红色 `failed` |
|
|||
|
|
|
|||
|
|
### 7.3 Access badge
|
|||
|
|
|
|||
|
|
| API 值 | 页面 badge |
|
|||
|
|
|---|---|
|
|||
|
|
| `unknown` | 灰色 `unknown` |
|
|||
|
|
| `active` | 绿色 `active` |
|
|||
|
|
| `degraded` | 黄色 `degraded` |
|
|||
|
|
| `broken` | 红色 `broken` |
|
|||
|
|
|
|||
|
|
## 8. 分页与排序建议
|
|||
|
|
|
|||
|
|
### 8.1 Runs 列表
|
|||
|
|
|
|||
|
|
默认排序:
|
|||
|
|
|
|||
|
|
- `started_at DESC`
|
|||
|
|
|
|||
|
|
### 8.2 Items 列表
|
|||
|
|
|
|||
|
|
默认排序:
|
|||
|
|
|
|||
|
|
1. `current_stage != done` 的在前
|
|||
|
|
2. `access_status = broken/degraded` 在前
|
|||
|
|
3. `updated_at DESC`
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- 结果页首先服务“快速定位问题”
|
|||
|
|
|
|||
|
|
## 9. Handler 约束
|
|||
|
|
|
|||
|
|
1. 列表接口只返回 projection,不返回原始 JSON 大对象
|
|||
|
|
2. item 详情才返回 `capability_profile` 与 `events`
|
|||
|
|
3. 不在 handler 里拼装 legacy 表结果
|
|||
|
|
4. 任何页面要显示的 warning 文案,都从 projection 层统一生成
|
|||
|
|
|
|||
|
|
## 10. 最小实现建议
|
|||
|
|
|
|||
|
|
实现顺序建议:
|
|||
|
|
|
|||
|
|
1. 先做 `POST /api/batch-import/runs`
|
|||
|
|
2. 再做 `GET /api/batch-import/runs`
|
|||
|
|
3. 再做 `GET /api/batch-import/runs/{run_id}`
|
|||
|
|
4. 再做 item 列表
|
|||
|
|
5. 最后做 item 详情和 event trail
|
|||
|
|
|
|||
|
|
理由:
|
|||
|
|
|
|||
|
|
- 列表页和 run 详情先能支撑运营查看批次
|
|||
|
|
- 复杂度最高的是 item detail / event trail
|
|||
|
|
|
|||
|
|
## 11. 验证点
|
|||
|
|
|
|||
|
|
文档层:
|
|||
|
|
|
|||
|
|
- 是否所有状态枚举都与 `SPEC/TDD/Architecture` 一致
|
|||
|
|
- 是否还存在 `warning` 与 `completed_with_warnings` 混用
|
|||
|
|
- 是否还存在 `confirmed_active` 等旧枚举残留
|
|||
|
|
|
|||
|
|
实现层:
|
|||
|
|
|
|||
|
|
1. `subscription/self_service` 条件必填校验正确
|
|||
|
|
2. run 列表能稳定分页
|
|||
|
|
3. item 详情能展示 capability + event trail
|
|||
|
|
4. 页面无需读取宿主数据库即可解释 warning/broken
|