Skip to content
GitHub

Vector (lexigram-vector)

Vector storage infrastructure for the Lexigram Framework with Qdrant, ChromaDB, PGVector, Pinecone, and in-memory backends. Provides embedding clients, vector search, hybrid retrieval, reranking, and Named DI multi-store support.


Vector storage infrastructure for the Lexigram Framework with Qdrant, ChromaDB, PGVector, Pinecone, and in-memory backends. Provides embedding clients, vector search, hybrid retrieval, reranking, and Named DI multi-store support.

Architecture note: This package provides infrastructure and data-layer functionality for vector storage and retrieval. While it is commonly used by AI and RAG features (lexigram-ai-rag), it is a general-purpose vector database abstraction suitable for any use case requiring semantic search, similarity matching, or high-dimensional data storage.

Full documentation: docs.lexigram.dev

Deep-dive guide: Vector Stores in lexigram-vector

Terminal window
uv add lexigram lexigram-vector
# With Qdrant support
uv add "lexigram-vector[qdrant]"
# With ChromaDB support
uv add "lexigram-vector[chroma]"
# With PGVector support (requires lexigram-sql for database access)
uv add "lexigram-vector[pgvector]"
# With Pinecone support
uv add "lexigram-vector[pinecone]"
# With embedding support
uv add openai # or anthropic, cohere, etc.
import asyncio
from lexigram import Application
from lexigram.contracts.data.vector import CollectionConfig, SearchQuery, VectorRecord, VectorStoreProtocol
from lexigram.vector import VectorModule
async def main() -> None:
async with Application.boot(modules=[VectorModule.stub()]) as app:
store = await app.container.resolve(VectorStoreProtocol)
# Create a collection
await store.create_collection(
CollectionConfig(name="documents", dimension=1536)
)
# Upsert vectors through the collection handle
collection = await store.get_collection("documents")
await collection.upsert(
[
VectorRecord(
id="doc1",
vector=[0.1] * 1536,
metadata={"title": "Document 1", "category": "tech"},
),
VectorRecord(
id="doc2",
vector=[0.2] * 1536,
metadata={"title": "Document 2", "category": "science"},
),
]
)
# Search
results = await collection.search(
SearchQuery(vector=[0.15] * 1536, top_k=5)
)
for result in results:
print(f"{result.id}: {result.metadata['title']} (score: {result.score})")
if __name__ == "__main__":
asyncio.run(main())

Zero-config usage: Call VectorModule.configure() with no arguments to start with all built-in defaults — no config file or environment variables needed. See the Config reference below for all default values.

Option 1 — YAML file (use when config lives in a single explicit file)

Section titled “Option 1 — YAML file (use when config lives in a single explicit file)”

Declare config in a YAML file loaded at a fixed, explicit path. LEX_* environment variables override YAML values at startup.

config_section = "vector" is already set on this class — section= can be omitted in all calls. Pass an explicit section= only to override the default (e.g. when this config is nested under a non-standard key).

# application.yaml — copy example.yaml for a fully-annotated starting point
vector:
backend: "qdrant" # memory, pgvector, pinecone, qdrant, chroma
default_dimension: 1536 # 1536 = OpenAI text-embedding-3-small
upsert_batch_size: 100
qdrant:
url: "http://localhost:6333"
api_key: null # LEX_VECTOR__QDRANT__API_KEY

Then load and wire it in your composition root:

from lexigram.vector.config import VectorConfig
from lexigram.vector import VectorModule
config = VectorConfig.from_yaml("application.yaml")
app.add_module(VectorModule.configure(config))

Environment variables override YAML values and use the LEX_VECTOR__ prefix:

Terminal window
LEX_VECTOR__BACKEND=qdrant
Section titled “Option 2 — Profiles + Environment Variables (recommended for production, staging, Docker, CI/CD)”

Loads a base application.yaml, then overlays an environment-specific file (application.production.yaml, application.staging.yaml, etc.) based on the LEX_PROFILE environment variable. LEX_* env vars are applied last as the final override layer.

Terminal window
# Set LEX_VECTOR__* env vars before starting the process
export LEX_VECTOR__ENABLED=true
from lexigram.vector.config import VectorConfig
from lexigram.vector import VectorModule
config = VectorConfig.from_env_profile()
app.add_module(VectorModule.configure(config))

Loading order: application.yaml (base) → application.{profile}.yaml (overlay, if LEX_PROFILE is set) → LEX_* environment variables (final override). Missing files are silently skipped so this is safe to call in all environments.

Option 3 — Python (use when config is dynamic or computed at boot)

Section titled “Option 3 — Python (use when config is dynamic or computed at boot)”

