Skip to content

AI models

Settings → AI models, admin only. Which model does each job.

Everything goes through the LiteLLM proxy; a model is registered here by its proxy id against one task.

The eight tasks

Task In the interface Does
teach Tutor The drawer a learner talks to beside a question
extraction Extraction Pulling questions out of a PDF, and the offline article batch writer
article Articles POST /articles/ai-draft and ai-refine
flashcard Cards Generating a deck from an article
keyword Classification Difficulty classification
tool Tool What the model on a job cannot do — reading an image, for one
tts Read aloud Speech
stt Transcription Speech to text

Anything else is refused at the route: "Task must be one of…".

Two helpers decide what happens when a task has no model:

  • get_model_for_task(db, task) falls back to settings.LITELLM_MODEL
  • get_configured_model(db, task) returns nothing instead — for work that must not run on a model nobody chose

Registering one

Browse asks the proxy for the chat models it actually serves (POST /admin/litellm/models) rather than making you type an id; Allow for picks the task.

Rule
One row per (model, task) A second is a 409
The first model added for a task Becomes the default automatically — a task with a model and no default would have no model
Marking one default Clears the flag on the others for that task
Off, not gone Deactivating keeps the row, its task and its default flag
Removing the default Leaves that job with no model until you pick another, and the confirmation says so

Voices

A speech model is registered with its voices: groq-orpheus-english expands to one row per voice the model accepts, so you add a model and the voices appear, ready to be tested one at a time. A model asked for a voice it does not accept is refused with the list of the ones it does.

Adding a model twice fills in whatever was missing rather than being refused.

Testing

Test exercises the model the way its job will: a chat model answers a prompt, a voice speaks, a transcriber listens, and the tool model reads a word off a picture. A failure comes back as a 502 with the proxy's own message, trimmed.

A test that only proved the id was spelled correctly taught administrators to distrust the button, which is worse than no button.

The two that are not settings

The embedding model

Shown, testable (POST /admin/embedding/test), and refused if you try to change it here:

The embedding model is set by LITELLM_EMBEDDING_MODEL in the environment. Changing it invalidates every stored vector, so it is a deployment rather than a setting.

Every vector in the database was produced by the current model. Changing it makes all of them incomparable, and search returns noise until some 3,000 questions, every article and every card have been re-embedded.

Regenerate (POST /admin/embedding/regenerate) re-embeds everything with the current model, as a background job. Search stays usable while it runs. GET /admin/embedding/health reports how much of the bank has a vector.

The reranker

settings:rerank_model in Redis, default cohere-rerank-v4.0-pro, testable with POST /admin/rerank/test.

Blank is a valid answer and means "keep the order rank fusion gave", so it is stored and read exactly as written rather than falling back to a default.

The reranker is a permutation and nothing else — an unset, unreachable, slow or malformed one returns the ids untouched. See Reranking.

Classification snapshots

GET /admin/classification-snapshots and POST /admin/classification-snapshots/{id}/rollback list and revert saved classification snapshots. They work — but nothing in the backend writes those rows; the offline tooling does.