Inferenzskalierung zur Verbesserung der multimodalen RAG

Inferenzskalierung zur Verbesserung des multimodalen RAG 

Die Inferenzskalierung in der künstlichen Intelligenz (KI) bezieht sich auf Techniken, die die Leistung von Modellen verbessern, indem sie Rechenressourcen während der Inferenzphase (wenn Modelle Ausgaben erzeugen) zuweisen, anstatt sich auf größere Trainingsdatensätze oder Modellarchitekturen zu verlassen. Da große Sprachmodelle (Large Language Models, LLMs) sowohl in Bezug auf die Modellparameter als auch den Umfang des Datensatzes immer größer werden, sind die Optimierung der Inferenzzeit und die Verwaltung der Skalierung der Inferenzberechnung - insbesondere auf GPU-Hardware - zu einer zentralen Herausforderung für den Einsatz hochleistungsfähiger multimodaler Retrieval-Augmented Generation (RAG)-Systeme geworden. 

Einführung in die Inferenzskalierung

Jüngste Fortschritte bei Inferenzstrategien, die die Rechenressourcen erhöhen und komplexe Algorithmen zur Testzeit einsetzen, definieren neu, wie LLMs komplexe Schlussfolgerungsaufgaben bewältigen und qualitativ hochwertigere Ergebnisse über verschiedene Eingabemodalitäten hinweg liefern. Die Inferenzskalierung optimiert die Gedankenkette (Chain of Thought, CoT) durch die Erweiterung der Argumentationstiefe. Diese Erweiterung ermöglicht es den Modellen, durch iteratives Prompting oder mehrstufige Generierung längere, detailliertere Gedankenketten zu erzeugen. Die Inferenzskalierung kann genutzt werden, um die multimodale RAG zu verbessern, wobei der Schwerpunkt auf dem Zusammenspiel von Modellgrößen, Computerbudgets und der praktischen Optimierung der Inferenzzeit für reale Anwendungen liegt.

Darüber hinaus unterstreichen Skalierungsgesetze und Benchmark-Ergebnisse die Kompromisse zwischen Vortraining, Feinabstimmung, Inferenzzeit-Strategien und fortschrittlichen Algorithmen für die Ausgabe-Auswahl. Sowohl größere als auch kleinere Modelle profitieren von der Skalierung der Inferenz, da sie es auch ressourcenbeschränkten Systemen ermöglicht, sich der Leistung modernster LLMs anzunähern. Dieses Tutorial demonstriert die Auswirkungen von Optimierungstechniken auf die Modellleistung und bietet umsetzbare Anleitungen für den Ausgleich von Genauigkeit, Latenz und Kosten bei multimodalen RAG-Bereitstellungen.

Dieses Tutorial richtet sich an Entwickler, Forscher und Enthusiasten der künstlichen Intelligenz, die ihr Wissen über Dokumentenmanagement und fortgeschrittene Techniken der Verarbeitung natürlicher Sprache (NLP) erweitern möchten. Sie werden lernen, wie Sie die Leistung der Inferenzskalierung nutzen können, um die multimodale RAG-Pipeline zu verbessern, die in einem früheren Rezept erstellt wurde. Dieses Tutorial konzentriert sich zwar auf Strategien für die Skalierbarkeit in multimodalen RAG, die speziell auf IBM® Granite® große Sprachmodelle ausgerichtet sind, aber ähnliche Prinzipien sind auf die meisten gängigen Modelle anwendbar, einschließlich der Modelle von OpenAI (z. B. GPT-4, GPT-4o, ChatGPT) und DeepMind.

Dieses Tutorial führt Sie durch die folgenden Prozesse:

  • Vorverarbeitung von Dokumenten: Sie lernen, wie man Dokumente aus verschiedenen Quellen verarbeitet, sie parst und in brauchbare Formate umwandelt und in Vektordatenbanken speichert, indem Sie Docling nutzen. Docling ist ein Open-Source-Toolkit von IBM zum effizienten Parsen von Dokumentformaten wie PDF, DOCX, PPTX, XLSX, Bilder, HTML, AsciiDoc und Markdown. Anschließend exportiert es die Dokumentinhalte in maschinenlesbare Formate wie Markdown oder JSON. Sie verwenden ein Granite-Modell für maschinelles Lernen (ML), um Bildbeschreibungen der Bilder in den Dokumenten zu generieren. In diesem Tutorial lädt Docling die PDF-Dokumente herunter und verarbeitet sie, damit wir den Text und die Bilder erhalten, die in den Dokumenten enthalten sind. In diesem Tutorial lädt Docling die PDF-Dokumente herunter und verarbeitet sie, damit wir den Text und die Bilder erhalten, die in den Dokumenten enthalten sind.

  • Retrieval-Augmented Generation (RAG): Erfahren Sie, wie Sie LLMs wie Granite mit externen Wissensdatenbanken verbinden, um Abfrageantworten zu verbessern und wertvolle Erkenntnisse zu generieren. RAG ist eine Technik für große Sprachmodelle (LLMs), die verwendet wird, um LLMs mit einer Wissensbasis zu verbinden, die Informationen außerhalb der Daten enthält, für die das LLM trainiert wurde. Diese Technik wird ohne Feinabstimmung auf LLMs angewendet. Herkömmliche RAG sind auf textbasierte Anwendungsfälle wie Textzusammenfassung und Chatbot beschränkt.

  • Multimodale RAG: Erfahren Sie, wie multimodale RAG multimodale Large Language Models (MLLMs) verwendet, um Informationen aus mehreren Datentypen zu verarbeiten. Diese Daten können dann in die in RAG verwendete externe Wissensdatenbank aufgenommen werden. Multimodale Daten können Text, Bilder, Audio, Video oder andere Formen enthalten. In diesem Tutorial verwenden wir das neueste multimodale Vision-Modell von IBM: Granite 3.2 Vision.

  • Implementierung von demonstrationsbasierter RAG (DRAG) und iterativer demonstrationsbasierter RAG (IterDRAG): Wenden Sie die Inferenzskalierungstechniken aus der Forschungsarbeit an, um die RAG-Leistung bei der Arbeit mit umfangreichem Kontext erheblich zu verbessern. Die DRAG-Methode nutzt kontextbezogenes Lernen, um die RAG-Leistung zu verbessern. Durch die Einbindung mehrerer RAG-Beispiele als Demonstrationen hilft DRAG den Modellen zu lernen, relevante Informationen in langen Kontexten zu finden. Im Gegensatz zu Standard-RAG, die bei mehr Dokumenten stagnieren können, zeigt DRAG lineare Verbesserungen mit zunehmender Kontextlänge. IterDRAG ist eine Erweiterung von DRAG, die komplexe MultiHop-Abfragen der Adresse adressiert, indem sie in einfachere Unterabfragen zerlegt. MultiHop ist ein Prozess, bei dem eine komplexe Anfrage in einfache Teilfragen unterteilt und beantwortet wird. Für jede Teilfrage können Informationen erforderlich sein, die aus verschiedenen Quellen abgerufen und/oder synthetisiert wurden. IterDRAG verschachtelt Abruf- und Generierungsschritte und schafft Argumentationsketten, die kompositorische Lücken schließen. Dieser Ansatz ist besonders effektiv für die Verarbeitung komplexer Abfragen in langen Kontexten.

  • LangChain für Workflow-Integration: Erfahren Sie, wie Sie LangChain verwenden können, um die Dokumentenverarbeitung und die Workflow-Abfrage-Workflows zu optimieren und zu orchestrieren und so eine nahtlose Interaktion zwischen verschiedenen Komponenten des Systems zu ermöglichen.

