Kicaulah AI

One router, five specialist models, one OpenAI-compatible endpoint. Small models with tuned personalities — not bigger ones pretending.

license models base router api

01The idea

Most "assistant" models sound the same because they are trained to. These are not.

Five personalities, not one compromise

A blunt senior dev and a patient teacher want opposite things. One model cannot be both. So there are five, and a router decides.

Anti-robotic by construction

QLoRA is used to lock voice, not to teach knowledge. A post-processor strips the “Certainly! Here's an explanation of…” openers so they cannot leak through.

Drop-in OpenAI protocol

Point Open WebUI, Cline, Continue, LangChain or curl at the endpoint. Same call signature, same streaming, same model list.

A safety net that does not trust a 73% classifier

Crisis detection runs on the raw text before routing, and fires regardless of the domain picked. See section 05.

02Architecture

The router is deliberately tiny. Routing is not interesting and does not deserve a GPU.

user message │ ▼ Router Kicaulah/router-multidomain distilbert · 135M · ~0.4s CPU │ ├─ therapist ─▶ model-therapist Qwen2.5-3B-Instruct warm, never judges ├─ health ─▶ model-health Qwen2.5-3B-Instruct calm, names red flags ├─ education ─▶ model-education Qwen2.5-3B-Instruct analogies, patient ├─ cybersec ─▶ model-cybersec Qwen2.5-3B-Instruct defensive only └─ coding ─▶ model-coding Qwen2.5-Coder-3B code first, blunt

03The models

Every repo carries a full Model Card with usage, an honest evaluation, and its own limitations.

04Take the prompt, skip the download

The system prompt is the most portable thing in this project. Paste it into any instruct model — GPT-4o-mini included — and you get this voice for free. The weights are there if you want them.

05Router accuracy, honestly

A 30-message test split cannot tell 0.80 from 0.87. Here is the number with a confidence interval behind it.

5-fold cross-validation 0.733 ± 0.070

Stratified, all 150 examples, seed 42. Fold range 0.60–0.80. Random baseline for five classes is 0.20.

$ python scripts/eval_router_cv.py 5 10
fold 1/5: accuracy 0.7667  f1 0.7610
fold 2/5: accuracy 0.8000  f1 0.7914
fold 3/5: accuracy 0.7667  f1 0.7660
fold 4/5: accuracy 0.6000  f1 0.5872
fold 5/5: accuracy 0.7333  f1 0.7181
accuracy  mean 0.7333  std 0.0699
95% CI on accuracy: +/- 0.0613

Where it still fails

InputGotShould be
“weird texts asking for my bank password”therapistcybersec
“two-factor authentication keeps failing”therapistcybersec
“why does the sky look red at sunset”healtheducation
“explain compound interest”therapisteducation

Two structural problems, both fixed with more data rather than a bigger model: cybersec is the hardest label, and health and therapist share vocabulary.

06Use it in 20 seconds

Start the server

pip install -r requirements.txt
python scripts/serve.py

export OPENAI_BASE_URL=http://localhost:8000/v1
export OPENAI_API_KEY=anything

Call it like OpenAI

Copyfrom openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="anything",
)
resp = client.chat.completions.create(
    model="kicaulah",              # or kicaulah-coding to pin one
    messages=[{"role": "user",
               "content": "explain recursion"}],
)
print(resp.choices[0].message.content)
Memory: five 3B models do not fit on a 16 GB GPU at once. The server keeps one specialist resident and evicts the previous one, so switching domains costs a reload. Set KICAULAH_KEEP_ALL=1 if you have the VRAM.

07Crisis guardrail

It does not depend on the router. That is the whole point.

Measured, and it matters: the router sends "kms" to education and "suicidal" to education as well. A guardrail gated on domain == "therapist" would have handed those to a maths model.

So the check runs on the raw text before the router is consulted, and fires regardless of the domain chosen. The model is never called — the reply is fixed text pointing at:

  • 988 Suicide & Crisis Lifeline (US) — call or text, 24/7
  • findahelpline.com — many countries
  • befrienders.org — worldwide
  • 116 123 Samaritans (UK & Ireland)

Deliberately biased toward false positives: 17/17 caught on real phrasings, 0/11 false positives on lookalikes. It is keyword matching — a safety net, not a guarantee.