53 lines
2.3 KiB
Python
53 lines
2.3 KiB
Python
"""Event-Ledger: eine Zeile je LLM-Versuch (im finally — jeder Ausgang zählt,
|
|
auch Hedge-Verlierer). Budget = harte Grenze, geprüft VOR und NACH jedem Call."""
|
|
from . import config, db
|
|
|
|
|
|
class BudgetErschoepft(Exception):
|
|
pass
|
|
|
|
|
|
def log_call(run_id: int, *, stufe: str = "", knoten: str = "", item: str = "",
|
|
skills_liste: list | None = None, skill_hash: str = "",
|
|
model: str = "", role: str = "", status: str = "",
|
|
dur_ms: int = 0, wait_ms: int = 0,
|
|
tokens: dict | None = None, meta: dict | None = None,
|
|
prompt: str = "", antwort: str = "") -> int | None:
|
|
t = tokens or {}
|
|
event_id = db.insert(
|
|
"events", run_id=run_id, ts=db.now(), stufe=stufe, knoten=knoten,
|
|
item=item, skills=db.j(skills_liste or []), skill_hash=skill_hash,
|
|
model=model, role=role, status=status, dur_ms=dur_ms,
|
|
wait_ms=wait_ms, tok_in=t.get("input", 0), tok_out=t.get("output", 0),
|
|
tok_cache_read=t.get("cache_read", 0),
|
|
tok_cache_write=t.get("cache_write", 0), meta=db.j(meta or {}))
|
|
if config.LLM_LOG and event_id and (prompt or antwort):
|
|
db.insert("call_texte", event_id=event_id, prompt=prompt, antwort=antwort)
|
|
return event_id
|
|
|
|
|
|
def verbraucht(run_id: int) -> int:
|
|
r = db.one("SELECT COALESCE(SUM(tok_in + tok_out), 0) s FROM events "
|
|
"WHERE run_id=?", run_id)
|
|
return r["s"]
|
|
|
|
|
|
def budget_pruefen(run_id: int) -> None:
|
|
run = db.one("SELECT budget_tokens FROM runs WHERE id=?", run_id)
|
|
limit = (run or {}).get("budget_tokens") or 0
|
|
if limit > 0 and verbraucht(run_id) >= limit:
|
|
raise BudgetErschoepft(f"Budget {limit} Tokens erreicht")
|
|
|
|
|
|
def kennzahlen(run_id: int) -> dict:
|
|
zeilen = db.query(
|
|
"SELECT stufe, knoten, COUNT(*) calls, SUM(tok_in) tok_in, "
|
|
"SUM(tok_out) tok_out, SUM(tok_cache_read) cache_read, "
|
|
"SUM(dur_ms) dur_ms, SUM(wait_ms) wait_ms, "
|
|
"SUM(status='ok') ok, SUM(status IN ('error','infra','parse','cap')) fehler "
|
|
"FROM events WHERE run_id=? GROUP BY stufe, knoten ORDER BY MIN(id)", run_id)
|
|
gesamt = verbraucht(run_id)
|
|
kosten = sum(z["tok_in"] or 0 for z in zeilen) / 1e6 * config.PREIS_IN + \
|
|
sum(z["tok_out"] or 0 for z in zeilen) / 1e6 * config.PREIS_OUT
|
|
return {"zeilen": zeilen, "verbraucht": gesamt, "kosten_usd": round(kosten, 2)}
|