Build config in code at boot time. Use this when settings are derived at runtime — e.g. secrets fetched from a vault, per-tenant configurations, or when you need multiple module instances with different settings.

from lexigram.vector import VectorModule
from lexigram.vector.config import QdrantConfig, VectorConfig
app.add_module(VectorModule.configure(
VectorConfig(
backend="qdrant",
qdrant=QdrantConfig(
url="http://localhost:6333",
),
)
))

Top-level configuration loaded from application.yaml’s vector: key or from LEX_VECTOR__* environment variables.

FieldDefaultEnv varDescription
enabledTrueLEX_VECTOR__ENABLEDEnable the vector store subsystem
backend"memory"LEX_VECTOR__BACKENDVector store backend ("memory", "qdrant", "chroma", "pgvector", "pinecone")
default_distance_metricDistanceMetric.COSINELEX_VECTOR__DEFAULT_DISTANCE_METRICDefault distance metric for new collections
default_index_typeIndexType.HNSWLEX_VECTOR__DEFAULT_INDEX_TYPEDefault index type for new collections
default_dimension1536LEX_VECTOR__DEFAULT_DIMENSIONDefault vector dimension (matches OpenAI text-embedding-ada-002)
upsert_batch_size100LEX_VECTOR__UPSERT_BATCH_SIZENumber of vectors per upsert batch
max_retries3LEX_VECTOR__MAX_RETRIESMaximum number of retries for operations
retry_delay0.5LEX_VECTOR__RETRY_DELAYDelay between retries in seconds
pgvectorPgVectorConfig()PGVector-specific settings
pineconePineconeConfig()Pinecone-specific settings
qdrantQdrantConfig()Qdrant-specific settings
weaviateWeaviateConfig()Weaviate-specific settings
memoryMemoryConfig()In-memory-specific settings
backends[]List of NamedVectorConfig entries for multi-store support
tenancyVectorTenancyConfig()Per-tenant collection isolation (VectorTenancyConfig)
collection_name"default"LEX_VECTOR__COLLECTION_NAMEDefault collection name for AI-layer operations
enable_cacheFalseLEX_VECTOR__ENABLE_CACHEEnable embedding caching (requires a CacheBackend binding)
cache_ttl86400LEX_VECTOR__CACHE_TTLEmbedding cache TTL in seconds (default: 24 hours)

When backends is non-empty, each entry is registered under Annotated[VectorStoreProtocol, Named(entry.name)]. The first entry (or the one with primary=True) also receives the unnamed VectorStoreProtocol binding for backward compatibility.

FieldDefaultEnv varDescription
url"http://localhost:6333"LEX_VECTOR__QDRANT__URLQdrant server URL
api_keyNoneLEX_VECTOR__QDRANT__API_KEYQdrant API key (optional)
grpc_port6334LEX_VECTOR__QDRANT__GRPC_PORTgRPC port for Qdrant
prefer_grpcTrueLEX_VECTOR__QDRANT__PREFER_GRPCWhether to prefer gRPC over HTTP
timeout30.0LEX_VECTOR__QDRANT__TIMEOUTRequest timeout in seconds
FieldDefaultEnv varDescription
database"primary"LEX_VECTOR__PGVECTOR__DATABASEName of the database backend from db.backends to use
schema"public"LEX_VECTOR__PGVECTOR__SCHEMADatabase schema for vector tables
default_lists100LEX_VECTOR__PGVECTOR__DEFAULT_LISTSDefault number of lists for IVFFlat index
default_probes10LEX_VECTOR__PGVECTOR__DEFAULT_PROBESDefault number of probes for IVFFlat index
default_ef_search64LEX_VECTOR__PGVECTOR__DEFAULT_EF_SEARCHDefault ef_search for HNSW index
table_prefix"vec_"LEX_VECTOR__PGVECTOR__TABLE_PREFIXPrefix for vector storage tables
create_extensionTrueLEX_VECTOR__PGVECTOR__CREATE_EXTENSIONWhether to create pgvector extension if missing

Note: PGVector requires lexigram-sql and a configured DatabaseProviderProtocol. The database field refers to a named database backend from db.backends.

FieldDefaultEnv varDescription
api_key""LEX_VECTOR__PINECONE__API_KEYPinecone API key (required)
environment""LEX_VECTOR__PINECONE__ENVIRONMENTPinecone environment (e.g., "us-west1-gcp")
index_name""LEX_VECTOR__PINECONE__INDEX_NAMEName of the Pinecone index
namespace""LEX_VECTOR__PINECONE__NAMESPACEDefault namespace for the index
timeout30.0LEX_VECTOR__PINECONE__TIMEOUTRequest timeout in seconds
pool_threads4LEX_VECTOR__PINECONE__POOL_THREADSNumber of threads for the connection pool
FieldDefaultEnv varDescription
max_collections100LEX_VECTOR__MEMORY__MAX_COLLECTIONSMaximum number of collections in memory
max_vectors_per_collection100,000LEX_VECTOR__MEMORY__MAX_VECTORS_PER_COLLECTIONMaximum number of vectors per collection

