Retrieval Augmented Generation (RAG) in Azure KI Search

Retrieval Augmented Generation (RAG) ist eine Architektur, welche die Funktionen eines Large Language Model (LLM) wie ChatGPT erweitert, indem ein Informationsempfangssystem hinzugefügt wird, das die Grunddaten bereitstellt. Durch das Hinzufügen eines Informationsempfangssystems können Sie die von einem LLM verwendeten Grunddaten steuern, wenn es eine Antwort formuliert. Für eine Unternehmenslösung bedeutet die RAG-Architektur, dass Sie die generative KI auf Ihre Unternehmensinhalte beschränken können, die aus vektorisierten Dokumenten und Bildern stammen, und andere Datenformate, wenn Sie Einbettungsmodelle für diese Inhalte haben.

Die Entscheidung darüber, welches Informationsempfangssystem verwendet werden soll, ist entscheidend, da sie die Eingaben für das LLM bestimmt. Das Informationsempfangssystem sollte Folgendes bereitstellen:

  • Indizierungsstrategien, die skaliert geladen und aktualisiert werden, für alle Ihre Inhalte in der von Ihnen benötigten Häufigkeit.

  • Abfragefunktionen und Relevanzoptimierung. Das System sollte relevante Ergebnisse in Kurzformaten zurückgeben, die für die Erfüllung der Tokenlängenanforderungen von LLM-Eingaben erforderlich sind.

  • Sicherheit, globale Reichweite und Zuverlässigkeit sowohl für Daten als auch für Vorgänge.

  • Integration in Einbettungsmodelle für die Indizierung und Chatmodelle oder Language Understanding-Modelle zum Abrufen.

Azure KI Search ist eine bewährte Lösung zum Abrufen von Informationen in einer RAG-Architektur. Es bietet Indizierungs- und Abfragefunktionen mit der Infrastruktur und Sicherheit der Azure-Cloud. Mithilfe von Code und anderen Komponenten können Sie eine umfassende RAG-Lösung entwerfen, die alle Elemente für generative KI über Ihre proprietären Inhalte enthält.

Hinweis

Sie sind neu bei Copilot und RAG-Konzepten? Sehen Sie sich Vektorsuche und modernstes Abrufen für Apps mit generativer KI an.

Microsoft verfügt über mehrere integrierte Implementierungen für die Verwendung von Azure KI Search in einer RAG-Lösung.

Kuratierte Ansätze erleichtern den Einstieg, aber für mehr Kontrolle über die Architektur benötigen Sie eine benutzerdefinierte Lösung. Diese Vorlagen erstellen End-to-End-Lösungen in:

Im restlichen Teil dieses Artikels wird erläutert, wie Azure KI Search in eine benutzerdefinierte RAG-Lösung passt.

Eine allgemeine Zusammenfassung des Musters sieht wie folgt aus:

  • Beginnen Sie mit einer Benutzerfrage oder Anfrage (Prompt).
  • Senden Sie sie an Azure KI Search, um relevante Informationen zu finden.
  • Senden Sie die am häufigsten bewerteten Suchergebnisse an das LLM.
  • Verwenden Sie die Funktionen für natürliches Sprachverständnis und natürliche Sprachfolgerung des LLM, um eine Antwort auf den ersten Prompt zu generieren.

Azure KI Search stellt Eingaben für den LLM-Prompt bereit, trainiert das Modell jedoch nicht. In der RAG-Architektur gibt es kein eigenes Training. Das LLM wird mit öffentlichen Daten vortrainiert, generiert jedoch Antworten, die durch Informationen vom Retriever erweitert werden.

RAG-Muster, die Azure KI Search enthalten, weisen die in der folgenden Abbildung angegebenen Elemente auf.

Architekturdiagramm des Informationsabrufs mit Suche und ChatGPT.

  • App-UX (Web-App) für die Benutzererfahrung
  • App-Server oder Orchestrator (Integrations- und Koordinationsebene)
  • Azure KI Search (Information Retrieval System)
  • Azure OpenAI (LLM für generative KI)

Die Web-App stellt die Benutzererfahrung, Präsentation, den Kontext und die Benutzerinteraktion bereit. Fragen oder Prompts von einem Benutzer beginnen hier. Eingaben durchlaufen die Integrationsebene, gehen zuerst zum Informationsabruf, um die Suchergebnisse zu erhalten, werden allerdings auch zum LLM übertragen, um den Kontext und die Absicht festzulegen.

