Padmanav commited on
Commit
81a4ebd
·
1 Parent(s): 51327a5

feat(metrics): add per-agent token tracking and cost estimation

Browse files

Record total_tokens from OpenRouter usage response in MetricsCollector.
Expose in /api/v1/metrics snapshot as total_tokens and estimated_cost_usd.
Cost rate set for llama-3.3-70b; update constant when switching models.

Files changed (2) hide show
  1. app/core/llm.py +6 -0
  2. app/core/metrics.py +7 -0
app/core/llm.py CHANGED
@@ -58,6 +58,12 @@ async def call_llm(prompt: str, system_prompt: Optional[str] = None, max_tokens:
58
  response.raise_for_status()
59
 
60
  data = response.json()
 
 
 
 
 
 
61
  return str(data["choices"][0]["message"]["content"])
62
 
63
  async def call_llm_for_json(prompt: str, max_tokens: int = 2000) -> dict:
 
58
  response.raise_for_status()
59
 
60
  data = response.json()
61
+ usage = data.get("usage", {})
62
+ total_tokens = usage.get("total_tokens", 0)
63
+ if total_tokens:
64
+ from app.core.metrics import metrics
65
+ metrics.record_tokens("llm_total", total_tokens)
66
+ return str(data["choices"][0]["message"]["content"])
67
  return str(data["choices"][0]["message"]["content"])
68
 
69
  async def call_llm_for_json(prompt: str, max_tokens: int = 2000) -> dict:
app/core/metrics.py CHANGED
@@ -11,6 +11,7 @@ class MetricsCollector:
11
  self._latencies: dict[str, list[float]] = defaultdict(list)
12
  self._errors: dict[str, int] = defaultdict(int)
13
  self._started_at = time.time()
 
14
 
15
  def record_run(self, agent: str, duration_seconds: float, success: bool) -> None:
16
  with self._lock:
@@ -19,6 +20,10 @@ class MetricsCollector:
19
  if not success:
20
  self._errors[agent] += 1
21
 
 
 
 
 
22
  def snapshot(self) -> dict[str, Any]:
23
  with self._lock:
24
  agents: dict[str, Any] = {}
@@ -29,6 +34,8 @@ class MetricsCollector:
29
  "errors": self._errors.get(agent, 0),
30
  "avg_latency_s": round(sum(lats) / len(lats), 3) if lats else 0.0,
31
  "p99_latency_s": round(sorted(lats)[int(len(lats) * 0.99)], 3) if lats else 0.0,
 
 
32
  }
33
  return {
34
  "uptime_seconds": round(time.time() - self._started_at, 1),
 
11
  self._latencies: dict[str, list[float]] = defaultdict(list)
12
  self._errors: dict[str, int] = defaultdict(int)
13
  self._started_at = time.time()
14
+ self._tokens: dict[str, int] = defaultdict(int)
15
 
16
  def record_run(self, agent: str, duration_seconds: float, success: bool) -> None:
17
  with self._lock:
 
20
  if not success:
21
  self._errors[agent] += 1
22
 
23
+ def record_tokens(self, agent: str, tokens: int) -> None:
24
+ with self._lock:
25
+ self._tokens[agent] += tokens
26
+
27
  def snapshot(self) -> dict[str, Any]:
28
  with self._lock:
29
  agents: dict[str, Any] = {}
 
34
  "errors": self._errors.get(agent, 0),
35
  "avg_latency_s": round(sum(lats) / len(lats), 3) if lats else 0.0,
36
  "p99_latency_s": round(sorted(lats)[int(len(lats) * 0.99)], 3) if lats else 0.0,
37
+ "total_tokens": self._tokens.get(agent, 0),
38
+ "estimated_cost_usd": round(self._tokens.get(agent, 0) * 0.0000009, 6),
39
  }
40
  return {
41
  "uptime_seconds": round(time.time() - self._started_at, 1),