Skip to main content

lsmvec-client — Python client for LSM-Vec

A thin, dependency-free Python client for the LSM-Vec vector database HTTP API. Uses only the Python standard library; numpy is optional (a convenience for bulk_build).

Install

pip install lsmvec-client            # core, zero dependencies
pip install lsmvec-client[numpy]     # + numpy for bulk_build convenience
pip install lsmvec-client[embed]     # + FastEmbed for client-side text embedding

Or run straight from the repo without installing:

import sys; sys.path.insert(0, "sdk/python")
from lsmvec_client import Client

Quickstart

from lsmvec_client import Client

client = Client(
    api_key="sk-live-...",                 # sent as Bearer token
    base_url="https://api.lsmvec.com",     # or http://localhost:8000 for local
)

# Insert with optional metadata
client.insert(1, [0.10, 0.20, 0.30, ...], metadata={"title": "intro"})

# Search
hits = client.search([0.10, 0.20, 0.30, ...], k=10)
for h in hits:
    print(h.id, h.distance)

# Filtered search (metadata predicate, same syntax as the HTTP API)
hits = client.search(
    [0.10, 0.20, ...], k=10,
    filter={"$and": [{"category": {"$eq": "docs"}}]},
)

Bulk build (initial load)

The fastest way to populate a new, empty database. Builds the whole index in memory (RNN-Descent) and writes it in one pass — 2-3× faster than per-vector inserts and higher recall. Initial-load only; the DB must be empty.

import numpy as np
from lsmvec_client import Client

client = Client(base_url="http://localhost:8000")

vectors = np.random.rand(100_000, 128).astype(np.float32)
report = client.bulk_build(vectors, threads=4)
print(report)   # {'n': 100000, 'elapsed_ms': ..., 'vectors_per_sec': ..., 'threads': 4}

bulk_build also accepts a plain list of equal-length float lists (no numpy required):

rows = [[0.1, 0.2, 0.3, 0.4], [0.5, 0.6, 0.7, 0.8], ...]
client.bulk_build(rows)

Pass payloads= (a list of n dicts/Nones, positionally mapped to the auto-assigned ids 0..n-1) to attach metadata during the build; the report then includes payloads_written. If the vectors build but a payload write fails, the raised LSMVecError.details carries rebuild_required: true.

report = client.bulk_build(vectors, payloads=[{"source": "docs"}] * len(vectors))

For incremental updates on an already-built index, use insert(), upsert(), or insert_batch() instead — bulk_build rejects a non-empty DB.

Batch insert (incremental)

insert_batch writes many already-embedded vectors over a non-empty index, keeping your own ids and payloads. It consumes an iterable lazily chunk_size at a time (a generator is fine) and POSTs each chunk in one request:

items = [(i, vec, {"source": "docs"}) for i, vec in enumerate(vectors)]
n = client.insert_batch(items, chunk_size=1000)   # -> total inserted

Items are (id, vector) or (id, vector, metadata). On a mid-batch engine error, LSMVecError.details carries inserted / failed_index so you can resume.

Text ingestion (client-side embedding)

With the [embed] extra, the client can chunk text, embed it, and store the vectors — embedding runs in the client; the server only stores and searches vectors.

from lsmvec_client import Client
from lsmvec_client.ingest import LocalEmbedder, ingest_text, search_text

client   = Client(base_url="http://localhost:8000")
embedder = LocalEmbedder("BAAI/bge-small-en-v1.5")   # 384-d, runs locally via FastEmbed

ids  = ingest_text(client, "doc-1", "Refunds take up to 30 days.", embedder, start_id=0)
hits = search_text(client, "how long do refunds take?", embedder, k=3)
print(hits[0].text)

LocalEmbedder needs the [embed] extra; ProviderEmbedder calls an OpenAI-compatible embeddings endpoint and is stdlib-only. The index dimension must equal the embedder's output dimension.

API

Method HTTP Notes
insert(id, vector, metadata=None) POST /v1/vectors metadata is any JSON object
upsert(id, vector) PUT /v1/vectors/:id insert-or-replace vector
get(id) -> dict GET /v1/vectors/:id {"id", "vector"}
delete(id) DELETE /v1/vectors/:id
get_payload(id) -> dict GET /v1/vectors/:id/payload
set_payload(id, payload) PUT /v1/vectors/:id/payload replace
merge_payload(id, partial) PATCH /v1/vectors/:id/payload RFC 7396 merge
search(vector, k=10, ef_search=None, filter=None) -> [SearchResult] POST /v1/search
insert_batch(items, chunk_size=1000) -> int POST /v1/vectors/batch incremental; keeps your ids + payloads
bulk_build(vectors, dim=None, threads=0, payloads=None) -> dict POST /v1/build/bulk empty DB only; optional payloads
stats() -> dict GET /v1/stats tombstone / bloom counters
health() -> bool GET /health
ready() -> bool GET /ready DB open + responsive

search returns a list of SearchResult(id: int, distance: float).

Errors

HTTP status codes map to typed exceptions (all subclass LSMVecError):

Status Exception
400 InvalidArgument
401 Unauthorized
404 NotFound
413 PayloadTooLarge
429 RateLimited
5xx ServerError
from lsmvec_client import NotFound

try:
    client.get(999999)
except NotFound:
    print("no such id")

Every exception keeps the full JSON error body on .details — e.g. inserted / failed_index after a mid-batch insert_batch error, or rebuild_required after a failed bulk_build(payloads=...).

Notes

  • Vectors are stored with 8-bit scalar quantization (SQ8). get() returns the dequantized vector, which differs from the input by up to ~range/255 per element. Distances and recall are computed on the quantized form.
  • id is an integer in [0, 2^63-1].
  • On insert / insert_batch, a non-empty metadata replaces the payload, an explicit {} clears it, and omitting it leaves the existing payload unchanged.
  • The client is synchronous and connection-per-request (stdlib urllib). For high-throughput ingestion, prefer bulk_build (empty index) or insert_batch (existing index) over a loop of insert.

Testing

Against a running server:

LSMVEC_TEST_URL=http://localhost:8000 LSMVEC_TEST_DIM=8 \
    python3 sdk/python/tests/test_client.py

Metadata

Release files for lsmvec-client 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lsmvec-client 0.2.0
File Size Uploaded
lsmvec_client-0.2.0.tar.gz 24.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lsmvec-client 0.2.0
File Interpreter ABI Platform
lsmvec_client-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 41.3 kB

Release files / lsmvec_client-0.2.0.tar.gz

Download URL lsmvec_client-0.2.0.tar.gz
Size 24.0 kB
Tags Source
SHA-256 checksum
How to use checksums
58b4cff72107aa1a5dfdc125b646c0caf94fb959a2369b9c6dd65b4b88e764e8
BLAKE2b-256 checksum
How to use checksums
bba20ab5751d71ab4808807aeeac304cc05cc67d31e8d31e162bf4bc3e95f143
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / lsmvec_client-0.2.0-py3-none-any.whl

Download URL lsmvec_client-0.2.0-py3-none-any.whl
Size 17.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
988a81709c597d6dbf146d944c599ae8e0843663f71bee54ebaafa7e1287a705
BLAKE2b-256 checksum
How to use checksums
295b064204b28d36d524fe4c4d66fcd67024b96c2c087c88682326145b25e850
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page