fix(P0-03): Prediction 幂等指纹——只追加,不覆盖
_upsert_prediction 改为 _insert_or_find_by_fingerprint: - 同 input_hash → 返回已有行(绝不 UPDATE pred_/reasoning/agent_outputs) - 不同 input_hash → INSERT 新行 input_hash 升级为规范 JSON SHA-256,捕获:match_id, cutoff, prompt_version, prompt_hash, system_prompt_hash, provider, model, mode, run_type, temperature, context_hash, agent_ids。移除旧 (match, provider, model, mode, run_type) 唯一约束, 改为 partial unique index(WHERE input_hash IS NOT NULL,兼容旧 NULL 数据)。 三条路径(single/multi/baseline)统一传足指纹字段。 迁移 0024 + 测试 test_p0_prediction_fingerprint(10/10);全量 295 通过。
This commit is contained in:
+20
-12
@@ -5,14 +5,15 @@
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
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, _upsert_prediction
|
||||
from src.llm.predict import PredictResult, _insert_or_find_by_fingerprint
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -97,8 +98,23 @@ async def predict_baseline(
|
||||
else:
|
||||
pred_1x2 = "X"
|
||||
|
||||
# P0-03: 基线指纹——基于主客场场均进球数据(context_hash) + 截止时间
|
||||
context_hash = hashlib.sha256(
|
||||
f"{home_avg:.4f}:{away_avg:.4f}:{before.isoformat() if before else 'none'}".encode("utf-8")
|
||||
).hexdigest()
|
||||
|
||||
values = {
|
||||
"match_id": match_id,
|
||||
"provider": "baseline",
|
||||
"model": "baseline",
|
||||
"mode": "baseline",
|
||||
"run_type": "live",
|
||||
"prompt_version": "baseline_v1",
|
||||
"prompt_hash": hashlib.sha256(b"baseline_v1").hexdigest(),
|
||||
"system_prompt_hash": hashlib.sha256(b"baseline").hexdigest(),
|
||||
"temperature": 0.0,
|
||||
"context_hash": context_hash,
|
||||
"agent_ids": [],
|
||||
"prompt_tokens": 0,
|
||||
"completion_tokens": 0,
|
||||
"latency_ms": 0,
|
||||
@@ -114,17 +130,9 @@ async def predict_baseline(
|
||||
"status": "success",
|
||||
}
|
||||
|
||||
# P3-2:服务层落库,回填真实 prediction_id(与 single/multi 统一)。
|
||||
# P0-03:服务层幂等插入,回填真实 prediction_id(与 single/multi 统一)。
|
||||
async with get_uow() as session:
|
||||
pred = await _upsert_prediction(
|
||||
session,
|
||||
match_id=match_id,
|
||||
provider_name="baseline",
|
||||
model="baseline",
|
||||
mode="baseline",
|
||||
run_type="live",
|
||||
values=values,
|
||||
)
|
||||
pred = await _insert_or_find_by_fingerprint(session, values=values)
|
||||
prediction_id = pred.id
|
||||
|
||||
return PredictResult(
|
||||
|
||||
Reference in New Issue
Block a user