Configuration for a single named vector store backend (used in multi-store setups):

FieldDescription
nameUnique backend identifier (used as the Named() DI key)
primaryWhether this backend also receives the unnamed VectorStoreProtocol binding
backendVector store driver for this named backend
pgvectorPgVectorConfig for this backend
pineconePineconeConfig for this backend
qdrantQdrantConfig for this backend
memoryMemoryConfig for this backend

Example multi-store setup:

from lexigram.vector.config import (
NamedVectorConfig,
PgVectorConfig,
QdrantConfig,
VectorConfig,
)
VectorModule.configure(
VectorConfig(
backends=[
NamedVectorConfig(
name="primary",
primary=True,
backend="qdrant",
qdrant=QdrantConfig(
url="http://qdrant-primary:6333",
),
),
NamedVectorConfig(
name="rag",
backend="pgvector",
pgvector=PgVectorConfig(
database="rag",
schema="vectors",
),
),
]
)
)

Inject named stores:

from typing import Annotated
from lexigram.contracts.data.vector.protocols import VectorStoreProtocol
from lexigram.di.markers import Named
class MyService:
def __init__(
self,
store: VectorStoreProtocol, # primary
rag: Annotated[VectorStoreProtocol, Named("rag")],
) -> None:
self.store = store
self.rag = rag
MethodDescription
VectorModule.configure(config=None, enable_reranking=False)Vector store with explicit VectorConfig; registers VectorStoreProtocol and VectorCollectionProtocol. enable_reranking enables cross-encoder reranking of retrieval results
VectorModule.stub(config=None)In-memory backend with no external service dependencies, for tests
  • Multi-backend vector storage — Qdrant, ChromaDB, PGVector, Pinecone, and in-memory backends
  • Embedding client — OpenAI-compatible async client for generating embeddings (OpenAICompatibleEmbeddingClient)
  • Embedding cache — In-memory and persistent caching to reduce embedding API calls (EmbeddingCache, InMemoryEmbeddingCache)
  • Vector search — Similarity search with metadata filtering and distance metrics
  • Hybrid retrieval — BM25 + vector search with reciprocal rank fusion (HybridRetriever, BM25Retriever, RRFReranker)
  • Reranking — Cross-encoder reranking, diversity reranking, and similarity reranking for improved relevance (CrossEncoderReranker, DiversityReranker, RerankerPipeline)
  • Metadata filtering — Structured filtering on metadata fields with backend-specific filter compilers
  • Named DI multi-store — Multiple vector stores registered as Annotated[VectorStoreProtocol, Named("rag")]
  • Collection management — Create, delete, list collections with automatic schema inference
  • Batch operations — Efficient batch upsert, delete, and search with configurable batch sizes
  • Distance metrics — Cosine, Euclidean, and dot product similarity metrics
  • Index types — HNSW, IVFFlat, and backend-specific index configuration
async with Application.boot(modules=[VectorModule.stub()]) as app:
store = await app.container.resolve(VectorStoreProtocol)
# Test with the in-memory backend
...
FileWhat it contains
src/lexigram/vector/module.pyVectorModule.configure() and .stub()
src/lexigram/vector/config.pyVectorConfig, VectorTenancyConfig, NamedVectorConfig, backend configs
src/lexigram/vector/di/provider.pyVectorProvider boot and registration
src/lexigram/vector/di/factories.pyFactory functions for creating vector stores
src/lexigram/vector/backends/qdrant/Qdrant backend implementation
src/lexigram/vector/backends/pgvector/PGVector backend implementation
src/lexigram/vector/backends/pinecone/Pinecone backend implementation
src/lexigram/vector/backends/chroma.pyChromaDB backend implementation
src/lexigram/vector/backends/memory.pyIn-memory backend implementation
src/lexigram/vector/tenancy/Tenancy resolver, decorator, and Pinecone namespace resolver
src/lexigram/vector/embedding/client.pyOpenAICompatibleEmbeddingClient
src/lexigram/vector/embedding/cache.pyEmbedding cache implementations
src/lexigram/vector/search/hybrid.pyHybrid retrieval and BM25
src/lexigram/vector/search/reranking.pyReranking strategies
src/lexigram/vector/adapters/vector_store.pyVectorStoreAdapter
src/lexigram/vector/adapters/document_store.pyDocumentVectorStoreAdapter