2026 г.

Глава 6. Генерация текста: сэмплирование и его параметры

Учебник «Большие языковые модели»

Модель обучена. Но на выходе у неё — не текст, а распределение вероятностей по словарю для очередной позиции. Превращение распределений в конкретный текст — декодирование — это отдельный слой инженерии со своими параметрами, компромиссами и патологиями. Именно здесь живут «температура» и «top_p», доступные во многих API, и именно здесь удобнее всего разобраться с природой галлюцинаций.

6.1. Авторегрессионный цикл

Генерация устроена как цикл: подать модели контекст → получить распределение следующего токена → выбрать токен → дописать его к контексту → повторить — и так до токена конца сообщения или исчерпания лимита. Каждый новый токен проходит через все слои, но ключи и значения предыдущих позиций обычно берутся из KV-кэша, а не вычисляются заново. Prefill обрабатывает позиции параллельно, decode идёт последовательно и часто хуже загружает ускоритель; поэтому выходные токены у многих провайдеров дороже входных, хотя тарифы зависят от сервиса.

Точнее, модель выдаёт логиты z1, …, zV — по числу на каждый токен словаря, — которые softmax превращает в вероятности. Вся свобода декодирования — в том, как по этим числам выбрать один токен.

6.2. Жадность и её ловушка

Простейшая стратегия — жадная: всегда брать самый вероятный токен (argmax). При неизменных вычислениях она детерминирована, но иногда вырождается в повторы. Попав в цикл («очень, очень, очень…»), жадная генерация не может из него выйти — каждое следующее повторение делает продолжение цикла ещё более вероятным. Кроме того, максимизация вероятности каждого шага по отдельности не максимизирует вероятность текста в целом (это задача поиска по дереву; её приближение — лучевой поиск, beam search, — применяется в машинном переводе, но для открытой генерации даёт скучный, вырожденный текст). Человеческая речь не является цепочкой самых вероятных слов — она постоянно «удивляет», и хорошее декодирование должно оставлять место случайности.

6.3. Температура

Основной инструмент управления случайностью — температура T: перед softmax логиты делятся на неё,

pi = exp(zi/T) / Σj exp(zj/T)

При T → 0 распределение стягивается к максимуму — получаем жадную генерацию; при T = 1 исходные логиты не масштабируются; при T > 1 распределение уплощается, и редкие токены получают больше шансов. Название — прямая отсылка к распределению Больцмана из статистической физики: «горячая» система охотнее посещает маловероятные состояния.

Практический режим зависит от модели и API. Для извлечения данных и классификации обычно начинают с жадного или низкотемпературного режима; для поиска разных идей пробуют более высокую температуру и несколько выборок. Числовые диапазоны нельзя переносить между моделями без теста, а некоторые reasoning-модели вовсе не дают управлять всеми параметрами сэмплирования. Даже условное T = 0 не гарантирует побитовой воспроизводимости при смене версии модели, конфигурации сервера или порядка вычислений.

6.4. Обрезание хвоста: top-k, top-p, min-p

Проблема высокой температуры не в случайности как таковой, а в том, что она открывает дорогу совокупности плохих токенов: каждый из тысяч токенов хвоста ничтожно вероятен, но суммарно хвост весит заметно, и одна неудачная выборка пускает генерацию под откос (а авторегрессия ошибку уже не исправит — следующие токены строятся на ней). Решение — обрезать хвост перед выборкой.

Top-k: оставить k самых вероятных токенов, остальным — вероятность ноль, перенормировать. Грубо: k фиксировано, а «естественное» число разумных продолжений меняется от шага к шагу — после «Столица Франции —» разумен один токен, после «Она открыла дверь и» — сотни.

Top-p (nucleus sampling): оставить минимальный набор токенов, суммарная вероятность которых достигает p. Размер набора адаптируется сам: где модель уверена — выживает один токен, где нет — десятки. Min-p — более поздний вариант: отсекать токены с вероятностью меньше заданной доли от вероятности лидера. Сравнительное поведение зависит от распределения и реализации. На практике температура и top-p действуют совместно, и менять оба параметра сразу не стоит — эффекты перепутываются.

Против дословных повторов применяются и прямые штрафы (repetition / frequency / presence penalty), понижающие логиты уже встречавшихся токенов; работают, но грубы — чрезмерный штраф запрещает законные повторения (термины, имена переменных в коде).

Соберём всё вместе — полный конвейер декодирования одного шага:

import numpy as np

