# 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` - `matched_account_state` - `account_resolution` - `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", "api_key_fingerprint": "sha256:8d8c4b5f", "requested_models": ["kimi-k2.6"], "canonical_model_families": ["kimi-k2.6"], "resolved_smoke_model": "kimi-k2.6", "current_stage": "done", "confirmation_status": "advisory", "access_status": "active", "matched_account_state": "active", "account_resolution": "reused", "provision_reused": true, "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", "api_key_fingerprint": "sha256:8d8c4b5f", "requested_models": ["kimi-k2.6"], "raw_models": ["kimi-k2.6"], "normalized_models": ["kimi-k2.6"], "canonical_model_families": ["kimi-k2.6"], "recommended_models": [], "resolved_smoke_model": "kimi-k2.6", "current_stage": "done", "confirmation_status": "advisory", "access_status": "active", "matched_account_state": "deprecated", "account_resolution": "reactivated", "provision_reused": true, "reused_from_provider_id": "kimi-a7m-7d7ac291", "reused_from_account_id": 4, "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", "canonical_model_family": "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` | ### 7.4 Reuse badge | 字段 | 页面 badge | |---|---| | `provision_reused=true` | 青色 `reused` | | `provision_reused=false` | 不显示 | ### 7.5 Account state badge | 字段 | 页面 badge | |---|---| | `matched_account_state=active` | 绿色 `已启用` | | `matched_account_state=disabled` | 灰色 `已停用` | | `matched_account_state=deprecated` | 黄色 `已弃用` | | `matched_account_state=broken` | 红色 `已损坏` | ### 7.6 Account resolution badge | 字段 | 页面 badge | |---|---| | `account_resolution=created` | 蓝色 `新建` | | `account_resolution=reused` | 青色 `复用` | | `account_resolution=reactivated` | 绿色 `已快速启用` | | `account_resolution=replaced` | 红色 `已替换` | ## 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 层统一生成 5. `provision_reused`、`reused_from_provider_id` 等复用字段必须来自 projection,不允许前端自行推断 6. `matched_account_state` 与 `account_resolution` 也必须来自 projection,不允许前端根据 account_id 是否存在自行推断 ## 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