In diesem Tutorial werden Sie auch drei hochmoderne Technologien verwenden:

  1. Docling: Ein Open-Source-Toolkit zum Parsen und Konvertieren von Dokumenten.

  2. Granite: Eine hochmoderne Familie von LLMs, die robuste natürliche Sprachfähigkeiten bieten, und ein Bildsprachmodell, das die Generierung von Bildern in Text ermöglicht.

  3. LangChain: Ein leistungsstarkes Framework zum Erstellen von Anwendungen, die auf Sprachmodellen basieren und darauf ausgelegt sind, komplexe Workflows zu vereinfachen und externe Tools nahtlos zu integrieren.

Am Ende dieses Tutorials werden Sie Folgendes erreicht haben:

  • Erwerben Sie Kompetenz in der Vorverarbeitung von Dokumenten, in Chunking und im Bildverständnis.

  • Integrieren Sie Vektordatenbanken, um die Abrufmöglichkeiten zu verbessern.

  • Implementieren Sie DRAG und IterDRAG, um einen effizienten und genauen Datenabruf mit Inferenzskalierung durchzuführen.

  • Erfahren Sie aus erster Hand, wie die Skalierung der Inferenzberechnung zu einer nahezu linearen Leistungsverbesserung der RAG-Leistung führen kann.

Verstehen von Herausforderungen im langen Kontext

Traditionelle Sprachmodelle haben aus mehreren Gründen Probleme mit langen Kontexten:

  • Traditionelle Aufmerksamkeitsmechanismen wie Transformatoren skalieren quadratisch, was immense Rechenressourcen beanspruchen kann. 

  • Schwierigkeit beim Auffinden relevanter Informationen in sehr langen Sequenzen. 

  • Herausforderungen bei der Wahrung der Kohärenz über entfernte Teile der Eingabe hinweg. 

  • Höherer Rechenaufwand für die Verarbeitung langer Sequenzen.

Die Techniken in diesem Tutorial gehen diese Herausforderungen durch die strategische Zuweisung von Inferenzberechnungen an.

Methoden zur Skalierung von Inferenz: DRAG und IterDRAG

DRAG vs IterDRAG
DRAG vs IterDRAG

Weitere Informationen zu diesen beiden fortschrittlichen Inferenzskalierungstechniken (DRAG und IterDRAG) finden Sie im Forschungsbericht „Inference Scaling for Long-Context Retrieval Augmented Generation“ (Inferenzskalierung für Long-Context Retrieval Augmented Generation)

Diese Methoden zeigen, dass eine Skalierung der Inferenzberechnung die RAG-Leistung bei optimaler Zuordnung nahezu linear verbessern kann, sodass RAG-Systeme die Funktionen moderner LLMs besser nutzen können. Für diese Implementierung werden wir ein IBM Granite-Modell verwenden, das verschiedene Modalitäten verarbeiten kann. Sie werden ein KI-System erstellen, um Benutzeranfragen aus unstrukturierten Daten in Echtzeit zu beantworten und dabei die Prinzipien aus dem Papier anzuwenden.

Voraussetzungen

  • Vertrautheit mit der Python-Programmierung.

  • Grundverständnis von LLMs, NLP-Konzepten und Computer Vision.

Schritte

Stellen Sie sicher, dass Sie Python 3.10, 3.11 oder 3.12 in einer neu erstellten virtuellen Umgebung ausführen. Hinweis: Sie können dieses Tutorial auch auf GitHub aufrufen.

Schritt 1: Einrichten der Umgebung

import sys
assert sys.version_info >= (3, 10) and sys.version_info < (3, 13), "Use Python 3.10, 3.11, or 3.12 to run this notebook."

Schritt 2: Installieren von Abhängigkeiten

! pip install "git+https://github.com/ibm-granite-community/utils.git" \
    transformers \
    pillow \
    langchain_community \
    langchain_huggingface \
    langchain_milvus \
    docling \
    replicate

Protokollierung

Um einige Protokollierungsinformationen zu sehen, können wir die Protokollstufe INFO konfigurieren.

HINWEIS: Es ist in Ordnung, die Ausführung dieser Zelle zu überspringen.

import logging

logging.basicConfig(level=logging.INFO)

Schritt 3: Auswahl der KI-Modelle

Laden der Granite-Modelle

Geben Sie das Einbettungsmodell an, das für die Erzeugung von Texteinbettungsvektoren verwendet werden soll. Hier werden wir eines der Granite Embeddings Modelle verwenden.

Wenn Sie ein anderes Einbettungsmodell verwenden möchten, ersetzen Sie diese Codezelle durch eine Zelle aus diesem Rezept für Einbettungsmodelle.

from langchain_huggingface import HuggingFaceEmbeddings
from transformers import AutoTokenizer

embeddings_model_path = "ibm-granite/granite-embedding-30m-english"
embeddings_model = HuggingFaceEmbeddings(
    model_name=embeddings_model_path,
)
embeddings_tokenizer = AutoTokenizer.from_pretrained(embeddings_model_path)

Geben Sie das MLLM an, das für das Bildverständnis verwendet werden soll. Wir verwenden das Visionsmodell Granite.

from ibm_granite_community.notebook_utils import get_env_var
from langchain_community.llms import Replicate
from transformers import AutoProcessor

vision_model_path = "ibm-granite/granite-vision-3.2-2b"
vision_model = Replicate(
    model=vision_model_path,
    replicate_api_token=get_env_var("REPLICATE_API_TOKEN"),
    model_kwargs={
        "max_tokens": embeddings_tokenizer.max_len_single_sentence, # Set the maximum number of tokens to generate as output.
        "min_tokens": 100, # Set the minimum number of tokens to generate as output.
        "temperature": 0.01,
    },
)
vision_processor = AutoProcessor.from_pretrained(vision_model_path)

Geben Sie das Sprachmodell an, das für die RAG-Generierungsoperation verwendet werden soll. Hier verwenden wir den Replicate LangChain-Client, um eine Verbindung zu einem Granite-Modell von der ibm-granite-Organisation auf Replicate herzustellen.

Informationen zur Einrichtung von Replicate finden Sie unter Erste Schritte mit Replicate.

Um eine Verbindung zu einem Modell auf einem anderen Provider als Replicate herzustellen, ersetzen Sie diese Codezelle durch eine aus dem LLM-Komponentenrezept.

