KYWIO
Deterministic, sub-millisecond entity resolution. Research preview.
Results — sequestered test set
One general model, zero-shot: no training data from you. Thresholds were selected on validation and frozen before the test set was read. The test set was read once. Data: Magellan / Zenodo 8164151 (CC-BY-4.0).
| dataset | KYWIO v0.2.0 | rapidfuzz | fine-tuned transformer (literature) |
|---|---|---|---|
| DBLP-ACM | 0.980 | 0.895 | ~0.99 |
| Abt-Buy | 0.863 | 0.199 | ~0.89 |
| company names | 0.794 | 0.735 | — |
| Amazon-Google | 0.609 | 0.406 | ~0.76 |
0.33–0.79 ms per pair (2 vCPU, CPU only) · $0.0008–$0.0013 per million pairs (measured, worst case) · byte-identical across runs, restarts and hash seeds.
Acme Corp. to ACME Corporation at all
(0.385) and lost to plain rapidfuzz on names. Training on real name aliases
fixed that (0.981), but it taught the model that similar strings mean the same
entity — which makes it more permissive. Amazon-Google fell
0.658 → 0.609, and a new false-positive mode appeared
(below). v0.1.0 missed obvious matches; v0.2.0 can merge distinct brands. There was no
free lunch, and we are not pretending there was.
Known limitations — read before trusting a score
1. FALSE POSITIVES on brand-disagreement pairs (new in v0.2.0).
CA Internet Security Suite vs McAfee Internet Security Suite -> 0.788 reported as a MATCH at the default threshold (0.48) ✗ These are DIFFERENT companies. v0.1.0 rejected this correctly.
v0.2.0 can merge distinct brands. If a false
merge is expensive for you, raise the threshold. Calibration: this
false pair scores 0.788, while true matches score
Acme/ACME Corporation 0.981, IBM 0.877,
Microsoft 0.945.
2. Acronyms are learned, not understood.
International Business Machines vs IBM →
0.877 (v0.1.0: 0.000). It works because Wikidata aliases contain many
acronym pairs — not because the model reasons about abbreviation. Expect it to
fail on acronyms unlike those in Wikidata.
- Field-count dependence: FIXED in v0.2.0. The same true pair now scores 0.977 with 1 field and 0.973 with 3 (v0.1.0: 0.412 vs 0.862 — it flipped across the threshold purely by adding columns).
- Amazon-Google regressed 0.658 → 0.609. Same cause as the false positives: the permissiveness that fixed names hurts the hardest product set.
- No blocking: dedupe is O(n²), capped at 1,000 records. Not a large-scale linkage engine.
Our default threshold (0.48) maximises F1 on OUR mixed distribution, not yours. Score your own labelled pairs and pick your own.
Method
- Every success criterion — and the consequence of failing it — was pre-registered before the code existed.
- The test set is hash-pinned and read-only; the loader refuses to open it without an explicit flag and a stated claim, and every read is logged. It was read twice, for two distinct pre-registered claims, and is now closed.
- Thresholds selected on validation and frozen. No threshold search on test. Test F1 came in below validation on every dataset — which is what sequestering is for, and we publish the drop.
- The experiment log includes every negative result, including three baselines we built badly, got flattering numbers from, and had to throw away. It is not yet public — see the honesty note above.
Use it
MCP (works today, no hosting needed):
claude mcp add kywio -- python api/mcp_server.py
Tools: match_records, dedupe_records, kywio_info.
REST: not yet publicly hosted. openapi.json · agent card · llms.txt