Nowy indeks podsumowań dokumentów dla systemów QA opartych na LLM
W tym poście na blogu przedstawiamy zupełnie nową strukturę danych LlamaIndex: indeks podsumowania dokumentów. Opisujemy, w jaki sposób może pomóc zapewnić lepszą wydajność wyszukiwania w porównaniu z tradycyjnym wyszukiwaniem semantycznym, a także przedstawiamy przykład.
Tło
Jednym z podstawowych przypadków użycia modeli dużych języków (LLM) jest odpowiadanie na pytania dotyczące własnych danych. Aby to zrobić, łączymy LLM z modelem „wyszukiwania”, który może wyszukiwać informacje w korpusie wiedzy i przeprowadzać syntezę odpowiedzi na pobranych tekstach za pomocą LLM. Ta ogólna struktura nazywa się Retrieval-Augmented Generation.
Większość użytkowników budujących obecnie systemy QA oparte na LLM ma tendencję do wykonywania następujących czynności:
- Weź dokumenty źródłowe, podziel każdy z nich na fragmenty tekstu
- Przechowuj fragmenty tekstu w wektorowej bazie danych
- W czasie wykonywania zapytania pobieraj fragmenty tekstu, osadzając filtry podobieństw i/lub słów kluczowych.
- Wykonaj syntezę odpowiedzi
Ograniczenia istniejących podejść
Istnieje kilka ograniczeń pobierania osadzania przy użyciu fragmentów tekstu.
- Fragmenty tekstu nie mają kontekstu globalnego. Często pytanie wymaga kontekstu wykraczającego poza to, co jest indeksowane w określonej porcji.
- Ostrożne dostrojenie progów wyniku najwyższego k / podobieństwa. Ustaw zbyt małą wartość, a przegapisz kontekst. Ustaw zbyt dużą wartość, a koszt/opóźnienie może wzrosnąć w przypadku bardziej nieistotnego kontekstu.
- Osadzenia nie zawsze wybierają najbardziej odpowiedni kontekst dla pytania. Osadzenia są z natury określane niezależnie od tekstu i kontekstu.
Indeks streszczenia dokumentu
Proponujemy nowy indeks w LlamaIndex , który wyodrębni/indeksuje nieustrukturyzowane podsumowanie tekstowe dla każdego dokumentu . Indeks ten może pomóc zwiększyć wydajność wyszukiwania poza istniejącymi metodami wyszukiwania. Pomaga zaindeksować więcej informacji niż pojedynczy fragment tekstu i ma większe znaczenie semantyczne niż znaczniki słów kluczowych. Pozwala również na bardziej elastyczną formę wyszukiwania: możemy zarówno pobierać LLM, jak i pobierać na podstawie osadzania.
Jak to działa
W czasie kompilacji przetwarzamy każdy dokument i używamy LLM do wyodrębnienia podsumowania z każdego dokumentu. Podzieliliśmy również dokument na fragmenty tekstu (węzły). Zarówno podsumowanie, jak i węzły są przechowywane w naszej abstrakcji magazynu dokumentów . Utrzymujemy mapowanie z podsumowania do dokumentu/węzłów źródłowych.
W czasie zapytania pobieramy odpowiednie dokumenty do zapytania na podstawie ich podsumowań, stosując następujące podejścia:
- Wyszukiwanie oparte na LLM: Przedstawiamy LLM zestawy streszczeń dokumentów i prosimy LLM o określenie, które dokumenty są istotne oraz ich ocenę trafności.
- Wyszukiwanie oparte na osadzeniu: pobieramy odpowiednie dokumenty na podstawie podobieństwa osadzania streszczenia (z odcięciem górnych k).
Przechowywanie podsumowań dokumentu umożliwia również pobieranie oparte na LLM . Zamiast podawać cały dokument do LLM na początku, możemy najpierw zlecić LLM sprawdzenie zwięzłego streszczenia dokumentu, aby sprawdzić, czy w ogóle jest ono istotne dla zapytania. Wykorzystuje to możliwości rozumowania LLM, które są bardziej zaawansowane niż wyszukiwanie oparte na osadzeniu, ale pozwala uniknąć kosztów/opóźnień związanych z dostarczaniem całego dokumentu do LLM
Dodatkowe informacje
Wyszukiwanie dokumentów za pomocą podsumowań można traktować jako „środek pośredni” między wyszukiwaniem semantycznym a streszczaniem siłowym we wszystkich dokumentach. Wyszukujemy dokumenty na podstawie sumarycznej trafności z podanym zapytaniem, a następnie zwracamy wszystkie *węzły* odpowiadające pobranym dokumentom.
Dlaczego powinniśmy to robić? Ta metoda wyszukiwania daje użytkownikowi więcej kontekstu niż top-k na kawałku tekstu, poprzez pobieranie kontekstu na poziomie dokumentu. Ale jest to również bardziej elastyczne/automatyczne podejście niż modelowanie tematyczne; koniec z martwieniem się o to, czy Twój tekst ma odpowiednie znaczniki słów kluczowych!
Przykład
Przyjrzyjmy się przykładowi, który prezentuje indeks streszczenia dokumentów, ponad artykułami Wikipedii dotyczącymi różnych miast.
W pozostałej części tego przewodnika przedstawiono odpowiednie fragmenty kodu. Możesz znaleźć pełny opis przejścia tutaj (a tutaj jest link do notatnika ).
Możemy zbudować GPTDocumentSummaryIndex
zestaw dokumentów i przekazać ResponseSynthesizer
obiekt do syntezy podsumowań dla dokumentów.
from llama_index import (
SimpleDirectoryReader,
LLMPredictor,
ServiceContext,
ResponseSynthesizer
)
from llama_index.indices.document_summary import GPTDocumentSummaryIndex
from langchain.chat_models import ChatOpenAI
# load docs, define service context
...
# build the index
response_synthesizer = ResponseSynthesizer.from_args(response_mode="tree_summarize", use_async=True)
doc_summary_index = GPTDocumentSummaryIndex.from_documents(
city_docs,
service_context=service_context,
response_synthesizer=response_synthesizer
)
summary = doc_summary_index.get_document_summary("Boston")
from llama_index.indices.document_summary import DocumentSummaryIndexRetriever
retriever = DocumentSummaryIndexRetriever(
doc_summary_index,
# choice_select_prompt=choice_select_prompt,
# choice_batch_size=choice_batch_size,
# format_node_batch_fn=format_node_batch_fn,
# parse_choice_select_answer_fn=parse_choice_select_answer_fn,
# service_context=service_context
)
retrieved_nodes = retriever.retrieve("What are the sports teams in Toronto?")
print(retrieved_nodes[0].score)
print(retrieved_nodes[0].node.get_text())The retriever will retrieve a set of relevant nodes for a given index.
8.0
Toronto ( (listen) tə-RON-toh; locally [təˈɹɒɾ̃ə] or [ˈtɹɒɾ̃ə]) is the capital city of the Canadian province of Ontario. With a recorded population of 2,794,356 in 2021, it is the most populous city in Canada...
Interfejs API wysokiego poziomu
query_engine = doc_summary_index.as_query_engine(
response_mode="tree_summarize", use_async=True
)
response = query_engine.query("What are the sports teams in Toronto?")
print(response)
# use retriever as part of a query engine
from llama_index.query_engine import RetrieverQueryEngine
# configure response synthesizer
response_synthesizer = ResponseSynthesizer.from_args()
# assemble query engine
query_engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer,
)
# query
response = query_engine.query("What are the sports teams in Toronto?")
print(response)
Podejście do automatycznego podsumowania dowolnego fragmentu tekstu jest naprawdę ekscytujące. Cieszymy się, że możemy rozwijać rozszerzenia w dwóch obszarach:
- Kontynuuj odkrywanie automatycznego podsumowania w różnych warstwach. Obecnie jest to na poziomie dokumentu, ale co z podsumowaniem dużego fragmentu tekstu w mniejszym? (np. jednolinijkowy).
- Kontynuuj odkrywanie pobierania opartego na LLM, którego podsumowanie pomaga odblokować.
Przewodnik podsumowujący dokumenty
Link do notebooka