Der App-Server oder Orchestrator ist der Integrationscode, der die Übergaben zwischen dem Abrufen von Informationen und dem LLM koordiniert. Eine Option besteht darin, den Workflow mithilfe der LangChain zu koordinieren. LangChain ist in Azure KI Searchintegriert und erleichtert die Einbindung von Azure KI Search als Retriever in Ihren Workflow. Semantic Kernel ist eine weitere Option.

Das Informationsabrufsystem stellt den durchsuchbaren Index, die Abfragelogik und die Nutzlast (Abfrageantwort) bereit. Der Suchindex kann Inhalte mit oder ohne Vektoren enthalten. Obwohl die meisten Beispiele und Demos Vektorfelder enthalten, ist das keine Notwendigkeit. Die Abfrage wird mithilfe der vorhandenen Suchmaschine in Azure KI Search ausgeführt, welches Schlüsselwort- (oder Ausdrucks-) und Vektorabfragen verarbeiten kann. Der Index wird im Voraus basierend auf einem von Ihnen definierten Schema erstellt und mit Ihren Inhalten geladen, die aus Dateien, Datenbanken oder Speicher stammen.

Das LLM erhält den ursprünglichen Prompt sowie die Ergebnisse von Azure KI Search. Das LLM analysiert die Ergebnisse und formuliert eine Antwort. Wenn es sich bei dem LLM um ChatGPT handelt, kann es sich bei der Benutzerinteraktion um ein Hin-und-Her-Gespräch handeln. Wenn Sie Davinci verwenden, ist der Prompt möglicherweise eine vollständig zusammengesetzte Antwort. Eine Azure-Lösung verwendet höchstwahrscheinlich Azure OpenAI, aber es gibt keine feste Abhängigkeit von diesem spezifischen Dienst.

Azure KI-Suche bietet keine native LLM-Integration für prompt flows oder Chaterhaltung, daher müssen Sie Code für die Orchestrierung und den Zustand schreiben. Sie können die Demoquelle (Azure-Samples/azure-search-openai-demo) als Vorlage betrachten, mit dem eine vollständige Lösung verbunden ist. Außerdem wird Azure KI Studio oder Azure OpenAI Studio empfohlen, um RAG-basierte Azure KI-Suche-Lösungen zu erstellen, die in LLMs integriert werden.

In der Azure KI-Suche werden alle durchsuchbaren Inhalte in einem Suchindex gespeichert, der in Ihrem Suchdienst gehostet wird. Ein Suchindex ist für schnelle Abfragen mit Millisekunden Antwortzeiten konzipiert, sodass die internen Datenstrukturen entworfen wurden, um dieses Ziel zu ermöglichen. Zu diesem Zweck speichert ein Suchindex indizierte Inhalteund nicht ganze Inhaltsdateien wie ganze PDFs oder Bilder. Intern enthalten die Datenstrukturen invertierte Indizes von tokenisiertem Text, Vektorindizes für Einbettungen und unveränderten Text für Fälle, in denen ein wortwörtlicher Abgleich erforderlich ist (z. B. in Filtern, Fuzzy-Suche, RegEx-Abfragen).

Wenn Sie die Daten für Ihre RAG-Lösung einrichten, verwenden Sie die Features, die einen Index in Azure KI Search erstellen und laden. Ein Index enthält Felder, die Ihre Quellinhalte duplizieren oder darstellen. Ein Indexfeld kann eine einfache Übertragung sein (ein Titel oder eine Beschreibung in einem Quelldokument wird zu einem Titel oder einer Beschreibung in einem Suchindex), oder ein Feld kann die Ausgabe eines externen Prozesses enthalten, z. B. Vektorisierung oder Skill-Verarbeitung, die eine Darstellung oder Textbeschreibung eines Bilds generiert.

Da Sie wahrscheinlich wissen, welche Art von Inhalt Sie durchsuchen möchten, bedenken Sie die Indizierungsfeatures, die für jeden Inhaltstyp gelten:

Inhaltstyp Indiziert als Features
text Token, unveränderter Text Indexer können Klartext aus anderen Azure-Ressourcen wie Azure Storage und Cosmos DB abrufen. Sie können auch jeden JSON-Inhalt an einen Index übertragen. Verwenden Sie zum spontanen Ändern von Text Analysetools und Normalizer, um während der Indizierung lexikalische Verarbeitung hinzuzufügen. Synonymzuordnungen sind nützlich, wenn Quelldokumente keine Terminologie enthalten, die in einer Abfrage verwendet werden kann.
text Vektoren 1 Text kann extern in Segmente unterteilt, vektorisiert und dann als Vektorfelder in Ihrem Index indiziert werden.
image Token, unveränderter Text 2 Skills für OCR und Bildanalyse können Bilder für die Texterkennung oder Bildmerkmale verarbeiten. Bildinformationen werden in durchsuchbaren Text konvertiert und dem Index hinzugefügt. Skills haben eine Indexeranforderung.
image Vektoren 1 Bilder können extern für eine mathematische Darstellung von Bildinhalten vektorisiert und dann als Vektorfelder in Ihrem Index indiziert werden. Sie können ein Open Source-Modell wie OpenAI CLIP verwenden, um Text und Bilder im gleichen Einbettungsbereich zu vektorisieren.

