[Router] 2381 unified interface for semantic_similarity and model classifier#2483
Conversation
eddierichter-amd
left a comment
There was a problem hiding this comment.
Looks great. Two small changes requested.
|
Decision: we're consolidating on this unified approach for #2381 over the single-concept variant in #2482. Reasoning is timing — the routing schema is still unreleased, so collapsing Two things to land before merge (both mechanical, per Eddie's review):
Heads-up on sequencing: #2380 (deterministic conditions) also touches |
Implements the
semantic_similarityclassifier for the Lemonade Router and unifies it with the genericclassifiertype: both now produce alabel → scoremap and are addressed bylabel+min_score/max_scoreband.reference_phrasesbecomes aconcept → phrasesmap, so one classifier can score many concepts in a single embedding pass.Rationale for the breaking change is here: https://github.com/lemonade-sdk/lemonade/blob/router/2381-semantic_similarity_classifier-unified/semantic_classifier_unification_rationale.md
What changed
semantic_similarityfillsScore::labelswith one entry per concept (max cosine over that concept's reference phrases), read back viascore_of(label)exactly likeclassifier. The condition layer (make_classifier_band_condition, leaf-factorylabel/default_labelresolution) has no semantic-vs-model branch.reference_phrasesis now an object mapping each concept name (the classifier's output label) to its exemplar phrases. Input is embedded once and scored against every concept; reference embeddings are computed once and cached (mutex-guarded, since classifiers are shared across concurrent requests).Score.labels[""]special case is gone.Score::primary()is now strict: it returns the lone entry of a genuinely label-less classifier and0.0otherwise, so a condition that omitslabelcan never silently match an arbitrary label of a multi-label score.make_classifierfactors outparse_labels/parse_default_label; the only type-specific step isparse_reference_phrases, which derives labels from the concept keys.semantic_similarityrejects an explicitlabelsfield (concept names are authoritative).route_policy.schema.jsonupdatesreference_phrasesto a non-empty object ofconcept → non-empty string[], and forbidslabelsonsemantic_similarity.Frozen-semantics / compatibility
reference_phrasesshape changes fromstring[]to{concept: string[]}— a breaking change to the (unreleased) routing schema, intentional and the whole point of the unification.Score::primary()redefined (lone-entry-or-0.0); the""-key convention is no longer special anywhere in the engine. Worth a row in the frozen-semantics table in README.md.Validation
test_routing_policy_semantic.cpp(multi-concept scoring, max-cosine, caching,on_error, failure paths) plus updates totest_routing_policy_registry.cpp,test_routing_policy_contract.cpp,test_routing_policy_evaluator.cpp, and thel2_semantic.jsonfixture /fake_classifier_services.h.ctest --output-on-failure -R "RoutingPolicy(Contract|Evaluator|Registry|Semantic)Test".Closes
Closes #2381.