Files
cleveragents-core/benchmarks/faiss_vector_backend_bench.py
aditya eff446f5e8 feat(acms): integrate FAISS into ACMS vector backend protocol
Add FAISS-backed ACMS read and write adapters on top of the shared VectorStoreService, wire them through the DI container, and cover indexing, scoped search, removal, and benchmark behavior with Behave and ASV.

Address review feedback by keeping the commit scoped to the FAISS backend work and replacing the loose vector-store cache typing with explicit FAISS store protocols instead of Any.

ISSUES CLOSED: #871
2026-03-30 13:19:08 +00:00

103 lines
3.4 KiB
Python

"""ASV benchmarks for the FAISS ACMS vector backend adapters."""
from __future__ import annotations
import importlib
import os
import shutil
import sys
import tempfile
from pathlib import Path
from typing import ClassVar
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
import cleveragents # noqa: E402
importlib.reload(cleveragents)
from cleveragents.application.services.config_service import ConfigService # noqa: E402
from cleveragents.application.services.faiss_vector_backend import ( # noqa: E402
FAISSVectorBackend,
FAISSVectorIndexBackend,
)
from cleveragents.application.services.vector_store_service import ( # noqa: E402
FAISS,
VectorStoreService,
)
from cleveragents.config.settings import Settings # noqa: E402
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork # noqa: E402
class VectorSearchLatencySuite:
"""Benchmark FAISS-backed ACMS vector indexing and search."""
params: ClassVar[list[int]] = [250, 1000]
param_names: ClassVar[list[str]] = ["documents"]
timeout = 120
def setup(self, documents: int) -> None:
if FAISS is None:
raise RuntimeError("FAISS is required for this benchmark")
self._saved_env = {
key: os.environ.get(key)
for key in (
"CLEVERAGENTS_INDEX_VECTOR_BACKEND",
"CLEVERAGENTS_INDEX_VECTOR_DIR",
"CLEVERAGENTS_EMBEDDING_PROVIDER",
"CLEVERAGENTS_EMBEDDING_DIMENSIONS",
)
}
self._tempdir = tempfile.mkdtemp(prefix="asv-faiss-vector-")
os.environ["CLEVERAGENTS_INDEX_VECTOR_BACKEND"] = "faiss"
os.environ["CLEVERAGENTS_INDEX_VECTOR_DIR"] = self._tempdir
os.environ["CLEVERAGENTS_EMBEDDING_PROVIDER"] = "fake"
os.environ["CLEVERAGENTS_EMBEDDING_DIMENSIONS"] = "32"
service = VectorStoreService(
Settings(),
UnitOfWork("sqlite:///:memory:", require_confirmation=False),
ConfigService(),
)
self._index_backend = FAISSVectorIndexBackend(service)
self._vector_backend = FAISSVectorBackend(service)
self._query = [1.0, 2.0, 3.0]
self._scope = frozenset({f"RES{i:04d}" for i in range(min(documents, 32))})
for i in range(documents):
vector = [float(i % 11), float((i * 3) % 17), float((i * 5) % 19)]
self._index_backend.index_embedding(
"local/bench",
f"uko:{i:04d}",
vector,
{
"resource_id": f"RES{i:04d}",
"location": f"src/file_{i:04d}.py",
"resource_type": "python",
},
)
def teardown(self, documents: int) -> None:
_ = documents
shutil.rmtree(self._tempdir, ignore_errors=True)
for key, value in self._saved_env.items():
if value is None:
os.environ.pop(key, None)
else:
os.environ[key] = value
def time_project_search(self, documents: int) -> None:
_ = documents
self._index_backend.search_similar("local/bench", self._query, limit=20)
def time_scoped_similarity_search(self, documents: int) -> None:
_ = documents
self._vector_backend.similarity_search(
self._query,
scope=self._scope,
top_k=20,
)