Skip to content
AI Chat System

System evals

Scripted evaluations run against a live backend and committed to the repository. Every number on this page is from the last run; nothing is typed in by hand. The chat page shows the same telemetry per message as it happens.

Last benchmark run

source: committed artifact

showing the copy committed at build time; checking the live API…

Run timestamp
2026-09-09 10:57:49 UTC
Commit
9ccfc09 (uncommitted changes)
Requests
187 in 149.4 s
Target
http://localhost:8000
Cache backend
memory
Semantic matching
openai-embeddings · text-embedding-3-small · threshold 0.76
Providers
gpt-4o-mini → groq:openai/gpt-oss-20b
Cost of this run
$0.003755 spent · $0.002419 avoided

Regenerate with make evals against a local backend. The artifact lives at evals/results/latest.json; this page also embeds a copy at build time so it works while the backend sleeps.

Semantic cache: precision and recall

Each labelled pair has one question already cached and a second question that either should reuse that answer (a paraphrase) or must not (a different ask that shares the words, a negation, or a swapped name or number). Precision is how often a cache hit returned the right answer; recall is how many true paraphrases were caught. The threshold is the similarity the cache demands before trusting a match, and it was set where F1 peaked in the sweep below, not by hand.

Precision
56.6%
30 right hits of 53 hits
Recall
90.9%
30 of 33 paraphrases caught
F1
0.698
harmonic mean of the two
Threshold
0.76
F1-optimal in sweep: 0.76
Pairs
68
text-embedding-3-small · 6 seeds shared an entry

Confusion matrix at threshold 0.76

Confusion matrix: expected versus predicted cache hits
predicted hitpredicted miss
should hit30 true positive3 false negative
should miss23 false positive12 true negative

By pair kind

Outcomes by pair kind
kindnTPFPFNTN
entity100307
intent1501005
negation1001000
normalisation33000
paraphrase3027030

Kinds: paraphrase and normalisation should hit; intent (same words, different ask), negation and entity swaps should miss.

Threshold sweep
Threshold sweep from 0.70 to 0.99: F1 peaks at 0.76. At the configured threshold 0.76: precision 56.6%, recall 90.9%, F1 0.698.1.00.700.99
  • precision
  • recall
  • F1
  • configured threshold
Full sweep table
Precision, recall and F1 at each threshold
thresholdprecisionrecallF1FPFN
0.7050.8%93.8%0.659292
0.7150.8%93.8%0.659292
0.7251.7%93.8%0.667282
0.7352.6%93.8%0.674272
0.7455.6%90.9%0.690243
0.7555.6%90.9%0.690243
0.7656.6%90.9%0.698233
0.7756.9%87.9%0.691224
0.7856.3%81.8%0.667216
0.7957.5%81.8%0.675206
0.8057.8%78.8%0.667197
0.8157.8%78.8%0.667197
0.8255.8%72.7%0.632199
0.8357.5%69.7%0.6301710
0.8459.0%69.7%0.6391610
0.8556.8%63.6%0.6001612
0.8656.8%63.6%0.6001612
0.8760.0%63.6%0.6181412
0.8861.3%57.6%0.5941214
0.8961.3%57.6%0.5941214
0.9062.1%54.5%0.5811115
0.9160.0%45.5%0.5171018
0.9255.0%33.3%0.415922
0.9364.3%27.3%0.383524
0.9444.4%12.1%0.191529
0.9550.0%9.1%0.154330
0.9650.0%3.0%0.057132
0.97100.0%3.0%0.059032
0.98100.0%3.0%0.059032
0.99100.0%3.0%0.059032

Re-scored offline from each probe's nearest-candidate similarity as recorded at the run threshold. At another threshold the set of stored probes would differ slightly, so the sweep is an estimate; the row at the run threshold is exact.

Five example pairs

Example pairs with similarity and outcome
cached questionnew questionkindsimilarityoutcome
What is the difference between P50 and P95 latency?How do P50 and P95 latency differ?paraphrase0.956true positive
What does a semantic cache do?Explain what semantic caching does.paraphrase0.912true positive
Summarize the benefits of semantic caching in two sentences.List the drawbacks of semantic caching in two sentences.intent0.736true negative
How many tokens are in a typical English sentence?How many characters are in a typical English sentence?intent0.725true negative
What should a semantic cache store?What should a semantic cache not store?negation0.828false positive

Provider failover

Each run forces the primary provider to fail with a 503 before it is called, then checks that a different provider answered, that the failure was recorded in the attempt log, and that the first token still streamed. Added latency compares against normal runs made the same way without the outage, so both sides are real provider calls.

Runs passed
10/10
100.0%
Fallback
groq
openai/gpt-oss-20b
First token
374 ms vs 732 ms
added -359 ms at p50
Total time
451 ms vs 1137 ms
added -686 ms at p50
Failover checks with pass and fail counts
checkpassedfailed
fallback_answered100
primary_recorded_failed100
fallback_is_different_provider100
first_token_delivered100
done_event_received100
content_non_empty100

Client-observed from the machine that ran the eval. The simulated outage fails before the primary is called, so 'added' latency is the fallback provider's own speed relative to the primary's, not a timeout wait.

Streaming contract

Every streamed answer must follow one shape: a meta event, then content deltas, then exactly one done or error event, delivered as Server-Sent Events that are never gzip-compressed. These are the guarantees the chat page relies on, checked across cache hits, misses, bypasses and failovers.

Streams passed
20/20
100.0%
Paths covered
5
bypass 4 · failover 4 · hit_exact 3 · hit_semantic 4 · miss 5
Event shapes
1
meta delta done
Streaming contract invariants with pass and fail counts
checkpassedfailed
content_type_event_stream200
not_gzip_encoded200
first_event_is_meta200
meta_before_any_delta200
exactly_one_terminal200
terminal_is_last200
done_has_usage_source200
done_has_cache_status200
delta_payloads_are_strings200
meta_and_done_request_id_match200

Latency by path

Client numbers are wall time measured by the machine that ran the evals, including the network; server numbers are what the backend reported for the same requests in its done event. P50 is the typical request, P95 and P99 are the slow tail. Every request the other evals made is pooled here, plus a block of exact repeats so the hit path has enough samples.

Latency percentiles per request path
pathnclient p50client p95client p99client first token p50server p50server p95
cache hit, exact142 ms3 ms15 ms2 ms0 ms1 ms
cache hit, semantic62207 ms293 ms391 ms226 ms205 ms291 ms
miss (provider call)831228 ms2173 ms2612 ms1070 ms1225 ms2170 ms
failover (fallback provider)14444 ms515 ms904 ms398 ms442 ms513 ms
bypass (cache skipped)141126 ms1776 ms2153 ms732 ms1124 ms1774 ms

client_ms is wall time on the eval machine (includes network); server_ms is the backend's own measurement from the done event. Non-streamed samples have no client_ttfb_ms.

Method and code: evals/ in the repository, summarised in evals/results/latest.md. Design decision: ADR 0006, system evals as committed artifacts.

The backend also exposes Prometheus counters at /metrics. They are per worker and reset on every deploy and free-tier sleep, like the in-process cache, so they describe the current process only; the evals above are the durable record.