Przenieś dema wektorowe Redis do wspólnego indeksu Azure AI Search
Przenieś wyszukiwanie wektorowe LangGraph z demonstracji Redis do wspólnego indeksu Azure AI Search: zadeklaruj schemat, filtrowaj według sesji, usuwaj na podstawie zapytania, zachowaj pozostałych użytkowników.
Dlaczego Redis nie był ostatecznym rozwiązaniem
Lokalne wyszukiwanie wektorowe w Redis jest idealne do demonstracji na laptopach. Środowiska współdzielone, wyszukiwanie z gwarancjami SLA oraz autoryzacja typu Azure skłaniają zespoły do wyboru Azure AI Search. Ta migracja zachowuje pipeline LangGraph, ale zmienia backend wektorowy.
Klasyczne wyszukiwanie w AI Search kontra ten model
Klasyczne wyszukiwanie według słów kluczowych opiera się na pokryciu leksykalnym. W migrowanym podejściu embeddingi są przechowywane obok tekstu, a wyniki są wybierane na podstawie podobieństwa semantycznego – opcjonalnie w połączeniu z filtrami. Azure AI Search staje się zarządzanym miejscem przechowywania tych wektorów.
Jedna decyzja, która musiała ulec zmianie: wspólny indeks czy indeks na sesję
Demostracje z Redis często tworzą tymczasowy indeks na każdą sesję. Azure AI Search preferuje indeks współdzielony z polem filtrującym sesję (lub użytkownika). Usuwanie całego indeksu w celu „wyłączenia sesji” to niewłaściwe rozwiązanie; właściwym sposobem jest usuwanie według filtru.
uv add langgraph langchain-core langchain-openai langchain-text-splitters \
azure-ai-documentintelligence azure-core \
langchain-redis redisvl \
python-dotenv
def get_vector_store() -> AzureSearch:
global _vector_store
if _vector_store is None:
_vector_store = AzureSearch(
azure_search_endpoint=config.AZURE_SEARCH_ENDPOINT,
azure_search_key=config.AZURE_SEARCH_API_KEY,
index_name=config.AZURE_SEARCH_INDEX_NAME,
embedding_function=embeddings,
fields=_FIELDS,
vector_search_dimensions=config.EMBEDDING_DIMENSIONS,
)
return _vector_store
_FIELDS = [
SimpleField(name="id", type=SearchFieldDataType.String, key=True, filterable=True),
SearchableField(name="content", type=SearchFieldDataType.String),
SearchField(
name="content_vector",
type="Collection(Edm.Single)",
searchable=True,
vector_search_dimensions=config.EMBEDDING_DIMENSIONS,
vector_search_profile_name="myHnswProfile",
),
SearchableField(name="metadata", type=SearchFieldDataType.String),
SimpleField(name="session_id", type=SearchFieldDataType.String, filterable=True),
SimpleField(name="file_name", type=SearchFieldDataType.String, filterable=True),
SimpleField(name="chunk_index", type=SearchFieldDataType.Int32, filterable=True, sortable=True),
]
state["retrieved"] = vs.similarity_search(
state["query"],
k=config.TOP_K,
filters=f"session_id eq '{state['session_id']}'",
)
def clear_session(session_id: str) -> None:
vs = get_vector_store()
results = vs.client.search(
search_text="*",
filter=f"session_id eq '{session_id}'",
select=["id"],
)
ids = [r["id"] for r in results]
if ids:
vs.delete(ids=ids)
az search service create \
--name "$SEARCH_SERVICE_NAME" \
--resource-group "$RESOURCE_GROUP" \
--location "$LOCATION" \
--sku basic \
--partition-count 1 \
--replica-count 1
SEARCH_ADMIN_KEY=$(az search admin-key show \
--resource-group "$RESOURCE_GROUP" \
--service-name "$SEARCH_SERVICE_NAME" \
--query primaryKey -o tsv)
AZURE_OPENAI_ENDPOINT=https://aif-cus-aisearchegs-dev-01.cognitiveservices.azure.com/
AZURE_OPENAI_API_KEY=<<redacted>>
# AZURE_OPENAI_API_VERSION = os.environ.get("AZURE_OPENAI_API_VERSION", "2024-10-21")
AZURE_OPENAI_EMBEDDING_DEPLOYMENT=text-embedding-3-small
AZURE_OPENAI_CHAT_DEPLOYMENT="gpt-5-mini"
# --- Azure Document Intelligence (used for all file text extraction) ---
DOCUMENTINTELLIGENCE_ENDPOINT=https://adi-cus-aisearchegs-dev-01.cognitiveservices.azure.com/
DOCUMENTINTELLIGENCE_KEY=<<redacted>>
AZURE_SEARCH_ENDPOINT=https://ais-cus-aisearchegs-dev-01.search.windows.net
AZURE_SEARCH_API_KEY=<<redacted>>
AZURE_SEARCH_INDEX_NAME=chat-file-search-index
azure.core.exceptions.HttpResponseError: The vector field 'content_vector'
must have the properties 'dimensions' and 'vectorSearchConfiguration' set.
TypeError: Object of type float32 is not JSON serializable
from azure.search.documents._utils.model_base import SdkJSONEncoder
_original_default = SdkJSONEncoder.default
def _numpy_safe_default(self, o):
if isinstance(o, np.floating):
return float(o)
if isinstance(o, np.integer):
return int(o)
return _original_default(self, o)
SdkJSONEncoder.default = _numpy_safe_default
uv run python -m aisearchmanualvectorization.main \
--session demo1 \
--files ./source/sample_bank_statement.pdf ./source/sample_loan_agreement.pdf
uv run python -m aisearchmanualvectorization.main \
--session demo1 \
--query "What's the overdraft protection fee?"
A: The overdraft protection transfer fee is $10.00 per occurrence.
Sources:
- sample_bank_statement.pdf (chunk 7): Overdraft Protection...
- sample_bank_statement.pdf (chunk 8): Interest Rate & Annual Percentage Yield...
- sample_bank_statement.pdf (chunk 9): Monthly Maintenance Fee...
- sample_bank_statement.pdf (chunk 3): <td>-$10.44</td> <td>$8,096.52</td>...
Krok po kroku: co zmieniło się w kodzie
get_vector_store() — nie jest już ograniczony do sesji
Zwraca klient powiązany z nazwą indeksu współdzielonego. Izolacja sesji odbywa się poprzez filtry metadanych, a nie oddzielne indeksy.
Schemat pola — deklarowany wyraźnie
Z góry definiuje się wymiary wektorów, pola zawartości oraz identyfikatory sesji podlegające filtrowaniu. Ukryte domyślne wartości, które działały w Redis, nie będą pasować do typów pól w Azure AI Search.
retrieve_node — filtr w postaci ciągu znaków zamiast obiektu filtru
Użyj wyrażenia session_id eq '…' (lub równoważnego filtru OData), aby fragmenty jednego użytkownika nie przeniknęły do wyników innego.
clear_session() — usuwanie za pomocą zapytania, a nie niszczenie indeksu
Wykonaj usunięcie z filtrem dla klucza sesji. Ponowne tworzenie indeksów dla każdej sesji przekroczy limity usługi i spowolni proces uruchamiania.
Lista kontrolna migracji
- Dostosuj wymiar embeddingu do pola wektora indeksu
- Ponownie wstaw fragmenty tylko wtedy, gdy zmienił się model embeddingu; w przeciwnym razie zaktualizuj istniejące fragmenty
- Zanim przeprowadzisz przeniesienie, uruchom Redis i Azure AI Search na przykładowych zapytaniach
- Gdzie to możliwe, przenieś dane poufne do Key Vault lub zarządzanej tożsamości
- Zaktualizuj instrukcje obsługi: nie zakładaj już, że „restart kontenera docker usunie stan Redis”
Wyniki i kompromisy
Azure AI Search wprowadza zarządzany skalowanie, narzędzia w portalu oraz mechanizm RBAC. Dodatkowo wprowadza czas przygotowania zasobów oraz ograniczenia związane z projektem wspólnych indeksów. W przypadku grafu pytań i odpowiedzi w formacie PDF struktura węzłów pozostała stabilna; zmieniły się jedynie adapter magazynowania i cykl życia sesji.
Zakończenie
Rozpatruj Redis jako koła pomocnicze, a Azure AI Search jako opony do jazdy po drodze. Zachowaj izolację sesji w filtrach, jasno zadeklaruj schemat danych i usuwaj elementy na podstawie zapytań. Orkiestracja LangGraph powinna ledwo to zauważyć – jeśli jednak tak się stanie, oznacza to, że abstrakcja była zbyt nieszczelna.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując najczęściej występujące pytania z zestawu referencyjnego. Jeśli stopień pokrycia spadnie, sprawdź klauzule filtrów i nazwy pól, zanim będziesz winić model embeddingu. Większość regresji podczas migracji w tym wzorcu wynika z błędów w filtrach, a nie z błędów w matematyce wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniesz model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniś model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najlepszych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniesz model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najlepszych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniś model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwini model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwini model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniesz model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniś model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniesz model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Wskazówka przy przenoszeniu: utrzymuj Redis w trybie tylko do odczytu przez tydzień, podczas gdy Azure AI Search obsługuje ruch produkcyjny, porównując pokrycie najwyższych 3 wyników w bazie pytań referencyjnych. Jeśli pokrycie spadnie, sprawdź klauzule filtrów i nazwy pól, zanim obwiniś model embeddingowy. Większość regresji podczas migracji w tym wzorcu to błędy filtrów, a nie błędy matematyki wektorowej.
Schemat dyscypliny ma znaczenie dwa razy: raz podczas tworzenia indeksu Azure AI Search, a ponownie przy aktualizacji modelu embeddingów. Niezgodności wymiarów powodują wyraźne błędy; niezgodności pól, które można filtrować, dają się zauważyć jedynie poprzez puste zestawy wyników. Należy dodać operację weryfikacyjną przy uruchamianiu, która odczytuje definicję indeksu i porównuje wymiary wektorów oraz nazwy pól sesji z aktualną konfiguracją.