Wzorzec podsumowywania Map-Reduce
Podsumuj każdy fragment niezależnie, a następnie połącz podsumowania w całość.
Wzorzec podsumowywania Map-Reduce to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Prompt Engineering, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Wzorzec Map-Reduce
Gdy dokument przekracza rozmiar okna kontekstu LLM, nie można przekazać go w całości za jednym razem. Rozwiązuje to wzorzec map-reduce:
- Mapowanie: niezależne podsumowanie każdego fragmentu
- Redukcja: synteza podsumowań wszystkich fragmentów w jedno podsumowanie końcowe
Przypomina to klasyczny MapReduce z systemów rozproszonych — tę samą logikę dzielenia problemu i rozwiązywania go przez podział na mniejsze części, zastosowaną do zadań językowych.
Krok 1: Faza mapowania
W fazie mapowania każdy fragment jest wysyłany do LLM wraz z promptem do podsumowania. Model zwraca krótkie podsumowanie wyłącznie tego fragmentu. Podsumowania są zbierane na liście.
Każde podsumowanie powinno być znacznie krótsze od oryginalnego fragmentu — zazwyczaj stanowić 10–20% jego pierwotnej długości. To właśnie ta kompresja umożliwia wykonanie kroku redukcji.
import openai
client = openai.OpenAI(api_key='sk-...')
def summarize_chunk(chunk, model='gpt-4o'):
resp = client.chat.completions.create(
model=model,
messages=[
{'role': 'system', 'content': 'Summarize the following text concisely in 3-5 sentences.'},
{'role': 'user', 'content': chunk}
]
)
return resp.choices[0].message.content
def map_phase(chunks):
return [summarize_chunk(c) for c in chunks]Krok 2: Faza redukcji
W fazie redukcji wszystkie podsumowania fragmentów są łączone i wysyłane do LLM wraz z promptem syntezy. Model tworzy jedno spójne podsumowanie końcowe.
Jeśli podsumowania fragmentów nadal są zbyt długie, aby zmieścić się w jednym oknie kontekstu, należy zastosować redukcję rekurencyjnie — najpierw podsumować grupy podsumowań, a następnie dokonać ich syntezy.
def reduce_phase(chunk_summaries, model='gpt-4o'):
combined = '\n\n'.join(
f'Section {i+1}:\n{s}'
for i, s in enumerate(chunk_summaries)
)
resp = client.chat.completions.create(
model=model,
messages=[
{'role': 'system', 'content': 'You are given summaries of consecutive sections of a document. Write a single coherent summary of the entire document.'},
{'role': 'user', 'content': combined}
]
)
return resp.choices[0].message.contentZłożenie całości: surowe wywołania API
Oto kompletny potok map-reduce wykorzystujący bezpośrednie wywołania OpenAI API — bez użycia frameworka. Zapewnia to pełną kontrolę nad promptami i parametrami w każdej fazie.
def map_reduce_summarize(document, chunk_size=1000):
chunks = fixed_chunk(document, max_tokens=chunk_size)
print(f'Chunks: {len(chunks)}')
chunk_summaries = map_phase(chunks)
print(f'Map phase complete. Summaries: {len(chunk_summaries)}')
final_summary = reduce_phase(chunk_summaries)
return final_summary
with open('long_report.txt') as f:
doc = f.read()
result = map_reduce_summarize(doc)
print(result)LangChain MapReduceDocumentsChain
LangChain udostępnia gotowy komponent MapReduceDocumentsChain, który obsługuje dzielenie na fragmenty, równoległe wywołania fazy mapowania oraz krok redukcji. Jest wygodny, ale mniej elastyczny niż bezpośrednie wywołania API.
from langchain_openai import ChatOpenAI
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.docstore.document import Document
llm = ChatOpenAI(model='gpt-4o', openai_api_key='sk-...')
splitter = RecursiveCharacterTextSplitter(chunk_size=3000, chunk_overlap=200)
with open('long_report.txt') as f:
text = f.read()
docs = splitter.create_documents([text])
chain = load_summarize_chain(llm, chain_type='map_reduce')
result = chain.invoke(docs)
print(result['output_text'])Równoległość w fazie mapowania
Podsumowanie każdego fragmentu jest niezależne, dlatego fazę mapowania można wykonywać równolegle. Przy użyciu języka Python i ThreadPoolExecutor wszystkie wywołania API dla fragmentów są wysyłane jednocześnie, co znacznie skraca rzeczywisty czas wykonania.
from concurrent.futures import ThreadPoolExecutor, as_completed
def map_phase_parallel(chunks, max_workers=10):
summaries = [None] * len(chunks)
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(summarize_chunk, chunk): i
for i, chunk in enumerate(chunks)
}
for future in as_completed(futures):
idx = futures[future]
summaries[idx] = future.result()
return summariesRekurencyjna redukcja
Gdy dokument jest bardzo długi, same podsumowania fragmentów mogą przekroczyć rozmiar okna kontekstu. Należy zastosować redukcję rekurencyjnie: pogrupować podsumowania w partie, zredukować każdą partię, a następnie zredukować podsumowania partii.
def recursive_reduce(summaries, batch_size=10):
while len(summaries) > 1:
batches = [
summaries[i:i + batch_size]
for i in range(0, len(summaries), batch_size)
]
summaries = [reduce_phase(batch) for batch in batches]
print(f'Reduced to {len(summaries)} summaries')
return summaries[0]Zachowywanie kluczowych szczegółów
Częsty problem naiwnego podejścia map-reduce polega na utracie ważnych szczegółów podczas kompresji. Można temu przeciwdziałać, stosując następujące rozwiązania:
- Poinstruować w prompcie fazy mapowania, aby zachować nazwy, liczby i daty
- Poprosić w fazie redukcji o sprawdzenie sprzeczności między sekcjami
- Użyć większego rozmiaru fragmentu, aby kontekst mapowania był bogatszy
- Wykonać etap weryfikacji: zapytać model, czy kluczowe encje z oryginału występują w podsumowaniu końcowym
MAP_PROMPT = '''Summarize the following section in 5 sentences.
Preserve all key names, numbers, dates, and conclusions.
Section:
{chunk}'''Łańcuch refine: alternatywny wzorzec
Łańcuch refine jest alternatywą dla map-reduce. Przetwarza fragmenty sekwencyjnie: podsumowanie fragmentu N jest przekazywane wraz z fragmentem N+1, a model aktualizuje bieżące podsumowanie. Zapewnia to bardziej spójny wynik, ale uniemożliwia równoległość i działa wolniej.
Należy użyć refine, gdy ważna jest spójność narracji (np. w umowach prawnych). Map-reduce należy stosować, gdy ważna jest szybkość (np. przy przetwarzaniu partii artykułów informacyjnych).
def refine_summarize(chunks):
current_summary = summarize_chunk(chunks[0])
for chunk in chunks[1:]:
prompt = (
f'Existing summary:\n{current_summary}\n\n'
f'New section:\n{chunk}\n\n'
'Update the summary to incorporate the new section.'
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
current_summary = resp.choices[0].message.content
return current_summaryZarządzanie kosztami i tokenami
Map-reduce wymaga wielu wywołań API. W przypadku dokumentu zawierającego 100 fragmentów, przy użyciu gpt-4o za 5 USD/1M tokenów wejściowych:
- Mapowanie: 100 fragmentów × 1000 tokenów = 100 tys. tokenów wejściowych ≈ 0,50 USD
- Redukcja: ~10 tys. tokenów (podsumowania) ≈ 0,05 USD
- Łącznie: ~0,55 USD na dokument
Aby ograniczyć koszt, należy użyć gpt-4o-mini w fazie mapowania (0,15 USD/1M), a gpt-4o tylko w fazie redukcji. To hybrydowe podejście obniża koszty o 70% przy minimalnej utracie jakości.
def map_phase_cheap(chunks):
# Use mini model for map — cheaper, sufficient for chunk summaries
return [
summarize_chunk(c, model='gpt-4o-mini')
for c in chunks
]
def reduce_phase_quality(summaries):
# Use full model for final synthesis
return reduce_phase(summaries, model='gpt-4o')Kiedy stosować Map-Reduce
Podsumowywanie metodą map-reduce najlepiej sprawdza się w przypadku:
- dokumentów dłuższych niż okno kontekstu modelu
- wsadowego podsumowywania wielu dokumentów (również na poziomie dokumentów można zastosować równoległość)
- sytuacji, w których potrzebna jest kontrola nad promptem na każdym etapie
Metoda ta jest mniej odpowiednia do: wyodrębniania konkretnego faktu (należy zamiast niej użyć wyszukiwania) lub sytuacji, gdy dokument jest wystarczająco krótki, aby zmieścić się w kontekście (wtedy wystarczy podsumować go bezpośrednio).
Sprawdzenie wiedzy
Co dzieje się podczas fazy redukcji we wzorcu podsumowywania map-reduce?
Podsumowanie: podsumowywanie metodą Map-Reduce
Wzorzec map-reduce obsługuje dokumenty zbyt długie dla pojedynczego wywołania LLM:
- Mapowanie: niezależne podsumowanie każdego fragmentu — można wykonywać równolegle
- Redukcja: synteza podsumowań fragmentów w jedno podsumowanie końcowe
- Redukcja rekurencyjna: stosowana, gdy same podsumowania są zbyt długie
- Wskazówka dotycząca kosztów: należy użyć taniego modelu do mapowania i bardziej zaawansowanego modelu do redukcji
LangChain's MapReduceDocumentsChain udostępnia gotową implementację. Następna lekcja obejmuje hierarchiczne podsumowywanie książek i artykułów naukowych.
Często zadawane pytania
Czy lekcja „Wzorzec podsumowywania Map-Reduce” jest bezpłatna?
Tak — pełny tekst „Wzorzec podsumowywania Map-Reduce” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Prompt Engineering, przejdź na CoddyKit PRO. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.
Co nauczysz się w „Wzorzec podsumowywania Map-Reduce”?
Podsumuj każdy fragment niezależnie, a następnie połącz podsumowania w całość. Ćwiczysz AI Prompt Engineering z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Prompt Engineering?
Nie wymagamy żadnego doświadczenia. AI Prompt Engineering w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Wzorzec podsumowywania Map-Reduce”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Prompt Engineering?
Tak. Każda lekcja AI Prompt Engineering zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Strategie dzielenia długich tekstów na fragmenty
- Wzorzec podsumowywania Map-Reduce
- Podsumowywanie hierarchiczne
- Zachowywanie kontekstu między fragmentami