- 数据源:全部文档统一为 bzzoiro 唯一来源,删除 understat/api-football 作为现行数据源的表述(仅保留历史注记);.env.example/docs/06 移除 失效的 API_FOOTBALL_KEY - 多 Agent:injuries 阵容完整性 → standings 联赛排名 (README/01/04 的专家表、数据流图、no_data 示例、agent_weights、 prompt 清单全部对齐 form/stats/home_away/standings/h2h) - 数据库:6 张表 → 12 张表,补 standings/app_settings/schedules 与 4 张治理表说明(标注 raw_events/data_quality_checks/data_lineage 为预留未启用,ingest_failures 已启用),predictions 补 agent_weights 列 - API 文档(03):新增鉴权模型三档表;context/standings/leagues 公开端点 补全;predictions/eval/backtest 标注需管理员;ingest/bzzoiro 补 task/limit/season 参数契约,删除 understat/injuries 端点小节 - 目录树(README/01/07):与真实 src/、frontend/src 结构一致 (core 7 文件、data 7 文件、移除不存在的 retry.py) - 采集命令(02/05):understat 回填 → task=stats/standings; 补管理员凭据提示;docs/08 文首标注历史/过时
7.6 KiB
03 · API 参考
Base URL: http://localhost:8000 · 交互式文档: /docs(Swagger)与 /redoc
所有数据端点返回 JSON。错误统一为 {"detail": "<message>"} + 对应 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: 公开站联赛筛选动态加载来源)。
[{"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):
{
"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 次交手
{
"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(空 = 各联赛最新赛季)。
{"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 预测。核心端点。
请求:
{
"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 模式):
{
"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(唯一数据源)采集数据并入库(幂等,重复跑安全)。任务在后台异步执行,请求立即返回。
{"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) |
- 响应含每联赛
inserted/updated/errors统计 task=stats只补空字段、不创建比赛(xG/射门/控球等统计回填)
历史版本曾有独立的 understat(xG)与 injuries(伤停)采集端点, 已随数据源收敛为 bzzoiro 唯一来源而移除。
评估
POST /api/v1/eval/settle(需管理员)
赛后回填实际比分:
{"prediction_id": 7, "home_goals": 2, "away_goals": 1}
GET /api/v1/eval/summary(需管理员)
按 provider × model 聚合已结算预测:
{"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 |
需管理员 | 历史回测(对已完赛比赛批量预测并评估) |