def sample_token(logits, temperature=0.8, top_p=0.95, rng=np.random):
    """logits: (V,) -- выход модели для очередной позиции."""
    z = logits / max(temperature, 1e-6)
    p = np.exp(z - z.max()); p /= p.sum()          # softmax

    # top-p: оставляем минимальное "ядро" с суммой >= top_p
    order = np.argsort(p)[::-1]                    # по убыванию
    csum = np.cumsum(p[order])
    cutoff = np.searchsorted(csum, top_p) + 1      # размер ядра
    keep = order[:cutoff]

    p_keep = p[keep] / p[keep].sum()               # перенормировка
    return rng.choice(keep, p=p_keep)

# Игрушечное распределение: один фаворит и длинный хвост
V = 1000
logits = np.full(V, -4.0); logits[:5] = [3.0, 2.2, 1.9, 0.5, 0.1]
for t in (0.2, 0.8, 1.5):
    tokens = [sample_token(logits, temperature=t) for _ in range(1000)]
    print(f"T={t}: доля фаворита {np.mean(np.array(tokens)==0):.2f}, "
          f"уникальных токенов {len(set(tokens))}")

Запустив, вы увидите механику воочию: при T = 0,2 фаворит побеждает почти всегда; при T = 1,5 тяжёлый хвост получает около 80% вероятностной массы, поэтому даже top-p = 0,95 оставляет ядро примерно из 940 токенов. Это важное ограничение: top-p сдерживает хвост при умеренной температуре, но при высокой температуре и тяжёлом хвосте ядро само разрастается.

6.5. Природа галлюцинаций

Теперь о главной болезни. Модель завершает фразу «Теорема доказана в работе…» по статистике продолжений, а цель следующего токена не проверяет существование статьи. Распределение не является калиброванной оценкой знания: оно может быть острым и для неверной фамилии. После первого выбранного элемента авторегрессия легко достраивает согласованные год, том и страницы, получая правдоподобную выдуманную ссылку. Случайная выборка может добавить вариативность, но корень галлюцинации — несоответствие между обучением на продолжение текста и требованием фактической истины. Пост-обучение (глава 5) может научить модель чаще выражать неопределённость, но не превращает вероятность токена в проверку факта.

Практические следствия: понижение температуры уменьшает разброс, но не добавляет знаний — уверенная галлюцинация при T = 0 никуда не денется. Контекст и RAG (глава 10) могут снизить риск, а критичные утверждения следует проверять внешними инструментами и первичными источниками; ни одна из этих мер по отдельности не гарантирует истинность.

6.6. Структурированный вывод

Отдельный практически важный режим — генерация в жёстком формате: JSON заданной схемы, SQL, вызов функции. Просить формат промптом — ненадёжно; более сильное решение — ограниченное декодирование (constrained decoding): на каждом шаге маскируются все токены, недопустимые по грамматике формата (логиты → −∞), и модель физически не может породить запрещённое грамматикой продолжение. Но контракты API различаются: JSON mode обычно обещает лишь корректный JSON, а режим со схемой — более строгую структуру. Отказ модели, обрыв по лимиту и ошибка API всё равно требуют обработки. Даже при соблюдении схемы валидный JSON может содержать выдуманные или недопустимые по предметной области значения; формат не заменяет бизнес-валидацию.

Упомянем и спекулятивное декодирование: маленькая модель-черновик быстро предлагает несколько токенов вперёд, большая за один проход проверяет их. Совместимые алгоритмы могут сохранить исходное распределение выборки, но выигрыш зависит от доли принятых токенов, оборудования и накладных расходов; его нужно измерять.

6.7. Итоги

Генерация — авторегрессионный цикл над распределениями: температура управляет остротой softmax, top-p/top-k/min-p отрезают хвост, штрафы подавляют повторы; крайние настройки могут давать циклы или бессвязность. Галлюцинации возникают прежде всего потому, что правдоподобное продолжение не равно проверенному факту; температура не добавляет знаний. Ограниченное декодирование может гарантировать синтаксическую структуру в оговорённых условиях, а спекулятивное — ускорить совместимую генерацию. Семантическая проверка остаётся обязанностью приложения.

Осталось разобраться с ресурсом, в котором всё это происходит, — контекстным окном: его устройством, стоимостью и грамотным использованием. Это следующая глава, завершающая вторую часть.

Упражнения

1. В коде из раздела 6.4 отключите top-p (top_p = 1.0) и повторите эксперимент при T = 1,5. Насколько выросло число уникальных токенов? Объясните результат через веса «хвоста» распределения.

2. Реализуйте min-p поверх функции sample_token и сравните с top-p на том же игрушечном распределении при высоких температурах.

3. Один и тот же фактологический вопрос (например, о малоизвестной исторической дате) задайте модели через API десять раз при T = 1,0. Согласованы ли ответы? Что согласованность ответов говорит (и чего не говорит) об их истинности? Проверьте факт по первичному источнику.

404 Not Found

404 Not Found


nginx/1.24.0 (Ubuntu)

Связь с редакцией