Skip to main content

AI Chat Observability

Prometheus Metrics

MetricTypeLabelsDescription
proxima_chat_messages_totalcounterrole, client_idTotal chat messages (user + assistant)
proxima_chat_tokens_totalcounterdirection (input/output), modelToken consumption
proxima_chat_cost_usd_totalcountermodel, client_idEstimated AI cost from LiteLLM
proxima_chat_tool_calls_totalcountertool, status, client_idTool call count
proxima_chat_tool_duration_secondshistogramtoolPer-tool execution latency
proxima_chat_response_duration_secondshistogrammodel, tierFull response latency (user-perceived)
proxima_chat_model_routing_totalcountertier, reasonRouting decisions (llm/keyword_fallback/user_override)
proxima_chat_conversations_activegaugeclient_idActive conversations
proxima_chat_errors_totalcountertypeError breakdown (llm_error, tool_error, rate_limit, encryption)
proxima_chat_credential_source_totalcountersource, client_idCredential source — currently always platform (BYOK is planned, not yet implemented)

Cost tracking: The proxima_chat_cost_usd_total metric reads cost data from LiteLLM's x-litellm-model-response-cost response header — no manual price table maintenance needed.

OpenTelemetry Traces

chat.request (root span)
├── chat.auth_resolve
├── chat.context_prefetch
├── chat.encryption.dek_resolve (cache hit/miss attribute)
├── chat.model_route.llm (tier + reason attributes)
├── chat.llm_call (model, tokens_in, tokens_out, cost)
├── ChatHandler.executeTool (repeated per tool call)
│ attributes: tool name, duration, success/error
├── chat.encryption.encrypt (message content encryption)
├── chat.store_message (DB insert)
└── chat.stream_response (streaming duration)

Structured Logging

All chat operations log with component=api.chat or component=chat.*:

LevelEventWhen
INFOAI chat enabledBackend startup with LiteLLM configured
INFOmodel routing via LLMEvery classification with tier + message preview
INFODEK created, encrypted, and cachedFirst chat for a new client
WARNLLM classification failed, falling back to keywordsLiteLLM unreachable
WARNcontext pre-fetch failedStore error during pre-fetch (graceful)
WARNValkey unavailable, auto-rejecting confirmationValkey down during write tool
ERRORLLM API errorLiteLLM/provider failure with status code
ERRORfailed to encrypt/decrypt DEKVault Transit failure

Grafana Dashboard

The backend observability dashboard includes an "AI Chat" row with the following panels:

  • Token usage over time (by model, by client)
  • Cost breakdown (by client, by model tier)
  • Tool call popularity (top 10 tools by call count)
  • Response latency P50/P95/P99
  • Credential source (currently always platform — BYOK is planned)
  • Error rate by type
  • Routing tier distribution
  • Active conversations gauge

LLM Evaluation

Promptfoo evaluation suite in tests/llm-eval/:

# Model routing accuracy (23 test cases)
DEEPSEEK_API_KEY=sk-... npx promptfoo eval -c tests/llm-eval/promptfooconfig.yaml

# Prompt injection defense (10 adversarial cases)
DEEPSEEK_API_KEY=sk-... npx promptfoo eval -c tests/llm-eval/promptfoo-redteam.yaml

# View HTML dashboard
npx promptfoo view