debt(D2): 统一预测结果类型为 PredictResult,路由去 dict 分支

- PredictResult 扩展可选字段 mode/agent_outputs/agent_weights/prompt_tokens/completion_tokens
- MultiPredictResult 变为 PredictResult 别名(保留 R4 守卫标记与 re-export)
- baseline 改返回 PredictResult(修复 backtest 对 baseline AttributeError 的潜伏 bug)
- 预测路由单一属性映射,删除全部 isinstance(result, dict) 分支
- _persist_baseline 属性化,baseline upsert 语义不变(prompt_version/token/latency 同前)
- TDD: 5 新测试 + test_baseline.py 属性化;全量 257 passed
This commit is contained in:
2026-09-21 19:23:50 +08:00
parent 3a9f3f5a0e
commit 5c7fdce0a3
6 changed files with 311 additions and 93 deletions
+25 -20
View File
@@ -12,6 +12,7 @@ from sqlalchemy import case, func, select
from src.db.base import AsyncSession, AsyncSessionLocal
from src.db.models import Match
from src.llm.predict import PredictResult
logger = logging.getLogger(__name__)
@@ -52,11 +53,13 @@ async def predict_baseline(
*,
backtest: bool = False,
cutoff_at: datetime | None = None,
) -> dict:
) -> PredictResult:
"""极简基线预测:主场场均进球 vs 客场场均进球。
返回 PredictResult 兼容的字典:
返回 PredictResult(D2 统一结果类型):
provider=model="baseline", 不调用 LLM,latency_ms≈0。
prediction_id 为占位 0 —— baseline 不在服务层落库,
由路由层 _persist_baseline 落库后取得真实 id。
"""
async with AsyncSessionLocal() as db:
match = await db.get(Match, match_id)
@@ -90,24 +93,26 @@ async def predict_baseline(
else:
pred_1x2 = "X"
return {
"pred_home_goals": float(pred_home),
"pred_away_goals": float(pred_away),
"alt_pred_home_goals": None,
"alt_pred_away_goals": None,
"pred_1x2": pred_1x2,
"subjective_confidence": 0.5,
"prompt_tokens": 0,
"completion_tokens": 0,
"reasoning": (
return PredictResult(
prediction_id=0, # 占位:真实 id 由路由层 _persist_baseline 落库后返回
provider="baseline",
model="baseline",
prompt_version="baseline_v1",
mode="baseline",
pred_home_goals=float(pred_home),
pred_away_goals=float(pred_away),
alt_pred_home_goals=None,
alt_pred_away_goals=None,
pred_1x2=pred_1x2,
subjective_confidence=0.5,
reasoning=(
f"基线估计(非投注建议): 主队主场场均进球 {home_avg:.2f} → 预测 {pred_home}; "
f"客队客场场均进球 {away_avg:.2f} → 预测 {pred_away}"
),
"provider": "baseline",
"model": "baseline",
"prompt_version": "baseline_v1",
"mode": "baseline",
"status": "success",
"latency_ms": 0,
"raw": {"home_avg": round(home_avg, 2), "away_avg": round(away_avg, 2)},
}
context="", # baseline 不构建 LLM 上下文
status="success",
latency_ms=0,
prompt_tokens=0,
completion_tokens=0,
raw={"home_avg": round(home_avg, 2), "away_avg": round(away_avg, 2)},
)