Files
Profeto/docs/01-architecture.md
T
shangfangjian c657e04679 docs: 同步文档与实现一致性
- 5 张表 → 6 张表(添加 injuries)
- 同步所有 docs 和 models.py docstring
2026-09-15 01:44:49 +08:00

6.6 KiB

01 · 架构总览

系统架构

┌─────────────────────────────────────────────────────┐
│  前端(单页 React + Vite + Tailwind)                   │
│  比赛列表 → 选比赛 → LLM 预测 → 专家报告 + 最终结论     │
└──────────────────────────▲──────────────────────────┘
                           │ REST (/api/v1)
┌──────────────────────────┴──────────────────────────┐
│  FastAPI(单进程,全 async)                            │
│                                                     │
│  数据查询   预测编排          采集(手动/cron 触发)    │
│  ┌──────┐  ┌────────────┐  ┌───────────────────┐    │
│  │matches│  │ orchestrator│  │ bzzoiro  (赛果)   │    │
│  │leagues│  │  ┌─ 5 专家并行(便宜模型)            │    │
│  └──┬───┘  │  │   h2h / form / stats /         │    │
│     │      │  │   home_away / injuries         │    │
│     │      │  └─ aggregator 终裁(强模型)        │    │
│     │      └────────────┘  └───────────────────┘    │
│     │              │              └ understat (xG)  │
│  ┌──┴──────────────┴──┐       └ injuries (伤停)     │
│  │ PostgreSQL (6 张表) │        httpx → 外部 API     │
│  └────────────────────┘                            │
└─────────────────────────────────────────────────────┘

核心数据流(一次多 Agent 预测)

  1. POST /predict {match_id} → orchestrator
  2. load_match_header: 查比赛 + 双方 + 联赛(一次 eager load)
  3. 5 个专家 agent 并行(asyncio.gather),每个:
    • 各自的数据切片函数查库(近况/交锋/积分榜 SQL 聚合/伤停/xG)
    • 切片无数据 → 跳过 LLM,直接 no_data stub(省 token、防幻觉)
    • 有数据 → 专属 prompt(专家模型,便宜快)→ 结构化 JSON 报告(home_edge 方向性评分 + 证据)
  4. 终裁 agent:5 份报告 + 比赛信息 → 权衡采信度(agent_weights)→ 最终预测 JSON
  5. predictions 表(含 agent_outputs 全部报告)
  6. 赛后 POST /eval/settle 回填实际比分 → GET /eval/summary 按 模型×prompt 版本 聚合准确率

关键设计决策

决策 理由
多专家并行而非单次大 prompt 每维度独立迭代 prompt;报告可归因(哪个维度分析错了);总延迟 ≈ 2 次串行调用
专家/终裁模型分档 专家用便宜模型快速分析,终裁用强模型汇总决策,成本与质量平衡(LLM_SPECIALIST_MODEL / LLM_AGGREGATOR_MODEL)
no_data 门控 无数据维度(如伤停未接入)不调 LLM,终裁知道维度缺失,不编造
fail-open 单个专家失败只标记 status=error,其余照常;研究场景可用性优先
match_date_date 天级去重 不同源时间精度不同,秒级匹配会产生重复行;天级 + 数据库唯一约束
积分榜 SQL 聚合 + season 过滤 UNION ALL 主客双视角 + GROUP BY 在库内算,只算当前赛季(修复过跨赛季 bug)
单 agent 模式保留 mode="single" 走旧单次路径,与 multi 形成天然 A/B(eval 按 prompt_version 分组)
无 worker/redis/队列 采集是 cron 触发的短任务,单进程足够;违背简化初衷的基础设施一律不加

目录结构

Profeto/
├── src/
│   ├── api/
│   │   ├── app.py               # FastAPI 工厂(lifespan 建表)
│   │   ├── schemas.py           # Pydantic v2 请求/响应
│   │   └── routes/
│   │       ├── matches.py       # 联赛/比赛查询(游标分页)
│   │       ├── predict.py       # 预测 + 预测历史
│   │       ├── ingest.py        # 采集触发(自管 session)
│   │       └── eval.py          # 赛后回填 + 准确率汇总
│   ├── db/
│   │   ├── base.py              # async engine + get_db/get_db_read
│   │   └── models.py            # 6 张表 ORM
│   ├── data/
│   │   ├── bzzoiro.py           # 赛果采集 + 幂等入库
│   │   ├── understat.py         # xG 回填
│   │   ├── injuries.py          # 伤停采集(带文件缓存)
│   │   ├── normalize.py         # NormalizedMatch 清洗契约
│   │   ├── team_names.py        # 队名归一映射
│   │   └── config.py            # 联赛代码映射
│   ├── llm/
│   │   ├── provider.py          # OpenAI-compatible 抽象(共享连接池/JSON 兜底解析)
│   │   ├── context_builder.py   # 数据切片(h2h/form/stats/home_away/injuries)+ 单 agent 拼接
│   │   ├── predict.py           # 预测入口(mode 分派 + 缓存)
│   │   ├── eval.py              # 准确率统计
│   │   ├── agents/
│   │   │   ├── base.py          # AgentSpec / AgentReport / run_agent
│   │   │   └── orchestrator.py  # 并行专家 → 终裁 → 存库
│   │   └── prompts/
│   │       ├── match_prediction_v1/v2.md   # 单 agent 模板
│   │       └── agents/{h2h,form,stats,home_away,injuries,aggregator}_v1.md
│   └── core/config.py           # pydantic-settings
├── alembic/versions/            # 0001 建表 + 0002 agent 字段
├── frontend/src/pages/Matches.tsx  # 单页(预测面板 + 专家报告折叠区)
├── tests/                       # 33 项(核心 13 + agent 20)
├── docker-compose.yml           # api + postgres 两容器
└── docs/                         # 本文档

技术栈

选型
API FastAPI + uvicorn(全 async)
ORM SQLAlchemy 2.0 async + asyncpg
数据库 PostgreSQL 16(JSONB 存 agent 报告)
HTTP httpx(共享连接池)/ urllib(bzzoiro 同步限速)
LLM OpenAI-compatible 接口(openai/deepseek/ollama 等任一)
前端 Vite + React 18 + TypeScript + Tailwind
测试 pytest + pytest-asyncio(33 项,自包含)
部署 Docker Compose(api + postgres)