Need more information? Visit here
VectorWave
Semantic caching and golden-data regression testing for your LLM functions — from one decorator.
@vectorize captures every call your function makes — inputs, outputs, vectors, timing. That single execution history powers two things teams usually build and wire up separately: a semantic cache that skips re-running work you've already done, and a pytest regression oracle that catches the drift assert a == b can't. Drift detection and an experimental auto-diagnosis step fall out of the same history — but caching and testing are the core.
pip install vectorwave # Pro mode (Weaviate)
pip install "vectorwave[lite]" # Lite mode (LanceDB, no Docker)
pip install "vectorwave[otel]" # + OpenTelemetry mirror
Requirements
- Python: 3.10 – 3.13
- Docker (Pro mode only): runs the Weaviate database. Skip with Lite mode.
- OpenAI API Key (optional): for AI auto-documentation and high-performance embeddings.
How to reach us
- GitHub Issues: https://github.com/cozymori/vectorwave/issues
- Contributors: github.com/Cozymori/VectorWave/graphs/contributors
- Contributing guide: Contributing.md
🚀 What is VectorWave?
VectorWave solves two problems that LLM-backed Python code keeps running into — with one mechanism:
- The same prompt is processed twice. Direct LLM calls are expensive; the same semantic input usually has the same useful output. → Semantic caching with cosine-similarity lookup.
- You can't
assert a == bon an LLM. Output drifts a little every run. A regression that drops a clause looks identical to one that swaps a word. → Pytest plugin that compares to golden data by similarity, exact match, or LLM judge.
Both come from the same source: @vectorize records every call, and that golden execution history is reused as the cache and as the test oracle. Two more capabilities fall out of the same history — semantic drift detection and an experimental automatic error diagnosis step (opt-in; see below) — but caching and testing are the load-bearing core.
😊 Quick Start
1. Install
pip install vectorwave # Pro mode (default; requires Weaviate)
# or
pip install "vectorwave[lite]" # Lite mode — embedded LanceDB, no Docker
For Pro mode (Weaviate), bring your own instance or use the bundled dev stack:
vectorwave dev start # starts Weaviate + console on localhost
For Lite mode, no setup beyond pip install:
export VECTORWAVE_MODE=lite
2. Two demos in one decorator
A. Semantic caching
import time
from vectorwave import vectorize, initialize_database
initialize_database() # Pro mode only; in Lite mode (VECTORWAVE_MODE=lite) skip this
@vectorize(semantic_cache=True, cache_threshold=0.95, capture_return_value=True)
def expensive_llm_task(query: str):
time.sleep(2)
return f"Processed result for: {query}"
# First call: cache miss → ~2.0s
print(expensive_llm_task("How do I fix a Python bug?"))
# Second call — different words, same meaning: cache hit → ~0.02s
print(expensive_llm_task("What's the best way to fix a bug in Python?"))
B. Pytest regression test
After your function has built up some golden executions, drop this in any test file:
import pytest
@pytest.mark.vectorwave(
target="myapp.expensive_llm_task",
strategy="similarity",
threshold=0.85,
limit=10,
)
def test_no_regression():
pass
pytest re-runs the function against captured inputs and fails the test if the new output drifts below the threshold. There is also a vw_replay fixture for programmatic inspection. Configuration layers from marker kwargs → [tool.vectorwave.check."<target>"] in pyproject.toml → global defaults.
To pick a threshold instead of guessing:
vectorwave check calibrate myapp.expensive_llm_task
# Reports p5/p10/p25/p50/p75/p95 of pairwise similarity and a recommended threshold.
# Use --rerun to measure the honest noise floor by re-executing the function.
Experimental — Automatic error diagnosis: VectorWave can also read a function's runtime errors from its execution history and open a GitHub PR with a suggested patch (opt-in, Pro-only, needs an LLM + GitHub token). It's deliberately not a headline guarantee — see Automatic Error Diagnosis & Patch PRs under Key Features below.
⭐ Key Features
⚡ Semantic Caching
Cache LLM calls by meaning, not by exact string. Powered by HNSW vector indexes in Weaviate (Pro) or LanceDB (Lite). Threshold-based hit decisions per function.
- Latency: seconds → milliseconds.
- Cost: up to 90% fewer LLM tokens.
🧪 Pytest Regression Testing — new in 1.0
One marker, one threshold. Reuses your golden execution history as the test oracle.
@pytest.mark.vectorwave(target="myapp.fn", strategy="similarity", threshold=0.85)
def test_fn_regression():
pass
Three strategies: exact, similarity, llm (LLM-as-a-judge). See ADR-0002 for the design rationale.
🎯 Threshold Calibration — new in 1.0
vectorwave check calibrate myapp.summarize # cheap: output diversity
vectorwave check calibrate myapp.summarize --rerun # honest: noise floor
Outputs a percentile distribution + a ready-to-paste [tool.vectorwave.check."<target>"] snippet. Recommends strategy="exact" for deterministic targets and strategy="llm" for highly variable ones.
💾 Lite Mode — new in 1.0
Embedded LanceDB backend. No Docker, no ports, single on-disk directory.
pip install "vectorwave[lite]"
export VECTORWAVE_MODE=lite
Trade-off documented in ADR-0001: Lite mode gives up server-side vectorization and distributed batching in exchange for zero setup.
📡 OpenTelemetry Mirror — new in 1.0
VW spans appear in your existing OTel stack (Datadog, Honeycomb, Jaeger, Tempo) alongside the rest of your service traces.
pip install "vectorwave[otel]"
export OTEL_SERVICE_NAME=myapp
Mirror, not replacement — VW's own pipeline keeps full semantic context. See ADR-0003.
📊 Semantic Drift Radar
Detect when your users start asking things your model wasn't trained for.
- Anomaly Detection: distance between new queries and the Golden Dataset.
- Alerting: Discord / webhook notifications past the drift threshold (default 0.25).
🧪 Automatic Error Diagnosis & Patch PRs — experimental
Opt-in and Pro-only. When a @vectorized function raises, VectorWave can read the error from its execution history, ask an LLM for a fix, and open a GitHub Pull Request with the suggested patch — for you to review, never auto-merged.
- RAG over your execution history for root-cause context.
- You stay in the loop: it opens a PR, you approve. A cooldown prevents PR spam for the same error.
- Requirements:
OPENAI_API_KEY,GITHUB_TOKEN+GITHUB_REPO_NAME, and Pro mode (Weaviate).
This is the most experimental part of VectorWave and is intentionally not one of its headline guarantees. Rationale and internals in healer.py.
🏗 Architecture
VectorWave sits as a transparent layer between your application and the LLM / infrastructure. Storage is pluggable behind a VectorStore protocol — Pro (Weaviate) and Lite (LanceDB) backends share every other component.
Core Components
- Optimization Engine: intercepts function calls, checks semantic cache, returns a hit if one exists within threshold.
- Trace Context Manager: collects execution logs, inputs, outputs, vectors — without modifying your code structure.
- VectorStore Layer: backend-neutral storage protocol. New backends are a single-file addition.
- Auto-Diagnosis Pipeline (experimental): on errors, diagnoses from history and opens a patch PR for review.
- Check Plugin (
vectorwave.check): pytest entry-point + calibration CLI.
⏱ Performance
Caching gains (Pro mode, real LLM call)
| Metric | Direct execution | With VectorWave | Improvement |
|---|---|---|---|
| Latency (cache hit) | ~2.5 s (LLM API) | ~0.02 s | 125× faster |
| Cost (cache hit) | $0.03 / call | $0.00 | 100% savings |
Wrapper overhead (@vectorize on a bare Python function)
Median time per call, measured via pytest src/tests/benchmarks/ --benchmark-only on Darwin / CPython 3.12 / Apple Silicon:
| Variant | Median | Overhead vs bare |
|---|---|---|
| bare Python function (anchor) | 33.8 ns | 1× |
@vectorize, no capture |
11.4 µs | ~338× |
@vectorize + capture_return_value |
13.9 µs | ~411× |
@vectorize + capture_inputs |
14.8 µs | ~439× |
For any function doing >1 ms of real work, the wrapper tax is in the noise. The 33.8 ns baseline is an empty function — the "× vs bare" numbers look dramatic until you remember that.
Embeddings: how many, and how to keep them cheap
VectorWave embeds input text, and does so sparingly — one small vector per stored call:
Per @vectorize call |
Embeddings |
|---|---|
cache hit (semantic_cache=True) |
1 — the lookup vector is reused for the hit log |
cache miss (semantic_cache=True) |
2 — one to look up, one to store the new execution |
logging only (no semantic_cache) |
1 — the stored execution vector |
| a call that errors | 1 — the error message (used for error search) |
Function registration embeds a one-line description once per function and caches it (.vectorwave_functions_cache.json) — it does not re-embed on every call. Drift detection reuses the stored vector, so it adds zero extra embeddings.
Keeping it cheap:
VECTORIZER=huggingface(default) — embeddings run locally on CPU withall-MiniLM-L6-v2(384-dim). No API calls, no per-call cost, nothing leaves the process.VECTORIZER=weaviate_module— Weaviate embeds server-side (one round trip, no Python-side model).VECTORIZER=openai_client— each embedding is an OpenAI API call (highest quality, but real cost + latency per call). Reserve it for when you need it.VECTORIZER=none— no embeddings at all (disables semantic caching and drift).
Only calibration batches embeddings (embed_batch); the per-call path embeds one text at a time, and the batch manager batches DB writes, not embeddings.
🆚 How does VectorWave compare?
| Feature | GPTCache | ragas / deepeval / promptfoo | VectorWave |
|---|---|---|---|
| Semantic caching (execution-level) | O | X | O |
| Golden-data regression testing | X | O | O |
| Pytest integration | X | △ | O (marker + fixture) |
| Threshold calibration (CLI) | X | △ | O (percentile-backed) |
| Auto error diagnosis & patch PR (experimental) | X | X | O |
| OpenTelemetry mirror | X | X | O |
| Drift detection | X | △ | O |
| Zero-config local mode | △ | △ | O (Lite mode) |
Most teams pick a caching tool and a regression-testing tool and an observability integration and wire them up themselves. VectorWave gives you one decorator and one config file.
🧠 How it works
Unlike traditional Key-Value caching (e.g., Redis), VectorWave understands Context.
- Vectorization: function arguments → high-dimensional vectors via OpenAI / HuggingFace.
- Search: Approximate Nearest Neighbor (ANN) lookup in the vector store.
- Decision:
- Neighbor within
threshold→ return cached result. - Otherwise → execute function → async-log to DB (the new entry becomes future golden data).
- Neighbor within
Golden executions feed the regression-test layer. Drift over time feeds the radar. Errors feed the experimental auto-diagnosis step. Same substrate — caching and testing at the core, the rest derived.
🔒 Data Handling
VectorWave stores what your functions do, so it's worth knowing exactly what lands where:
- What's captured: per call, the function's inputs (with
capture_inputs/replay), return value (withcapture_return_value), a vector embedding of the input text, and timing/status metadata. The function's source code is also stored (used by regression replay and the experimental auto-diagnosis). - Redaction: before anything is stored, values whose keys match
sensitive_keysare replaced with[MASKED](defaults:password,api_key,token,secret,auth_token). Add your own PII/secret keys via settings — masking runs in themask_and_serializepath on the way in. - Where it lives: Lite mode keeps everything in a local on-disk directory (
.vectorwave/) — nothing leaves your machine. Pro mode writes to the Weaviate instance you run. - Embeddings & third parties: with
VECTORIZER=huggingface, embeddings are computed locally; withopenai_clientor Weaviate'stext2vec-openai, the input text is sent to OpenAI to be embedded. The experimental auto-diagnosis also sends source + error context to an LLM. - Retention: 1.0 has no automatic TTL — you own the store's lifecycle. Drop collections to delete history; back up the Weaviate volume (Pro) or the
.vectorwave/directory (Lite) as you would any datastore.
Treat the execution store like application logs that may contain user data: scope sensitive_keys to your fields, and prefer Lite mode with local embeddings when inputs are sensitive.
📚 Further reading
- CHANGELOG.md — release history.
- docs/adr/ — architectural decision records.
- Contributing.md — how to set up the dev environment and submit a PR.
😍 Contributing
We are extremely open to contributions — new vectorizers, better diagnosis prompts, additional backends, doc improvements, typo fixes. Please read the Contributing guide before opening a PR.
Metadata
Release files for vectorwave 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vectorwave-1.0.1.tar.gz | 79.7 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| vectorwave-1.0.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl | CPython 3.14 | CPython 3.14 | macOS 10.12+ x86-64, macOS 11.0+ ARM64, macOS 10.12+ universal2 (ARM64, x86-64) | Details |
| vectorwave-1.0.1-cp313-cp313-manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64 | Details |
| vectorwave-1.0.1-cp312-cp312-win_amd64.whl | CPython 3.12 | CPython 3.12 | Windows x86-64 | Details |
| vectorwave-1.0.1-cp312-cp312-manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64 | Details |
| vectorwave-1.0.1-cp311-cp311-manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.28+ x86-64 | Details |
| vectorwave-1.0.1-cp310-cp310-manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.28+ x86-64 | Details |
Total release size: 2.8 MB
Release files / vectorwave-1.0.1.tar.gz
| Download URL | vectorwave-1.0.1.tar.gz |
|---|---|
| Size | 79.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
958fe08766f8315ce2a70fc5ed4b5cfdfa23062d2ce419f2f494fa5ba00156c3
|
|
BLAKE2b-256 checksum How to use checksums |
9f0eb395b532ab6ab226b71945ab97f6f9a67b4fdb0ed1192511e1be24ab076d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|
Release files / vectorwave-1.0.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
| Download URL | vectorwave-1.0.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl |
|---|---|
| Size | 684.2 kB |
| Tags | CPython 3.14 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
99cf48f34771d112f89ebce40eb74e80a97cee8fe8d64f0ee45d9324dbb1383d
|
|
BLAKE2b-256 checksum How to use checksums |
76ce5c0871e04ea570a80198ba5e9c7091b857a6a8e178acc20f86dabdec5c89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|
Release files / vectorwave-1.0.1-cp313-cp313-manylinux_2_28_x86_64.whl
| Download URL | vectorwave-1.0.1-cp313-cp313-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 437.6 kB |
| Tags | CPython 3.13 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
28d0b1bc029262028a93024e8bf654bba250545c0b3c31f373d14b8ba531022d
|
|
BLAKE2b-256 checksum How to use checksums |
910f963ad559a699132df3c022f4cec02dc321e720000732ea536021e4a1059b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|
Release files / vectorwave-1.0.1-cp312-cp312-win_amd64.whl
| Download URL | vectorwave-1.0.1-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 286.4 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
c13f7425521d06b8aa4c54d1bd6a3236be92cc24e7c6e8416f60cbf1ae0f8ab7
|
|
BLAKE2b-256 checksum How to use checksums |
b95f0ea77d00b5f283b67f68b2dc3b87cf1d3408973137e62d403ab11145db7d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|
Release files / vectorwave-1.0.1-cp312-cp312-manylinux_2_28_x86_64.whl
| Download URL | vectorwave-1.0.1-cp312-cp312-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 437.3 kB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
67179585ecaff150508602cbacbfa5978f63ca7fea9020a3c225897a5bb9cf8c
|
|
BLAKE2b-256 checksum How to use checksums |
23f8a8e72447bb8cd8ee180eb318bfc7ed599c3251a91dbf2bf40c7bc2dca9c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|
Release files / vectorwave-1.0.1-cp311-cp311-manylinux_2_28_x86_64.whl
| Download URL | vectorwave-1.0.1-cp311-cp311-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 437.7 kB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
343b488b18f4e3135ddf8a77a6d38a18a89f5c216876eac9bff046f0dca74629
|
|
BLAKE2b-256 checksum How to use checksums |
86c3b8c3a4b4806b693131a2417038d0969a1aebb30d1f192cc9f2e21329a795
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|
Release files / vectorwave-1.0.1-cp310-cp310-manylinux_2_28_x86_64.whl
| Download URL | vectorwave-1.0.1-cp310-cp310-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 439.9 kB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
271c4c27c9081fb78127c3dc2e6d54dff993dd7e2e8612d28d8f9a80e362370b
|
|
BLAKE2b-256 checksum How to use checksums |
535e5f9d1372948ac72eb57a9dfc8870ff26c226982a754d23b1ae8ffa385663
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.15.0
|