Суммаризация длинных документов: map-reduce или 1M контекста
Map-reduce нужен, когда документ не влезает в контекст или нужна параллельность, а не ради экономии. Разбираем оба подхода с кодом и расчётом стоимости.
6 мин · · разработка · автоматизация
Суммаризация длинных документов — частая задача: годовой отчёт, пакет договоров, выгрузка переписки, толстый PDF с исследованием. Есть два подхода: нарезать текст на части и суммировать их по отдельности (map-reduce) или отправить документ целиком в модель с большим контекстом. Ниже — когда какой выбирать, рабочий код и расчёт стоимости по ценам Zukko.
Главное про выбор
Распространённый миф — «map-reduce дешевле». На одной и той же модели это не так: в map-reduce модель всё равно читает весь документ (каждый кусок по разу), а сверху добавляются инструкции к каждому куску, промежуточные резюме на выходе и их повторное чтение на шаге reduce. Токенов получается больше, а не меньше.
Map-reduce выбирают по другим причинам:
- Документ не влезает в контекст модели. У
glm-5.3иglm-5.3-flashконтекст 128K токенов; документ на 300K туда целиком не поместится. - Параллельность. Куски можно обрабатывать одновременно, и итоговое время зависит от размера куска, а не всего документа.
- Резюме по разделам. Если нужен отчёт «по главам» или ссылки на конкретные части, промежуточные резюме полезны сами по себе.
Отправка целиком выигрывает, когда документ помещается в контекст выбранной модели: модель видит связи между разделами (ссылка из приложения на пункт договора, вывод в конце, опирающийся на таблицу в начале), а код проще. У claude-sonnet-5, claude-opus-5-5, gpt-5.6-sol и gpt-5.6-luna контекст 1M токенов.
Сколько токенов в документе
Условно: сотня страниц деловой прозы — это десятки тысяч токенов, а текст на русском обычно занимает больше токенов, чем тот же объём на английском. Для точной цифры по Claude-моделям есть эндпоинт подсчёта токенов — см. документацию count_tokens; для остальных ориентируйтесь на usage в ответе первого запроса.
Код: оба подхода и автоматический выбор
Нужен pip install openai и ключ fetch_... в OPENAI_API_KEY.
import os
from concurrent.futures import ThreadPoolExecutor
from openai import OpenAI
client = OpenAI(
base_url="https://api.zukko.pro/v1",
api_key=os.environ["OPENAI_API_KEY"],
)
CONTEXT = {
"glm-5.3-flash": 128_000, "glm-5.3": 128_000,
"gpt-5.6-luna": 1_000_000, "gpt-5.6-sol": 1_000_000,
"claude-sonnet-5": 1_000_000, "claude-opus-5-5": 1_000_000,Что здесь важно:
summarizeотправляет документ целиком, если он с запасом помещается в контекст модели, и переключается на map-reduce только когда не помещается.- Куски режутся по абзацам; абзац длиннее лимита останется одним большим куском — для таких текстов добавьте резку по предложениям.
- Map-шаг идёт параллельно в 5 потоков. Zukko не ограничивает частоту запросов на своей стороне, но у ключа могут стоять дневной и месячный лимиты в долларах: при их исчерпании придёт 429 с кодом
key_daily_limit_reachedилиkey_monthly_limit_reached. - Если частей очень много и их резюме сами не помещаются в контекст, делайте reduce в несколько уровней: сначала группами по 10–20, потом итог.
Подробнее о клиенте — в руководстве по Python SDK.
Сравнение стоимости
Все модели в Zukko стоят одинаково за вход и выход, поэтому формула простая: (вход + выход) × цена / 1 000 000. Допущения: инструкция — около 50 токенов, резюме куска — около 400, итоговое резюме — около 1500.
Документ на 50 тыс. токенов, одна и та же модель
Map-reduce с кусками по 4000 токенов — 13 кусков. Вход: 50 000 (документ) + 13 × 50 (инструкции) + около 5 250 (чтение промежуточных резюме на шаге reduce) ≈ 56 000. Выход: 13 × 400 + 1 500 = 6 700. Итого ≈ 62 700 токенов.
Целиком: вход ≈ 50 050, выход 1 500. Итого ≈ 51 550 токенов.
| Модель | Map-reduce | Целиком |
|---|---|---|
glm-5.3-flash ($0.04) | 62 700 × 0.04 / 1 000 000 ≈ $0.0025 | 51 550 × 0.04 / 1 000 000 ≈ $0.0021 |
claude-sonnet-5 ($0.3) | 62 700 × 0.3 / 1 000 000 ≈ $0.019 | 51 550 × 0.3 / 1 000 000 ≈ $0.015 |
На одной модели map-reduce дороже примерно на 11 тыс. токенов — это плата за нарезку.
Документ на 400 тыс. токенов
В glm-5.3-flash (128K) он целиком не влезет, значит варианты такие: map-reduce на дешёвой модели или целиком в модель с 1M контекста.
- Map-reduce на
glm-5.3-flash: 100 кусков. Вход ≈ 400 000 + 100 × 50 + 40 050 ≈ 445 000, выход ≈ 100 × 400 + 1 500 = 41 500. Итого 486 500 × 0.04 / 1 000 000 ≈ $0.019. - Целиком в
gpt-5.6-luna: (400 000 + 1 500) × 0.1 / 1 000 000 ≈ $0.040. - Целиком в
claude-sonnet-5: 401 500 × 0.3 / 1 000 000 ≈ $0.12. - Map-reduce на
claude-sonnet-5: 486 500 × 0.3 / 1 000 000 ≈ $0.15.
Разница в цене здесь идёт от цены модели, а не от метода. Какой результат вам подходит, проверьте на двух-трёх своих документах: сравните, какие факты, цифры и решения попали в резюме каждого варианта. Актуальный список моделей — GET https://api.zukko.pro/v1/models или страница «Модели» в кабинете.
Оговорка про повторные вопросы и кэш
Если вы задаёте по одному большому документу много вопросов, каждый запрос заново отправляет весь документ во входе. У вендоров чтение такого повторяющегося префикса из кэша стоит около 10% входной цены, а в Zukko кэшированные токены оплачиваются по обычной входной цене. Десять вопросов по документу на 400 тыс. токенов в gpt-5.6-luna — это 10 × 400 000 × 0.1 / 1 000 000 = $0.40. Выгоднее один раз сделать подробное резюме и задавать вопросы по нему.
Как выбрать: короткая шпаргалка
| Ситуация | Подход |
|---|---|
| Документ помещается в контекст выбранной модели | Целиком |
| Документ больше контекста модели | Map-reduce или модель с 1M контекста |
| Нужно резюме по каждому разделу | Map-reduce |
| Важны связи между далёкими частями текста | Целиком |
| Много документов, важна скорость | Map-reduce с параллельными запросами |
Чтобы запустить код, создайте ключ в кабинете; порядок подключения описан в быстром старте.
Частые вопросы
Теряет ли map-reduce информацию?
Может: связь, которая проходит через границу кусков, модель на шаге map не видит. Помогают перекрытие кусков (последний абзац предыдущего куска в начале следующего) и просьба отмечать в промежуточных резюме незакрытые ссылки. Для договоров и документов с перекрёстными ссылками надёжнее отправка целиком.
Как обрабатывать PDF и DOCX?
Сначала извлеките текст, затем передайте его в summarize:
import pdfplumber
from docx import Document
with pdfplumber.open("report.pdf") as pdf:
pdf_text = "\n\n".join(page.extract_text() or "" for page in pdf.pages)
docx_text = "\n\n".join(p.text for p in Document("contract.docx").paragraphs)Для сканов без текстового слоя нужен OCR — extract_text вернёт пустые строки.
Как получить резюме на нужном языке?
Добавьте в промпт строку вроде «Answer in Russian». Качество на вашем языке и в вашей предметной области проверьте на нескольких документах до запуска на весь архив.
Как управлять длиной резюме?
Задавайте длину в промпте: «не больше 300 слов» или «5 пунктов». Параметр max_tokens — это жёсткий обрез ответа, а не регулятор длины: если лимит мал, резюме оборвётся на полуслове.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Перевод субтитров нейросетью: SRT без сбитых таймкодовГлавный риск при переводе SRT нейросетью — сломанная структура файла. Показываем схему, где таймкоды не попадают к модели, и скрипт на Python с проверкой.
- Редактирование текстов нейросетью: корректура, стиль и сокращениеРазные виды редактуры требуют разных промптов. Показываем формулировки для корректуры, стиля и сокращения, как получать правки с объяснением и не терять авторский голос.
- Нейросеть для написания скриптов: Bash, PowerShell и PythonМодель быстро пишет скрипты для рутины, но запускать их вслепую нельзя. Показываем, как ставить задачу, требовать безопасный режим dry-run и проверять результат до запуска.
- Dify в Docker: установка, первичная настройка и подключение моделейСтавим Dify через Docker Compose, создаём администратора и подключаем модели Claude, GPT и DeepSeek по одному ключу. Отдельно — что делать, если контейнеры не стартуют.