Skip to main content
ot.distill() runs the full 4-phase BOND distillation pipeline (data-generation → curation → training → export) in-process and returns a callable Student. No FastAPI service, no ClickHouse, no job-polling — if you just want to train a student from a dataset and use it, this is the API. For the long-running, queued, multi-tenant REST flow, see the Distiller client — same engine, different surface.
ot.distill() needs opentracy[distill] and a CUDA GPU. It fails fast (before any teacher API spend) if torch can’t import or torch.cuda.is_available() is False.

Signature

Parameters

The Student returned by distill()

A thin wrapper around the freshest artifact.
After .deploy(alias), calling ot.completion(model=alias, ...) dispatches to this student locally — no provider call, no HTTP hop. See the Student reference below for the full API.

Dataset shapes

All three are equivalent:
Row field aliases: prompt / input / text all work for the input; response / expected_output all work for the gold answer.

Progress callback

Useful for building a UI around the run or just keeping a tidy timeline in a notebook:

Graceful export fallback

If phase 4 (GGUF conversion) fails — for example, llama.cpp isn’t installed on the host — ot.distill() does not crash. It logs a warning and returns a Student(backend="peft", model_path=<adapter>) pointing at the LoRA adapter that was successfully trained. You still get a working model; you just serve it via PEFT (1 GB base model in VRAM) instead of a standalone GGUF file. To force a GGUF-only path and raise on failure, call the REST-backed Distiller instead.

Errors — DistillError

ot.distill() raises opentracy.DistillError for pipeline failures. Common causes: The preflight that raises the torch/CUDA errors can be bypassed in tests by setting OPENTRACY_SKIP_DISTILL_PREFLIGHT=1. Don’t set this in production — it’ll let a GPU-less job burn money on teacher calls before dying in phase 3.

Student class

opentracy.Student is callable and serializes to disk. It’s what ot.distill() returns, but you can also instantiate it yourself to load a previously trained adapter.

Constructor

Methods

student(prompt, max_new_tokens=512, temperature=0.0, **kwargs) → str

Single-prompt inference. Returns the text response.

student.batch(prompts, max_new_tokens=512, temperature=0.0) → list[str]

Many prompts in one call (sequential).

student.generate(messages, *, max_tokens=512, temperature=0.0, top_p=None, stop=None) → dict

Full-chat-shape generation. Returns an OpenAI-shaped dict — this is what ot.completion(model=<Student instance>, ...) dispatches to internally.

student.save(path) → Path

Copy the artifact (adapter dir or .gguf file) to a durable location. Returns the resolved destination path.

student.deploy(alias, engine_url=None) → dict

Register the student under alias in the local file-based registry (~/.opentracy/aliases.json). After this, ot.completion(model=alias, ...) resolves to this student. If engine_url is provided, the call also POSTs to the engine’s /v1/models/register so server-side callers see the alias — failures there only emit a warning.

Preflights at load time

Loading a PEFT student checks:
  • torch, transformers, and peft are importable — else raises StudentError pointing at pip install opentracy[distill].
  • jinja2 >= 3.1 is present — else raises StudentError with the exact {sys.executable} -m pip install -U 'jinja2>=3.1' command for the interpreter currently running. Stale jinja2 3.0.x in a system Python is a common footgun when a uvicorn on PATH picks up a different interpreter than the one that has opentracy installed.

Alias registry

Aliases map a logical name to a Student. The registry lives at ~/.opentracy/aliases.json (or $OPENTRACY_DATA_HOME/aliases.json) and is read by ot.completion() on every call.
Any ot.completion(model="ticket-classifier", ...) call from any Python process owned by the same user will resolve through this registry and dispatch locally — no provider call, no HTTP hop, no shared state with a remote engine. The alias-swap pattern:

Serving the alias as an OpenAI-compatible HTTP endpoint

For a network-accessible endpoint, wrap the alias in a few lines of FastAPI:
Launch with the interpreter that has opentracy installed (not a random uvicorn on PATH):

Next

Distillation concepts

What the 4-phase pipeline is and when to retrain.

Distiller (REST client)

Long-running, queued jobs against a remote engine.