Instructions to use bottlecapai/ThinkingCap-Qwen3.6-27B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use bottlecapai/ThinkingCap-Qwen3.6-27B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="bottlecapai/ThinkingCap-Qwen3.6-27B") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("bottlecapai/ThinkingCap-Qwen3.6-27B") model = AutoModelForMultimodalLM.from_pretrained("bottlecapai/ThinkingCap-Qwen3.6-27B", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Inference
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use bottlecapai/ThinkingCap-Qwen3.6-27B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "bottlecapai/ThinkingCap-Qwen3.6-27B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bottlecapai/ThinkingCap-Qwen3.6-27B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/bottlecapai/ThinkingCap-Qwen3.6-27B
- SGLang
How to use bottlecapai/ThinkingCap-Qwen3.6-27B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "bottlecapai/ThinkingCap-Qwen3.6-27B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bottlecapai/ThinkingCap-Qwen3.6-27B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "bottlecapai/ThinkingCap-Qwen3.6-27B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bottlecapai/ThinkingCap-Qwen3.6-27B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use bottlecapai/ThinkingCap-Qwen3.6-27B with Docker Model Runner:
docker model run hf.co/bottlecapai/ThinkingCap-Qwen3.6-27B
TC-Qwen3.6-27B bf16 vs. Qwen3.6-27B bf16
A/B Test: ThinkingCap-Qwen3.6-27B vs. base Qwen3.6-27B on Complex Tasks
Date: 2026-07-20 · Environment: vs201 (Ubuntu 26.04, Hyper-V/DDA), NVIDIA RTX PRO 6000 Blackwell 96 GB, vLLM 0.24.0
Task design, grading criteria, and the full evaluation were performed by Claude Fable 5 (Anthropic). Test execution was driven by the operator via the Hermes agent (benchmark.py, included in the archive).
1. Purpose
The architecture decision "ThinkingCap (TC) = primary implementer model, base Qwen3.6-27B = rollback" had so far been supported by tests on simple queries (TC saving ~24–31% of time). This test measures both models on complex tasks, where reasoning models spend most of their time thinking — i.e., exactly where TC's thinking reduction (the model card's headline claim: 2–6×) should matter most.
2. Models and Configuration
| ThinkingCap-Qwen3.6-27B | base Qwen/Qwen3.6-27B | |
|---|---|---|
| Type | RL fine-tune of the base model (thinking reduction) | original checkpoint |
| Precision | BF16 | BF16 |
| Server | vLLM 0.24.0, --max-model-len 163840, --max-num-seqs 5, FP8 KV cache, MTP speculative decoding n=3, --generation-config auto |
identical (same systemd unit template) |
| Sampling | creators' defaults from generation_config.json: temperature 1.0, top_p 0.95, top_k 20 |
identical |
| API | unified alias rtx6000-impl (model swaps are invisible to clients) |
identical |
3. Methodology
- 20 tasks across 5 categories: coding (8), algorithms & logic (4), Czech language (3), structured output (2), diagnostics (3). Full task texts in
benchmark-20-uloh.md; each task has a predefined grading criterion. - Parallelism: 5 concurrent workers (ThreadPoolExecutor), identical for both models — matching the production profile (max-num-seqs 5).
- max_tokens: 16,384 (base second run: 32,768 after budget overflows were observed).
- No sampling parameters sent — server defaults (creators' recipe) apply, identical for both models.
- Runs: TC 2× (second after fixing collection of the
reasoningfield), base 2× (second with the larger budget). Temperature 1.0 means natural run-to-run variance; repetition partially captures it. - Grading: mechanics automatically (finish_reason, tokens, timings, thinking/content lengths); factual correctness by checking content against the criteria — automated markers (regex for key elements) plus manual review of the critical tasks (9, 10, 11, 12, 14, 20) performed by Claude Fable 5, including independent ground-truth computation (coin-change DP, knapsack, time-zone arithmetic).
4. Summary Results
| Metric | TC run 1 (16k) | TC run 2 (16k) | TC run 3 (32k) | base run 1 (16k) | base run 2 (32k) |
|---|---|---|---|---|---|
| Factual correctness | 20/20 | 19/20 | 19/20 | 17/20 | 19/20¹ |
finish_reason: stop |
20/20 | 20/20 | 20/20 | 18/20 | 19/20¹ |
| Wall time (20 tasks, 5∥) | 259 s | 298 s | 233 s | 471 s | 468 s |
| Total completion tokens | 77,456 | 83,369 | 70,701 | 117,391 | 105,013¹ |
| Thinking share (chars) | — (not collected) | 82% | 78% | 86% | 84% |
| Heaviest task (tokens) | 11,009 (T11) | 15,695 (T9) | 8,670 (T11) | 16,384 (T11, truncated) | 9,604 (T9) |
Three TC runs establish a variance band (temp 1.0): wall 233–298 s, tokens 70.7–83.4k (±13% around the mid-point). Base (468–471 s) sits outside that band by +57 to +100% — the difference is robust to variance, not a single-run artifact. At an equal budget (both 32k), TC's saving is −33% in both tokens and time.
¹ excluding T11, which ended in a client timeout (300 s) — see finding F2.
Headline numbers: on complex tasks the base model is ~57% slower (wall) and consumes ~40% more tokens at comparable output quality. TC's savings therefore scale with task complexity (simple queries showed ~25%), consistent with the model card.
5. Per-Task Results (representative runs: TC run 2, base run 2)
| T | Task (abbrev.) | TC | base | Note |
|---|---|---|---|---|
| 1 | Czech IBAN validation (mod-97) | ✅ | ✅ | both incl. 6 unit tests |
| 2 | LRU cache + TTL, O(1) | ✅ | ✅ | |
| 3 | CSV parser from scratch | ✅ | ✅ | escaped quotes, BOM, CRLF |
| 4 | Czech phone regex (VERBOSE) | ✅ | ✅ | |
| 5 | SQL window functions + indexes | ✅ | ✅ | PARTITION BY, RANK |
| 6 | Bash log rotation (shellcheck) | ✅ | ✅ | print0, dry-run |
| 7 | PowerShell Test-DdaReady | ✅ | ✅ | Dismount-VMHostAssignableDevice |
| 8 | Refactoring with the bool trap | ✅ | ✅ | both explicitly excluded bool (subclass of int) |
| 9 | Knapsack DP + reconstruction | ✅ 205 CZK | ✅ 205 CZK² | ²base run 1 overflowed the budget (F2) |
| 10 | Dijkstra step by step | ✅ 13 | ✅ 13 | path A-C-B-D-E-F |
| 11 | Coin change for 100 CZK (DP) | ❌³ | ❌ timeout | ³run 1 ✅ 4,562; unstable for both (F1) |
| 12 | Time-zone trap (CET/CEST) | ✅ 19:05/12:05 | ✅ 19:05/12:05 | both models 2/2 — see F3 |
| 13 | Contract extraction to JSON | ✅ | ✅ | amounts, deadlines, diacritics |
| 14 | Czech diacritics restoration | ✅ 100% | ✅ 100% | incl. the required comma |
| 15 | Formal e-mail with ROI | ✅ 17.8 mo | ✅ | |
| 16 | JSON Schema 2020-12 | ✅ | ✅ | TC: thinking 18 B — effectively skipped, 9.4 s |
| 17 | docker-compose for LiteLLM | ✅ | ✅ | |
| 18 | "ninja not found" diagnosis | ✅ | ✅ | apt ninja-build (not pip) |
| 19 | Context window × max_tokens | ✅ | ✅ | |
| 20 | Race-condition code review | ✅ 3/3 bugs | ✅ 3/3 | join, Lock, GIL, <500,000 |
6. Key Findings
F1 — Hand-computed arithmetic DP tables are unstable for both models. Task 11 (number of ways to make 100 CZK; ground truth 4,562, verified by independent computation): TC run 1 ✅ 4,562; TC run 2 ❌ 1,504 (intermediate values wrong too); TC run 3 ❌ 5,056 (delivered with the false assurance "verified against the known sequence; all intermediate steps are consistent" — confident wrongness); base run 1 ❌ 4,365 plus budget exhaustion; base run 2 ❌ client timeout at 300 s (TC solves the same task in ~120 s). Score: 1/5 — five attempts, four different numbers. A 100-cell table computed "in the head" at temperature 1.0 is a dice roll. Recommendation: in agentic workflows, delegate arithmetic DP to code execution, not to the model.
F2 — The base model needs a larger budget and longer timeouts on complex tasks. At max_tokens 16,384 the base model failed twice (T9 overflow with empty content, T11 truncation); TC always fit (maximum 15,695 — tight). Base as a rollback therefore requires max_tokens 32,768 and a client timeout ≥ 600 s; for TC, 16,384 is a sufficient default.
F3 — Reasoning quality is high for both, including trick questions. The time-zone trap T12 (departure at 23:45 the day before the CET→CEST transition, with the prompt deliberately mislabeling the departure as "CEST") was solved correctly by both models in all runs: they recognized CET still applied at departure, converted via UTC correctly (22:45 + 11:20 = 10:05 UTC), and applied CEST to the Prague arrival-time answer (12:05).
F4 — The models corrected the benchmark author's own errors. The task sheet contained two mistakes in its check hints (T9: expected value stated as 225 CZK, correct is 205; T12: 11:05 UTC/20:05 Tokyo, correct is 10:05/19:05 — the error came from adding flight time to local time without converting to UTC). TC explicitly identified and politely corrected both errors in its answers, with sound justification. Ground truth was subsequently verified by independent computation — the models were right.
F5a — TC savings by category (both @ 32k; TC run 3 × base run 2). Completion-token breakdown per category (initial analysis by the Hermes agent, sums independently recomputed from the JSONs):
| Category | TC | base | TC saving |
|---|---|---|---|
| Czech language (3 tasks) | 4,634 | 14,604 | −68% |
| Structured output (2) | 3,790 | 8,891 | −57% |
| Diagnostics (3) | 5,407 | 8,228 | −34% |
| Coding (8) | 33,810 | 50,419 | −33% |
| Algorithms (4) | 23,060 | 22,871 | +1% |
The pattern is legible: savings are largest where the base model generates boilerplate deliberation (Czech prose, templated outputs) and vanish where the computation is irreducible (arithmetic DP — both models simply have to compute). TC's reduction is adaptive, not uniform.
F5 — Thinking profile. TC: 82% of completion characters are thinking; extremes range from 18 B (JSON Schema — thinking effectively skipped) to 23,673 B (knapsack). Base: 84–86%, and ~40% more thinking in absolute terms on the same tasks. TC's thinking reduction is thus not a uniform "thinks less" but adaptive — trivial structured output streams immediately, hard combinatorics still gets full deliberation.
7. Conclusions
- The "TC = primary" decision is confirmed with the strongest evidence to date: equal quality, ~57% time saving, ~40% token saving on complex tasks.
- Base remains a fully viable rollback — it held up qualitatively (trick questions included); operating conditions: 32k budget, longer timeouts, ~1.6× higher latency.
- Systemic recommendations: arithmetic DP → code execution (both models); keep a T11-style task in the regression suite as an instability canary.
8. Limitations
Temperature 1.0 implies natural run-to-run variance (TC across 3 runs: ±13% in tokens/time; T11 demonstrates the instability directly); 3+2 runs suffice to establish a band, not full statistics. Factual grading combines automated markers with manual review — full responses are preserved in the archived JSONs (benchmark_TC_run1/2.json, benchmark_base_run1/2.json) and can be re-examined. Parallelism of 5 means per-task timings include contention (appropriate for throughput comparison, not single-task latency).
Prepared by Claude Fable 5 (Anthropic) — task design, grading criteria, ground-truth computations, and evaluation. Test execution: operator + Hermes agent on the vs201 infrastructure.
benchmark.py
#!/usr/bin/env python3
"""Benchmark: 20 úloh — A/B ThinkingCap vs base Qwen3.6-27B."""
import json, time, sys, requests
from pathlib import Path
from datetime import datetime
URL = "http://192.168.110.67:8000/v1/chat/completions"
MODEL = "rtx6000-impl"
MAX_TOKENS = 16384
RESULTS = Path(file).parent / "benchmark_results.json"
Sampling recipe ze serveru: neposílat temp/top_p atd., necháme defaulty vLLM
HEADERS = {"Content-Type": "application/json"}
TASKS = [
{
"id": 1,
"category": "Kódování",
"prompt": "Napiš Python funkci validuj_iban_cz(iban: str) -> bool pro český IBAN (CZ + 22 znaků, mod-97 kontrola dle ISO 13616) včetně normalizace mezer a malých písmen. Přidej 6 unit testů (3 platné, 3 neplatné).\nKontrola: CZ65 0800 0000 1920 0014 5399 → True; změna jedné číslice → False.",
"check": "mod97, CZ prefix, 6 testů"
},
{
"id": 2,
"category": "Kódování",
"prompt": "Napiš Python třídu LRUCacheTTL(kapacita, ttl_s) — LRU vytěsňování + expirace položek po TTL. Metody get/put O(1). Bez externích knihoven. Unit testy s mockovaným časem.\nKontrola: get po expiraci vrací None; nejstarší se vytěsní při přeplnění.",
"check": "O(1), get/put, TTL, LRU"
},
{
"id": 3,
"category": "Kódování",
"prompt": "Napiš robustní CSV parser v Pythonu (bez modulu csv): uvozovky, escapované uvozovky (""), čárky i \n uvnitř polí, BOM, CRLF. Vrať list[list[str]].\nKontrola: 'a,"b,""c""\nd",e' → [['a','b,"c"\nd','e']].",
"check": "quotes, escaped quotes, newlines, BOM, CRLF"
},
{
"id": 4,
"category": "Kódování",
"prompt": "Regulární výraz (Python, komentovaný re.VERBOSE) pro česká telefonní čísla: volitelně +420/00420, mezery/pomlčky mezi trojicemi, celkem 9 číslic. Uveď 8 testovacích případů.\nKontrola: "+420 601 123 456" ✅, "601123456" ✅, "60112345" ❌.",
"check": "re.VERBOSE, +420/00420, 9 číslic, 8 testů"
},
{
"id": 5,
"category": "Kódování",
"prompt": "Máš SQL tabulky objednavky(id, zakaznik_id, datum, castka) a zakaznici(id, jmeno, region). Napiš dotaz: pro každý region top 3 zákazníci dle součtu částek za rok 2025, včetně pořadí. Pak vysvětli, jaké indexy dotaz potřebuje a proč.\nKontrola: window funkce (RANK/ROW_NUMBER) + PARTITION BY region; index (datum) a (zakaznik_id).",
"check": "window function, PARTITION BY, index recommendation"
},
{
"id": 6,
"category": "Kódování",
"prompt": "Napiš bash skript pro rotaci logů: adresář /var/log/aplikace, soubory *.log starší 7 dní zagzipovat, starší 30 dní smazat, s dry-run přepínačem a ošetřením mezer v názvech. Shellcheck-clean.\nKontrola: find -print0 | while read -d '', žádné neuvozené proměnné.",
"check": "find -print0, gzip, rm, dry-run, spaces safe"
},
{
"id": 7,
"category": "Kódování",
"prompt": "Napiš PowerShell funkci Test-DdaReady pro Hyper-V host: ověří SR-IOV/ACS, vypne kartu dle PCI ID (parametr), vrátí objekt se stavem (Připraveno/Chybí kroky + důvody). Bez skutečného spuštění — jen kód.\nKontrola: Get-PnpDevice dle InstanceId, Disable-PnpDevice -Confirm:$false, Dismount-VMHostAssignableDevice.",
"check": "Get-PnpDevice, Disable-PnpDevice, Dismount-VMHostAssignableDevice"
},
{
"id": 8,
"category": "Kódování",
"prompt": "Refaktoruj tento kód (uveď ho modelu doslovně):\n\ndef zprac(d):\n r=[]\n for i in range(len(d)):\n if d[i]!=None:\n if type(d[i])==str:\n if d[i].strip()!="":\n r.append(d[i].strip().lower())\n else:\n if type(d[i])==int or type(d[i])==float:\n if d[i]>0: r.append(str(d[i]))\n return r\n\nCíl: idiomatický Python, type hints, docstring, zachovat chování 1:1, přidej testy dokazující ekvivalenci.\nKontrola: isinstance, comprehension/guard klauzule, chování identické (i pořadí podmínek pro bool — pozor, bool je subclass int!).",
"check": "isinstance, type hints, docstring, bool subclass int"
},
{
"id": 9,
"category": "Algoritmy",
"prompt": "Batoh (0/1 knapsack): kapacita 15 kg, předměty [(3,40),(5,70),(7,90),(2,20),(4,55),(6,80)] (kg, Kč). Najdi optimum dynamickým programováním, ukaž tabulku a rekonstruuj vybrané předměty.\nKontrola: optimum 225 Kč (3+5+4+2=14 kg? ověř — model musí ukázat výpočet; správnost = konzistentní DP tabulka + rekonstrukce).",
"check": "DP table, reconstruction, optimal value"
},
{
"id": 10,
"category": "Algoritmy",
"prompt": "Graf: města A–F, silnice s časy A-B:4, A-C:2, B-C:1, B-D:5, C-D:8, C-E:10, D-E:2, D-F:6, E-F:3. Najdi nejkratší cestu A→F Dijkstrou, ukaž tabulku vzdáleností krok po kroku.\nKontrola: A→C→B→D→E→F? model musí ukázat kroky; správná délka = ověř ručně dle jeho tabulky (očekávám A-C-B-D-E-F = 2+1+5+2+3=13).",
"check": "Dijkstra steps, path A-F, distance"
},
{
"id": 11,
"category": "Algoritmy",
"prompt": "Kolika způsoby lze rozměnit 100 Kč na mince 1, 2, 5, 10, 20, 50 Kč? Vyřeš DP, uveď mezivýsledky pro 10, 20, 50 Kč a finální číslo.\nKontrola: konzistence mezivýsledků (10 Kč = 10 způsobů? model ukáže); finální číslo musí sedět s jeho mezikroky.",
"check": "DP change-making, intermediate results, final count"
},
{
"id": 12,
"category": "Algoritmy",
"prompt": "Letadlo odlétá z Prahy 23:45 SELČ 28.3.2026 (noc přechodu na letní čas je 29.3.), letí 11 h 20 min do Tokia (UTC+9). Kolik je v Tokiu při příletu a kolik v Praze? Pozor na změnu času během letu.\nKontrola: SELČ už platí (změna 29.3. 02:00 SEČ→SELČ — ale 28.3. večer je ještě SEČ! Chyták: 23:45 28.3. = SEČ/UTC+1; přílet 11:05 UTC 29.3. = 20:05 Tokio; Praha v tu chvíli 13:05 SELČ). Správně = model si všimne přechodu.",
"check": "SEČ vs SELČ trap, UTC+1 departure, arrival times"
},
{
"id": 13,
"category": "Čeština",
"prompt": "Shrň následující text do 3 vět a vytěž strukturovaně (JSON: strany, předmět, částka, lhůty): „Smlouva o dílo uzavřená mezi objednatelem XYZ s.r.o., IČO 12345678, se sídlem v Liberci, a zhotovitelem ABC a.s. Předmětem je dodávka a instalace serverové infrastruktury v hodnotě 2 450 000 Kč bez DPH. Zhotovitel se zavazuje dílo dokončit do 90 dnů od podpisu, záruka činí 24 měsíců. Smluvní pokuta za prodlení je 0,05 % z ceny díla za každý den."\nKontrola: JSON validní, částka 2450000, lhůty 90 dnů/24 měsíců/0,05 %, diakritika bezchybná.",
"check": "valid JSON, amount 2450000, deadlines, diacritics"
},
{
"id": 14,
"category": "Čeština",
"prompt": "Oprav diakritiku a pravopis (text uveď modelu doslovně): „Vazeny pane rediteli, dovolte mi abych Vas informoval ze nase spolecnost uspesne dokoncila migraci datoveho centra. Behem cele akce nedoslo k zadnemu vypadku sluzeb a vsechna data byla prenesena bez ztraty. Dekuji vsem clenum tymu za jejich usili."\nKontrola: 100 % správná diakritika (Vážený, řediteli, abych Vás, že naše společnost úspěšně, datového, Během celé, nedošlo k žádnému výpadku služeb, přenesena, Děkuji všem členům týmu, úsilí) + čárka za „mi".",
"check": "100% diacritics, comma after mi"
},
{
"id": 15,
"category": "Čeština",
"prompt": "Napiš formální email jednateli firmy: žádost o schválení nákupu GPU serveru za 800 000 Kč, argumentace úsporou cloudu (současné náklady 45 000 Kč/měsíc), návratnost, rizika, 150–200 slov, formální čeština.\nKontrola: návratnost ~18 měsíců zmíněna a spočtena správně, struktura (oslovení/věc/argumenty/závěr), bezchybná čeština.",
"check": "ROI ~18 months, structure, formal Czech, word count"
},
{
"id": 16,
"category": "Strukturovaný výstup",
"prompt": "Navrhni JSON Schema (draft 2020-12) pro konfiguraci vLLM služby: model_path (povinné, regex ^/ai_models/), served_name, port (1024–65535), dtype (enum bfloat16/auto), max_model_len (násobek 1024, max 262144), speculative (objekt: method enum [mtp], num_tokens 1–5). Přidej validní a nevalidní příklad.\nKontrola: schema syntakticky validní, required pole, multipleOf 1024, oba příklady konzistentní se schématem.",
"check": "valid schema, required, multipleOf, valid+invalid examples"
},
{
"id": 17,
"category": "Strukturovaný výstup",
"prompt": "Převeď na docker-compose.yml: kontejner litellm (image ghcr.io/berriai/litellm:main-latest), port 4000:4000, mount ./config.yaml:/app/config.yaml, env LITELLM_MASTER_KEY ze souboru .env, restart unless-stopped, healthcheck curl /health po 30 s, síť ai-net (externí). Přidej komentáře česky.\nKontrola: validní YAML, env_file/environment správně, healthcheck syntaxe, external network.",
"check": "valid YAML, env_file, healthcheck, external network"
},
{
"id": 18,
"category": "Diagnostika",
"prompt": "Diagnostikuj (traceback uveď modelu doslovně): „FileNotFoundError: [Errno 2] No such file or directory: 'ninja'" v subprocess.run volaném z flashinfer/jit/core.py build_and_load při startu vLLM. Systém Ubuntu, driver OK, nvcc nainstalován. Co je příčina, jak opravit, jak ověřit?\nKontrola: chybí ninja-build balík (ne pip ninja!), apt install ninja-build, which ninja; bonus: zmínka build-essential.",
"check": "apt install ninja-build, not pip ninja, which ninja"
},
{
"id": 19,
"category": "Diagnostika",
"prompt": "Analyzuj log a urči příčinu (uveď doslovně): „Maximum concurrency for 262,144 tokens per request: 3.61x" a poté klient dostává 400 Bad Request s hláškou o překročení max_model_len při požadavku s max_tokens=163840 a promptem 5000 tokenů. Vysvětli vztah context window × max_tokens a navrhni správné hodnoty.\nKontrola: prompt+max_tokens ≤ max_model_len; 5000+163840 > 163840 (pokud server na 163840) resp. vysvětlení dvou limitů; doporučení max_tokens 8–16k.",
"check": "context window explanation, two limits, recommendation"
},
{
"id": 20,
"category": "Diagnostika",
"prompt": "Code review: najdi VŠECHNY chyby (uveď kód doslovně):\n\nimport threading\ncitac = 0\ndef pridej():\n global citac\n for _ in range(100000):\n citac += 1\nvlakna = [threading.Thread(target=pridej) for _ in range(5)]\nfor v in vlakna: v.start()\nprint(f"Vysledek: {citac}")\n\nKontrola: (1) chybí join před print, (2) race condition citac += 1 není atomické → Lock, (3) GIL nezaručuje atomicitu složené operace; bonus: očekávaný výsledek < 500000.",
"check": "join, race condition/Lock, GIL explanation, <500000"
},
]
def run_task(task: dict, model_name: str) -> dict:
"""Run a single task against the model and return result."""
payload = {
"model": MODEL,
"messages": [{"role": "user", "content": task["prompt"]}],
"max_tokens": MAX_TOKENS,
}
t0 = time.monotonic()
try:
resp = requests.post(URL, headers=HEADERS, json=payload, timeout=300)
elapsed = time.monotonic() - t0
if resp.status_code != 200:
return {
"error": f"HTTP {resp.status_code}",
"error_body": resp.text[:500],
"elapsed": round(elapsed, 2),
}
data = resp.json()
choice = data["choices"][0]
content = choice["message"].get("content", "")
# Parse reasoning vs content
reasoning = ""
content_clean = content
if "<think>" in content and "</think>" in content:
reasoning = content[content.index("<think>") + 7:content.index("</think>")].strip()
content_clean = content[content.index("</think>") + 8:].strip()
elif "<think>" in content:
# unclosed think tag
reasoning = content[content.index("<think>") + 7:].strip()
content_clean = ""
usage = data.get("usage", {})
return {
"completion_tokens": usage.get("completion_tokens", 0),
"prompt_tokens": usage.get("prompt_tokens", 0),
"total_tokens": usage.get("total_tokens", 0),
"finish_reason": choice.get("finish_reason", "unknown"),
"reasoning_len": len(reasoning),
"content_len": len(content_clean),
"elapsed": round(elapsed, 2),
"content": content_clean,
"reasoning": reasoning,
}
except Exception as e:
elapsed = time.monotonic() - t0
return {
"error": str(e),
"elapsed": round(elapsed, 2),
}
def run_task_with_meta(task: dict, model_name: str) -> dict:
"""Wrapper that attaches task metadata to the result."""
res = run_task(task, model_name)
res["task_id"] = task["id"]
res["category"] = task["category"]
res["check"] = task["check"]
return res
def run_benchmark(model_name: str):
"""Run all tasks with max 5 parallel workers."""
from concurrent.futures import ThreadPoolExecutor, as_completed
print(f"\n{'='*70}")
print(f"BENCHMARK: {model_name}")
print(f"Model: {MODEL} @ {URL}")
print(f"max_tokens: {MAX_TOKENS}")
print(f"{'='*70}\n")
results = []
total_tokens = 0
total_time = 0
finished = 0
t0 = time.monotonic()
with ThreadPoolExecutor(max_workers=5) as pool:
futures = {
pool.submit(run_task_with_meta, task, model_name): task
for task in TASKS
}
for future in as_completed(futures):
task = futures[future]
res = future.result()
finished += 1
tid = task["id"]
cat = task["category"]
if "error" in res:
print(f"[{tid}/20] {cat} — ERROR: {res['error']} ({finished}/20)")
results.append(res)
continue
tokens = res["completion_tokens"]
total_tokens += tokens
total_time += res["elapsed"]
print(f"[{tid}/20] {cat} — ✅ {tokens} tok, {res['elapsed']}s, "
f"think={res['reasoning_len']}B, "
f"content={res['content_len']}B, "
f"finish={res['finish_reason']} ({finished}/20)")
results.append(res)
total_wall = time.monotonic() - t0
# Sort by task_id
results.sort(key=lambda r: r["task_id"])
print(f"\n{'='*70}")
print(f"SUMMARY: {len(results)} tasks, {total_tokens} tokens, "
f"{total_time:.1f}s (sum), {total_wall:.1f}s (wall)")
print(f"{'='*70}\n")
return {
"model": model_name,
"timestamp": datetime.now().isoformat(),
"total_tokens": total_tokens,
"total_time": round(total_time, 2),
"total_wall": round(total_wall, 2),
"results": results,
}
def save_run(data: dict, model_name: str):
"""Save results to file."""
run_file = Path(file).parent / f"benchmark_{model_name}.json"
with open(run_file, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"Saved: {run_file}")
def print_summary(tc_data: dict, base_data: dict):
"""Print comparison table."""
tc = {r["task_id"]: r for r in tc_data["results"]}
base = {r["task_id"]: r for r in base_data["results"]}
print(f"\n{'='*120}")
print(f"{'#':>2} | {'TC ✅/❌':>6} | {'TC tok':>7} | {'TC s':>6} | {'Base ✅/❌':>8} | {'Base tok':>8} | {'Base s':>7} | Pozn.")
print(f"{'-'*120}")
for tid in range(1, 21):
tc_r = tc.get(tid, {})
base_r = base.get(tid, {})
tc_ok = "✅" if "error" not in tc_r and tc_r.get("finish_reason") == "stop" else "❌"
base_ok = "✅" if "error" not in base_r and base_r.get("finish_reason") == "stop" else "❌"
tc_tok = tc_r.get("completion_tokens", 0)
base_tok = base_r.get("completion_tokens", 0)
tc_time = tc_r.get("elapsed", 0)
base_time = base_r.get("elapsed", 0)
print(f"{tid:>2} | {tc_ok:>6} | {tc_tok:>7} | {tc_time:>6.1f} | {base_ok:>8} | {base_tok:>8} | {base_time:>7.1f} |")
print(f"{'='*120}")
tc_pass = sum(1 for r in tc_data["results"] if "error" not in r and r.get("finish_reason") == "stop")
base_pass = sum(1 for r in base_data["results"] if "error" not in r and r.get("finish_reason") == "stop")
print(f"TC pass: {tc_pass}/20, tokens: {tc_data['total_tokens']}, time: {tc_data['total_time']}s")
print(f"Base pass: {base_pass}/20, tokens: {base_data['total_tokens']}, time: {base_data['total_time']}s")
print(f"Token diff: {tc_data['total_tokens'] - base_data['total_tokens']:+d}")
print(f"Time diff: {tc_data['total_time'] - base_data['total_time']:+.1f}s")
if name == "main":
model_name = sys.argv[1] if len(sys.argv) > 1 else "TC"
print(f"Starting benchmark run for: {model_name}")
data = run_benchmark(model_name)
save_run(data, model_name)
# Check if both runs exist and print comparison
tc_file = Path(__file__).parent / "benchmark_TC.json"
base_file = Path(__file__).parent / "benchmark_base.json"
if tc_file.exists() and base_file.exists():
with open(tc_file) as f:
tc_data = json.load(f)
with open(base_file) as f:
base_data = json.load(f)
print_summary(tc_data, base_data)
Thank you so much for contributing!