Klix
Decoupled decision heads on a shared semantic backbone.
A text passes through the embedding model exactly once (dense + sparse), after which any number
of heads (Choice, Score, Flag) operate on the precomputed vectors — each in its own
mathematical space. No model training, no slot limits, fully offline and CPU-only.
Architecture
Text ──► HybridBackbone (FastEmbed dense + TF-IDF sparse, once, ~10 ms)
│
├──► Choice (routing/classification: max-similarity + keyword boost)
├──► Score (continuous axis: low/high anchors + sigmoid)
├──► Flag (boolean: 2/3-class softmax with temperature)
└──► custom heads (subclass BaseHead)
- Shared backbone: Each text is embedded and TF-IDF-transformed exactly once. Whether you register 3 heads or 50, the extraction cost stays the same.
- Decoupled heads: Adding options to one
Choicenever affectsScoreorFlagresults. Every head encapsulates its own logic. - Declarative: Define schemas with example sentences, call
compile(), done. - Honest uncertainty: Optional reject poles (
Choice(reject_anchors=...),Flag(neutral_anchors=...)) returnNoneinstead of guessing; theScorehead reports acoveragesignal so you know when a score is noise.
Installation
uv add klix-engine
# or
pip install klix-engine
On first use, FastEmbed downloads the paraphrase-multilingual-MiniLM-L12-v2 model
(~120 MB, one-time, then cached locally). Everything runs offline afterwards.
Quickstart
from klix import DecisionEngine, Choice, Score, Flag
engine = DecisionEngine()
engine.add_head(
Choice(
name="target",
options={
"it_ops": ["VPN down", "server unreachable", "laptop won't boot"],
"ot_plant": ["robot cell stopped", "PLC fault", "plc-34 error", "cycle time deviation"],
"finance": ["cost center over budget", "approve invoice"],
"facility": ["oil spill in hall 2", "heating broken"],
},
# Optional: texts resembling these get value=None instead of a forced guess.
reject_anchors=["casual office chat", "birthday wishes", "off topic request"],
)
)
engine.add_head(
Score(
name="urgency",
low_anchors=["routine maintenance", "casual question"],
high_anchors=["emergency right now", "production line down", "acute danger"],
min_val=0.0,
max_val=3.0,
# "topk" pools the best 2 anchors per pole (robust against a single
# noisy anchor). Result dict carries "coverage": if it is low (< ~0.3),
# the text matched neither pole and the score is mostly noise.
aggregation="topk",
)
)
engine.add_head(
Flag(
name="is_security",
true_anchors=["hacker attack", "ransomware infection", "data exfiltration"],
false_anchors=["hardware broken", "ordinary IT problem", "network outage"],
neutral_anchors=["routine request", "general question", "other topic"],
threshold=0.5,
)
)
engine.compile()
res = engine.decide("plc-34 reports a fault, conveyor belt stopped immediately!")
print(res) # <DecisionResult (11 ms): target=ot_plant, urgency=2.9, is_security=False>
print(res.target) # 'ot_plant'
print(res.urgency) # 2.87
print(res.is_security) # False
print(res.details("is_security")) # {'value': False, 'probability': 0.03}
The heads are language-agnostic — the example uses English anchors, but German, French, or any other language works the same way (the backbone model is multilingual).
Custom Heads
Subclass BaseHead and implement evaluate(encoded):
import re
from klix import BaseHead
class RegExExtractionHead(BaseHead):
def __init__(self, name: str, pattern: str):
super().__init__(name)
self.re = re.compile(pattern)
def get_reference_texts(self) -> list[str]:
return [] # no reference texts needed
def fit(self, backbone) -> None:
pass
def evaluate(self, encoded) -> dict:
match = self.re.search(encoded.text)
return {"value": match.group(0) if match else None}
Development
uv sync # install dependencies
uv run pytest # run tests
uv run python examples/demo.py
Release chain (automated): bump the version in pyproject.toml and __init__.py,
commit, tag, push — GitHub Actions builds and publishes to PyPI automatically
(workflow publish.yml, secret PYPI_TOKEN):
git tag vX.Y.Z
git push origin main vX.Y.Z
License
MIT
Release files for klix-engine 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| klix_engine-0.1.4.tar.gz | 133.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| klix_engine-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 144.4 kB
Release files / klix_engine-0.1.4.tar.gz
| Download URL | klix_engine-0.1.4.tar.gz |
|---|---|
| Size | 133.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d0f98acf59d9c0b2366e46c71ed0d478c27908e5dba2dbe088c5868721358a90
|
|
BLAKE2b-256 checksum How to use checksums |
ab3c58de947d8cae250fa13f220270919046451d9196e4e10d79671974ecd6d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / klix_engine-0.1.4-py3-none-any.whl
| Download URL | klix_engine-0.1.4-py3-none-any.whl |
|---|---|
| Size | 10.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f5a7dc3f5275c2530fe96425c7b0181b39c8512210c9de80ef36ea93ced398af
|
|
BLAKE2b-256 checksum How to use checksums |
3be8f01d970e84925973981315b42f157dd6d44f92c938fc620fc4e5aabe1295
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|