Repository navigation
Expand file tree
/
Copy pathvector_store.py
More file actions
203 lines (165 loc) · 7.93 KB
/
Copy pathvector_store.py
File metadata and controls
203 lines (165 loc) · 7.93 KB
1
2
3
4
5
6
7
8
9
10
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# Copyright 2025 © BeeAI a Series of LF Projects, LLC
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Protocol
from beeai_framework.backend.embedding import EmbeddingModel
from beeai_framework.backend.types import Document, DocumentWithScore
from beeai_framework.backend.utils import load_module, parse_module
from beeai_framework.utils.strings import validate_class_name
class QueryLike(Protocol):
"""Protocol for objects that can be converted to query strings.
Any object that implements the `__str__` method can be used as a query
for vector store searches.
"""
def __str__(self) -> str: ...
__all__ = ["QueryLike", "VectorStore"]
class VectorStore(ABC):
"""Abstract base class for vector database implementations.
VectorStore provides a unified interface for storing and retrieving document
embeddings in vector databases. It supports semantic search by finding documents
similar to a query based on vector similarity.
The class handles:
- Adding documents with automatic embedding generation
- Semantic search with similarity scoring
- Dynamic instantiation of provider-specific stores
Subclasses must implement:
- `add_documents`: Store documents in the vector database
- `search`: Perform similarity search
- `_class_from_name`: Factory method for dynamic instantiation
Example:
>>> from beeai_framework.backend import EmbeddingModel, VectorStore
>>>
>>> # Create embedding model
>>> embedding_model = EmbeddingModel.from_name("openai:text-embedding-3-small")
>>>
>>> # Create vector store
>>> vector_store = VectorStore.from_name(
... "langchain:Chroma",
... embedding_model=embedding_model,
... collection_name="my_documents"
... )
>>>
>>> # Add documents
>>> documents = [
... Document(content="Python is a programming language", metadata={"source": "doc1"}),
... Document(content="JavaScript is used for web development", metadata={"source": "doc2"})
... ]
>>> ids = await vector_store.add_documents(documents)
>>>
>>> # Search for similar documents
>>> results = await vector_store.search("programming languages", k=2)
>>> for doc_with_score in results:
... print(f"Score: {doc_with_score.score}, Content: {doc_with_score.document.content}")
>>>
>>> # Use different vector stores
>>> vector_store = VectorStore.from_name(
... "langchain:FAISS",
... embedding_model=embedding_model
... )
"""
@classmethod
def from_name(cls, name: str, *, embedding_model: EmbeddingModel, **kwargs: Any) -> VectorStore:
"""
Import and instantiate a VectorStore class dynamically.
Args:
name:
A *case-sensitive* string in the format "integration:ClassName".
- `integration` is the name of the Python package namespace (e.g. "langchain").
- `ClassName` is the name of the vector store class to load (e.g. "Milvus").
embedding_model:
An instance of the embedding model required to initialize the vector store.
**kwargs:
Additional positional or keyword arguments to be passed to the class.
Returns:
VectorStore:
An instantiated vector store object of the requested class.
Raises:
ImportError:
If the specified class cannot be found in any known integration package.
ValueError:
If the provided name is not in the required "integration:ClassName" format.
"""
parsed_module = parse_module(name)
if not parsed_module.entity_id:
raise ValueError(
f"Only provider {parsed_module.provider_id} was specified. Vector Store name was not specified."
)
validate_class_name(parsed_module.entity_id)
target: type[VectorStore] = load_module(parsed_module.provider_id, "vector_store")
return target._class_from_name(
class_name=parsed_module.entity_id,
embedding_model=embedding_model,
**kwargs,
)
@abstractmethod
async def add_documents(self, documents: list[Document]) -> list[str]:
"""Add documents to the vector store.
This method takes a list of documents, generates embeddings for their content
using the configured embedding model, and stores them in the vector database.
Each document is assigned a unique identifier.
Args:
documents: List of Document objects to add to the vector store.
Each document should have content and optional metadata.
Returns:
A list of unique identifiers (IDs) for the added documents,
in the same order as the input documents.
Raises:
NotImplementedError: If the subclass doesn't implement this method.
Example:
>>> documents = [
... Document(content="First document", metadata={"source": "file1.txt"}),
... Document(content="Second document", metadata={"source": "file2.txt"})
... ]
>>> ids = await vector_store.add_documents(documents)
>>> print(ids) # ['id1', 'id2']
"""
raise NotImplementedError("Implement me")
@abstractmethod
async def search(self, query: QueryLike, k: int = 4, **kwargs: Any) -> list[DocumentWithScore]:
"""Search for documents similar to the query.
This method performs semantic search by converting the query to an embedding
and finding the k most similar documents in the vector store based on
vector similarity (e.g., cosine similarity).
Args:
query: The search query. Can be a string or any object implementing
the QueryLike protocol (has __str__ method).
k: The number of most similar documents to return. Defaults to 4.
**kwargs: Additional provider-specific search parameters
(e.g., filter conditions, score threshold).
Returns:
A list of DocumentWithScore objects, sorted by similarity score
(highest first). Each contains the document and its similarity score.
Raises:
NotImplementedError: If the subclass doesn't implement this method.
Example:
>>> # Basic search
>>> results = await vector_store.search("machine learning", k=3)
>>> for result in results:
... print(f"Score: {result.score:.3f}")
... print(f"Content: {result.document.content}")
>>>
>>> # Search with filters (provider-specific)
>>> results = await vector_store.search(
... "python programming",
... k=5,
... filter={"source": "documentation"}
... )
"""
raise NotImplementedError("Implement me")
@classmethod
@abstractmethod
def _class_from_name(cls, class_name: str, embedding_model: EmbeddingModel, **kwargs: Any) -> VectorStore:
"""Create a vector store instance from a class name (internal method).
This method must be implemented by integration-specific subclasses to
handle the dynamic instantiation of vector store classes.
Args:
class_name: The name of the vector store class to instantiate.
embedding_model: The embedding model to use for generating vectors.
**kwargs: Arguments to pass to the vector store constructor.
Returns:
An instantiated VectorStore of the specified class.
Raises:
NotImplementedError: If the subclass doesn't implement this method.
"""
raise NotImplementedError("Implement me")