Declare an embedding contract on the collection: the model name and dimensions that produced its vectors. From then on, any query vector whose length doesn't match is rejected with an error that names the declared model — instead of being silently padded or searched as if models were interchangeable. The contract is also discoverable by every client of the collection, so a teammate (or an AI agent) six months from now can ask the collection which model to embed with rather than guessing from tribal knowledge. Vector Panda never embeds text and never calls an embedding provider on your behalf — the contract is an attestation about vectors you produce client-side, and that's precisely what makes it trustworthy: nothing on our side can drift from it.
Why this matters: two different embedding models produce vectors in unrelated spaces. Query a MiniLM collection with an OpenAI embedding and every score is meaningless — no error, just quietly wrong results. Dimension mismatch is the one detectable symptom, and the contract turns it into a loud, named failure.
Declare it right after creating the collection:
from veep import VP, samples
df = samples.dataframe()
vp = VP.from_creds()
vp.collections.create("contract-demo", tier="hot")
vp.vectors.upsert("contract-demo", dataframe=df)
vp.collections.update("contract-demo", embedding_contract={
"model": "sentence-transformers/all-MiniLM-L6-v2",
"dimensions": 384,
})
Any client can now discover it:
col = vp.collections.get("contract-demo")
print(col.embedding_contract)
{'dimensions': 384, 'model': 'sentence-transformers/all-MiniLM-L6-v2', 'version': 1}
And a wrong-model query fails by name instead of succeeding wrongly:
try:
vp.vectors.query("contract-demo", vector=[0.1] * 768) # wrong model's shape
except Exception as e:
print(e)
Query vector has dimension 768 but collection 'contract-demo' declares embeddings from 'sentence-transformers/all-MiniLM-L6-v2' at 384 dimensions. Embed queries with that model, or update the collection's embedding_contract.
Correct-model queries are unaffected — declare a contract on a live collection and nothing changes for clients already embedding with the right model:
hit = vp.vectors.query("contract-demo",
vector=samples.encode("a small team plans an elaborate casino heist"),
top_k=1)[0]
print(f"{hit.score:.4f} {hit.metadata['title']}")
0.4782 Ocean's Eleven
A few details worth knowing:
- The declared dimensions must match the collection's actual vector dimension — you can't declare a 768-dim contract on a 384-dim collection. The declaration is validated against reality at write time.
- Optional keys:
metricandnormalized, if you want to record those conventions too. - Clearing: pass
embedding_contract=Nonetoupdate()to remove a declared contract. - For agents: the
com.vectorpanda/databaseMCP server exposesget_embedding_contract/set_embedding_contract, so an agent connecting to your collection can discover the right model programmatically before embedding a single query.
Pair the contract with an empirically chosen score threshold — both are per-model decisions, and What score does vector search return? covers the other half.
vp.collections.delete("contract-demo")
