/
Вопросы и ответы
/
Промт-инжиниринг
/

Как работать с длинными документами в LLM?

Как работать с длинными документами в LLM?

9 часов назад

Никита Вихров

Ответы

0

Как работать с длинными документами в LLM

Документ не влезает в контекст — классическая проблема. PDF на 200 страниц, кодовая база из 50 файлов, лог на 100 000 строк. Разбираем три стратегии: разбивка на чанки, суммаризация, иерархическая обработка.


Стратегия 1: Map-Reduce

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

from anthropic import Anthropic

client = Anthropic()


def chunk_text(text: str, chunk_size: int = 4000, overlap: int = 200) -> list[str]:
    """Разбивает текст на чанки с перекрытием"""
    chunks = []
    start = 0

    while start < len(text):
        end = start + chunk_size

        # Ищем конец предложения чтобы не обрывать на середине
        if end < len(text):
            last_period = text.rfind(".", start, end)
            if last_period > start + chunk_size // 2:
                end = last_period + 1

        chunks.append(text[start:end])
        start = end - overlap  # перекрытие между чанками

    return chunks


def map_reduce_summarize(document: str, question: str = None) -> str:
    chunks = chunk_text(document)
    print(f"Разбито на {len(chunks)} чанков")

    # Map: обрабатываем каждый чанк
    chunk_summaries = []
    for i, chunk in enumerate(chunks):
        print(f"Обрабатываю чанк {i+1}/{len(chunks)}...")

        prompt = f"Кратко изложи ключевые факты из этого фрагмента текста:\n\n{chunk}"
        if question:
            prompt = f"Из этого фрагмента извлеки информацию релевантную вопросу: '{question}'\n\n{chunk}"

        response = client.messages.create(
            model="claude-haiku-4-5",  # дешевле для map-шага
            max_tokens=512,
            messages=[{"role": "user", "content": prompt}]
        )
        chunk_summaries.append(response.content[0].text)

    # Reduce: объединяем результаты
    combined = "\n\n---\n\n".join(chunk_summaries)

    final_prompt = f"На основе этих фрагментов {'ответь на вопрос: ' + question if question else 'напиши итоговое резюме'}:\n\n{combined}"

    response = client.messages.create(
        model="claude-opus-4-5",  # лучшая модель для финального синтеза
        max_tokens=1024,
        messages=[{"role": "user", "content": final_prompt}]
    )
    return response.content[0].text

Стратегия 2: иерархическая суммаризация

Суммаризируем чанки, потом суммаризируем суммари — для очень длинных документов:

def hierarchical_summarize(document: str, target_length: int = 2000) -> str:
    """Суммаризирует документ любой длины"""

    # Если влезает — суммаризируем напрямую
    if len(document) < 20_000:
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=target_length // 4,
            messages=[{"role": "user", "content": f"Кратко изложи:\n\n{document}"}]
        )
        return response.content[0].text

    # Разбиваем на чанки
    chunks = chunk_text(document, chunk_size=8000)

    # Первый уровень: суммаризируем чанки
    level1_summaries = []
    for chunk in chunks:
        response = client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=500,
            messages=[{"role": "user", "content": f"Изложи суть в 3-5 предложениях:\n\n{chunk}"}]
        )
        level1_summaries.append(response.content[0].text)

    combined_l1 = "\n\n".join(level1_summaries)

    # Если суммари первого уровня всё ещё велики — рекурсия
    if len(combined_l1) > 20_000:
        return hierarchical_summarize(combined_l1, target_length)

    # Финальное суммари
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=target_length // 4,
        messages=[{"role": "user", "content": f"Объедини эти фрагменты в связное резюме:\n\n{combined_l1}"}]
    )
    return response.content[0].text

Стратегия 3: скользящее окно для анализа

Для задач где важен локальный контекст — анализ кода, поиск паттернов:

def sliding_window_analysis(
    text: str,
    window_size: int = 3000,
    stride: int = 1500,
    analysis_prompt: str = "Найди аномалии или важные паттерны в этом фрагменте"
) -> list[dict]:

    chunks = []
    start = 0
    while start < len(text):
        chunks.append({
            "start": start,
            "end": min(start + window_size, len(text)),
            "text": text[start:start + window_size]
        })
        start += stride

    results = []
    for chunk in chunks:
        response = client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=256,
            messages=[{
                "role": "user",
                "content": f"{analysis_prompt}:\n\n{chunk['text']}"
            }]
        )

        # Сохраняем только если нашли что-то важное
        answer = response.content[0].text
        if "нет" not in answer.lower() and len(answer) > 50:
            results.append({
                "position": f"символы {chunk['start']}-{chunk['end']}",
                "finding": answer
            })

    return results


# Пример: анализ логов на аномалии
with open("app.log") as f:
    logs = f.read()

findings = sliding_window_analysis(
    logs,
    analysis_prompt="Найди ошибки, предупреждения и аномальные паттерны"
)

for finding in findings:
    print(f"\n📍 {finding['position']}:")
    print(finding['finding'])

Когда какую стратегию

Map-Reduce — когда нужен ответ на конкретный вопрос по всему документу. Работает для Q&A, извлечения данных, анализа.

Иерархическая суммаризация — когда нужно общее резюме очень длинного документа. Документы, книги, большие логи.

Скользящее окно — когда важен локальный контекст и нужно найти паттерны. Анализ кода, логов, последовательных данных.


На курсе «ИИ для разработчиков» на Хекслете разбирают как работать с реальными данными через агентов и пайплайны — включая обработку больших документов.

9 часов назад

Никита Вихров

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845