model_path = "ibm-granite/granite-3.3-8b-instruct"
model = Replicate(
    model=model_path,
    replicate_api_token=get_env_var("REPLICATE_API_TOKEN"),
    model_kwargs={
        "max_tokens": 1000, # Set the maximum number of tokens to generate as output.
        "min_tokens": 100, # Set the minimum number of tokens to generate as output.
        "temperature": 0.01
    },
)
tokenizer = AutoTokenizer.from_pretrained(model_path)

Schritt 4: Vorbereiten der Dokumente für die Vektordatenbank mit Docling

from docling.document_converter import DocumentConverter, PdfFormatOption
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions

pdf_pipeline_options = PdfPipelineOptions(
    do_ocr=False,
    generate_picture_images=True,
)
format_options = {
    InputFormat.PDF: PdfFormatOption(pipeline_options=pdf_pipeline_options),
}
converter = DocumentConverter(format_options=format_options)

sources = [
    "https://midwestfoodbank.org/images/AR_2020_WEB2.pdf",
]
conversions = { source: converter.convert(source=source).document for source in sources }

Nach der Verarbeitung der Dokumente verarbeiten wir die Textelemente in den Dokumenten weiter und teilen sie in geeignete Größen für das von uns verwendete Einbettungsmodell ein. Aus den Textbausteinen wird eine Liste von LangChain-Dokumenten erstellt.

from docling_core.transforms.chunker.hybrid_chunker import HybridChunker
from docling_core.types.doc import DocItem, TableItem
from langchain_core.documents import Document

doc_id = 0
texts: list[Document] = []
for source, docling_document in conversions.items():
    for chunk in HybridChunker(tokenizer=embeddings_tokenizer).chunk(docling_document):
        items: list[DocItem] = chunk.meta.doc_items # type: ignore
        if len(items) == 1 and isinstance(items[0], TableItem):
            continue # we will process tables later
        refs = " ".join(map(lambda item: item.get_ref().cref, items))
        print(refs)
        text = chunk.text
        document = Document(
            page_content=text,
            metadata={
                "doc_id": (doc_id:=doc_id+1),
                "source": source,
                "ref": refs,
            },
        )
        texts.append(document)

print(f"{len(texts)} text document chunks created")

Als nächstes bearbeiten wir alle Tabellen in den Dokumenten. Wir konvertieren die Tabellendaten in das Markdown-Format, damit das Sprachmodell sie verarbeiten kann. Eine Liste von LangChain-Dokumenten wird aus den Markdown-Renderings der Tabelle erstellt.

from docling_core.types.doc import DocItemLabel

doc_id = len(texts)
tables: list[Document] = []
for source, docling_document in conversions.items():
    for table in docling_document.tables:
        if table.label in [DocItemLabel.TABLE]:
            ref = table.get_ref().cref
            print(ref)
            text = table.export_to_markdown(docling_document)
            document = Document(
                page_content=text,
                metadata={
                    "doc_id": (doc_id:=doc_id+1),
                    "source": source,
                    "ref": ref
                },
            )
            tables.append(document)


print(f"{len(tables)} table documents created")

Abschließend verarbeiten wir alle Bilder in den Dokumenten. Hier verwenden wir das Vision-Sprachmodell, um den Inhalt der Bilder zu verstehen. In diesem Beispiel interessieren uns alle Textinformationen im Bild.

Die Wahl eines geeigneten Prompts ist kritisch, da er festlegt, auf welche Aspekte des Bildes sich das Modell konzentrieren soll. Einige Beispiele:

  • Ein Prompt wie „Geben Sie eine detaillierte Beschreibung dessen, was auf dem Bild dargestellt ist“ (siehe unten) enthält allgemeine Informationen zu allen visuellen Elementen.

  • Ein Prompt wie „Welcher Text erscheint in diesem Bild?“ würde sich speziell auf die Extraktion von Textinhalten konzentrieren.

  • Eine Prompt wie „Beschreiben Sie die Datenvisualisierung in diesem Bild“ wäre besser für Diagramme und Grafiken geeignet.

  • Sie sollten mit verschiedenen Prompts experimentieren, basierend auf den Arten von Bildern in Ihren Dokumenten und den Informationen, die Sie daraus extrahieren müssen.

HINWEIS: Die Bildverarbeitung kann je nach Anzahl der Bilder und des Dienstes, der das Vision-Sprachmodell ausführt, eine erhebliche Verarbeitungszeit in Anspruch nehmen.

import base64
import io
import PIL.Image
import PIL.ImageOps

def encode_image(image: PIL.Image.Image, format: str = "png") -> str:
    image = PIL.ImageOps.exif_transpose(image) or image
    image = image.convert("RGB")

    buffer = io.BytesIO()
    image.save(buffer, format)
    encoding = base64.b64encode(buffer.getvalue()).decode("utf-8")
    uri = f"data:image/{format};base64,{encoding}"
    return uri

# Feel free to experiment with this prompt
image_prompt = "Give a detailed description of what is depicted in the image"
conversation = [
    {
        "role": "user",
        "content": [
            {"type": "image"},
            {"type": "text", "text": image_prompt},
        ],
    },
]
vision_prompt = vision_processor.apply_chat_template(
    conversation=conversation,
    add_generation_prompt=True,
)
pictures: list[Document] = []
doc_id = len(texts) + len(tables)
for source, docling_document in conversions.items():
    for picture in docling_document.pictures:
        ref = picture.get_ref().cref
        print(ref)
        image = picture.get_image(docling_document)
        if image:
            text = vision_model.invoke(vision_prompt, image=encode_image(image))
            document = Document(
                page_content=text,
                metadata={
                    "doc_id": (doc_id:=doc_id+1),
                    "source": source,
                    "ref": ref,
                },
            )
            pictures.append(document)

print(f"{len(pictures)} image descriptions created")

Dann können wir die LangChain-Dokumente anzeigen, die aus den Eingabedokumenten erstellt wurden.

import itertools
from docling_core.types.doc import RefItem
from IPython.display import display

# Print all created documents
for document in itertools.chain(texts, tables):
    print(f"Document ID: {document.metadata['doc_id']}")
    print(f"Source: {document.metadata['source']}")
    print(f"Content:\n{document.page_content}")
    print("=" * 80)  # Separator for clarity

for document in pictures:
    print(f"Document ID: {document.metadata['doc_id']}")
    source = document.metadata['source']
    print(f"Source: {source}")
    print(f"Content:\n{document.page_content}")
    docling_document = conversions[source]
    ref = document.metadata['ref']
    picture = RefItem(cref=ref).resolve(docling_document)
    image = picture.get_image(docling_document)
    print("Image:")
    display(image)
    print("=" * 80)  # Separator for clarity

Füllen der Vektordatenbank

Mithilfe des Einbetten-Modells laden wir die Dokumente aus den Textblöcken und generierten Bildunterschriften in eine Vektordatenbank. Die Erstellung dieser Vektordatenbank ermöglicht es uns, auf einfache Weise eine semantische Ähnlichkeitssuche in unseren Dokumenten durchzuführen.

