Files
Profeto/README.md
T
shangfangjian 74586aa5b7 docs: 更新 README 反映当前架构
- 更新架构图(添加分层架构、backtest 端点)
- 更新项目结构(添加 unit_of_work.py、repositories.py、backtest.py)
- 更新核心模块表
- 添加数据正确性保障章节
- 修正表数量(6 张表)
- confidence → subjective_confidence
2026-09-15 00:48:43 +08:00

228 lines
9.0 KiB
Markdown

# 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/* 评估回填 │
│ └── /api/v1/backtest 回测 │
└──────────┬─────────────────────────────┬────────────┘
│ │
┌──────────▼──────────┐ ┌─────────────▼────────────┐
│ PostgreSQL │ │ LLM (OpenAI-compatible) │
│ 6 张表 │ │ OpenAI / Deepseek / │
│ leagues/teams/ │ │ Ollama / 任意网关 │
│ matches/match_ │ └──────────────────────────┘
│ stats/predictions/ │
│ injuries │
└─────────────────────┘
│ 采集
┌──────────┴─────────────────────────────────────────┐
│ 数据源 (DataSource 协议 + 注册表) │
│ ├── bzzoiro 比分 / 统计 / xG │
│ ├── understat xG 回填 │
│ └── injuries 伤停数据 (api-football) │
└────────────────────────────────────────────────────┘
```
### 分层架构
```
API Route → Application Service → Repository → UnitOfWork → DB
```
- **UnitOfWork**: 统一事务边界,业务层不再自行 commit
- **Repository**: 封装数据访问,提供类型化查询接口
- **DataSource**: 采集外部数据,通过注册表动态分发
### 多 Agent 预测
默认模式 (`mode=multi`) 采用 **5 专家 + 终裁** 架构:
```
比赛数据 → 切片 ─┬─→ A 近期状态专家 ─┐
├─→ B 攻防数据专家 ─┤
├─→ C 主客因素专家 ─┼─→ 终裁专家 ─→ 最终预测
├─→ D 阵容完整专家 ─┤
└─→ E 历史交锋专家 ─┘
```
- 各专家**只看到自己维度的数据切片**,避免信息过载
- **fail-open**: 单个专家失败不影响整体
- **no_data 门控**: 无数据维度跳过 LLM 调用,省 token 防幻觉
- 终裁根据各报告的 `subjective_confidence` / `data_sufficiency` 输出 `agent_weights`
### 数据正确性保障
- **Cutoff 机制**: 回测时只使用 `cutoff_at` 之前已采集的数据
- **Injury 防泄漏**: 伤停查询强制 `retrieved_at <= cutoff`
- **LLM 输出校验**: Pydantic 严格校验 + 语义一致性检查
- **数据库约束**: CHECK 约束作为最后一道防线
## 快速开始
### 前置条件
- Python >= 3.11
- Docker (运行 PostgreSQL)
- LLM API Key (OpenAI / Deepseek / Ollama 等)
### 1. 安装
```bash
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. 启动数据库
```bash
docker compose up -d postgres
alembic upgrade head # 首次运行需要执行迁移
```
### 3. 启动服务
```bash
# 后端 (终端 1)
uvicorn src.api.app:app --reload
# 前端 (终端 2)
cd frontend && npm install && npm run dev
```
后端运行在 `http://localhost:8000`,前端在 `http://localhost:5173`
## API 概览
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | `/api/v1/matches` | 比赛查询(筛选/分页) |
| GET | `/api/v1/leagues` | 联赛列表 |
| POST | `/api/v1/predict` | LLM 预测 (`mode=single`/`multi`) |
| GET | `/api/v1/predictions` | 预测历史 |
| POST | `/api/v1/ingest/bzzoiro` | 采集比分/统计 |
| POST | `/api/v1/ingest/understat` | 回填 xG |
| POST | `/api/v1/ingest/injuries` | 采集伤停 |
| POST | `/api/v1/eval/settle` | 回填实际结果 |
| GET | `/api/v1/eval/summary` | 准确率汇总 |
| POST | `/api/v1/backtest` | 历史回测 |
| GET | `/health` | 存活检查 |
| GET | `/health/ready` | 就绪检查(含 DB) |
## 项目结构
```
Profeto/
├── src/
│ ├── api/ # FastAPI 路由层
│ │ ├── app.py # 应用工厂 + lifespan
│ │ ├── schemas.py # Pydantic 请求/响应模型
│ │ └── routes/
│ │ ├── matches.py # 比赛查询
│ │ ├── predict.py # 预测入口
│ │ ├── ingest.py # 数据采集
│ │ ├── eval.py # 评估回填
│ │ └── backtest.py # 回测
│ ├── core/ # 基础设施
│ │ ├── config.py # pydantic-settings 配置
│ │ ├── http_client.py # 共享 httpx 客户端
│ │ └── retry.py # 重试工具(指数退避)
│ ├── data/ # 数据层
│ │ ├── sources.py # DataSource 协议 + 注册表
│ │ ├── 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 模型 (6 表)
│ │ ├── unit_of_work.py # UnitOfWork 事务封装
│ │ └── repositories.py # Repository 数据访问
│ └── llm/ # LLM 预测核心
│ ├── predict.py # 预测服务 (缓存 + 单/多模式)
│ ├── context_builder.py # 数据切片 + 上下文拼接
│ ├── eval.py # 评估统计
│ ├── backtest.py # 回测框架
│ ├── provider.py # 多提供商 LLM 抽象
│ ├── validation.py # LLM 输出校验
│ ├── agents/
│ │ ├── base.py # Agent 基础设施 + 解析
│ │ └── orchestrator.py # 多 Agent 编排
│ └── prompts/ # Prompt 模板
├── alembic/ # 数据库迁移
├── frontend/ # React 前端
├── docs/ # 详细文档
├── tests/ # 单元测试
├── docker-compose.yml
├── Dockerfile
└── pyproject.toml
```
## 核心模块
| 模块 | 作用 |
|---|---|
| `context_builder.py` | **最重要**: 数据切片 + 拼接 LLM 看到的上下文 |
| `prompts/` | Prompt 模板 (迭代最频繁) |
| `provider.py` | OpenAI-compatible 多提供商抽象 |
| `sources.py` | 数据源协议 + 注册表 |
| `unit_of_work.py` | 统一事务边界 |
| `repositories.py` | 数据访问封装 |
| `validation.py` | LLM 输出严格校验 |
| `backtest.py` | 回测框架(防未来数据泄漏) |
## 配置
通过 `.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` |
## 测试
```bash
pytest
```
## 数据库迁移
```bash
alembic upgrade head
```
## License
个人研究项目,预测结果不构成投注建议。