zuhut-align
Cross-model embedding alignment. Bridge any two embedding models — zero-shot, no labels, no reindexing.
The Problem
You have millions of documents indexed with bge-large-en-v1.5 (1024d).
You want to query with MiniLM (384d) — faster, cheaper, fits on edge.
Without alignment: R@5 = 0.13 (unusable).
With ZUHUT: R@5 = 0.70 (91% of same-model ceiling) — zero reindexing.
Install
# Level 1 — ZeroShot (free, no GPU needed)
pip install zuhut-align
# Level 2 — PhaseMLP training (requires PyTorch)
pip install 'zuhut-align[mlp]'
# Full install
pip install 'zuhut-align[full]'
Quick Start
Level 1 — ZeroShot (Free)
from zuhut_align import ZUHUTClient
# No API key needed
client = ZUHUTClient()
adapter = client.create_adapter(src_dim=1024) # bge-large → MiniLM space
# Align your corpus vectors once (store the result in Qdrant/FAISS/etc.)
corpus_aligned = adapter.transform(corpus_vectors_1024d) # shape (N, 384)
# Align query at search time
query_aligned = adapter.transform(query_vector_1024d) # shape (1, 384)
# Now search corpus_aligned with query_aligned using cosine similarity
Result: R@5 jumps from 0.13 → 0.40. Zero training. Zero data. Instant.
Level 2 — PhaseMLP (Paid, ~5 min training)
from zuhut_align import ZUHUTClient
from sentence_transformers import SentenceTransformer
model_b = SentenceTransformer("paraphrase-MiniLM-L6-v2")
client = ZUHUTClient(api_key="zuhut-your-key-here")
trainer = client.create_adapter(src_dim=1024, tier="phasemlp")
# Train on 200–500 sample docs from your corpus (NOT the full corpus)
# Training time: ~5 min on CPU regardless of corpus size
trainer.train(
corpus_texts=sample_docs, # List[str], 200–500 docs
embedder=model_b.encode, # Your query-side encoder
)
# Now trainer is a PhaseMLP_Trainer with a trained .mlp
adapter = trainer # .transform() is available after training
corpus_aligned = adapter.transform(corpus_vectors_1024d)
query_aligned = adapter.transform(query_vector_1024d)
Result: R@5 = 0.70 — 91% of same-model ceiling.
Full Qdrant Example
from zuhut_align import ZUHUTClient
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
# 1. Models
model_a = SentenceTransformer("BAAI/bge-large-en-v1.5") # corpus model
model_b = SentenceTransformer("paraphrase-MiniLM-L6-v2") # query model
# 2. ZUHUT alignment (zero-shot)
client = ZUHUTClient()
adapter = client.create_adapter(src_dim=1024)
# 3. Encode & align corpus
corpus_vecs = model_a.encode(corpus_docs, normalize_embeddings=True)
corpus_zuhut = adapter.transform(corpus_vecs) # shape (N, 384)
# 4. Index into Qdrant (384d, one-time)
qdrant = QdrantClient(host="localhost", port=6333)
qdrant.recreate_collection("my_corpus", vectors_config=VectorParams(
size=384, distance=Distance.COSINE
))
qdrant.upsert("my_corpus", points=[
PointStruct(id=i, vector=corpus_zuhut[i].tolist())
for i in range(len(corpus_docs))
])
# 5. Search with cheap query model
query = "how do neural networks learn?"
q_vec = model_b.encode(query, normalize_embeddings=True)
q_zuhut = adapter.transform(q_vec)
results = qdrant.query_points("my_corpus", query=q_zuhut[0].tolist(), limit=5)
How It Works
Source Model (1024d)
↓
SVD Projection → 384d
↓
Procrustes Rotation ← synthetic anchors (N=250, SEED=42)
↓
L2 Normalize
↓
[PhaseMLP] ← optional, trained on your corpus pseudo-pairs
↓
Target Space (384d) — compatible with your indexed corpus
Zero-Shot (Level 1)
- Generates 250 synthetic Gaussian anchor pairs
- Learns an SVD projection (dim reduction) + Procrustes rotation
- No real data, no training, reproducible across runs
PhaseMLP (Level 2)
- Residual MLP (x + net(x)) with zero-init last layer
- Trained with InfoNCE contrastive loss on corpus pseudo-pairs
- Pseudo-pairs via word dropout (10% random word removal)
- Training invariant to corpus size: 200–500 docs → 5 min on CPU
Benchmark Results
Tested on Qdrant with BGE-large (corpus) vs MiniLM (query):
| Condition | R@5 | vs Ceiling |
|---|---|---|
| Same-model baseline (ceiling) | 0.767 | — |
| Cross-model, no alignment | 0.133 | -63.3% |
| + ZUHUT ZeroShot (Level 1) | 0.400 | -36.7% |
| + ZUHUT PhaseMLP v3 (Level 2) | 0.700 | -6.7% |
Vector databases tested: Qdrant ✓, FAISS ✓, LanceDB ✓, ChromaDB ✓
Tiers
| Level 1 ZeroShot | Level 2 PhaseMLP | Level 3 Engine | |
|---|---|---|---|
| Price | Free | Paid | Enterprise |
| Training data | None | 200–500 docs | None |
| Training time | 0s | ~5 min CPU | 0s |
| R@5 gain | +30% | +57% | +57% |
| Inference speed | Fast (NumPy) | Fast (PyTorch) | Ultra (Rust) |
| API key | Not required | Required | License key |
Requirements
- Python ≥ 3.9
- numpy ≥ 1.24
- scipy ≥ 1.10
- torch ≥ 2.0 (Level 2 only)
- sentence-transformers ≥ 2.7 (Level 2 only)
License
Apache 2.0 — Python SDK is open source.
The Rust engine (zuhri_engine) is proprietary (Level 3 / Enterprise).
Links
- 🌐 Website: zuhut.ai (coming soon)
- 📖 Docs: docs.zuhut.ai (coming soon)
- 📧 Enterprise: contact@zuhut.ai
- 🐛 Issues: github.com/zuhut-ai/zuhut-align/issues
Metadata
Release files for zuhut-align 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| zuhut_align-0.1.1.tar.gz | 15.0 kB | Without provenance | Details for zuhut_align-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| zuhut_align-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for zuhut_align-0.1.1-py3-none-any.whl |
Total release size: 29.7 kB
Release files / zuhut_align-0.1.1.tar.gz
| Download URL | zuhut_align-0.1.1.tar.gz |
|---|---|
| Size | 15.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2b2837a08fb8844279d6d1af8278fe12d64398cda51fcfb4f8128f9039ca339d
|
|
BLAKE2b-256 checksum How to use checksums |
fd5e569f0c07d8bc78de4b43a63614e6e9aeba32d1102557febfd99904eff79c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|
Release files / zuhut_align-0.1.1-py3-none-any.whl
| Download URL | zuhut_align-0.1.1-py3-none-any.whl |
|---|---|
| Size | 14.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dcf5343dd3efac3b7c6cf737d67b4154c4224a27ebfc63395e2c659e8a11d54c
|
|
BLAKE2b-256 checksum How to use checksums |
bcaf2f5d14c8cfc18db97513a730cee8a3b82e71a57e8bdbcda0e62bdc062f7f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|
Security for zuhut-align 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.