HINWEIS: Die Bevölkerung der Vektordatenbank kann je nach Einbetten und Service eine erhebliche Verarbeitungszeit erfordern.

Auswahl Ihrer Vektordatenbank

Geben Sie die Datenbank an, die zum Speichern und Abrufen von Einbetten-Vektoren verwendet werden soll. Für dieses Tutorial verwenden wir Milvus mittels Langchain. Als Vektordatenbank speichert, indiziert und verwaltet Milvus numerische Einbettungen, die von neuronalen Netzwerken und verschiedenen ML-Algorithmen erzeugt werden.

Wenn Sie eine Verbindung zu einer anderen Vektordatenbank als Milvus herstellen möchten, ersetzen Sie diese Zelle durch eine Zelle aus diesem Rezept für den Vektorspeicher.

import tempfile
from langchain_core.vectorstores import VectorStore, VectorStoreRetriever
from langchain_milvus import Milvus

db_file = tempfile.NamedTemporaryFile(prefix="vectorstore_", suffix=".db", delete=False).name
print(f"The vector database will be saved to {db_file}")

vector_db: VectorStore = Milvus(
    embedding_function=embeddings_model,
    connection_args={"uri": db_file},
    auto_id=True,
    enable_dynamic_field=True,
    index_params={"index_type": "AUTOINDEX"},
)

Jetzt fügen wir alle LangChain-Dokumente für die Text-, Tabellen- und Bildbeschreibungen zur Vektordatenbank hinzu.

import itertools

documents = list(itertools.chain(texts, tables, pictures))
ids = vector_db.add_documents(documents)
print(f"{len(ids)} documents added to the vector database")
retriever: VectorStoreRetriever = vector_db.as_retriever(search_kwargs={"k": 10})

Schritt 5: RAG mit Granite

Nachdem wir unsere Dokumente nun erfolgreich konvertiert und vektorisiert haben, können wir unsere RAG-Pipeline einrichten.

Validieren Sie die Retrievalqualität

Hier testen wir die Vektordatenbank, indem wir im Vektorraum nach Abschnitten mit relevanten Informationen für unsere Abfrage suchen. Es werden die Dokumente angezeigt, die mit der abgerufenen Bildbeschreibung verknüpft sind.

Dieser Validierungsschritt ist wichtig, um sicherzustellen, dass unser Abfragesystem korrekt funktioniert, bevor wir unsere vollständige RAG-Pipeline aufbauen. Wir möchten sehen, ob die zurückgegebenen Dokumente für unsere Abfrage relevant sind.

Probieren Sie gerne verschiedene Abfragen aus.

query = "Analyze how Midwest Food Bank's financial efficiency changed during the pandemic by comparing their 2019 and 2020 performance metrics. What specific pandemic adaptations had the greatest impact on their operational capacity, and how did their volunteer management strategy evolve to maintain service levels despite COVID-19 restrictions? Provide specific statistics from the report to support your analysis."
for doc in vector_db.as_retriever().invoke(query):
    print(doc)
    print("=" * 80)  # Separator for clarity

Die zurückgegebenen Dokumente sollten auf die Anfrage reagieren. Lassen Sie uns fortfahren und unsere RAG-Pipeline konstruieren.

Die zurückgegebenen Dokumente sollten auf die Anfrage reagieren. Lassen Sie uns fortfahren und unsere RAG-Pipeline konstruieren.

Erstellen Sie die RAG-Pipeline für Granite

Zuerst erstellen wir die Prompts für Granite, um die RAG-Abfrage durchzuführen. Wir verwenden die Chatvorlage Granite und geben die Platzhalterwerte an, die durch die LangChain RAG-Pipeline ersetzt werden.

{context} enthält die abgerufenen Chunks, wie in der vorherigen Suche gezeigt, und gibt diese an das Modell als Dokumentenkontext zur Beantwortung unserer Frage weiter.

Anschließend konstruieren wir die RAG-Pipeline mithilfe der von uns erstellten Granite-Prompt-Vorlagen.

from ibm_granite_community.notebook_utils import escape_f_string
from langchain.prompts import PromptTemplate
from langchain.chains.retrieval import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain

# Create a Granite prompt for question-answering with the retrieved context
prompt = tokenizer.apply_chat_template(
    conversation=[{
        "role": "user",
        "content": "{input}",
    }],
    documents=[{
        "doc_id": "0",
        "text": "{context}",
    }],
    add_generation_prompt=True,
    tokenize=False,
)
prompt_template = PromptTemplate.from_template(template=escape_f_string(prompt, "input", "context"))

# Create a Granite document prompt template to wrap each retrieved document
document_prompt_template = PromptTemplate.from_template(template="""\
<|end_of_text|>
<|start_of_role|>document {{"document_id": "{doc_id}"}}<|end_of_role|>
{page_content}""")
document_separator=""

# Assemble the retrieval-augmented generation chain
combine_docs_chain = create_stuff_documents_chain(
    llm=model,
    prompt=prompt_template,
    document_prompt=document_prompt_template,
    document_separator=document_separator,
)
rag_chain = create_retrieval_chain(
    retriever=retriever,
    combine_docs_chain=combine_docs_chain,
)

Generieren Sie eine abrufgestützte Antwort auf eine Frage

Die Pipeline verwendet die Abfrage, um Dokumente aus der Vektordatenbank zu finden und sie als Kontext für die Abfrage zu verwenden.

outputs = rag_chain.invoke({"input": query})
print(outputs['answer'])

Standard-RAG-Beschränkungen und warum wir Inferenzskalierung benötigen

Obwohl der RAG-Standardansatz einigermaßen gut funktioniert, weist er bei der Arbeit mit langen oder komplexen Inhalten mehrere wesentliche Einschränkungen auf:

  1. Kontextmanagement: Bei der Verarbeitung vieler Dokumente hat Standard-RAG Schwierigkeiten, den gesamten verfügbaren Kontext effektiv zu nutzen.

  2. Qualität des Abrufs: Ohne Anleitung zur Verwendung abgerufener Informationen konzentrieren sich Modelle häufig auf die falschen Teile von Dokumenten.

  3. Kompositorisches Denken: Der Prozess des Verständnisses komplexer Abfragen, die mehrstufige Schlussfolgerungen erfordern, stellt für Standard-RAG eine Herausforderung dar.

  4. Die Leistung stagniert: Das Hinzufügen weiterer Dokumente zur Standard-RAG führt ab einem bestimmten Schwellenwert oft zu abnehmenden Erträgen.

Techniken zur Skalierung von Schlussfolgerungen beheben diese Einschränkungen, indem sie strategisch mehr Rechenleistung zur Schlussfolgerungszeit zuweisen.

Erweiterte RAG mit DRAG (demonstrationsbasierte RAG)

Jetzt werden wir die DRAG-Technik aus dem Forschungspapier „Inference Scaling for Long-Context Retrieval Augmented Generation“ implementieren, um unser RAG-System zu verbessern.

