mixle.reason.llm module¶
Uncertainty quantification for LLM output – the thing LLMs famously lack, on the mixle UQ spine.
An LLM emits fluent text with no honest sense of whether it knows the answer. Wrapping any
generate(prompt) -> str callable, LLMUncertainty turns repeated stochastic samples into
calibrated uncertainty:
Semantic entropy (Kuhn et al. 2023): sample the model
ntimes, cluster the answers by meaning (not surface form), and take the entropy over meaning-clusters. High = the model disagrees with itself about what the answer is – a hallucination signal – while merely rephrasing one answer clusters to low entropy. (mixle.inference.semantic_entropy().)Epistemic vs aleatoric split: draw samples under several members (paraphrased prompts, or higher temperature as a proxy ensemble); the disagreement across members is epistemic (the model is unsure), the spread within is aleatoric (the question is genuinely open). (
mixle.inference.decompose_entropy().)Conformal answer-or-abstain: calibrate a confidence threshold on labeled examples so that when the model answers, it is correct with probability >= 1 - alpha – a finite-sample selective- risk guarantee. The model abstains on questions it does not know instead of confabulating.
Domain-neutral in its dependency: it takes a plain generate callable and an equivalent
relation, so it works with a local mixle.task model, an OpenAI-compatible endpoint (mlops), or a
mock – no hard LLM dependency here.
- sentence_claims(text)[source]
Split a response into atomic claims (sentence-ish units) – the default claim extractor.
- content_overlap(sample, claim, *, threshold=0.6)[source]
Simple corroboration test: does
samplecover >=thresholdofclaim’s content words?Counts every content word equally, so boilerplate shared across responses (“the tower is located in …”) can mask that the informative word (the city) differs.
information_corroborator()fixes that by weighting words by their information content; it is the default inLLMUncertainty.assess_claims().
- information_corroborator(samples, *, overlap=0.5)[source]
Build a corroboration test that weights each word by its information content over
samples.A word appearing in nearly every sample is boilerplate (low information, low weight); a rare word carries the actual claim (high weight). A sample corroborates a claim when it covers at least
overlapof the claim’s information-weighted words – so whether the distinctive fact (a city, a number, a name) matches drives the decision, not the shared filler. Inverse-document-frequency weighting:w(word) = log((N + 1) / (df + 0.5)).
- class LLMAssessment(answer, confidence, semantic_entropy, clusters, samples)[source]
Bases:
objectOne prompt’s assessed answer with uncertainty.
answeris the majority meaning-cluster’s representative;confidenceits cluster share in[0, 1];semantic_entropythe nats of meaning-uncertainty;clustersthe[(representative, probability), ...]distribution over meanings;samplesthe raw draws.- Parameters:
- answer: Any
- confidence: float
- semantic_entropy: float
- class ClaimAssessment(claim, support, reliable)[source]
Bases:
objectReliability of one claim inside a response, by cross-sample corroboration.
supportis the fraction of independent resamples that corroborate the claim (in[0, 1]);reliableissupport >= threshold. A claim the model actually knows recurs across samples (high support); a fabricated one appears once and vanishes (low support).- claim: str
- support: float
- reliable: bool
- class InformationAssessment(claims, reliability)[source]
Bases:
objectUQ over the information content of a response: every claim scored, plus a summary.
claimsis the per-claim reliability;reliabilitythe mean support (how trustworthy the response’s information is overall);fabricatedthe claims below threshold (likely hallucinated).- claims: list[ClaimAssessment]
- reliability: float
- property fabricated: list[ClaimAssessment]
- class FactualityModel(calibrator, signal, discrimination)[source]
Bases:
objectA fitted map from a per-prompt uncertainty signal to a calibrated
P(answer is correct).The signal (self-consistency, a token likelihood, …) is only a raw number; the calibrator turns it into a genuine probability of the information being correct, learned against labeled facts.
discrimination(held-out AUC on the fit set) reports how much the signal actually knew about correctness – ~0.5 means the signal was unrelated to truth, no matter how confident it looked.- Parameters:
- calibrator: ProbabilityCalibrator
- discrimination: float
- class LLMUncertainty(generate, *, equivalent=None, n=10)[source]
Bases:
objectCalibrated uncertainty and selective prediction for any
generate(prompt) -> strLLM.- Parameters:
generate (Callable[[str], Any]) –
callable(prompt) -> str– one stochastic sample from the model.equivalent (Callable[[Any, Any], bool] | None) –
callable(a, b) -> booldeciding whether two answers mean the same thing (default exact match; pass a normalizer / embedding / entailment check for real text).n (int) – default number of samples per prompt.
- sample(prompt, n=None)[source]
Draw
nstochastic responses toprompt.generatemay return a plain string, or a(text, logprob)pair – the sequence log-probabilitylog P(s). When logprobs are provided they are used to marginalize the string distribution over meaning classes exactly (mixle.inference.marginalize_meaning()) rather than by sample counting.
- assess(prompt, n=None)[source]
Sample, marginalize the string distribution over meaning classes, and report the answer.
The reported
confidenceis the marginal probability of the top meaning (summed over its equivalence class of strings), andsemantic_entropythe entropy of that meaning marginal – not a per-string token probability.
- decompose(prompts, n=None)[source]
Epistemic/aleatoric split across member prompts (paraphrases of one question).
Each prompt is a member; all members’ samples are pooled to define shared meaning-clusters, then each member’s distribution over those clusters feeds
decompose_entropy(). Epistemic = disagreement across paraphrasings (prompt-sensitivity / model uncertainty); aleatoric = within-member spread.
- assess_claims(prompt, *, extract=None, corroborates=None, n=None, threshold=0.5)[source]
Score the reliability of each claim in the response by cross-sample corroboration.
Finer-grained than
assess(): a response can be internally consistent (low semantic entropy) yet contain one fabricated fact. This decomposes the response into claims and checks each unit of information separately – a claim the model knows recurs across independent resamples; a hallucinated one appears once. This is UQ on the information in what is said, not just on the answer as a whole.- Parameters:
prompt (str) – the query.
extract (Callable[[str], Sequence[str]] | None) –
response -> [claim, ...](defaultsentence_claims()).corroborates (Callable[[str, str], bool] | None) –
(other_sample, claim) -> bool– does a resample support the claim? (defaultcontent_overlap(); pass an entailment/NLI check for real text).n (int | None) – number of samples (the first is the response scored; the rest corroborate).
threshold (float) – support below which a claim is flagged as unreliable/fabricated.
- Return type:
InformationAssessment
- calibrate(examples, *, correct=None, alpha=0.1, n=None)[source]
Calibrate a confidence threshold for selective risk
<= alphaon labeled(prompt, gold).For each example, the model’s answer (majority meaning-cluster) and its confidence are computed;
correct(answer, gold)(default theequivalentrelation) marks it right or wrong. The threshold is the lowest confidence at which the selective error rate on the calibration set is<= alpha– soanswer()abstains below it and, when it answers, is right with probability about1 - alpha.
- answer(prompt, n=None)[source]
Answer
promptif confident enough, elseNone(abstain).Requires a prior
calibrate(). Returns theLLMAssessmentwhenconfidence >= threshold(so the answer meets the selective-risk guarantee), elseNone.
- fit_factuality(examples, *, signal=None, correct=None, method='isotonic', n=None)[source]
Learn a calibrated
P(answer is correct)from a raw signal, on labeled(prompt, gold).The model’s raw confidence (its self-consistency, or a token likelihood) is not a probability that the information is correct – it can be systematically over/under-confident, or unrelated to truth. This fits a
ProbabilityCalibratormapping the signal to the empirical correctness rate, so the output is a probability of the information being right.discrimination(AUC of signal vs correctness) reports how much the raw signal knew at all – ~0.5 means it was unrelated to truth, calibration or not.- Parameters:
examples (Sequence[tuple[str, Any]]) – labeled
(prompt, gold_answer)pairs.signal (Callable[[str], float] | None) –
prompt -> floatraw score (default: the self-consistency confidence fromassess()).correct (Callable[[Any, Any], bool] | None) –
(answer, gold) -> bool(default theequivalentrelation).method (str) – calibration map –
"isotonic"or"platt".n (int | None) – samples per prompt.
- Return type:
FactualityModel