shangfangjian f3160e3062 feat: Sprint 1 - 数据正确性整改
P2-01: 移除 lifespan create_all,改为仅验证连接
       新增 /health/ready 就绪检查
P0-04: LLM 输出严格 Pydantic 校验
       - Agent 输出越界/非法 → parse_error
       - 预测输出自动修正 1X2 与比分一致性
P0-01: injuries cutoff 修复
       - get_injuries_for_match 增加 as_of 参数
       - injuries_slice 使用 as_of 过滤 retrieved_at
       - 防止回测时未来采集数据泄漏
P1-12: 批量入库优化
       - 预加载 teams 到内存 dict
       - 预加载 existing matches 到内存 set
       - 消灭 N+1 查询
2026-09-14 23:36:35 +08:00

Profeto — 先知

给 LLM 提供结构化数据,让 LLM 预测足球比分。

架构

┌─────────────────────────────────────────────────────┐
│  前端 (React + Vite + Tailwind)                     │
│  http://localhost:5173                              │
└──────────────────────┬──────────────────────────────┘
                       │ REST API
┌──────────────────────▼──────────────────────────────┐
│  FastAPI                                            │
│  ├── /api/v1/matches     比赛查询                   │
│  ├── /api/v1/predict     LLM 预测 (单/多 Agent)     │
│  ├── /api/v1/ingest/*    数据采集                   │
│  └── /api/v1/eval/*      评估回填                   │
└──────────┬─────────────────────────────┬────────────┘
           │                             │
┌──────────▼──────────┐    ┌─────────────▼────────────┐
│  PostgreSQL         │    │  LLM (OpenAI-compatible)  │
│  5 张表             │    │  OpenAI / Deepseek /      │
│  leagues/teams/     │    │  Ollama / 任意网关        │
│  matches/match_     │    └──────────────────────────┘
│  stats/predictions/ │
│  injuries           │
└─────────────────────┘
           ▲
           │ 采集
┌──────────┴─────────────────────────────────────────┐
│  数据源 (DataSource 协议 + 注册表)                   │
│  ├── bzzoiro    比分 / 统计 / xG                    │
│  ├── understat  xG 回填                             │
│  └── injuries   伤停数据 (api-football)             │
└────────────────────────────────────────────────────┘

多 Agent 预测

默认模式 (mode=multi) 采用 5 专家 + 终裁 架构:

比赛数据 → 切片 ─┬─→ A 近期状态专家 ─┐
                 ├─→ B 攻防数据专家 ─┤
                 ├─→ C 主客因素专家 ─┼─→ 终裁专家 ─→ 最终预测
                 ├─→ D 阵容完整专家 ─┤
                 └─→ E 历史交锋专家 ─┘
  • 各专家只看到自己维度的数据切片,避免信息过载
  • fail-open: 单个专家失败不影响整体
  • no_data 门控: 无数据维度跳过 LLM 调用,省 token 防幻觉
  • 终裁根据各报告的 confidence / data_sufficiency 加权输出 agent_weights

快速开始

前置条件

  • Python >= 3.11
  • Docker (运行 PostgreSQL)
  • LLM API Key (OpenAI / Deepseek / Ollama 等)

1. 安装

# 克隆
git clone https://git.bilidili.cn/shangfangjian/Profeto.git
cd Profeto

# 后端依赖
pip install -e ".[dev]"

# 配置环境变量
cp .env.example .env
# 编辑 .env,填入 LLM_API_KEY 和 BZZOIRO_KEY

2. 启动数据库

docker compose up -d postgres

3. 启动服务

# 后端 (终端 1)
uvicorn src.api.app:app --reload

# 前端 (终端 2)
cd frontend && npm install && npm run dev

后端运行在 http://localhost:8000,前端在 http://localhost:5173

使用流程

1. 采集数据

# 采集 bzzoiro 比分与统计
curl -X POST http://localhost:8000/api/v1/ingest/bzzoiro \
  -H "Content-Type: application/json" \
  -d '{"leagues":["E0","SP1"],"date_from":"2026-08-01","date_to":"2026-09-06"}'

# 回填 understat xG
curl -X POST http://localhost:8000/api/v1/ingest/understat \
  -H "Content-Type: application/json" \
  -d '{"league":"E0","season":2026}'

# 采集伤停
curl -X POST http://localhost:8000/api/v1/ingest/injuries \
  -H "Content-Type: application/json" \
  -d '{"date":"2026-09-09"}'

2. 查询比赛

curl "http://localhost:8000/api/v1/matches?league=E0&status=scheduled"

3. LLM 预测

# 多 Agent 预测 (默认)
curl -X POST http://localhost:8000/api/v1/predict \
  -H "Content-Type: application/json" \
  -d '{"match_id": 1}'

# 单次调用模式
curl -X POST http://localhost:8000/api/v1/predict \
  -H "Content-Type: application/json" \
  -d '{"match_id": 1, "mode": "single"}'

4. 评估

# 赛后回填实际比分
curl -X POST http://localhost:8000/api/v1/eval/settle \
  -H "Content-Type: application/json" \
  -d '{"prediction_id": 1, "home_goals": 2, "away_goals": 1}'

# 查看准确率汇总
curl http://localhost:8000/api/v1/eval/summary

项目结构

Profeto/
├── src/
│   ├── api/                    # FastAPI 路由层
│   │   ├── app.py              # 应用工厂 + lifespan
│   │   ├── schemas.py          # Pydantic 请求/响应模型
│   │   └── routes/
│   │       ├── matches.py      # 比赛查询
│   │       ├── predict.py      # 预测入口
│   │       ├── ingest.py       # 数据采集
│   │       └── eval.py         # 评估回填
│   ├── core/                   # 基础设施
│   │   ├── config.py           # pydantic-settings 配置
│   │   └── http_client.py      # 共享 httpx 客户端
│   ├── data/                   # 数据层
│   │   ├── sources.py          # DataSource 协议 + 注册表
│   │   ├── match_lookup.py     # 比赛匹配辅助函数
│   │   ├── normalize.py        # 数据规范化契约
│   │   ├── bzzoiro.py          # bzzoiro 数据源
│   │   ├── understat.py        # understat xG 数据源
│   │   ├── injuries.py         # 伤停数据 (独立领域)
│   │   ├── config.py           # 联赛映射常量
│   │   └── team_names.py       # 队名归一化
│   ├── db/                     # 数据库
│   │   ├── base.py             # SQLAlchemy async engine
│   │   └── models.py           # ORM 模型 (5 表)
│   └── llm/                    # LLM 预测核心
│       ├── predict.py          # 预测服务 (缓存 + 单/多模式)
│       ├── context_builder.py  # 数据切片 + 上下文拼接
│       ├── eval.py             # 评估统计
│       ├── provider.py         # 多提供商 LLM 抽象
│       ├── agents/
│       │   ├── base.py         # Agent 基础设施 + 解析
│       │   └── orchestrator.py # 多 Agent 编排
│       └── prompts/            # Prompt 模板
│           ├── match_prediction_v1.md
│           ├── match_prediction_v2.md
│           └── agents/         # 各专家 prompt
├── alembic/                    # 数据库迁移
├── frontend/                   # React 前端
├── docs/                       # 详细文档
├── tests/                      # 单元测试
├── docker-compose.yml
├── Dockerfile
└── pyproject.toml

核心模块

模块 作用
context_builder.py 最重要: 数据切片 + 拼接 LLM 看到的上下文
prompts/ Prompt 模板 (迭代最频繁)
provider.py OpenAI-compatible 多提供商抽象
sources.py 数据源协议 + 注册表
normalize.py 数据清洗契约 (校验/范围/归一)
orchestrator.py 多 Agent 编排 (并行专家 + 终裁)

配置

通过 .env 或环境变量配置:

变量 说明 默认值
DATABASE_URL PostgreSQL 连接 postgresql+asyncpg://football:football@localhost:5432/football
LLM_PROVIDER 提供商标识 openai
LLM_API_KEY API 密钥 (必填)
LLM_BASE_URL API 地址 https://api.openai.com/v1
LLM_MODEL 模型名 gpt-4o
LLM_SPECIALIST_MODEL 专家模型 (空=回落 LLM_MODEL)
LLM_AGGREGATOR_MODEL 终裁模型 (空=回落 LLM_MODEL)
BZZOIRO_KEY bzzoiro API Key (必填)
API_FOOTBALL_KEY api-football Key (伤停)
CORS_ORIGINS 允许的跨域来源 http://localhost:5173

测试

pytest

数据库迁移

生产环境建议使用 Alembic:

alembic upgrade head

License

个人研究项目,预测结果不构成投注建议。

S
Description
No description provided
Readme
2.2 MiB
Languages
Python 58.3%
TypeScript 40.7%
CSS 0.6%
JavaScript 0.2%