qdrant-client.cr
qdrant-client
Idiomatic, RAG-oriented Qdrant client for Crystal — a thin, stable wrapper over qdrant-api (the generated, fully-typed transport layer). It exposes exactly the vector working set a retrieval engine needs — create a collection, upsert vectors, KNN search, delete by id, count — and nothing else.
Need the full Qdrant surface (filters, scroll, snapshots, cluster, aliases, sparse/multi-vectors…)? Reach for
qdrant-apidirectly. This shard is the opinionated sugar on top of it.
Features
- Stable, hand-written API —
Qdrant::Collection+Qdrant::Hit. No generated type ever leaks into the public surface (anti-corruption layer): whenqdrant-apiis regenerated against a new Qdrant release, the compiler localizes any drift to a handful of internal call sites, not your code. - The RAG working set, ~5 ops —
ensure,upsert(single + batch),search,delete(ids),count. Deliberately no filter DSL: deletes go by id, KNN is unfiltered (fuse on your side). - Connection as the happy path — an existing, often remote Qdrant (Qdrant Cloud): HTTPS +
api-keyheader, one dedicated collection per corpus. - Tested against a real Qdrant — the spec suite runs against a Qdrant container, doubling as a contract/canary check in CI.
Installation
Add the dependency to your shard.yml:
dependencies:
qdrant-client:
github: jbox-web/qdrant-client.cr
Then run shards install.
Usage
require "qdrant-client"
# An existing Qdrant, often remote / Cloud → HTTPS + api-key header.
docs = Qdrant::Collection.new("docs",
url: "https://my-qdrant:6333",
api_key: ENV["QDRANT_API_KEY"]?)
docs.ensure(dim: 768, distance: :cosine) # idempotent
docs.upsert(42_i64, embedding) # single
docs.upsert([ # batch
{43_i64, embedding_a},
{44_i64, embedding_b},
])
hits = docs.search(query_embedding, top_k: 20) # => Array(Qdrant::Hit){id, score}
hits.first.id # Int64
hits.first.score # Float32
docs.delete([42_i64, 43_i64]) # purge by id
docs.count # Int64
Qdrant::Hit is the only stable result type — {id : Int64, score : Float32, payload : Hash(String, JSON::Any)}. Search returns {id, score}; hydrate the content from your own store of record by id.
Compatibility
The chain qdrant-client → qdrant-api → pinned OpenAPI spec → Qdrant server isn't obvious from a version number alone, so it's spelled out here:
qdrant-client |
qdrant-api |
Qdrant server (CI canary) |
|---|---|---|
| 0.1.x | ~> 0.1 | v1.12.x |
Qdrant point ids are modeled as
Int32by the OpenAPI layer (ExtendedPointId).Qdrant::Hit#idis exposed asInt64but round-trips throughInt32— safe as long as ids stay below 2³¹.
Development
mise dev:deps # shards install
mise dev:qdrant-up # local Qdrant container (integration specs)
mise dev:check # build + ameba + specs
mise dev:qdrant-down
License
MIT — Nicolas Rodriguez.
qdrant-client.cr
- 0
- 0
- 0
- 0
- 3
- about 4 hours ago
- June 20, 2026
MIT License
Sat, 20 Jun 2026 01:42:53 GMT