Vector Stores
Six backends, one interface. VectorRetriever, GraphLLM, and MonitoredGraph only ever talk to BaseVectorStore — swapping backends never touches any other file.
The contract
class BaseVectorStore(ABC):
@abstractmethod
def add(self, chunks: list[Chunk]) -> None: ...
@abstractmethod
def search(self, query_embedding: list[float], k: int = 4) -> list[ScoredChunk]: ...
@abstractmethod
def __len__(self) -> int: ...
def clear(self) -> None: ... # optional overrideImplement these four methods to add your own backend — Pinecone, Weaviate, Milvus. Nothing else in the library changes.
Compare
| Class | Install | Infra | Scale | Persists |
|---|---|---|---|---|
InMemoryVectorStore | numpy (always) | None | ~100k chunks | No |
SQLiteVectorStore | stdlib only | Single .db file | ~100k chunks | Yes |
ChromaVectorStore | pip install chromadb | None / Docker | Millions | Yes |
FAISSVectorStore | pip install faiss-cpu | Two local files | Billions (exact: ~1M) | Yes |
PGVectorStore | pip install psycopg2-binary pgvector | PostgreSQL server | Hundreds of millions | Yes |
QdrantVectorStore | pip install qdrant-client | None / Docker / Cloud | Billions | Yes |
Backends
InMemoryVectorStoreDefault — zero setupstore = InMemoryVectorStore()numpy L2-normalised vectors in a single (N × D) matrix. search() is one matrix–vector multiply — no Python loops. Vectors are lost when the process exits.
SQLiteVectorStorePersistent, zero new depsstore = SQLiteVectorStore(
db_path = "./knowledge_base.db",
table_name = "vector_chunks", # default
)Embeddings stored as BLOB columns (serialized float32). Loads all rows into a numpy matrix on first search(), cached until the next add(). Same scale ceiling as in-memory — the win here is purely persistence.
ChromaVectorStoreBest DX at scale# Embedded (local directory)
store = ChromaVectorStore(path="./chroma_db", collection="my_docs")
# HTTP server
store = ChromaVectorStore(url="http://localhost:8000", collection="my_docs")Exactly one of path or url. HNSW approximate nearest-neighbor indexing — fast and memory-efficient at scale, no in-memory matrix loading.
FAISSVectorStoreExact search, two filesstore = FAISSVectorStore(
index_path = "./docs.faiss",
meta_path = "./docs_meta.pkl",
dimension = None, # inferred from first add()
)IndexFlatIP — exact inner-product search on L2-normalised vectors. FAISS holds only raw floats; a parallel pickle file carries chunk text/metadata in the same order. Both files auto-load on restart if present.
PGVectorStoreStage 2 production targetstore = PGVectorStore(
connection_string = "postgresql://user:pass@localhost:5432/mydb",
table_name = "vector_chunks",
dimension = 1536, # must match your embedding model
)
store.close() # closes the psycopg2 connectionUses the <=> cosine-distance operator for server-side nearest-neighbour search. add() raises ValueError on any dimension mismatch. Live tests gated by PYWRAPAI_TEST_PG_URL.
QdrantVectorStoreMost deployment flexibilitystore = QdrantVectorStore(collection="my_docs", location=":memory:", dimension=1536)
store = QdrantVectorStore(collection="my_docs", location="./qdrant_data")
store = QdrantVectorStore(collection="my_docs", url="http://localhost:6333")
store = QdrantVectorStore(collection="my_docs", url="https://xyz.qdrant.io", api_key="...")Same constructor API for in-memory, local disk, Docker, and Cloud. Local disk mode holds an exclusive file lock — call store.close() before opening a second instance on the same path.
Optional dependencies
Everything beyond in-memory and SQLite is a pip extra — lazy-imported, so a missing package only raises when you actually instantiate that backend.
pip install pywrapai-graph | InMemoryVectorStore + SQLiteVectorStore always available |
pip install pywrapai-graph[chroma] | adds ChromaVectorStore |
pip install pywrapai-graph[faiss] | adds FAISSVectorStore |
pip install pywrapai-graph[pgvector] | adds PGVectorStore |
pip install pywrapai-graph[qdrant] | adds QdrantVectorStore |