DRAG verwendet kontextbezogene Beispiele, um dem Modell zu demonstrieren, wie Informationen aus Dokumenten extrahiert und verwendet werden können, was die Leistung bei Szenarien mit langem Kontext verbessert.

Schritt 1: Erstellen Sie Beispiele für kontextbezogene Demonstrationen

Diese stammen in der Regel aus einem kuratierten Datensatz mit qualitativ hochwertigen QA-Paaren. Zu diesem Zweck erstellen wir einige synthetische Beispiele, die der erwarteten Domain entsprechen.

Hier definieren wir eine Datenklasse, die eine einzelne Demonstration darstellt, und erstellen dann einige Demonstrationen.

from dataclasses import dataclass, field, InitVar
from langchain_core.documents import Document

@dataclass
class DRAG_Demonstration:
    query: str
    answer: str
    retriever: InitVar[VectorStoreRetriever] = field(kw_only=True)
    documents: list[Document] = field(default_factory=list, kw_only=True)

    def __post_init__(self, retriever: VectorStoreRetriever):
        if not self.documents:
            self.documents = retriever.invoke(self.query)

    def __format__(self, format_spec: str) -> str:
        formatted_documents = "\n".join(
            f"Document {i+1}:\n{document.page_content}"
            for i, document in enumerate(self.documents)
        )
        return f"""\
{formatted_documents}
Question: {self.query}
Answer: {self.answer}
"""

def create_enhanced_drag_demonstrations(vector_db: VectorStore) -> list[DRAG_Demonstration]:
    """Create high-quality demonstrations for DRAG technique that showcase effective document analysis"""
    demonstration_retriever: VectorStoreRetriever = vector_db.as_retriever(search_kwargs={"k": 5})
    demonstrations = [
        DRAG_Demonstration(
            query="How did the COVID-19 pandemic impact Midwest Food Bank's operations in 2020?",
            answer="The COVID-19 pandemic significantly impacted Midwest Food Bank's operations in 2020. Despite challenges, MFB remained open and responsive to increased needs. They implemented safety protocols, reduced volunteer numbers for social distancing, and altered their distribution model to allow partner agencies to receive food safely. The pandemic created unprecedented food insecurity, with many people seeking assistance for the first time. MFB distributed 37% more food than in 2019, with a record 179 semi-loads of Disaster Relief family food boxes sent nationwide. The organization also faced supply chain disruptions and food procurement challenges in the early months but continued to find and distribute food. Community, business, and donor support helped fund operations and food purchases. Additionally, MFB began participating in the USDA Farmers to Families Food Box program in May 2020, distributing over $52 million worth of nutritious produce, protein, and dairy products.",
            retriever=demonstration_retriever
        ),
        DRAG_Demonstration(
            query="What role did volunteers play at Midwest Food Bank during 2020, and how were they affected by the pandemic?",
            answer="Volunteers were described as 'the life-blood of the organization' in the 2020 annual report. Despite the pandemic creating safety challenges, volunteers demonstrated courage and dedication by increasing their hours to meet growing needs. MFB implemented safety protocols at each location and limited volunteer group sizes to allow for social distancing. This created a challenge as food needs increased while fewer volunteers were available to help. To address this gap, multiple MFB locations received assistance from the National Guard, who filled vital volunteer positions driving trucks, operating forklifts, and helping with food distributions. In 2020, 17,930 individuals volunteered 300,898 hours of service, equivalent to 150 full-time employees. The volunteer-to-staff ratio was remarkable with 450 volunteers for every 1 paid MFB staff member, highlighting the volunteer-driven nature of the organization during the crisis.",
            retriever=demonstration_retriever
        ),
        DRAG_Demonstration(
            query="How did Midwest Food Bank's international programs perform during 2020, particularly in Haiti and East Africa?",
            answer="In 2020, Midwest Food Bank's international operations in East Africa and Haiti faced unique challenges but continued to serve communities. In East Africa (operated as Kapu Africa), strict lockdowns led to mass hunger, especially in slum areas. Kapu Africa distributed 7.2 million Tender Mercies meals, working with partner ministries to share food in food-insecure slums. A notable outcome was a spiritual awakening among recipients, with many asking why they were receiving help. In Haiti, the pandemic added to existing challenges, closing airports, seaports, factories, and schools. MFB Haiti more than doubled its food shipments to Haiti, delivering over 160 tons of food relief, nearly three-quarters being Tender Mercies meals. As Haitian children primarily receive nourishment from school lunches, MFB Haiti distributed Tender Mercies through faith-based schools and also partnered with over 20 feeding centers serving approximately 1,100 children daily. Nearly 1 million Tender Mercies meals were distributed in Haiti during 2020.",
            retriever=demonstration_retriever
        ),
    ]

    return demonstrations

Schritt 2: Formatieren Sie die Demonstrationen so, dass sie in den Prompt aufgenommen werden können

Anschließend formatieren wir alle Demonstrationen gemeinsam für den Prompt.

# Format all demonstrations together
demonstrations = create_enhanced_drag_demonstrations(vector_db)

formatted_demonstrations = "\n\n".join(
    f"Example {i+1}:\n{demo}"
    for i, demo in enumerate(demonstrations)
)

Schritt 3: Erstellen Sie die Vorlage für DRAG-Prompts

Anschließend erstellen wir den DRAG-Prompt für das Modell, der die formatierten Demonstrationsbeispiele enthält.

drag_prompt = tokenizer.apply_chat_template(
    conversation=[{
        "role": "user",
        "content": f"""\
Here are examples of effectively extracting information from documents to answer questions.

{formatted_demonstrations}

Follow these examples when answering the user's question:

{{input}}""",
    }],
    documents=[{
        "doc_id": "0",
        "text": "Placeholder{context}",
    }],
    add_generation_prompt=True,
    tokenize=False,
)

# Convert to prompt template
drag_prompt_template = PromptTemplate.from_template(template=escape_f_string(drag_prompt, "input", "context"))

Schritt 4: Erstellen Sie einen benutzerdefinierten Retriever, der Dokumente neu anordnet

Normalerweise gibt der Retriever die Dokumente in der Reihenfolge der Ähnlichkeit zurück, wobei das ähnlichste Dokument zuerst an der Reihe ist. Wir definieren einen Neuordnungsabruf (Reordering Retriever), um die Reihenfolge der Ergebnisse umzukehren. In der Bestellung wird nun das ähnlichste Dokument zuletzt angezeigt, also näher am Ende des Prompts.

import typing
from langchain_core.retrievers import BaseRetriever, RetrieverInput, RetrieverOutput
from langchain_core.callbacks.manager import CallbackManagerForRetrieverRun

class ReorderingRetriever(BaseRetriever):
    base_retriever: BaseRetriever

    def _get_relevant_documents(
        self, query: RetrieverInput, *, run_manager: CallbackManagerForRetrieverRun, **kwargs: typing.Any
    ) -> RetrieverOutput:
        docs = self.base_retriever._get_relevant_documents(query, run_manager=run_manager, **kwargs)
        return list(reversed(docs))  # Reverse the order so higher-ranked docs are closer to query in prompt

