RU ▾
Получить API-ключ

Практика с контекстом 100k: дописывание, суммирование, сегментация, бюджет

Контекст 100,000 токенов кажется большим, но роман не влезает. Управляйте контекстом как бюджетом: оценивайте токены, оставляйте место под вывод, суммируйте документы, используйте скользящее окно и скользящий план для романов. Код на Python.

Обновлено

Ключевые моменты

  • 100,000 — это сумма промпта и завершения (completion), а не отдельный лимит ввода.
  • Количество токенов в китайском тексте можно только приблизительно оценить: около 1–1.5 токена на иероглиф. Итоговое значение смотрите в поле usage ответа.
  • Для суммаризации используйте разбиение и слияние, для продолжения романа — фрагменты последних глав и динамический план.
  • По умолчанию max_tokens = 2048, максимум — 16 000. Рассчитайте бюджет перед написанием длинного контента, затем установите значение.

Сначала рассчитайте лимиты

Три числа определяют всё:

  • Контекстное окно на 100 000 токенов, сумма промпта и completion.
  • max_tokens по умолчанию равен 2048, максимум на один запрос — 16,000.
  • Тело запроса не должно превышать 8 МБ. Этот лимит редко становится узким местом — обычно вы упираетесь в лимит токенов.

Формула бюджета проста: prompt available = 100000 - max_tokens. Вы планируете вывод на 4000 токенов, значит, для промпта остаётся максимум 60,000. При превышении API возвращает 400, не обрезая данные автоматически. Поэтому «просто впихнуть всю книгу» — не стратегия, а лотерея.

Еще одно заблуждение: чем больше max_tokens, тем надежнее. На самом деле это зарезервированное место под вывод. Установка 16,000 означает, что под промпт останется только 48,000. Устанавливайте значение по необходимости, не ставьте максимум наугад.

Пример расчёта: у вас есть расшифровка интервью на 300 000 знаков для суммаризации. При грубой оценке 1.3 токена на знак это около 390 000 токенов — более чем в шесть раз превышает лимит, отправить целиком нельзя. Если требуется вывод на 800 токенов, то на блок ввода остаётся максимум 63,000, с учётом 10% запаса — около 50 000. Но это не оптимально: при больших блоках модель хуже фокусируется на середине текста. Поэтому лучше разбивать блоки на меньшие и вызывать модель несколько раз.

Оценка токенов: приблизительный алгоритм

Если нет локального токенизатора, используйте следующие эмпирические значения для грубой оценки. Ниже приведены приблизительные данные, а не точные, погрешность может достигать 10–20% в зависимости от текста:

Тип текстаПриблизительный коэффициент
Основной текст на китайскомОколо 1–1.5 токена на иероглиф
Английский языкОколо 1 токена на 4 символа или 1.3 токена на слово
Код, JSON, текст с обилием спецсимволовТребует больше токенов, чем обычный текст. Рекомендуется использовать консервативную верхнюю оценку.

Пример функции для оценки и расчета бюджета с резервом:

CONTEXT = 100000

def est_tokens(text: str) -> int:
    """粗估:中文按每字 1.3 token,其余字符按每 4 个字符 1 token。仅为近似。"""
    zh = sum(1 for c in text if "\u4e00" <= c <= "\u9fff")
    other = len(text) - zh
    return int(zh * 1.3 + other / 4) + 1

def max_prompt_budget(max_tokens: int, margin: float = 0.1) -> int:
    """给定计划的 max_tokens,返回 prompt 最多能用多少 token(留 margin 余量)。"""
    return int((CONTEXT - max_tokens) * (1 - margin))

# 例:计划让模型写 3000 token,prompt 预算
print(max_prompt_budget(3000))   # 54900

Метод калибровки: отправьте типичный ввод, прочитайте usage.prompt_tokens в ответе, сравните с оценкой и вычислите реальный коэффициент для ваших данных. Затем измените коэффициент на измеренное значение. Оценка нужна только для решения «делить или нет», а для сверки смотрите usage.

Суммаризация длинных документов: разбиение и слияние

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

  1. Разбивайте по границам абзацев, а не по фиксированному количеству символов, чтобы не разрезать предложения.
  2. Оставляйте достаточный бюджет для каждого фрагмента. Рекомендуется не превышать треть от лимита, чтобы оставить место для инструкций и вывода.
  3. При суммаризации фрагментов требуйте сохранения имен, цифр и ключевых событий, иначе информация будет потеряна при объединении.
  4. Если итог суммаризации все еще слишком длинный, выполните рекурсивное сжатие.
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.wushenchaapi.com/v1", api_key=os.environ["API_KEY"])

def split_paragraphs(text, budget):
    """按段落切块,每块估算不超过 budget token。"""
    chunks, cur, used = [], [], 0
    for p in text.split("\n"):
        t = int(len(p) * 1.3) + 1          # 中文粗估
        if used + t > budget and cur:
            chunks.append("\n".join(cur))
            cur, used = [], 0
        cur.append(p)
        used += t
    if cur:
        chunks.append("\n".join(cur))
    return chunks

def ask(prompt, max_tokens=800):
    r = client.chat.completions.create(
        model="uncensored",
        temperature=0.3,
        max_tokens=max_tokens,
        messages=[{"role": "user", "content": prompt}],
    )
    return r.choices[0].message.content

def summarize_long(text, budget=12000):
    parts = split_paragraphs(text, budget)
    partial = [ask("用不超过 200 字概括下面这段,保留人名和关键事件:\n\n" + p) for p in parts]
    merged = "\n".join(f"第{i+1}部分:{s}" for i, s in enumerate(partial))
    return ask("下面是分段摘要,请合并成一份 400 字以内的整体摘要:\n\n" + merged, max_tokens=900)

