@anvia/qdrant
Qdrant vector store adapter for Anvia.
@anvia/qdrant connects Anvia's vector store interface to Qdrant. Use it for high-performance vector search with Qdrant's filtering and payload features.
Install
pnpm add @anvia/qdrantThe Qdrant client (@qdrant/js-client-rest) is a transitive dependency. You need a running Qdrant instance.
Quick Start
import { QdrantVectorStore } from "@anvia/qdrant";
import { createFastEmbedEmbeddingModel } from "@anvia/fastembed";
const model = await createFastEmbedEmbeddingModel();
// Connect (creates collection if missing)
const store = await QdrantVectorStore.connect({
collectionName: "documents",
vectorSize: 384, // must match your embedding model's dimensions
});
// Upsert embedded documents
await store.upsertDocuments([
{
id: "doc-1",
document: "Anvia is a TypeScript AI agent framework.",
embeddings: await model.embedTexts(["Anvia is a TypeScript AI agent framework."]),
},
]);
// Search
const index = store.index(model);
const results = await index.search({ query: "What is Anvia?", topK: 5 });
console.log(results[0].document);Connection Options
type QdrantVectorStoreConnectOptions = {
client?: QdrantClientLike; // pre-configured Qdrant client
collectionName: string; // required
vectorSize: number; // required: embedding dimensions
createIfMissing?: boolean; // default: true
distance?: QdrantDistance; // default: "Cosine"
};// Default: creates collection if missing, cosine distance
const store = await QdrantVectorStore.connect({
collectionName: "docs",
vectorSize: 384,
});
// Don't create if missing
const store = await QdrantVectorStore.connect({
collectionName: "docs",
vectorSize: 384,
createIfMissing: false,
});
// Custom distance metric
const store = await QdrantVectorStore.connect({
collectionName: "docs",
vectorSize: 384,
distance: "Euclid",
});
// Pre-configured client
import { QdrantClient } from "@qdrant/js-client-rest";
const store = await QdrantVectorStore.connect({
client: new QdrantClient({ url: "http://localhost:6333" }),
collectionName: "docs",
vectorSize: 384,
});Upserting Documents
await store.upsertDocuments([
{
id: "doc-1",
document: { title: "Getting Started", content: "..." },
metadata: { category: "guide", version: 2 },
embeddings: await model.embedTexts(["Getting Started content..."]),
},
]);- Documents are stored as Qdrant points with the document content and metadata in the payload
- Documents with multiple embeddings get indexed as
doc-1#embedding:0,doc-1#embedding:1, etc. - Point IDs are deterministic SHA-256 hashes of the document ID
Searching
const index = store.index(model);
// Basic search
const results = await index.search({ query: "agent tools", topK: 5 });
// With threshold
const results = await index.search({
query: "agent tools",
topK: 10,
threshold: 0.7,
});
// With metadata filter
const results = await index.search({
query: "agent tools",
topK: 5,
filter: { type: "eq", key: "category", value: "guide" },
});Metadata Filters
// Equality
{ type: "eq", key: "category", value: "guide" }
// Range (numeric values)
{ type: "gt", key: "version", value: 2 }
{ type: "lt", key: "version", value: 5 }
// Logical combinators
{ type: "and", filters: [...] }
{ type: "or", filters: [...] }Filters are translated to Qdrant's native filter format (must, should).
Distance Metrics
| Metric | Qdrant value | Notes |
|---|---|---|
| Cosine (default) | "Cosine" | Best for text embeddings |
| Euclid | "Euclid" | L2 distance |
| Dot | "Dot" | Dot product similarity |
Agent Tool
Expose the vector index as an agent tool:
const searchTool = index.asTool({
name: "search_docs",
description: "Search the documentation.",
});
const agent = new AgentBuilder("support", model)
.tool(searchTool)
.build();Error Handling
connect()throws if Qdrant is unreachableconnect({ createIfMissing: false })throws if the collection does not existupsertDocuments()throws if a document has zero embeddings- Metadata keys starting with
__anvia_are reserved and rejected
Related
- Retrieval Guide for RAG concepts
- Qdrant Reference for full API types
@anvia/fastembedfor local embeddings