reordering_retriever = ReorderingRetriever(base_retriever=retriever)

Schritt 5: Erstellen einer DRAG-Pipeline

Wir erstellen die Pipeline für die DRAG-Abfrage unter Verwendung der DRAG-Promptvorlage und des Neuordnungsabrufs.

drag_combine_docs_chain = create_stuff_documents_chain(
    llm=model,
    prompt=drag_prompt_template,
    document_prompt=document_prompt_template,
    document_separator=document_separator,
)

drag_chain = create_retrieval_chain(
    retriever=reordering_retriever,
    combine_docs_chain=drag_combine_docs_chain,
)

Schritt 6: Generieren einer DRAG-erweiterten Antwort auf eine Frage

drag_outputs = drag_chain.invoke({"input": query})
print("\n=== DRAG-Enhanced Answer ===")
print(drag_outputs['answer'])

Großartig, es sieht so aus, als hätten wir die Antwort durch einige Beispiele verbessert. Probieren wir als Nächstes eine noch gründlichere RAG-Technik aus!

Implementierung von IterDRAG (iterative Demonstrations-basierte RAG)

IterDRAG erweitert DRAG, indem es komplexe Abfragen in einfachere Unterabfragen zerlegt und eine verschachtelte Abfrage durchführt. Dieser Ansatz ist besonders effektiv für komplexe Multihop-Fragen, die die Integration von Informationen aus mehreren Quellen oder eine Argumentation in mehreren Schritten erfordern.
 
Die wichtigsten Hauptvorteile des iterativen Ansatzes:

  • Zerlegt komplexe Fragen in überschaubare Teile.

  • Ruft relevantere Informationen für jede Unterfrage ab.

  • Erzeugt explizite Argumentationsketten.

  • Ermöglicht die Bewältigung von Fragen, die eine Herausforderung darstellen würden, in einem einzigen Schritt.

Schritt 1: Erstellen einer Abfragezerlegungskette

Der Schritt der Zerlegung ist entscheidend, da er eine komplexe Abfrage in einfachere, gezieltere Unterabfragen zerlegt, die einzeln beantwortet werden können.

decompose_prompt = tokenizer.apply_chat_template(
    conversation=[{
        "role": "user",
        "content": """\
You are a helpful assistant that breaks down complex questions into simpler sub-questions.
For multi-part or complex questions, generate 1-3 sub-questions that would help answer the main question.

Here are examples of how to decompose complex questions:
{demonstrations}

Follow the above examples when breaking down the user's question.
If the following question is already simple enough, just respond with "No follow-up needed."

Otherwise, break down the following question into simpler sub-questions. Format your response as:
Follow up: [sub-question]

Question: {input}"""
    }],
    add_generation_prompt=True,
    tokenize=False,
)

decompose_prompt_template = PromptTemplate.from_template(template=escape_f_string(decompose_prompt, "input", "demonstrations"))
decompose_chain = decompose_prompt_template | model

Schritt 2: Erstellen einer Antwortkette für Unterabfragen

Die Komponente zur Beantwortung von Unterfragen bearbeitet jede einzelne Unterfrage, indem sie relevante Dokumente abruft und gezielte Zwischenantworten erzeugt.

intermediate_prompt = tokenizer.apply_chat_template(
    conversation=[{
        "role": "user",
        "content": """\
You are a helpful assistant that answers specific questions based on the provided documents.

Focus only on the sub-question and provide a concise intermediate answer.
Please answer the following sub-question based on the provided documents.
Format your response as:
Intermediate answer: [your concise answer to the sub-question]

Sub-question: {input}
"""
    }],
    documents=[{
        "doc_id": "0",
        "text": "Placeholder{context}",
    }],
    add_generation_prompt=True,
    tokenize=False,
)

intermediate_prompt_template = PromptTemplate.from_template(template=escape_f_string(intermediate_prompt, "input", "context"))
intermediate_combine_docs_chain = create_stuff_documents_chain(
    llm=model,
    prompt=intermediate_prompt_template,
    document_prompt=document_prompt_template,
    document_separator=document_separator,
)
intermediate_chain = create_retrieval_chain(
    retriever=reordering_retriever,
    combine_docs_chain=intermediate_combine_docs_chain,
)

Schritt 3: Erstellen einer abschließenden Antwortgenerierungskette

Die abschließende Komponente zur Generierung von Antworten kombiniert alle Zwischenantworten, um eine umfassende Antwort auf die ursprüngliche Frage zu erhalten.

final_prompt = tokenizer.apply_chat_template(
    conversation=[{
        "role": "user",
        "content": """\
You are a helpful assistant that provides comprehensive answers to questions.
Use the intermediate answers to sub-questions to formulate a complete final answer.
Please provide a final answer to the main question based on the intermediate answers to sub-questions.
Format your response as:
So the final answer is: [your comprehensive answer to the main question]

Main question: {input}

Sub-questions and intermediate answers:
{context}"""
    }],
    add_generation_prompt=True,
    tokenize=False,
)

final_prompt_template = PromptTemplate.from_template(template=escape_f_string(final_prompt, "input", "context"))
final_chain = final_prompt_template | model

Schritt 4: Erstellen Sie Beispieldemonstrationen für IterDRAG

Die Erstellung effektiver Demonstrationen ist entscheidend für die Leistung von InterDRAG. In diesen Beispielen wird gezeigt, wie das Modell Folgendes ausführt:

  1. Zerlegen komplexer Fragen in einfachere Unterfragen.

  2. Generieren relevanter Zwischenantworten.

  3. Kombinieren dieser Antworten zu einer kohärenten endgültigen Antwort.
@dataclass
class IterDRAG_Demonstration_Base:
    query: str
    answer: str

@dataclass
class IterDRAG_Demonstration(IterDRAG_Demonstration_Base):
    intermediate: list[IterDRAG_Demonstration_Base]

    def __format__(self, format_spec: str) -> str:
        sub_questions="\n".join(
            f"Follow up: {sub.query}"
            for sub in self.intermediate
        )

        return f"Question: {self.query}\n{sub_questions}"