1 Die allgemein verfügbare Funktionalität für die Vektorunterstützung erfordert, dass Sie andere Bibliotheken oder Modelle für die Datensegmentierung und Vektorisierung aufrufen. Bei der integrierten Vektorisierung (Vorschau) sind diese Schritte jedoch eingebettet. Codebeispiele mit beiden Ansätzen finden Sie unter azure-suche-vektoren repo.

2Skills sind integrierte Unterstützung für KI-Anreicherung. Für OCR- und Bildanalyse führt die Indizierungspipeline einen internen Aufruf der Azure KI Vision-APIs durch. Diese Skills übergeben ein extrahiertes Bild zur Verarbeitung an Azure KI und erhalten die Ausgabe als Text, der von Azure KI Search indiziert wird.

Vektoren bieten die beste Möglichkeit für unterschiedliche Inhalte (mehrere Dateiformate und Sprachen), da Inhalte universell in mathematischen Darstellungen ausgedrückt werden. Vektoren unterstützen auch die Ähnlichkeitssuche: Übereinstimmung mit den Koordinaten, die der Vektorabfrage am ehesten ähneln. Im Vergleich zur Stichwortsuche (oder Begriffssuche), die mit tokenisierten Ausdrücken übereinstimmt, ist die Ähnlichkeitssuche differenzierter. Es ist eine bessere Wahl, wenn im Inhalt oder in Abfragen Mehrdeutigkeit oder Interpretationsanforderungen vorliegen.

Sobald sich Ihre Daten in einem Suchindex befindet, verwenden Sie die Abfragefunktionen von Azure KI Search, um Inhalte abzurufen.

In einem Nicht-RAG-Muster erstellen Abfragen einen Roundtrip von einem Suchclient. Die Abfrage wird übermittelt und in einer Suchmaschine ausgeführt. Die Antwort wird daraufhin an die Clientanwendung zurückgegeben. Die Antwort oder Suchergebnisse bestehen ausschließlich aus den im Index gefundenen wortwörtlichen Inhalten.

In einem RAG-Muster werden Abfragen und Antworten zwischen der Suchmaschine und dem LLM koordiniert. Die Frage oder Abfrage eines Benutzers wird sowohl an die Suchmaschine als auch an das LLM als Prompt weitergeleitet. Die Suchergebnisse kommen von der Suchmaschine zurück und werden zu einem LLM umgeleitet. Die Antwort, die sie an den Benutzer zurückgibt, ist generative KI, entweder eine Summierung oder Antwort von dem LLM.

Es gibt keinen Abfragetyp in Azure KI Search – nicht einmal semantische oder Vektorsuche – welche neue Antworten erstellt. Nur das LLM stellt generative KI bereit. Hier sind die Funktionen in Azure KI Search, die zum Formulieren von Abfragen verwendet werden:

Abfragefeature Zweck Argumente für die Verwendung
Einfache oder vollständige Lucene-Syntax Abfrageausführung für Text und numerische Inhalte ohne Vektoren Die Volltextsuche eignet sich am besten für genaue Übereinstimmungen und nicht für ähnliche Übereinstimmungen. Volltextsuchabfragen werden mithilfe des BM25-Algorithmus bewertet und unterstützen die Relevanzoptimierung durch Bewertungsprofile. Sie unterstützt auch Filter und Facetten.
Filter und Facetten Gilt nur für Textfelder oder numerische Felder (ohne Vektoren). Reduziert den Suchumfang basierend auf Einschluss- oder Ausschlusskriterien. Fügt Präzision zu Ihren Abfragen hinzu.
Semantische Rangfolge Bewertet ein BM25-Resultset mit semantischen Modellen neu. Erzeugt Beschriftungen und Antworten im Kurzformat, die als LLM-Eingaben nützlich sind. Einfacher als Bewertungsprofile und je nach Inhalt eine zuverlässigere Technik für die Relevanzoptimierung.
Vektorsuche Abfrageausführung über Vektorfelder für die Ähnlichkeitssuche, wobei die Abfragezeichenfolge ein oder mehrere Vektoren ist. Vektoren können alle Inhaltstypen in jeder Sprache darstellen.
Hybridsuche Kombiniert jegliche oder sämtliche oben genannte Abfragetechniken. Abfragen mit und ohne Vektoren werden parallel ausgeführt und in einem einzelnen Resultset zurückgegeben. Die wichtigsten Gewinne bei Genauigkeit und Rückruf kommen von hybride Abfragen.

