Haben Sie Lappen über PDFs, Dokumenten und Berichten durchgeführt? Viele wichtige Dokumente sind nicht nur einfacher Textual content. Denken Sie über Forschungsarbeiten, Finanzberichte oder Produkthandbücher nach. Sie enthalten oft eine Mischung aus Absätzen, Tabellen und anderen strukturierten Elementen. Dies schafft eine bedeutende Herausforderung für die serienmäßigen Abruf-Generationssysteme (RAGS-Augmented Era). Effektiver Lappen bei semi-strukturierten Daten erfordert mehr als nur eine grundlegende Textaufteilung. Dieser Leitfaden bietet eine praktische Lösung mit intelligenter unstrukturierter Datenanalyse und einer fortschrittlichen RAG-Technik, die als Multi-Vektor-Retriever bekannt ist, alle im Langchain-Rag-Framework.
Bedarf an Lappen auf halbstrukturierten Daten
Traditionell LAPPEN Pipelines stolpern oft mit diesen Dokumenten mit gemischten Instrengungen. Erstens kann ein einfacher Textsplitter eine Tabelle in zwei Hälften hacken und die wertvollen Daten in sich zerstören. Zweitens kann das Einbetten des rohen Textes einer großen Tabelle laute, ineffektive Vektoren für die semantische Suche erzeugen. Das Sprachmodell sieht möglicherweise nie den richtigen Kontext, um die Frage eines Benutzers zu beantworten.
Wir werden ein intelligentes System erstellen, das Textual content clever von Tabellen trennt und verschiedene Strategien zum Speichern und Abrufen von jeweils anwendet. Dieser Ansatz stellt sicher, dass unser Sprachmodell genaue Informationen erhält, die es benötigt, um genaue Antworten zu geben.
Die Lösung: ein intelligentere Ansatz zum Abrufen
Unsere Lösung wird mit zwei Schlüsselkomponenten die Kernherausforderungen direkt angepackt. Bei dieser Methode geht es darum, Daten auf eine Weise vorzubereiten und abzurufen, die ihre ursprüngliche Bedeutung und Struktur bewahrt.
- Intelligente Daten Parsen: Wir verwenden die unstrukturierte Bibliothek, um das anfängliche schwere Anheben durchzuführen. Anstatt blind den Textual content zu spalten, unstrukturierte sie
partition_pdfFunktionsanalysen das Format eines Dokuments. Es kann den Unterschied zwischen einem Absatz und einer Tabelle erkennen, die jedes Ingredient sauber extrahiert und seine Integrität bewahrt. - Der Multi-Vektor-Retriever: Dies ist der Kern unserer Fortgeschrittene Lappentechnik. Mit dem Multi-Vektor-Retriever können wir mehrere Darstellungen unserer Daten speichern. Zum Abrufen werden wir präzise Zusammenfassungen unserer Textbrocken und -Tische verwenden. Diese kleineren Zusammenfassungen sind für die Einbettung und Ähnlichkeitssuche viel besser. Zur Antwortgenerierung übergeben wir die vollständige, rohe Tabelle oder den Textanteil an das Sprachmodell. Dies gibt dem Modell den vollständigen Kontext, den es benötigt.
Der allgemeine Workflow sieht so aus:
Bauen der Lag -Pipeline
Gehen wir durch, wie Sie dieses System Schritt für Schritt aufbauen. Wir werden die verwenden Lama2 Forschungsarbeit Als Beispieldokument.
Schritt 1: Einrichten der Umgebung
Zuerst müssen wir die notwendigen installieren Python Pakete. Wir werden Langchain für das Kerngerüst verwenden, das für Parsen unstrukturiert ist, und Chroma für unseren Vektor Retailer.
! pip set up langchain langchain-chroma "unstructured(all-docs)" pydantic lxml langchainhub langchain_openai -q
Die PDF -Parsing von unstrukturiertem Unstrukturierter beruht auf einigen externen Instruments zur Verarbeitung und Optische Charaktererkennung (OCR). Wenn Sie sich auf einem Mac befinden, können Sie sie einfach mit Homebrew installieren.
!apt-get set up -y tesseract-ocr
!apt-get set up -y poppler-utils
Schritt 2: Datenbelastung und Parsen mit unstrukturierter Analyse
Unsere erste Aufgabe ist es, die PDF zu verarbeiten. Wir verwenden Partition_PDF von unstrukturiertem, was für diese Artwork von unstrukturierten Datenanalysen speziell erstellt wird. Wir konfigurieren es, um Tabellen zu identifizieren und den Textual content des Dokuments durch seine Titel und Untertitel zu unterteilen.
from typing import Any
from pydantic import BaseModel
from unstructured.partition.pdf import partition_pdf
# Get parts
raw_pdf_elements = partition_pdf(
filename="/content material/LLaMA2.pdf",
# Unstructured first finds embedded picture blocks
extract_images_in_pdf=False,
# Use structure mannequin (YOLOX) to get bounding bins (for tables) and discover titles
# Titles are any sub-section of the doc
infer_table_structure=True,
# Publish processing to mixture textual content as soon as we now have the title
chunking_strategy="by_title",
# Chunking params to mixture textual content blocks
# Try to create a brand new chunk 3800 chars
# Try to hold chunks > 2000 chars
max_characters=4000,
new_after_n_chars=3800,
combine_text_under_n_chars=2000,
image_output_dir_path=path,
)
Nachdem wir den Partitioner ausgeführt haben, können wir sehen, welche Arten von Elementen es gefunden hat. Die Ausgabe zeigt zwei Haupttypen: CompositeElement Für unsere Textbrocken und Desk für die Tische.
# Create a dictionary to retailer counts of every kind
category_counts = {}
for ingredient in raw_pdf_elements:
class = str(kind(ingredient))
if class in category_counts:
category_counts(class) += 1
else:
category_counts(class) = 1
# Unique_categories can have distinctive parts
unique_categories = set(category_counts.keys())
category_counts
Ausgabe:

Wie Sie sehen können, hat unstrukturierte Arbeiten hervorragende Arbeit geleistet, um 2 verschiedene Tabellen und 85 Textbrocken zu identifizieren. Lassen Sie uns diese nun in verschiedene Pay attention trennen, um die Verarbeitung zu vereinfachen.
class Ingredient(BaseModel):
kind: str
textual content: Any
# Categorize by kind
categorized_elements = ()
for ingredient in raw_pdf_elements:
if "unstructured.paperwork.parts.Desk" in str(kind(ingredient)):
categorized_elements.append(Ingredient(kind="desk", textual content=str(ingredient)))
elif "unstructured.paperwork.parts.CompositeElement" in str(kind(ingredient)):
categorized_elements.append(Ingredient(kind="textual content", textual content=str(ingredient)))
# Tables
table_elements = (e for e in categorized_elements if e.kind == "desk")
print(len(table_elements))
# Textual content
text_elements = (e for e in categorized_elements if e.kind == "textual content")
print(len(text_elements))
Ausgabe:

Schritt 3: Zusammenfassungen zum besseren Abrufen erstellen
Große Tabellen und lange Textblöcke erzeugen keine sehr effektiven Einbettungen für die semantische Suche. Eine kurze Zusammenfassung ist jedoch perfekt. Dies ist die zentrale Idee, einen Multi-Vektor-Retriever zu verwenden. Wir werden ein einfaches erstellen Langchain Kette, um diese Zusammenfassungen zu erzeugen.
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from getpass import getpass
OPENAI_KEY = getpass('Enter Open AI API Key: ')
LANGCHAIN_API_KEY = getpass('Enter Langchain API Key: ')
LANGCHAIN_TRACING_V2="true"
# Immediate
prompt_text = """You might be an assistant tasked with summarizing tables and textual content. Give a concise abstract of the desk or textual content. Desk or textual content chunk: {ingredient} """
immediate = ChatPromptTemplate.from_template(prompt_text)
# Abstract chain
mannequin = ChatOpenAI(temperature=0, mannequin="gpt-4.1-mini")
summarize_chain = {"ingredient": lambda x: x} | immediate | mannequin | StrOutputParser()
Jetzt wenden wir diese Kette auf unsere extrahierten Tabellen und Textbrocken an. Die Batch -Methode ermöglicht es uns, diese gleichzeitig zu verarbeiten, was die Dinge beschleunigt.
# Apply to tables
tables = (i.textual content for i in table_elements)
table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})
# Apply to texts
texts = (i.textual content for i in text_elements)
text_summaries = summarize_chain.batch(texts, {"max_concurrency": 5})
Schritt 4: Aufbau des Multi-Vektor-Retrievers
Mit unseren Zusammenfassungen ist es Zeit, den Retriever aufzubauen. Es verwendet zwei Speicherkomponenten:
- Eine Vektorstore (Chromadb) speichert das eingebettete Zusammenfassungen.
- Ein Docstore (ein einfacher In-Reminiscence-Retailer) hält die roh Tabelle und Textinhalt.
Der Retriever verwendet eindeutige IDs, um eine Verbindung zwischen einer Zusammenfassung im Vektor Retailer und seinem entsprechenden Rohdokument im DocStore zu erstellen.
import uuid
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.storage import InMemoryStore
from langchain_chroma import Chroma
from langchain_core.paperwork import Doc
from langchain_openai import OpenAIEmbeddings
# The vectorstore to make use of to index the kid chunks
vectorstore = Chroma(collection_name="summaries", embedding_function=OpenAIEmbeddings())
# The storage layer for the mother or father paperwork
retailer = InMemoryStore()
id_key = "doc_id"
# The retriever (empty to start out)
retriever = MultiVectorRetriever(
vectorstore=vectorstore,
docstore=retailer,
id_key=id_key,
)
# Add texts
doc_ids = (str(uuid.uuid4()) for _ in texts)
summary_texts = (
Doc(page_content=s, metadata={id_key: doc_ids(i)})
for i, s in enumerate(text_summaries)
)
retriever.vectorstore.add_documents(summary_texts)
retriever.docstore.mset(record(zip(doc_ids, texts)))
# Add tables
table_ids = (str(uuid.uuid4()) for _ in tables)
summary_tables = (
Doc(page_content=s, metadata={id_key: table_ids(i)})
for i, s in enumerate(table_summaries)
)
retriever.vectorstore.add_documents(summary_tables)
retriever.docstore.mset(record(zip(table_ids, tables)))
Schritt 5: Lagkette laufen
Schließlich bauen wir die komplette Langchain -Lag -Pipeline. Die Kette wird eine Frage stellen, unseren Retriever verwenden, um die entsprechenden Zusammenfassungen abzurufen, die entsprechenden Rohdokumente zu ziehen und dann alles an das Sprachmodell weiterzugeben, um eine Antwort zu generieren.
from langchain_core.runnables import RunnablePassthrough
# Immediate template
template = """Reply the query primarily based solely on the next context, which may embrace textual content and tables:
{context}
Query: {query}
"""
immediate = ChatPromptTemplate.from_template(template)
# LLM
mannequin = ChatOpenAI(temperature=0, mannequin="gpt-4")
# RAG pipeline
chain = (
{"context": retriever, "query": RunnablePassthrough()}
| immediate
| mannequin
| StrOutputParser()
)
Let's check it with a selected query that may solely be answered by a desk within the paper.
chain.invoke("What's the variety of coaching tokens for LLaMA2?")
Ausgabe:

Das System funktioniert perfekt. Durch die Überprüfung des Prozesses können wir feststellen, dass der Retriever die Zusammenfassung von Tabelle 1 zuerst gefunden hat, in der die Modellparameter und Schulungsdaten erörtert werden. Dann holte es die vollständige rohe Tabelle aus dem DocStore und lieferte sie dem an die Llm. Dies gab dem Modell die genauen Daten, die zur korrekten Beantwortung der Frage erforderlich waren, und beweist die Leistung dieses Lappen beim semi-strukturierten Datenansatz.
Sie können auf den vollständigen Code auf dem zugreifen Colab Pocket book oder die Github -Repository.
Abschluss
Das Handeln von Dokumenten mit gemischten Textual content und Tabellen ist ein häufiges Drawback mit der realen Welt. Eine einfache Lag -Pipeline reicht in den meisten Fällen nicht aus. Durch die Kombination intelligenter unstrukturierter Daten, die mit dem Multi-Vektor-Retriever analysiert werden, erstellen wir ein viel robusteres und genauereres System. Diese Methode stellt sicher, dass die komplexe Struktur Ihrer Dokumente zu einer Stärke und nicht zu einer Schwäche wird. Es bietet dem Sprachmodell einen vollständigen Kontext auf leicht verständliche Weise, was zu besseren, zuverlässigeren Antworten führt.
Mehr lesen: Erstellen Sie eine Lag -Pipeline mit dem Lama -Index
Häufig gestellte Fragen
A. Ja, die unstrukturierte Bibliothek unterstützt eine Vielzahl von Dateitypen. Sie können einfach die Funktion partition_pdf mit der entsprechenden tauschen, z. B. partition_docx.
A. Nein, Sie könnten hypothetische Fragen aus jedem Chunk erstellen oder einfach den rohen Textual content einbetten, wenn er klein genug ist. Eine Zusammenfassung ist oft die effektivste für komplexe Tabellen.
A. Große Tabellen können „verrauschte“ Einbettungen erzeugen, bei denen die Kernbedeutung in den Particulars verloren geht. Dies macht die semantische Suche weniger effektiv. Eine kurze Zusammenfassung erfasst die Essenz der Tabelle für ein besseres Abruf.
Melden Sie sich an, um weiter zu lesen und Experten-Kuratinhalte zu genießen.