def create_iterdrag_demonstrations() -> list[IterDRAG_Demonstration]:
    """Create examples showing how to decompose and answer complex questions"""

    demonstrations = [
        IterDRAG_Demonstration(
            query="What impact did the pandemic have on the food bank's operations and distribution?",
            answer="The pandemic had a profound impact on food bank operations and distribution. Distribution volume increased by 60% to over 100 million pounds of food in 2020. Operationally, the food bank faced supply chain disruptions, volunteer shortages, and safety protocol challenges. In response, they implemented contactless distribution, expanded mobile pantries, created emergency food boxes for vulnerable populations, and developed virtual nutrition education. Despite these challenges, they successfully scaled operations to meet the unprecedented community need during the crisis.",
            intermediate=[
                IterDRAG_Demonstration_Base(
                    query="How did food distribution volume change during the pandemic?",
                    answer="Food distribution volume increased by 60% during the pandemic, rising from approximately 62 million pounds in 2019 to over 100 million pounds in 2020.",
                ),
                IterDRAG_Demonstration_Base(
                    query="What operational challenges did the food bank face during the pandemic?",
                    answer="The food bank faced challenges including supply chain disruptions, volunteer shortages due to social distancing requirements, and the need to implement new safety protocols for food handling and distribution.",
                ),
                IterDRAG_Demonstration_Base(
                    query="What new programs were implemented in response to the pandemic?",
                    answer="New programs included contactless distribution methods, expanded mobile pantry operations, emergency food boxes for vulnerable populations, and virtual nutrition education classes.",
                ),
            ],
        ),
        IterDRAG_Demonstration(
            query="How does the food bank's financial management compare to industry standards for non-profits?",
            answer="The food bank demonstrates excellent financial management compared to industry standards. With 94% of its budget allocated to program services and only 6% to administrative and fundraising costs, it exceeds the industry benchmark of 85-90% for program spending. This financial efficiency places the food bank among the top-performing non-profits in terms of maximizing donor impact and minimizing overhead expenses.",
            intermediate=[
                IterDRAG_Demonstration_Base(
                    query="What percentage of the food bank's budget goes to program services versus administrative costs?",
                    answer="94% of the food bank's budget goes directly to program services, with only 6% allocated to administrative and fundraising costs.",
                ),
                IterDRAG_Demonstration_Base(
                    query="What are the industry standards for program spending versus overhead for food banks?",
                    answer="Industry standards suggest that well-run food banks typically allocate 85-90% of their budget to program services, with 10-15% for administrative and fundraising expenses.",
                ),
            ],
        ),
    ]
    return demonstrations

Schritt 5: Implementieren der IterDRAG-Funktion

Diese Funktion orchestriert den gesamten iterativen Prozess:

  1. Zerlegen Sie die Hauptfrage in Teilfragen.

  2. Rufen Sie für jede Teilfrage relevante Dokumente ab und generieren Sie eine Zwischenantwort.

  3. Kombinieren Sie alle Zwischenantworten, um die endgültige Antwort zu erhalten.
import re

def iterative_drag(main_question: str) -> dict[str, typing.Any]:
    """
    Implements IterDRAG: decomposing queries, retrieving documents for sub-queries,
    and generating a final answer based on intermediate answers.
    """
    print(f"\n=== Processing query with IterDRAG: '{main_question}' ===")

    # Step 1: Decompose the main question into sub-questions
    print("Step 1: Decomposing the query into sub-questions...")
    iterdrag_demonstrations = create_iterdrag_demonstrations()
    formatted_demonstrations = "\n\n".join(
        f"Example {i+1}:\n{demo}"
        for i, demo in enumerate(iterdrag_demonstrations)
    )
    decompose_result = decompose_chain.invoke({
        "input": main_question,
        "demonstrations": formatted_demonstrations,
    })
    decompose_answer = decompose_result

    # Extract sub-questions using regex
    sub_questions = re.findall(r"Follow up: (.*?)(?=Follow up:|\n|$)", decompose_answer, re.DOTALL)
    sub_questions = [sq.strip() for sq in sub_questions if sq.strip()]
    if not sub_questions:
        print("No decomposition needed or found. Using standard DRAG approach.")
        return drag_chain.invoke({"input": main_question})
    print(f"Decomposed into {len(sub_questions)} sub-questions")

    # Step 2: Answer each sub-question
    intermediate_pairs: list[dict[str, str]] = []
    for i, sub_question in enumerate(sub_questions):
        print(f"\nStep 2.{i+1}: Processing sub-question: '{sub_question}'")

        # Generate answer for this sub-question
        intermediate_result = intermediate_chain.invoke({"input": sub_question})
        intermediate_answer = intermediate_result["answer"]

        # Extract intermediate answer using regex
        intermediate_answer_match = re.search(r"Intermediate answer: (.*?)$", intermediate_answer, re.DOTALL)
        if intermediate_answer_match:
            intermediate_answer = intermediate_answer_match.group(1).strip()

        print(f"Generated intermediate answer: {intermediate_answer[:100]}...")

        # Store the sub-question and its answer
        intermediate_pairs.append({"input": sub_question, "answer": intermediate_answer})

    # Step 3: Generate the final answer based on sub-question answers
    print("\nStep 3: Generating final answer based on intermediate answers...")
    final_result = final_chain.invoke({
        "input": main_question,
        "context": "\n\n".join(
            f"Sub-question: {pair['input']}\nIntermediate answer: {pair['answer']}"
            for pair in intermediate_pairs
        ),
    })
    final_answer = final_result

    # Extract final answer
    final_answer_match = re.search(r"So the final answer is: (.*?)$", final_answer, re.DOTALL)
    if final_answer_match:
        final_answer = final_answer_match.group(1).strip()

    return {"input": main_question, "answer": final_answer, "intermediate": intermediate_pairs}

Vergleich der RAG-Ansätze

Nun, da wir alle drei RAG-Ansätze eingerichtet haben, lassen Sie uns ihre Antworten auf dieselbe Abfrage vergleichen, die dieses Mal viel komplexer ist, um die Unterschiede zu sehen.

Der Vergleich wird uns helfen, die Nutzen der einzelnen Ansätze zu verstehen und herauszufinden, wann jeder Ansatz am besten geeignet sein könnte.

# Run all approaches on the same complex query
comparison_query = "What was the full impact chain of the National Guard's assistance during the pandemic? Specifically, how did their involvement affect volunteer operations, what specific tasks did they perform, and how did this ultimately translate to community impact in terms of food distribution capabilities and reach?"

print("\n=== Standard RAG ===")
standard_result = rag_chain.invoke({"input": comparison_query})
print(standard_result["answer"])

print("\n=== DRAG ===")
drag_result = drag_chain.invoke({"input": comparison_query})
print(drag_result["answer"])

print("\n=== IterDRAG ===")
iterdrag_result = iterative_drag(comparison_query)
print(iterdrag_result["answer"])

Ergebnisvergleich und -analyse

Hier fassen wir die Leistungsunterschiede zwischen den drei implementierten RAG-Ansätzen zusammen:

Lösung

 

Stärken

 

Begrenzungen

 

Die besten Anwendungsfälle

 

Standard RAG

  • Einfache Implementierung
  • Gut geeignet für einfache Anfragen
  • Geringerer Rechenaufwand
  • Eingeschränkte Kontextnutzung
  • Leistungsplateaus mit mehr Dokumenten
  • Schlecht in komplexem Denken 
  • Einfache sachliche Fragen
  • Wenn die Berechnung begrenzt ist
  • Wenn der Kontext beschränkt ist 

DRAG

  • Bessere Kontextnutzung
  • Verbesserte Leistung mit mehr Dokumenten
  • Gut für mäßig komplexe Abfragen
  • Immer noch begrenzt durch die einstufige Generation
  • Weniger effektiv bei Multi-Hop-Fragen
  • Abfragen mit mittlerer Komplexität
  • Wenn mehr Dokumente verfügbar sind
  • Wenn kontextbezogene Beispiele angegeben werden können