Здесь temperature равно 0.3 для стабильности задач суммирования. Каждый вызов независим, их можно выполнять параллельно, но помните о лимите в 300 запросов в минуту на ключ; для документов из нескольких десятков частей это ограничение не станет проблемой.

Нет универсального ответа на вопрос о размере фрагмента. Опытным путем оптимальным считается размер от 10 000 до 15 000 токенов. Протестируйте фрагменты размером 5000, 12000 и 25000 токенов и сравните количество упущенных фактов. Для документов с высокой плотностью информации (договоры, техдокументация) фрагменты должны быть меньше, для диалогов с большим количеством повторов — больше.

Продолжение романа: скользящее окно и динамический план

К десятой главе весь текст уже не помещается в контекст, и это не нужно. Используйте двухуровневую память:

  • Близкий план: последние 2–3 главы оригинала для сохранения стиля, ритма диалогов и деталей сцены.
  • Дальний план:ранние главы сжимаются в outline, сохраняя связи, закладки и нерешённые нити.

После написания главы просите модель сжать её до 3–5 строк и добавить в план. Если план превышает 3000 токенов, сжимайте его целиком.

def continue_story(chapters, outline, new_hint, keep_last=3):
    """chapters: 已写章节列表。只带最近 keep_last 章原文,更早的用 outline(滚动大纲)代替。"""
    recent = "\n\n".join(chapters[-keep_last:])
    prompt = (
        f"【全书大纲(早期章节摘要)】\n{outline}\n\n"
        f"【最近章节原文】\n{recent}\n\n"
        f"【下一章要求】\n{new_hint}\n\n请写下一章,约 2000 字。"
    )
    return ask(prompt, max_tokens=4000)

Закладки — то, что最容易 теряется. Выделите в плане отдельный раздел «Нераскрытые закладки» и требуйте обрабатывать одну из них в каждой главе. Также выведите список имен и локаций в system prompt, чтобы модель не меняла их при выходе за пределы окна.

Еще одна проблема при продолжении — дрейф стиля. Модель начинает подражать последним главам, что может исказить предыдущий стиль. Добавьте в system prompt «эталонный фрагмент» — отрывок текста, который вам нравится. Он будет служить якорем и не будет смещаться при движении окна.

max_tokens и обрезание

Обрезание ответа происходит по двум причинам:

  1. Если finish_reason равен length, значит, вы уперлись в установленный max_tokens. Решение: увеличить max_tokens или попросить модель писать частями: «остановись здесь, продолжай, когда я скажу».
  2. Прямая ошибка 400: сумма промпта и max_tokens превысила 100,000. Решение: сократите ввод или уменьшите max_tokens.

Практическая таблица соответствия бюджета:

ЗадачаРекомендуемое значение max_tokensдоступный промпт (приблизительно)
саммари, извлечение80063,200
продолжение главы (около 2000 слов)400060,000
длинный вывод на уровне десятков тысяч слов16000 (лимит)48,000

Длинный вывод также зависит от времени ответа; рекомендуется использовать потоковую передачу, чтобы отображать результат по мере генерации.

Когда продолжение обрезается, не стоит просто передавать модели обрезанный фрагмент с командой «продолжить». Более надёжный подход — вернуть сгенерированную часть в сообщения в качестве assistant и добавить новое user-сообщение «продолжи с последнего предложения, не повторяя предыдущее». Это обеспечит наиболее естественную связность. Обратите внимание, что этот шаг увеличивает длину промпта, поэтому необходимо пересчитать бюджет.

Чек-лист для работы с длинным контекстом

  • Перед каждым запросом рассчитывайте длину промпта с помощью функции оценки; если лимит превышен, используйте ветвление с разбивкой текста.
  • Фиксируйте usage в каждом ответе и постоянно калибруйте коэффициенты оценки.
  • Размещайте system-инструкции и план в самом начале, а ключевые требования из инструкций повторяйте в конце.
  • Проверяйте finish_reason: если это length, выдавайте предупреждение или инициируйте продолжение.
  • Установите лимит на историю диалога; при его превышении удаляйте самые старые сообщения, не дожидаясь ошибки 400 от API.

Похожие материалы: структура промптов см. в Гид по промптам, обработка ошибок — в Справочнике по кодам ошибок, тарификация — на Странице с ценами.

Помните: длинный контекст не означает долговременную память. Модель читает предоставленные вами данные с нуля при каждом запросе и не запоминает результаты предыдущих вызовов. Для сохранения непрерывности вы должны самостоятельно передавать историю.

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

Входит ли вывод в 100k контекста?

Да. Лимит относится к сумме промпта и completion, поэтому чем больше вы установите max_tokens, тем меньше места останется для входных данных.

Сколько токенов приходится на один китайский иероглиф?

Можно оценить лишь приблизительно: в среднем от 1 до 1,5 токена на иероглиф, в зависимости от текста. Самый точный способ — прочитать поле usage в ответе и откалибровать оценку по фактическим данным.

Входные данные автоматически обрезаются при превышении лимита?

Нет, API вернёт 400. Вам нужно самостоятельно сегментировать или удалить старые данные перед вызовом.

Какова максимальная длина одного ответа?

По умолчанию max_tokens = 2048, максимум — 16 000. Для более длинного контента генерируйте его в несколько этапов, используя план или резюме для сохранения связности.

Заполните форму, чтобы получить ключ

Создайте аккаунт, скопируйте ключ, измените Base URL. Конфигурация проста.