# 03 · API 参考 Base URL: `http://localhost:8000` · 交互式文档: `/docs`(Swagger)与 `/redoc` 所有数据端点返回 JSON。错误统一为 `{"detail": ""}` + 对应 HTTP 状态码。 ## 鉴权模型 | 级别 | 端点 | 说明 | |---|---|---| | **公开只读** | `GET /leagues`、`GET /matches`、`GET /matches/{id}`、`GET /matches/{id}/context`、`GET /standings`、`GET /health*` | 无需任何凭据;公开站直接调用 | | **公开 + 限流** | `POST /predict` | 内存滑动窗口限流(10 次/分钟/IP) | | **需管理员** | `GET /predictions*`、`POST /ingest/bzzoiro`、`/eval/*`、`POST /backtest`、`/admin/**` | Cookie 会话(`POST /auth/login` 颁发)或 `X-API-Key` 头 | 管理端点在生产环境未配置鉴权时 fail-closed(503),不会静默放行。 --- ## 数据查询(公开只读) ### `GET /api/v1/leagues` 列出已入库联赛(P1-3: 公开站联赛筛选动态加载来源)。 ```json [{"id": 1, "code": "E0", "name": "Premier League", "country": "England"}] ``` 仅返回 `id/code/name/country` 四个展示字段,不含任何配置或密钥信息。 ### `GET /api/v1/matches` 比赛列表,游标分页。 | 参数 | 说明 | |---|---| | `league` | 联赛代码,如 `E0` / `SP1` / `D1` / `I1` / `F1` | | `status` | `scheduled` / `finished`(不传 = 全部) | | `date` | `YYYY-MM-DD`,当天比赛 | | `cursor` | 上一页返回的 `next_cursor` | | `limit` | 1–100,默认 50 | 响应(倒序,含双方中文名与 xG): ```json { "items": [ {"id": 42, "league_code": "E0", "season": "2026-2027", "home_team": "Arsenal", "away_team": "Manchester United", "home_team_zh": null, "away_team_zh": null, "match_date": "2026-09-15T19:00:00Z", "match_status": "scheduled", "home_goals": null, "away_goals": null, "match_stage": "第 5 轮", "home_xg": null, "away_xg": null} ], "next_cursor": "2026-09-15T19:00:00+00:00|41", "has_more": true } ``` ### `GET /api/v1/matches/{id}` 单场比赛详情,字段同上,另含 `stats`(统计)与 `recent_predictions`(最近 5 条预测摘要)。 ### `GET /api/v1/matches/{id}/context` 比赛上下文(公开只读,P1-2: 公开站详情页「近况/交锋」数据来源;不触发 LLM): - `home_recent`: 主队最近 5 场已完赛 - `away_recent`: 客队最近 5 场已完赛 - `h2h`: 双方最近 5 次交手 ```json { "home_recent": [ {"match_date": "2026-09-12T14:00:00+00:00", "home_team": "阿森纳", "away_team": "切尔西", "home_goals": 2, "away_goals": 1} ], "away_recent": [], "h2h": [] } ``` 数据不足时对应列表为空(前端展示空态)。比赛不存在返回 404。 ### `GET /api/v1/standings` 联赛积分榜(公开只读)。参数:`league`(联赛代码,空 = 全部)、`season`(空 = 各联赛最新赛季)。 ```json {"leagues": [ {"league_code": "E0", "league_name": "Premier League", "season": "2026-2027", "retrieved_at": "2026-09-20T08:00:00+00:00", "rows": [{"position": 1, "team": "阿森纳", "team_en": "Arsenal", "played": 5, "won": 4, "drawn": 1, "lost": 0, "goals_for": 11, "goals_against": 3, "goal_diff": 8, "points": 13, "xg_for": 9.8, "xg_against": 3.9, "form": "WWWDW", "zone": "UEFA Champions League"}]} ]} ``` --- ## 预测 ### `POST /api/v1/predict` 对一场比赛做 LLM 预测。**核心端点。** 请求: ```json { "match_id": 42, "mode": "multi", "model": "gpt-4o", "prompt_version": "v1" } ``` | 字段 | 默认 | 说明 | |---|---|---| | `match_id` | 必填 | 比赛 ID | | `mode` | `multi` | `multi` = 5 专家 + 终裁;`single` = 单次调用 | | `model` | 配置值 | 覆盖本次模型(single 模式下生效) | | `prompt_version` | `v1` | prompt 版本(multi 模式即 agent prompt 版本) | 响应(multi 模式): ```json { "prediction_id": 7, "provider": "openai", "model": "gpt-4o", "prompt_version": "multi_v1", "mode": "multi", "pred_home_goals": 2.1, "pred_away_goals": 1.0, "pred_1x2": "1", "subjective_confidence": 0.68, "reasoning": "综合 xg 报告的进球期望 2.1-1.0 与 form 报告的三连胜势头……", "agent_outputs": [ {"agent": "h2h", "status": "ok", "data_sufficiency": "medium", "analysis": "近 5 次交锋主队 3 胜……", "home_edge": 0.4, "subjective_confidence": 0.7, "key_evidence": ["近5次交锋主队3胜", "主场交锋3连胜"], "exp_home_goals": null, "exp_away_goals": null, "probable_score": null, "model": "gpt-4o-mini", "latency_ms": 2100, "prompt_tokens": 380, "completion_tokens": 120}, {"agent": "standings", "status": "no_data", "data_sufficiency": "none", "analysis": "该维度无数据,跳过分析。", "home_edge": null, "subjective_confidence": null, "key_evidence": [], "exp_home_goals": null, "exp_away_goals": null, "probable_score": null, "model": "", "latency_ms": null, "prompt_tokens": null, "completion_tokens": null} ], "agent_weights": {"form": 0.9, "stats": 0.8, "home_away": 0.7, "standings": 0.8, "h2h": 0.8}, "context": "[5 份报告的 JSON 串]", "latency_ms": 9800 } ``` `agent.status` 取值:`ok` / `no_data`(维度无数据,已跳过 LLM)/ `error`(调用失败,fail-open 不阻断)/ `parse_error`。 错误:404 比赛不存在;502 LLM 调用失败(终裁失败时整体失败,专家失败不会)。 ### `GET /api/v1/predictions?match_id=&limit=`(需管理员) 预测历史(倒序),含 `settled` 与实际比分回填状态。 ### `GET /api/v1/predictions/{id}`(需管理员) 单条预测详情(含完整 `agent_outputs`)。 --- ## 数据采集 ### `POST /api/v1/ingest/bzzoiro`(需管理员) 从 bzzoiro(唯一数据源)采集数据并入库(幂等,重复跑安全)。任务在后台异步执行,请求立即返回。 ```json {"task": "all", "leagues": ["E0", "SP1"], "date_from": "2025-08-01", "date_to": "2026-09-08", "status": "finished"} ``` | 字段 | 默认 | 说明 | |---|---|---| | `task` | `events` | 采集任务:`events`(比赛)/ `standings`(积分榜)/ `stats`(统计回填,含 xG)/ `all` | | `leagues` | 全部已知联赛 | 联赛代码列表,如 `["E0", "SP1"]` | | `date_from` / `date_to` | 空 | 日期范围(`YYYY-MM-DD`) | | `status` | 空(两者都采) | `finished`(已完赛)/ `scheduled`(未来赛程) | | `season` | 当前赛季 | standings 赛季,如 `"2026-2027"` | | `limit` | 100 | stats 回填单次最大比赛数(1–500) | - 响应:`{"ok": true, "job_id": "", "message": "……"}`,`job_id` 用于查询任务状态 - `task=stats` 只补空字段、不创建比赛(xG/射门/控球等统计回填) ### `GET /api/v1/admin/ingest/jobs/{job_id}`(需管理员) 查询一次采集任务的状态(`ingest_jobs` 表,任务级可观测性): ```json {"id": "…", "task": "standings", "params": {"leagues": ["E0"]}, "status": "success", "result": {"total_upserted": 20, "errors": []}, "error": null, "created_at": "…", "started_at": "…", "finished_at": "…"} ``` - `status` 取值:`pending`(已创建未开始)/ `running` / `success` / `failed` - 管理端采集页提交后凭 `job_id` 轮询本端点直至终态 - 与 `ingest_failures` 死信独立:死信记录单条管线抓取失败(行级),job 记录整次任务结果 ### `GET /api/v1/admin/ingest/jobs?limit=20&status=`(需管理员) 列出最近采集任务(最新在前),可按 `status` 过滤,`limit` 1–100。 > 历史版本曾有独立的 understat(xG)与 injuries(伤停)采集端点, > 已随数据源收敛为 bzzoiro 唯一来源而移除。 --- ## 评估 ### `POST /api/v1/eval/settle`(需管理员) 赛后回填实际比分: ```json {"prediction_id": 7, "home_goals": 2, "away_goals": 1} ``` ### `GET /api/v1/eval/summary`(需管理员) 按 `provider × model` 聚合已结算预测: ```json {"summary": [ {"provider": "openai", "model": "gpt-4o", "total": 12, "accuracy_1x2": 58.3, "avg_score_rmse": 1.21, "avg_subjective_confidence": 0.65} ]} ``` > 提示:multi 模式存的 `model` 是终裁模型、`prompt_version` 是 `multi_v1`, > 因此 summary 里天然可对比 multi vs single、以及不同 prompt 版本的效果。 --- ## 基础 | 端点 | 权限 | 说明 | |---|---|---| | `GET /health` | 公开 | 存活检查 | | `GET /docs`、`GET /redoc` | 公开 | Swagger UI / ReDoc | | `POST /auth/login`、`POST /auth/logout`、`GET /auth/me` | 公开 | 管理员 Cookie 会话登录/登出/当前用户 | | `POST /auth/change-password` | 需管理员 | 修改管理员密码 | | `POST /backtest` | 需管理员 | 历史回测(对已完赛比赛批量预测并评估) |