IterDRAG

  • Am besten für komplexe Abfragen
  • Explizite Argumentationsketten
  • Effektivste Nutzung des Kontexts
  • Höchste Rechenanforderungen
  • Komplexere Implementierung
  • Multi-Hop-Fragen
  • Komplexe Analysen, die eine zusammengesetzte Schlussfolgerung erfordern
  • Wenn maximale Leistung erforderlich ist 
    

Wie wir bei unseren Implementierungsinferenz-Skalierungstechniken wie DRAG und IterDRAG gesehen haben, können die RAG-Leistung erheblich verbessern. Diese Methode eignet sich insbesondere für komplexe Abfragen, die eine tiefgreifende Analyse mehrerer Dokumente erfordern.

Zusammenfassung

In diesem Tutorial haben wir erkundet, wie die RAG-Leistung durch Inferenzskalierung erheblich verbessert werden kann. Durch die strategische Zuweisung zusätzlicher Berechnungen zur Inferenzzeit durch Techniken wie DRAG und IterDRAG können wir die Antwortqualität bei komplexen Abfragen erheblich steigern.

Herausforderungen bei traditionellen RAG- und Transformer-basierten Modellen

Kostenintensive Inferenz: Transformer-basierte Modelle, die Selbstbeobachtungsmechanismen verwenden, haben Inferenzkosten, die quadratisch mit der Eingabelänge skalieren. Diese Methode macht den Umgang mit langen Kontexten rechenintensiv, wodurch die praktische Anwendung von RAG auf kürzere Dokumente beschränkt wird oder eine aggressive Kürzung erforderlich ist.

Eingeschränkte Kontextnutzung: Standard-RAG-Systeme rufen oft eine feste Anzahl von Dokumenten ab und verarbeiten sie, was für komplexe MultiHop-Abfragen möglicherweise nicht ausreicht. Die Leistung sinkt mit zunehmender Länge des Kontexts, insbesondere jenseits von 128.000 Token, weil das Modell Schwierigkeiten hat, Informationen über viele abgefragte Passagen hinweg zu synthetisieren.

Ineffiziente Zuteilung von Berechnungen: Ohne eine sorgfältige Zuteilung erhöht das Hinzufügen weiterer abgerufener Dokumente oder Kontexte einfach nur die Rechenkosten, ohne dass sich die Genauigkeit proportional erhöht. Dies führt zu abnehmenden Erträgen oder sogar zu Leistungseinbußen aufgrund von Informationsüberlastung.

Wie DRAG und IterDRAG diese Herausforderungen adressiert

Demonstrationsbasierte RAG (DRAG):

DRAG nutzt mehrere abrufbare Beispiele, Questions and Answers als Demonstrationen innerhalb der Eingabeaufforderung, so dass das Modell im Kontext lernen kann, wie man relevante Informationen findet und anwendet.

Dieser Ansatz ist besonders effektiv bei kürzeren effektiven Kontextlängen, da er es dem Modell ermöglicht, reichhaltigen Kontext zu nutzen, ohne den Aufmerksamkeitsmechanismus zu überfordern, was sowohl die Abfrage- als auch die Generierungsqualität verbessert.

Iterative demonstrationsbasierte RAG (IterDRAG):

IterDRAG zerlegt komplexe Abfragen in einfachere Unterabfragen, wobei die Antworten für jeden Teilschritt iterativ abgerufen und generiert werden.

Durch die Verschachtelung von Abruf und Generierung baut IterDRAG Schlussfolgerungsketten auf, die die Lücke für Multihop-Abfragen überbrücken und damit besonders effektiv für außergewöhnlich lange Kontexte sind.

Dieser Prozess ermöglicht es dem Modell, die Berechnungen effizienter zu verteilen, sich bei jedem Schritt auf die relevantesten Informationen zu konzentrieren und das Risiko einer Überlastung der Aufmerksamkeit bei langen Kontexten zu vermeiden. Wenn Sie diese Techniken zur Skalierung von Schlussfolgerungen auf Ihre RAG-Anwendungen anwenden, können Sie eine deutlich bessere Leistung bei wissensintensiven Aufgaben erzielen, ohne Ihre zugrunde liegenden Modelle zu ändern.

Nächste Schritte:

  • Experimentieren Sie mit verschiedenen Abrufmodellen und Ansätzen zur Dokumentenvorverarbeitung.

  • Probieren Sie verschiedene Prompt-Formulierungen aus, um Bilder zu verstehen.

  • Erkunden Sie die Optimierung der Modellparameter, um die idealen Einstellungen für Ihren spezifischen Anwendungsfall zu finden.
Weiterführende Lösungen
IBM watsonx.ai

Trainieren, validieren, optimieren und implementieren Sie generative KI, Foundation Models und maschinelle Lernfunktionen mit IBM watsonx.ai, einem Studio der nächsten Generation für AI Builder in Unternehmen. Erstellen Sie KI-Anwendungen mit einem Bruchteil der Zeit und Daten.

Entdecken sie watsonx.ai
Lösungen im Bereich künstlicher Intelligenz

Setzen Sie KI in Ihrem Unternehmen ein – mit branchenführendem Fachwissen im Bereich KI und dem Lösungsportfolio von IBM an Ihrer Seite.

Erkunden Sie KI-Lösungen
KI-Beratung und -Services

Erfinden Sie kritische Workflows und Abläufe neu, indem Sie KI einsetzen, um Erfahrungen, Entscheidungsfindung in Echtzeit und den geschäftlichen Nutzen zu maximieren.

KI-Services entdecken
Machen Sie den nächsten Schritt

Profitieren Sie von einem einheitlichen Zugriff auf Funktionen, die den gesamten Lebenszyklus der KI-Entwicklung abdecken. Erstellen Sie leistungsstarke KI-Lösungen mit benutzerfreundlichen Oberflächen, Workflows und Zugriff auf branchenübliche APIs und SDKs.

watsonx.ai erkunden Buchen Sie eine Live-Demo
Fußnoten

1. „A Survey of Frontiers in LLM Reasoning: Inference Scaling, Learning to Reason, and Agentic Systems“, Ke, Zixuan, Fangkai Jiao, Yifei Ming, Xuan-Phi Nguyen, Austin Xu, Do Xuan Long, Minzhi Li, et al.,  ArXiv.org, 2025.

2. „Reasoning in Granite 3.2 Using Inference Scaling“, Lastras, Luis. 2025, IBM Forschung, IBM, 26. Februar 2025.

3. „Inference Scaling for Long-Context Retrieval Augmented Generation“, Zhenrui Yue, Honglei Zhuang, Aijun Bai, Kai Hui, Rolf Jagerman, Hansi Zeng, Zhen Qin, Dong Wang, Xuanhui Wang, Michael Bendersky, ArXiv.org, 2024.