From 74586aa5b7ee48b002d548a5f30f4d328b554e5c Mon Sep 17 00:00:00 2001 From: shangfangjian Date: Tue, 15 Sep 2026 00:48:43 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20README=20=E5=8F=8D?= =?UTF-8?q?=E6=98=A0=E5=BD=93=E5=89=8D=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新架构图(添加分层架构、backtest 端点) - 更新项目结构(添加 unit_of_work.py、repositories.py、backtest.py) - 更新核心模块表 - 添加数据正确性保障章节 - 修正表数量(6 张表) - confidence → subjective_confidence --- README.md | 118 +++++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 4fd387c..14a5396 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,13 @@ │ ├── /api/v1/matches 比赛查询 │ │ ├── /api/v1/predict LLM 预测 (单/多 Agent) │ │ ├── /api/v1/ingest/* 数据采集 │ -│ └── /api/v1/eval/* 评估回填 │ +│ ├── /api/v1/eval/* 评估回填 │ +│ └── /api/v1/backtest 回测 │ └──────────┬─────────────────────────────┬────────────┘ │ │ ┌──────────▼──────────┐ ┌─────────────▼────────────┐ │ PostgreSQL │ │ LLM (OpenAI-compatible) │ -│ 5 张表 │ │ OpenAI / Deepseek / │ +│ 6 张表 │ │ OpenAI / Deepseek / │ │ leagues/teams/ │ │ Ollama / 任意网关 │ │ matches/match_ │ └──────────────────────────┘ │ stats/predictions/ │ @@ -36,6 +37,16 @@ └────────────────────────────────────────────────────┘ ``` +### 分层架构 + +``` +API Route → Application Service → Repository → UnitOfWork → DB +``` + +- **UnitOfWork**: 统一事务边界,业务层不再自行 commit +- **Repository**: 封装数据访问,提供类型化查询接口 +- **DataSource**: 采集外部数据,通过注册表动态分发 + ### 多 Agent 预测 默认模式 (`mode=multi`) 采用 **5 专家 + 终裁** 架构: @@ -51,7 +62,14 @@ - 各专家**只看到自己维度的数据切片**,避免信息过载 - **fail-open**: 单个专家失败不影响整体 - **no_data 门控**: 无数据维度跳过 LLM 调用,省 token 防幻觉 -- 终裁根据各报告的 `confidence` / `data_sufficiency` 加权输出 `agent_weights` +- 终裁根据各报告的 `subjective_confidence` / `data_sufficiency` 输出 `agent_weights` + +### 数据正确性保障 + +- **Cutoff 机制**: 回测时只使用 `cutoff_at` 之前已采集的数据 +- **Injury 防泄漏**: 伤停查询强制 `retrieved_at <= cutoff` +- **LLM 输出校验**: Pydantic 严格校验 + 语义一致性检查 +- **数据库约束**: CHECK 约束作为最后一道防线 ## 快速开始 @@ -64,7 +82,6 @@ ### 1. 安装 ```bash -# 克隆 git clone https://git.bilidili.cn/shangfangjian/Profeto.git cd Profeto @@ -80,6 +97,7 @@ cp .env.example .env ```bash docker compose up -d postgres +alembic upgrade head # 首次运行需要执行迁移 ``` ### 3. 启动服务 @@ -94,58 +112,22 @@ cd frontend && npm install && npm run dev 后端运行在 `http://localhost:8000`,前端在 `http://localhost:5173`。 -## 使用流程 +## API 概览 -### 1. 采集数据 - -```bash -# 采集 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. 查询比赛 - -```bash -curl "http://localhost:8000/api/v1/matches?league=E0&status=scheduled" -``` - -### 3. LLM 预测 - -```bash -# 多 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. 评估 - -```bash -# 赛后回填实际比分 -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 -``` +| 方法 | 路径 | 说明 | +|---|---|---| +| 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) | ## 项目结构 @@ -159,34 +141,36 @@ Profeto/ │ │ ├── matches.py # 比赛查询 │ │ ├── predict.py # 预测入口 │ │ ├── ingest.py # 数据采集 -│ │ └── eval.py # 评估回填 +│ │ ├── eval.py # 评估回填 +│ │ └── backtest.py # 回测 │ ├── core/ # 基础设施 │ │ ├── config.py # pydantic-settings 配置 -│ │ └── http_client.py # 共享 httpx 客户端 +│ │ ├── http_client.py # 共享 httpx 客户端 +│ │ └── retry.py # 重试工具(指数退避) │ ├── data/ # 数据层 │ │ ├── sources.py # DataSource 协议 + 注册表 -│ │ ├── match_lookup.py # 比赛匹配辅助函数 │ │ ├── normalize.py # 数据规范化契约 │ │ ├── bzzoiro.py # bzzoiro 数据源 │ │ ├── understat.py # understat xG 数据源 -│ │ ├── injuries.py # 伤停数据 (独立领域) +│ │ ├── injuries.py # 伤停数据 │ │ ├── config.py # 联赛映射常量 │ │ └── team_names.py # 队名归一化 │ ├── db/ # 数据库 │ │ ├── base.py # SQLAlchemy async engine -│ │ └── models.py # ORM 模型 (5 表) +│ │ ├── 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 模板 -│ ├── match_prediction_v1.md -│ ├── match_prediction_v2.md -│ └── agents/ # 各专家 prompt ├── alembic/ # 数据库迁移 ├── frontend/ # React 前端 ├── docs/ # 详细文档 @@ -204,8 +188,10 @@ Profeto/ | `prompts/` | Prompt 模板 (迭代最频繁) | | `provider.py` | OpenAI-compatible 多提供商抽象 | | `sources.py` | 数据源协议 + 注册表 | -| `normalize.py` | 数据清洗契约 (校验/范围/归一) | -| `orchestrator.py` | 多 Agent 编排 (并行专家 + 终裁) | +| `unit_of_work.py` | 统一事务边界 | +| `repositories.py` | 数据访问封装 | +| `validation.py` | LLM 输出严格校验 | +| `backtest.py` | 回测框架(防未来数据泄漏) | ## 配置 @@ -232,8 +218,6 @@ pytest ## 数据库迁移 -生产环境建议使用 Alembic: - ```bash alembic upgrade head ```