Helpers
Helpers
Language detection
laya.detect_language is laya.lang.analyse.
Names, types, defaults and code stay in English; the rest is translated (entries not translated yet are shown in the original English).
analyse
analyse(state: Union[str, bytes, Mapping, list, None]) -> Dict[str, object]Full detection result for a state.
Returns script, script_profile, language (best effort, may be None),
is_english, non_latin_fraction and mixed_segment (the line or field that made a mostly
English state non-English, else None).
String values are what get read. When a state has several of them, one non-English value is enough: joining every value into one window let a long English note fill the 4000 characters, or outvote a short German message, and that message was then sent to the English checkpoint (#384). The segment scan still stops at 4000 characters, which is what keeps a huge field cheap; a value it did not reach is read on its own afterwards.
Parameters
stateUnion[str, bytes, Mapping, list, None]
detect_script
detect_script(text: str) -> strDominant script of text: 'latin', 'han', 'devanagari', ... or 'unknown' if there are no letters.
Parameters
textstr
is_english
is_english(state: Union[str, bytes, Mapping, list, None]) -> boolTrue when the English checkpoint can be expected to read this state.
Parameters
stateUnion[str, bytes, Mapping, list, None]
clean_email_body
clean_email_body(body: str, max_chars: int = 3000) -> strRemove quoted email history, signatures and disclaimers to keep input focused.
max_chars is the length the result is cut to, 3000 characters unless raised -- see
email_state, which takes the same budget and passes it through.
Parameters
bodystrmax_charsint=3000
email_state
email_state(
subject: str,
body: str,
sender: Optional[str] = None,
clean: bool = True,
max_chars: int = 3000,
extra,
) -> DictConstruct a clean state dictionary for email classification.
max_chars is the budget clean_email_body cuts the body to, and it is worth raising for a
long message: at the default the body stops after 3000 characters, so a request that arrives in
the last paragraphs never reaches the model -- including through predict_long, which scans a
state in windows precisely so it can read past one window's worth. Ignored when clean=False,
which passes the body through whole.
Any other keyword becomes a field of the state, so it is read by the model; a typo here is an input mutation, not an error.
Parameters
subjectstrbodystrsenderOptional[str]=Nonecleanbool=Truemax_charsint=3000extra
Question presets
triage_questions
triage_questions() -> DictPreset questions for customer support ticket triage.
email_questions
email_questions(categories: Optional[Dict[str, str]] = None) -> DictPreset questions for inbound email triage and threat filtering.
Parameters
categoriesOptional[Dict[str, str]]=None
guard_questions
guard_questions() -> DictPreset questions for real-time LLM input guardrails.
moderation_questions
moderation_questions() -> DictPreset questions for content safety and moderation.
router_questions
router_questions() -> DictPreset questions for intelligent model routing.
Shortlisting
shortlist_choice
shortlist_choice(
state: Any,
criteria: Any,
embed_fn: Callable[[Sequence[str]], Any],
k: int = DEFAULT_SHORTLIST_K,
DEFAULT_SHORTLIST_K,
instructions: Optional[str] = None,
) -> List[Any]Return the top-k choice labels for state.
embed_fn maps a list of strings to an array of shape (len(texts), dim).
It is called once, with the query text first and then one string per option in
criteria order. Option strings match render_options for a choice question.
When k is at least the number of labels, every label is returned in its
original order and embed_fn is not called.
Ties keep the earlier label. A zero vector scores 0 and does not outrank a label that came before it.
Parameters
stateAnycriteriaAnyembed_fnCallable[[Sequence[str]], Any]kint=DEFAULT_SHORTLIST_KDEFAULT_SHORTLIST_KinstructionsOptional[str]=None
predict_shortlist
predict_shortlist(
agent: Any,
state: Any,
questions: Dict[str, Dict[str, Any]],
embed_fn: Callable[[Sequence[str]], Any],
k: int = DEFAULT_SHORTLIST_K,
DEFAULT_SHORTLIST_K,
predict_kwargs: Any,
) -> Dict[str, Any]Shortlist each choice question, then call predict or system_one once.
Non-choice questions are forwarded unchanged. A choice whose label count is
<= k is forwarded unchanged and does not call embed_fn. The caller's
questions dict is not mutated.
The returned dict is the model result plus a shortlist entry. Probabilities
on a shortlisted choice are over the kept labels only. shortlist[qid] holds
labels (rank order), scores (cosine, or None when nothing was
dropped), k, n, and passthrough.
Extra keyword arguments are forwarded to predict / system_one (for
example model= on a Router).
Parameters
agentAnystateAnyquestionsDict[str, Dict[str, Any]]embed_fnCallable[[Sequence[str]], Any]kint=DEFAULT_SHORTLIST_KDEFAULT_SHORTLIST_Kpredict_kwargsAny
embed_fn_from_agent
embed_fn_from_agent(
agent: Any,
max_length: int = 512,
batch_size: int = 32,
) -> Callable[[Sequence[str]], np.ndarray]Mean-pool the checkpoint encoder already loaded on agent.
The callable embeds a list of strings with agent.tok and agent.model.encoder.
It does not run the decision head and does not download weights. A dedicated
bi-encoder passed as embed_fn will usually shortlist better; this helper is
for callers who only have the Laya checkpoint in memory.
Padding positions are excluded from the mean. The encoder's train/eval flag is
left as the caller set it (a loaded Agent is already in eval).
Each call uses the current agent.device, including after CPU fallback.
Parameters
agentAnymax_lengthint=512batch_sizeint=32
cached_embed_fn
cached_embed_fn(
embed_fn: Callable[[Sequence[str]], Any],
maxsize: int = 4096,
) -> Callable[[Sequence[str]], np.ndarray]Cache embed_fn output per input string, under an LRU bound.
predict_shortlist embeds the query plus every option text on each call. When the
same option set is shortlisted on every request -- a fixed intent or label list, as
in the README's BANKING77 example -- the option rows do not change between calls,
yet they are re-embedded every time. Wrapping the embedder once::
embed_fn = cached_embed_fn(embed_fn_from_agent(agent))
leaves the first call unchanged and reduces each repeat call to embedding the new query alone.
Lookups are exact string matches. Texts missing from the cache are deduplicated and
embedded in a single embed_fn call, so a cold cache costs the same number of
batched calls as the unwrapped function. Rows are stored as float32; the cache holds
at most maxsize strings and then evicts the least recently used entry, bounding
memory at about maxsize * dim * 4 bytes. Nothing is cached when embed_fn
raises or returns a bad shape.
The wrapper is safe to share between threads: the lock covers only cache reads and
writes, never the embedding call. The returned callable carries cache_info() --
a dict with size, maxsize, hits and misses -- and cache_clear().
Clear the cache if the model or weights behind embed_fn change.
Parameters
embed_fnCallable[[Sequence[str]], Any]maxsizeint=4096
Abstention
check_min_confidence
check_min_confidence(v: Any) -> floatValidate opt-in abstention threshold min_confidence (#361).
Must be a real number in [0.0, 1.0]. Booleans are rejected (even though isinstance(True, int)).
Parameters
vAny
flag_low_confidence
flag_low_confidence(results: List[Dict[str, Any]], min_confidence: float) -> NoneOpt-in abstention marker (#361): flag answers whose confidence falls below min_confidence.
Reads answer_confidence (max(p), the quantity the calibration figures describe and the one
that does not drift with the number of options), falling back to confidence if
answer_confidence is absent.
The raw answer and confidence stay intact; low_confidence: True is added.
Parameters
resultsList[Dict[str, Any]]min_confidencefloat
Calibration and training
answer_confidence
answer_confidence(p: np.ndarray, k: int) -> floatProbability mass on the answer being reported: max(p).
This is the quantity temperature scaling fits, and the quantity every calibration figure in
this repository is computed on -- both benchmark harnesses take conf = max(probs) before
calling ece_score. The README's gating section relies on the property that goes with it:
of the answers returned at confidence c, about c of them are right. That property is
conditional, and the condition is not met by default -- it holds only after the temperatures
have been fitted and validated on held-out data for this checkpoint and this option count.
The shipped checkpoints are over-confident: choice:11+ is a ~10x sharpener that returns a
point mass at 1.0, so a threshold applied to them selects below model accuracy (issue #394).
confidence_from_probs below reports a different quantity on a different scale and carries
no such guarantee, so the two must not be compared against the same threshold.
Parameters
pnp.ndarraykint
confidence_from_probs
confidence_from_probs(p: np.ndarray, k: int) -> floatNormalized Shannon entropy confidence: 1 - H(p) / log(k).
How concentrated the whole distribution is. Useful, but not calibrated: it is not what
temperature scaling fits and not what the reported ECE measures. See answer_confidence.
Parameters
pnp.ndarraykint
ece_score
ece_score(conf: np.ndarray, correct: np.ndarray, bins: int = 15) -> floatExpected Calibration Error across confidence bins.
Parameters
confnp.ndarraycorrectnp.ndarraybinsint=15
fit_temperatures
fit_temperatures = fit_temperature_mapfit_one_temperature
fit_one_temperature(pairs: Sequence, min_n: Optional[int] = None) -> floatFit one scalar T by NLL + LBFGS on log T.
The result is clamp_temperature of the optimised scale, so it lies in
[TEMP_MIN, TEMP_MAX] (or is the neutral 1.0 when the value is not a number).
Returns 1.0 when fewer than min_n pairs are given. min_n defaults to
MIN_BUCKET_N (the per-bucket floor). Type-level fits pass MIN_TYPE_N, which
is lower, so a dataset that fills no bucket still gets a scalar instead of
staying at 1.0.
Parameters
pairsSequencemin_nOptional[int]=None
fit_temperature_map
fit_temperature_map(
records: Iterable,
compute_ece: bool = False,
seed: int = 0,
) -> Dict[str, Any]Fit type-level scalars and per-bucket temperatures.
MIN_BUCKET_N is the per-bucket floor: smaller buckets are omitted from
temperature_by_options and the type-level scalar covers them. MIN_TYPE_N is
the separate, lower floor for that scalar only.
compute_ece=False (the default, and the path Agent.fit_temperatures stores)
fits on every record and returns no report key. seed is ignored on this path.
compute_ece=True holds out ECE_HOLDOUT_FRAC of each bucket, stratified by
temp_bucket, using seed so the same records always split the same way. Temperatures
are fit on the remainder only and ECE is scored only on the held-out records.
report["n"] is the number of records passed in; report["n_eval"] is the held-out
count the ECE rests on. A bucket that would drop below MIN_BUCKET_N after the
holdout is fit on all of its records, left out of the eval set, and named in
report["buckets_excluded_from_eval"] instead of being dropped. n_by_bucket
always counts the full input, including when the fit itself used a subset.
Parameters
recordsIterablecompute_ecebool=Falseseedint=0
render_options
render_options(q: Dict) -> List[str]Render option texts in label-index order. Noul semantic order is always [false, true].
Parameters
qDict
proper_reward
proper_reward(
q: torch.Tensor,
target: torch.Tensor,
qtype: torch.Tensor,
mask: torch.Tensor,
w_sph: float = 0.5,
w_rps: float = 1.0,
log_floor: float = -9.21,
) -> torch.TensorStrictly proper scoring rule reward: log score + spherical score + ranked probability score.
q: [..., N, K] reported distributions target: [N, K] (one-hot or soft target distributions)
Parameters
qtorch.Tensortargettorch.Tensorqtypetorch.Tensormasktorch.Tensorw_sphfloat=0.5w_rpsfloat=1.0log_floorfloat=-9.21
td_lambda_targets
td_lambda_targets(p_true: torch.Tensor, batch: Dict, lam: float = 1.0) -> torch.TensorTD(lambda) targets for multi-turn conversation trajectories.
Parameters
p_truetorch.TensorbatchDictlamfloat=1.0
QTYPES
QTYPES = {"choice": 0, "score": 1, "noul": 2}QTYPE_NAMES
QTYPE_NAMES = {v: k for k, v in QTYPES.items()}