Die Abfrageantwort strukturieren

Die Antwort einer Abfrage liefert die Eingabe an das LLM, sodass die Qualität Ihrer Suchergebnisse für den Erfolg von entscheidender Bedeutung ist. Die Ergebnisse sind ein tabellarischer Zeilensatz. Die Zusammensetzung oder Struktur der Ergebnisse hängt ab von:

  • Feldern, die bestimmen, welche Teile des Indexes in der Antwort enthalten sind.
  • Zeilen, die eine Übereinstimmung aus dem Index darstellen.

Felder werden in Suchergebnissen angezeigt, wenn das Attribut „abrufbar“ ist. Eine Felddefinition im Indexschema weist Attribute auf, und diese bestimmen, ob ein Feld in einer Antwort verwendet wird. Nur „abrufbare“ Felder werden in Volltext- oder Vektorabfrageergebnissen zurückgegeben. Standardmäßig werden alle „abrufbaren“ Felder zurückgegeben, aber Sie können „select“ verwenden, um eine Teilmenge anzugeben. Neben „abrufbar“ gibt es keine Einschränkungen für das Feld. Felder können eine beliebige Länge oder einen beliebigen Typen aufweisen. Hinsichtlich der Länge gibt es in Azure KI Search keine maximale Feldlängenbeschränkung, aber es gibt Grenzwerte für die Größe einer API-Anforderung.

Zeilen sind Übereinstimmungen mit der Abfrage, priorisiert nach Relevanz, Ähnlichkeit oder beidem. Standardmäßig werden die Ergebnisse für die Volltextsuche oder k-nearest-neighbour Übereinstimmungen für die Vektorsuche auf die obersten 50 Übereinstimmungen begrenzt. Sie können die Standardwerte ändern, um den Grenzwert bis zum Maximum von 1.000 Dokumenten zu erhöhen oder zu reduzieren. Sie können auch die „top“ verwenden und Paging-Parameter überspringen, um Ergebnisse als eine Reihe von in Seiten eingeteilten Ergebnissen abzurufen.

Nach Relevanz bewerten

Wenn Sie mit komplexen Prozessen, einer großen Menge an Daten und Erwartungen von Antworten in Millisekunden arbeiten, ist es wichtig, dass jeder Schritt etwas beiträgt und die Qualität des Endergebnisses verbessert. Auf der Informationsabrufseite gibt es die Relevanzoptimierung, eine Aktivität, welche die Qualität der an das LLM gesendeten Ergebnisse verbessert. Nur die relevantesten oder am meisten übereinstimmenden Dokumente sollten in Ergebnisse einbezogen werden.

Relevanz gilt für die Suche über Schlüsselwörter (ohne Vektor) und für Hybridabfragen (für die Felder ohne Vektor). In Azure KI Search gibt es keine Relevanzoptimierung für Ähnlichkeitssuche und Vektorabfragen. BM25 Ranking wird als Bewertungsalgorithmus für die Volltextsuche verwendet.

Die Relevanzoptimierung wird durch Features unterstützt, welche die BM25-Rangfolge verbessern. Zu diesen Ansätzen gehören:

  • Bewertungsprofile, welche die Suchbewertung erhöhen, wenn Übereinstimmungen in einem bestimmten Suchfeld oder in anderen Kriterien gefunden werden.
  • Semantische Rangfolge, die ein BM25-Resultset neu bewertet, indem semantische Modelle von Bing verwendet werden, um Ergebnisse für eine passendere Semantik an die ursprüngliche Abfrage neu zu ordnen.

Im Vergleichs- und Benchmarktest erzeugen Hybridabfragen mit Text- und Vektorfeldern, ergänzt durch semantische Rangfolge über die BM25-bewerteten Ergebnisse, die relevantesten Ergebnisse.

Beispielcode einer Azure KI Search-Abfrage für RAG-Szenarien

Der folgende Code wird aus der Datei retrievethenread.py von einer Demowebsite kopiert. Sie erzeugt content für das LLM aus hybriden Abfragesuchergebnissen. Sie können eine einfachere Abfrage schreiben, aber dieses Beispiel ist einschließlich der Vektorsuche und der Stichwortsuche mit semantischer Neubewertung und Rechtschreibprüfung. In der Demo wird diese Abfrage verwendet, um anfängliche Inhalte abzurufen.

