0Pricing
AI Prompt Engineering · Урок

Шаблон обобщения Map-Reduce

Обобщайте каждый блок отдельно, а затем объединяйте получившиеся резюме

«Шаблон обобщения Map-Reduce» — бесплатный урок AI Prompt Engineering на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Prompt Engineering, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Prompt Engineering содержит 4 уроков всего.

Паттерн MapReduce

Если документ превышает контекстное окно LLM, его нельзя передать целиком за один раз. Паттерн MapReduce решает эту задачу:

  • Сопоставление: независимо суммировать каждый фрагмент
  • Сведение: объединить сводки всех фрагментов в одну итоговую сводку

Это повторяет классический MapReduce из распределенных систем — та же логика разделения задачи и ее решения по частям применяется к языковым задачам.

Шаг 1: фаза сопоставления

На фазе сопоставления каждый фрагмент передается LLM вместе с запросом на суммаризацию. Модель возвращает краткую сводку только этого фрагмента. Эти сводки собираются в список.

Каждая сводка должна быть намного короче исходного фрагмента — обычно составлять 10–20% его исходной длины. Именно это сжатие делает этап сведения выполнимым.

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]

Шаг 2: фаза сведения

На фазе сведения все сводки фрагментов объединяются и передаются LLM вместе с запросом на синтезирование. Модель создает одну связную итоговую сводку.

Если сводки фрагментов по-прежнему слишком длинные и не помещаются в одно контекстное окно, применяйте сведение рекурсивно — сначала суммируйте группы сводок, а затем объединяйте полученные результаты.

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.content

Собираем всё вместе: прямые вызовы API

Ниже приведен полный конвейер MapReduce с использованием прямых вызовов API OpenAI — фреймворк не требуется. Это дает полный контроль над запросами и параметрами на каждом этапе.

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)

MapReduceDocumentsChain в LangChain

LangChain предоставляет готовую цепочку MapReduceDocumentsChain, которая выполняет разбиение на фрагменты, параллельные вызовы на этапе сопоставления и этап сведения. Это удобно, но менее гибко, чем прямые вызовы 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'])

Параллельное выполнение фазы сопоставления

Сводка каждого фрагмента не зависит от остальных, поэтому фазу сопоставления можно выполнять параллельно. С помощью ThreadPoolExecutor из Python все вызовы API для фрагментов отправляются одновременно, что значительно сокращает фактическое время выполнения.

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 summaries

Рекурсивное сведение

Если документ очень длинный, сами сводки фрагментов могут превысить размер контекстного окна. Применяйте сведение рекурсивно: группируйте сводки в пакеты, сводите каждый пакет, а затем сводите сводки пакетов.

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]

Сохранение важных деталей

Распространенная проблема простого MapReduce: важные детали теряются во время сжатия. Меры против этого:

  • В запросе для этапа сопоставления просите сохранять имена, числа и даты
  • Просите на этапе сведения проверять наличие противоречий между разделами
  • Используйте фрагменты большего размера, чтобы контекст на этапе сопоставления был более содержательным
  • Проводите этап проверки: спрашивайте модель, присутствуют ли ключевые сущности из исходного документа в итоговой сводке
MAP_PROMPT = '''Summarize the following section in 5 sentences.
Preserve all key names, numbers, dates, and conclusions.

Section:
{chunk}'''

Цепочка уточнения: альтернативный паттерн

Цепочка уточнения — это альтернатива MapReduce. Она последовательно обрабатывает фрагменты: сводка фрагмента N передается вместе с фрагментом N+1, а модель обновляет текущую сводку. Это дает более связный результат, но не позволяет выполнять обработку параллельно и работает медленнее.

Используйте уточнение, когда важна связность повествования (например, в юридических договорах). Используйте MapReduce, когда важна скорость (например, при пакетной обработке новостных статей).

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_summary

Управление стоимостью и токенами

MapReduce требует множества вызовов API. Для документа из 100 фрагментов при использовании gpt-4o по цене $5 за 1 млн входных токенов:

  • Сопоставление: 100 фрагментов × 1000 токенов = 100 тыс. входных токенов ≈ $0.50
  • Сведение: около 10 тыс. токенов (сводки) ≈ $0.05
  • Итого: около $0.55 на документ

Чтобы снизить стоимость, используйте gpt-4o-mini на этапе сопоставления ($0.15 за 1 млн токенов), а gpt-4o — только на этапе сведения. Такой гибридный подход снижает затраты на 70% при минимальной потере качества.

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')

Когда использовать MapReduce

Суммаризация MapReduce лучше всего подходит для:

  • документов, длина которых превышает контекстное окно модели
  • пакетной суммаризации множества документов (параллельно обрабатывайте документы и на уровне документов)
  • ситуаций, в которых нужен контроль над запросом на каждом этапе

Этот подход хуже подходит для извлечения конкретного факта (вместо него используйте поиск) и для документов, которые достаточно коротки и помещаются в контекстное окно (просто суммируйте их напрямую).

Проверка знаний

Что происходит на фазе сведения в паттерне суммаризации MapReduce?

Повторение: суммаризация MapReduce

Паттерн MapReduce позволяет обрабатывать документы, слишком длинные для одного вызова LLM:

  • Сопоставление: независимо суммировать каждый фрагмент — можно выполнять параллельно
  • Сведение: объединить сводки фрагментов в одну итоговую сводку
  • Рекурсивное сведение: применять, когда сами сводки слишком длинные
  • Совет по стоимости: используйте недорогую модель для сопоставления и качественную модель для сведения

MapReduceDocumentsChain в LangChain предоставляет готовую реализацию. В следующем уроке рассматривается иерархическая суммаризация книг и научных статей.

Часто задаваемые вопросы

Урок «Шаблон обобщения Map-Reduce» бесплатный?

Да — полный текст урока «Шаблон обобщения Map-Reduce» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Prompt Engineering, подпишись на CoddyKit PRO. Курс AI Prompt Engineering содержит 4 уроков всего.

Чему я научусь в уроке «Шаблон обобщения Map-Reduce»?

Обобщайте каждый блок отдельно, а затем объединяйте получившиеся резюме Ты практикуешь AI Prompt Engineering с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Prompt Engineering?

Предыдущий опыт не требуется. AI Prompt Engineering на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Шаблон обобщения Map-Reduce»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Prompt Engineering?

Да. Каждый урок AI Prompt Engineering включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Стратегии разбиения длинных текстов
  2. Шаблон обобщения Map-Reduce
  3. Иерархическое обобщение
  4. Сохранение контекста между блоками
← Назад к AI Prompt Engineering