feat: Sprint 2 - 概率语义 + 轻量快照 + 数据库约束

P0-05: confidence → subjective_confidence 改名(15 文件)
       LLM 主观置信度与概率分离
P0-02: predictions 增加 cutoff_at + input_hash(轻量快照)
       MatchContext 暴露 match_dt
       单/多 Agent 路径均记录快照元数据
P2-05: 数据库 CHECK 约束
       - pred_home_goals >= 0
       - pred_away_goals >= 0
       - subjective_confidence 0~1
       - pred_1x2 IN (1,X,2)
       - mode IN (single,multi)
P2-06: limit 分页约束(ge=1, le=200)
P2-01: 新增 /health/ready 就绪检查
This commit is contained in:
shangfangjian
2026-09-15 00:14:24 +08:00
parent f3160e3062
commit cb36dc3ef9
14 changed files with 70 additions and 41 deletions
+3 -3
View File
@@ -48,7 +48,7 @@ class AgentReport:
data_sufficiency: str = "medium" # high | medium | low | none
analysis: str = ""
home_edge: float | None = None # -1.0 ~ 1.0, 正=利主队
confidence: float | None = None # 0.0 ~ 1.0
subjective_confidence: float | None = None # 0.0 ~ 1.0
key_evidence: list[str] = field(default_factory=list)
# xg agent 专属
exp_home_goals: float | None = None
@@ -67,7 +67,7 @@ class AgentReport:
"data_sufficiency": self.data_sufficiency,
"analysis": self.analysis,
"home_edge": self.home_edge,
"confidence": self.confidence,
"subjective_confidence": self.subjective_confidence,
"key_evidence": self.key_evidence,
"exp_home_goals": self.exp_home_goals,
"exp_away_goals": self.exp_away_goals,
@@ -122,7 +122,7 @@ def _parse_report(agent: str, parsed: dict, resp: LLMResponse, model: str) -> Ag
data_sufficiency=validated.data_sufficiency,
analysis=validated.analysis,
home_edge=validated.home_edge,
confidence=validated.confidence,
subjective_confidence=validated.subjective_confidence,
key_evidence=validated.key_evidence,
exp_home_goals=validated.exp_home_goals,
exp_away_goals=validated.exp_away_goals,
+12 -3
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import hashlib
import json
import logging
import time
@@ -68,7 +69,7 @@ class MultiPredictResult:
pred_home_goals: float | None
pred_away_goals: float | None
pred_1x2: str | None
confidence: float | None
subjective_confidence: float | None
reasoning: str | None
agent_outputs: list[dict]
agent_weights: dict | None
@@ -164,6 +165,7 @@ async def predict_match_multi(
# 1. 比赛头(各 agent 共享;不存在则 404)
header = await load_match_header(match_id)
cutoff_at = header.match_dt
# 2. 并行专家
specialist_provider = _get_specialist_provider()
@@ -177,6 +179,11 @@ async def predict_match_multi(
latency_ms = int((time.perf_counter() - start) * 1000)
# 3.5 计算输入 hash(基于终裁报告)
input_hash = hashlib.sha256(
_reports_to_json(reports).encode("utf-8")
).hexdigest()
# 4. 存库
async with AsyncSessionLocal() as db:
m = await db.get(Match, match_id)
@@ -203,10 +210,12 @@ async def predict_match_multi(
pred_home_goals=validated.pred_home_goals,
pred_away_goals=validated.pred_away_goals,
pred_1x2=validated.pred_1x2,
confidence=validated.confidence,
subjective_confidence=validated.subjective_confidence,
reasoning=validated.reasoning,
raw_response=final,
agent_outputs=[r.to_dict() for r in reports],
cutoff_at=cutoff_at,
input_hash=input_hash,
)
db.add(pred)
await db.commit()
@@ -221,7 +230,7 @@ async def predict_match_multi(
pred_home_goals=pred.pred_home_goals,
pred_away_goals=pred.pred_away_goals,
pred_1x2=pred.pred_1x2,
confidence=pred.confidence,
subjective_confidence=pred.subjective_confidence,
reasoning=pred.reasoning,
agent_outputs=pred.agent_outputs,
agent_weights=agent_weights,