Same question, same knowledge, three models.
A dependency-free demo and eval harness that races Kimi K2.6, Kimi K3, and Claude Opus 5 on DigitalOcean Serverless Inference against the same question, side by side. It then grades every answer with an LLM judge and rolls the results into a scorecard with cost-at-scale projections.
Built for the DigitalOcean Kimi K3 launch webinar (2026-07-29). The demo segment and the aggregate numbers shown there come from this code.
- Identical prompts by construction. Every model gets the byte-identical system prompt
(
SYSMSGinrace_server.py) and, when retrieval is on, the same retrieved context. Retrieval runs once per question and is shared across all arms. Prompt and persona differences can move benchmark scores more than the model does. We measured one persona directive costing 9.5 faithfulness points, so the comparison holds those constant. - A third-family, open-source judge. Verdicts come from
deepseek-v4-pro(setJUDGE_MODELto change it). No candidate is graded by its own vendor's model, so there is no self-preference bias to argue about. - Rate limits are not a quality signal. The suite runner retries 429 and 5xx failures in later sweeps until they complete cleanly. Only clean completions are scored, and the excluded count is printed next to the results.
- Degenerate output is a serving fault, not a score. A response that is mostly one
repeated character gets excluded and re-run, the same as a 429. We watched a model emit
4,096 tokens of
!under launch-day load. Scoring those as zeros would have buried a model that was otherwise answering in the 90s. - Reasoning tokens are counted. Reasoning-first models spend completion tokens thinking before they answer, out of the same budget. The stats separate time-to-first-reasoning from time-to-first-answer, so a slower model that reasons is visible as such.
You need a DigitalOcean model access key with access to the models you want to race (create one in the GenAI Platform console).
cp .env.example .env # put your key in DO_KEY
./run_local.sh # serves http://localhost:8130Open the page, pick a question, Ask all three, then Grade the answers.
The bundled evalset.csv (57 questions with ground truth about the DO GenAI Platform) feeds
both the dropdown and the batch run:
set -a; . ./.env; set +a
python3 suite_runner.py --out suite_results.jsonThat prints per-model correctness, faithfulness, latency, p95, cost per answer, the excluded-call count, and monthly cost projections at 10k, 100k, and 1M questions.
The Podium tab reads suite_results_merged.json and renders the aggregate: a
quality-against-cost scatter, per-model score and latency panels, a per-question heat strip,
and cost-at-scale bars. The bundled file holds the real webinar numbers, so the tab has
something to show before you run anything.
Three modes, in precedence order:
RAG_CACHE=chunks.json, a precomputed{question: [chunk, …]}map. This is how the webinar numbers stay reproducible: every run sees byte-identical context.RAG_URL+RAG_KEY, any live endpoint speakingPOST /search {"query", "collection", "top_k"}and returning{"results": [{"text": …}]}.- Neither, a context-free comparison of the bare models (noted at startup).
top_p: Kimi K3 rejects any value other than0.95if the parameter is sent. Omitting it entirely is also fine. The other models get notop_p.- Prices in
race_server.py MODELScame from the DO API's own model records (GET /v2/gen-ai/models, thepricingfield). Re-check them before quoting numbers. OPUS_BACKEND=anthropicplusANTHROPIC_KEYroutes the Opus arm through the Anthropic API instead of DO, which helps if your DO key does not include Anthropic models.K3_BASE(withK3_MODEL_IDandK3_KEY) routes the K3 arm to any OpenAI-compatible endpoint. The comparison is about models, not providers, and list price is unchanged.- The judge budget is 2,000 tokens on purpose. Smaller budgets truncate on long answers and produce unparseable verdicts that look like scoring failures.
MIT licensed. PRs welcome.