Interfaces (ABCs)¶
Medha is built around three abstract base classes. Implement these to add new backends, embedders, or L1 cache implementations.
BaseEmbedder¶
BaseEmbedder defines the contract for any embedding provider. Implement embed() at minimum; override embed_batch() for efficiency.
from medha.interfaces.embedder import BaseEmbedder
class MyEmbedder(BaseEmbedder):
async def embed(self, text: str) -> list[float]:
...
async def embed_batch(self, texts: list[str]) -> list[list[float]]:
return [await self.embed(t) for t in texts]
Bases: ABC
Abstract base class for all embedding providers.
Source code in src/medha/interfaces/embedder.py
dimension
abstractmethod
property
¶
Return the vector dimension (e.g. 384, 768, 1536).
model_name
abstractmethod
property
¶
Return the model identifier for logging/debugging.
aembed(text)
abstractmethod
async
¶
Generate an embedding for a single text string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input text to embed. Must be non-empty. |
required |
Returns:
| Type | Description |
|---|---|
list[float]
|
A list of floats with length == self.dimension. |
Raises:
| Type | Description |
|---|---|
EmbeddingError
|
If the embedding generation fails. |
Source code in src/medha/interfaces/embedder.py
aembed_batch(texts, **kwargs)
abstractmethod
async
¶
Generate embeddings for multiple texts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
texts
|
list[str]
|
List of non-empty strings. |
required |
Returns:
| Type | Description |
|---|---|
list[list[float]]
|
A list of embeddings, one per input text, each with length == self.dimension. |
list[list[float]]
|
Order is preserved: result[i] corresponds to texts[i]. |
Raises:
| Type | Description |
|---|---|
EmbeddingError
|
If any embedding generation fails. |
Source code in src/medha/interfaces/embedder.py
embed(text)
¶
embed_batch(texts, **kwargs)
¶
VectorStorageBackend¶
VectorStorageBackend defines the contract for any vector store. Implement all abstract methods, then register your class in medha/backends/__init__.py.
from medha.interfaces.storage import VectorStorageBackend
class MyBackend(VectorStorageBackend):
async def initialize(self, collection: str, dimension: int) -> None: ...
async def upsert(self, entries: list[CacheEntry]) -> None: ...
async def query(self, vector: list[float], top_k: int) -> list[tuple[CacheEntry, float]]: ...
async def delete(self, entry_ids: list[str]) -> None: ...
async def count(self) -> int: ...
async def close(self) -> None: ...
Bases: ABC
Abstract base class for vector storage backends.
Source code in src/medha/interfaces/storage.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
initialize(collection_name, dimension, **kwargs)
abstractmethod
async
¶
Set up the storage backend (create collection, indexes, quantization).
This method is idempotent: calling it twice with the same arguments must not raise or duplicate data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
collection_name
|
str
|
Name of the vector collection. |
required |
dimension
|
int
|
Vector dimensionality (must match the embedder). |
required |
**kwargs
|
Any
|
Backend-specific configuration (quantization, HNSW params, etc.). |
{}
|
Raises:
| Type | Description |
|---|---|
StorageInitializationError
|
If setup fails. |
Source code in src/medha/interfaces/storage.py
search(collection_name, vector, limit=5, score_threshold=0.0)
abstractmethod
async
¶
Search for similar vectors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
collection_name
|
str
|
Collection to search. |
required |
vector
|
list[float]
|
Query vector. |
required |
limit
|
int
|
Max number of results. |
5
|
score_threshold
|
float
|
Minimum similarity score (0.0 - 1.0). |
0.0
|
Returns:
| Type | Description |
|---|---|
list[CacheResult]
|
List of CacheResult, sorted by descending score. |
Raises:
| Type | Description |
|---|---|
StorageError
|
If the search fails. |
Source code in src/medha/interfaces/storage.py
upsert(collection_name, entries)
abstractmethod
async
¶
Insert or update cache entries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
collection_name
|
str
|
Target collection. |
required |
entries
|
list[CacheEntry]
|
List of CacheEntry objects to upsert. |
required |
Raises:
| Type | Description |
|---|---|
StorageError
|
If the upsert fails. |
Source code in src/medha/interfaces/storage.py
scroll(collection_name, limit=100, offset=None, with_vectors=False)
abstractmethod
async
¶
Iterate over all points in a collection.
Used by fuzzy search (Tier 4) and admin operations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
collection_name
|
str
|
Collection to scroll. |
required |
limit
|
int
|
Batch size per scroll. |
100
|
offset
|
str | None
|
Pagination token from a previous scroll. |
None
|
with_vectors
|
bool
|
Whether to include vectors in results. |
False
|
Returns:
| Type | Description |
|---|---|
tuple[list[CacheResult], str | None]
|
Tuple of (results, next_offset). next_offset is None when done. |
Raises:
| Type | Description |
|---|---|
StorageError
|
If the scroll fails. |
Source code in src/medha/interfaces/storage.py
count(collection_name)
abstractmethod
async
¶
Return the number of points in a collection.
Raises:
| Type | Description |
|---|---|
StorageError
|
If the count fails. |
delete(collection_name, ids)
abstractmethod
async
¶
Delete points by ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
collection_name
|
str
|
Target collection. |
required |
ids
|
list[str]
|
List of point IDs to delete. |
required |
Raises:
| Type | Description |
|---|---|
StorageError
|
If the delete fails. |
Source code in src/medha/interfaces/storage.py
find_expired(collection_name)
abstractmethod
async
¶
Return IDs of entries with expires_at < now(UTC).
Raises:
| Type | Description |
|---|---|
StorageError
|
If the query fails. |
search_by_normalized_question(collection_name, normalized_question)
abstractmethod
async
¶
Find a single entry by exact normalized_question match.
Returns:
| Type | Description |
|---|---|
CacheResult | None
|
CacheResult if found, None otherwise. |
Source code in src/medha/interfaces/storage.py
find_by_query_hash(collection_name, query_hash)
abstractmethod
async
¶
Return all point IDs whose payload.query_hash matches query_hash.
Returns:
| Type | Description |
|---|---|
list[str]
|
List of string IDs (may be empty). |
Source code in src/medha/interfaces/storage.py
find_by_template_id(collection_name, template_id)
abstractmethod
async
¶
Return all point IDs whose payload.template_id matches template_id.
Returns:
| Type | Description |
|---|---|
list[str]
|
List of string IDs (may be empty). |
Source code in src/medha/interfaces/storage.py
drop_collection(collection_name)
abstractmethod
async
¶
Permanently delete the entire collection and all its data.
Raises:
| Type | Description |
|---|---|
StorageError
|
If the drop fails. |
close()
abstractmethod
async
¶
L1CacheBackend¶
L1CacheBackend defines the contract for the fast in-process cache layer (Tier 0 of the waterfall).
from medha.interfaces.l1_cache import L1CacheBackend
class MyL1Cache(L1CacheBackend):
async def get(self, key: str) -> CacheEntry | None: ...
async def set(self, key: str, entry: CacheEntry, ttl: int | None = None) -> None: ...
async def delete(self, key: str) -> None: ...
async def clear(self) -> None: ...
Bases: ABC
Interface for L1 (fast-lookup) cache backends.
L1 cache sits in front of the vector backend and provides sub-millisecond
responses for recently seen questions. The default implementation is
in-memory (InMemoryL1Cache); a Redis-backed implementation
(RedisL1Cache) enables sharing the cache across multiple service
instances in a horizontally-scaled deployment.