Skip to main content

Crate cratefield_adapter_classifier_llm

Crate cratefield_adapter_classifier_llm 

Source
Expand description

cratefield-adapter-classifier-llm: the Classifier port over the TextModel port the venture already wired (issue #456) — the third of the three Classifier adapters, and the only one with no vendor of its own. It reaches whichever model the TextModel tiers are routed to, a local model included, through JSON-schema structured output, and it is the honest fallback when neither a purpose-trained classifier nor a vendor binding is wired.

Calibration is the language model’s. This adapter reports Calibration::LanguageModel, and the point is not nominal: a probability elicited from a general language model is not the same number as one from a purpose-trained classifier. A 0.8 here is the model’s own rating of its certainty — a different sharpness at the same number, drifting with every model version the venture re-wires the tier to — so a threshold tuned against a Calibration::Classifier adapter is wrong against this one, and a module that thresholds on Answer::confidence says in its own docs which calibration it tuned.

The state ceiling is inherited, and the port cannot see the real one. Whatever TextModel allows, this adapter allows: it reports the port’s conservative DEFAULT_MAX_STATE_CHARS by default, and .max_state_chars exists because the actual budget is the underlying model’s context window, which the TextModel port has no way to report. Whoever wires the model knows it and says so here.

Crate docs use plain backticks, never intra-doc links — the same rule the rest of the classifier work follows.

§cratefield-adapter-classifier-llm

Classifier port over the harness’s own TextModel port for the Cratefield harness (issue #456). The third of the three Classifier adapters and the only one with no vendor of its own: it reaches whichever model the venture’s TextModel tiers are wired to — a local model included — asking for JSON-schema structured output. When neither a purpose-trained classifier nor a vendor binding is wired, this is the honest fallback.

§Usage

ⓘ
use cratefield_adapter_classifier_llm::ClassifierLlm;
use std::sync::Arc;

// `text_model` is the `Arc<dyn TextModel>` the venture already wired —
// the same router its drafting modules use. No new account, no new key.
let runtime = runtime.classifier(Arc::new(ClassifierLlm::new(text_model)));

// A model whose context window cannot carry the default 96_000-char
// state budget says so here, the only place that knows it:
let adapter = ClassifierLlm::new(text_model)
    .tier(cratefield_core::ModelTier::Fast)
    .max_state_chars(24_000);

§Calibration is the language model’s

This adapter reports Calibration::LanguageModel, and that is not a technicality. A probability elicited from a general language model is not the same number as one from a purpose-trained classifier. A 0.8 this adapter returns is the model’s own rating of its certainty — sharper when the model is confident, floppier at the decision boundary, and drifting with every model version the venture re-wires the tier to. A threshold tuned against a Calibration::Classifier adapter is simply wrong against this one. A module that thresholds on Answer::confidence documents the calibration it tuned against, and re-tunes when the adapter swaps.

§Behaviour

  • One TextModel::complete call per ask, carrying all questions — asking as a set is the port’s whole point. The prompt requests structured output through Prompt::json_schema, with a schema built per call that pins, for every question id, the chosen label and a probability for every label the question actually offers.
  • Structured output is a request: a provider that cannot honour the schema answers plain text (Completion::json is None). The adapter then parses Completion::text as JSON, tolerating the markdown code fence real models wrap it in. Neither yields a JSON object with an answers mapping and the call fails Transport — with a message that does not quote the completion back.
  • The model’s answer is validated, never trusted: a missing or invented question id, a chosen label the question never offered, a probability under a label the question never offered, or a distribution that is not finite and normalisable is Rejected. A distribution that sums to something other than 1 is normalised; NaN and infinities never pass.
  • state longer than max_state_chars is truncated with the port’s deterministic, char-boundary-safe cut, and a tracing::warn! fires. The default is the port’s conservative ceiling; the real ceiling is the underlying model’s context window, which this port cannot see — set .max_state_chars to match whatever the tiers are wired to.
  • Errors map one-to-one from TextModelError: NotConfigured (the tier is unwired — how “no classifier vendor wired” surfaces honestly), Rejected, Transient { retry_after } with the back-off preserved, and Transport. Provider text only ever rides inside variants whose Display scrubs it.

MIT. Built in the open for Cratefield, a Factory Zero venture.

Structs§

ClassifierLlm
Classifier over the venture’s own TextModel wiring. Construct with ClassifierLlm::new and the two builder methods; everything else is the Classifier trait.