# Use semantic ranker if requested and if retrieval mode is text or hybrid (vectors + text)
if overrides.get("semantic_ranker") and has_text:
    r = await self.search_client.search(query_text,
                                  filter=filter,
                                  query_type=QueryType.SEMANTIC,
                                  query_language="en-us",
                                  query_speller="lexicon",
                                  semantic_configuration_name="default",
                                  top=top,
                                  query_caption="extractive|highlight-false" if use_semantic_captions else None,
                                  vector=query_vector,
                                  top_k=50 if query_vector else None,
                                  vector_fields="embedding" if query_vector else None)
else:
    r = await self.search_client.search(query_text,
                                  filter=filter,
                                  top=top,
                                  vector=query_vector,
                                  top_k=50 if query_vector else None,
                                  vector_fields="embedding" if query_vector else None)
if use_semantic_captions:
    results = [doc[self.sourcepage_field] + ": " + nonewlines(" . ".join([c.text for c in doc['@search.captions']])) async for doc in r]
else:
    results = [doc[self.sourcepage_field] + ": " + nonewlines(doc[self.content_field]) async for doc in r]
content = "\n".join(results)

Integrationscode und LLMs

Eine RAG-Lösung, die Azure KI Search enthält, erfordert andere Komponenten und Code zum Erstellen einer vollständigen Lösung. Während in den vorherigen Abschnitten der Abruf von Informationen über Azure KI Search behandelt wurde und welche Features zum Erstellen und Abfragen von durchsuchbaren Inhalten verwendet werden, führt dieser Abschnitt die LLM-Integration und -Interaktion ein.

Notizbücher in den Demo-Repositories sind ein guter Ausgangspunkt, da sie Muster zum Übergeben von Suchergebnissen an ein LLM zeigen. Der Großteil des Codes in einer RAG-Lösung besteht aus Aufrufen des LLM, sodass Sie ein Verständnis dafür entwickeln müssen, wie diese APIs funktionieren, was jenseits des Umfangs dieses Artikels liegt.

Der folgende Zellenblock im Chat-read-retrieve-read.ipynb Notebook zeigt Suchaufrufe im Kontext einer Chatsitzung an:

# Execute this cell multiple times updating user_input to accumulate chat history
user_input = "Does my plan cover annual eye exams?"

# Exclude category, to simulate scenarios where there's a set of docs you can't see
exclude_category = None

if len(history) > 0:
    completion = openai.Completion.create(
        engine=AZURE_OPENAI_GPT_DEPLOYMENT,
        prompt=summary_prompt_template.format(summary="\n".join(history), question=user_input),
        temperature=0.7,
        max_tokens=32,
        stop=["\n"])
    search = completion.choices[0].text
else:
    search = user_input

# Alternatively simply use search_client.search(q, top=3) if not using semantic ranking
print("Searching:", search)
print("-------------------")
filter = "category ne '{}'".format(exclude_category.replace("'", "''")) if exclude_category else None
r = search_client.search(search, 
                         filter=filter,
                         query_type=QueryType.SEMANTIC, 
                         query_language="en-us", 
                         query_speller="lexicon", 
                         semantic_configuration_name="default", 
                         top=3)
results = [doc[KB_FIELDS_SOURCEPAGE] + ": " + doc[KB_FIELDS_CONTENT].replace("\n", "").replace("\r", "") for doc in r]
content = "\n".join(results)

prompt = prompt_prefix.format(sources=content) + prompt_history + user_input + turn_suffix

completion = openai.Completion.create(
    engine=AZURE_OPENAI_CHATGPT_DEPLOYMENT, 
    prompt=prompt, 
    temperature=0.7, 
    max_tokens=1024,
    stop=["<|im_end|>", "<|im_start|>"])

prompt_history += user_input + turn_suffix + completion.choices[0].text + "\n<|im_end|>" + turn_prefix
history.append("user: " + user_input)
history.append("assistant: " + completion.choices[0].text)

print("\n-------------------\n".join(history))
print("\n-------------------\nPrompt:\n" + prompt)

Erste Schritte

Hinweis

Einige Azure KI Search-Features sind für die menschliche Interaktion vorgesehen und sind in einem RAG-Muster nicht hilfreich. Konkret können Sie „Auto-Vervollständigen“ und „Vorschläge“ überspringen. Andere Features wie Facetten und orderby können nützlich sein, wären aber in einem RAG-Szenario ungewöhnlich.

Siehe auch