feat(acms): integrate FAISS into ACMS vector backend protocol
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 19s
CI / helm (pull_request) Successful in 21s
CI / lint (pull_request) Successful in 26s
CI / typecheck (pull_request) Successful in 50s
CI / quality (pull_request) Successful in 3m44s
CI / integration_tests (pull_request) Successful in 3m58s
CI / unit_tests (pull_request) Successful in 4m5s
CI / security (pull_request) Successful in 4m6s
CI / docker (pull_request) Successful in 1m18s
CI / coverage (pull_request) Successful in 14m17s
CI / e2e_tests (pull_request) Successful in 21m13s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Successful in 58m23s

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
This commit is contained in:
2026-03-26 13:13:35 +00:00
committed by Forgejo
parent 007af498b8
commit eff446f5e8
6 changed files with 1048 additions and 14 deletions
+102
View File
@@ -0,0 +1,102 @@
"""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,
)