ALLM.ClassificationAnswer (allm v0.6.1)

Copy Markdown View Source

The typed answer to one ALLM.ClassificationQuestion — Layer A serializable data.

iex> a = ALLM.ClassificationAnswer.new(type: :choice, choice: "billing", confidence: 0.88)
iex> ALLM.ClassificationAnswer.value(a)
"billing"

One struct, three shapes

An answer is a tagged union carried in one struct: :type says which question type it answers, and that decides which fields are populated.

Field:choice:score:yes_no
:choicethe chosen option namenilnil
:scorenila float between 0.0 and the number of levels minus onenil
:yes_probabilitynilnila float between 0.0 and 1.0
:probabilitiesa map of option name to probability, one key per optiona list of probabilities, one per levelnil
:legendnila list of level descriptions, one per levelnil
:confidencea float between 0.0 and 1.0a float between 0.0 and 1.0nil

value/1 returns the headline field for each type.

Why score lists, but choice maps

Score levels are ordered, so :probabilities and :legend are lists where index = level: Enum.at(answer.probabilities, 2) is the probability of level 2. A list round-trips through JSON unchanged, whereas an integer-keyed map would come back with string keys. Choice options are caller-chosen names with no order, so their probabilities stay a string-keyed map.

Confidence is reported, never computed

:confidence is whatever the provider reports; ALLM does not derive it. A :yes_no answer carries confidence: nil because the probability is itself the answer. There is no built-in threshold either: the decision of what probability counts as "yes" belongs to the caller.

Floats

An adapter coerces every probability, score and confidence to a float when it decodes a provider response, since JSON 1 and 0 decode as integers. Decoding a persisted answer does not coerce: the maps and lists come back exactly as they were stored.

Construction

:type is enforced, so new/1 without it raises ArgumentError. Unknown keys raise KeyError.

Summary

Functions

Build a %ClassificationAnswer{} from keyword opts.

The headline value: choice → option name, score → position, yes_no → P(yes).

Types

t()

@type t() :: %ALLM.ClassificationAnswer{
  choice: String.t() | nil,
  confidence: float() | nil,
  legend: [term()] | nil,
  metadata: map(),
  probabilities: %{required(String.t()) => float()} | [float()] | nil,
  score: float() | nil,
  type: ALLM.ClassificationQuestion.question_type(),
  yes_probability: float() | nil
}

Functions

new(opts)

@spec new(keyword()) :: t()

Build a %ClassificationAnswer{} from keyword opts.

:type is required (ArgumentError without it); unknown keys raise KeyError.

Examples

iex> a = ALLM.ClassificationAnswer.new(type: :yes_no, yes_probability: 0.93)
iex> {a.type, a.yes_probability, a.confidence}
{:yes_no, 0.93, nil}

value(classification_answer)

@spec value(t()) :: String.t() | float()

The headline value: choice → option name, score → position, yes_no → P(yes).

Examples

iex> ALLM.ClassificationAnswer.value(ALLM.ClassificationAnswer.new(type: :score, score: 1.05))
1.05

iex> ALLM.ClassificationAnswer.value(ALLM.ClassificationAnswer.new(type: :yes_no, yes_probability: 0.2))
0.2