Языковая модель как предсказатель следующего токена
Этот урок объясняет главную идею: всё, что делает ChatGPT или Claude, вырастает из одной задачи — угадать следующий кусочек текста.
Языковая модель (language model) — это функция, которая по уже написанному тексту оценивает вероятность каждого возможного следующего токена.
Одна задача, из которой растёт всё
Кажется, что чат-бот «понимает вопрос», «рассуждает» и «отвечает». Но под капотом происходит нечто куда более скромное и механическое: модель снова и снова отвечает на один и тот же вопрос — «какой токен идёт дальше?». Возьмите фразу «Москва — столица», и модель оценит, что после неё вероятнее всего стоит «России», а не «банана». Затем она добавляет этот токен к тексту и спрашивает себя то же самое заново. Так, шаг за шагом, рождается целый ответ.
Это называется авторегрессией: каждый новый токен предсказывается на основе всех предыдущих, включая только что сгенерированные. Магии диалога нет — есть очень хорошо настроенный угадыватель продолжений.
Почему «токен», а не «слово»
Дальше в курсе мы посвятим токенизации целый раздел, но запомните сразу: модель работает не со словами и не с буквами, а с токенами — кусочками текста (часто это части слов). Слово «предсказание» может разбиться на «пред», «сказ», «ание». Для модели текст — это последовательность номеров токенов из заранее построенного словаря.
Что значит «вероятность следующего токена»
На каждом шаге модель выдаёт не один ответ, а целое распределение вероятностей по всему словарю (это десятки тысяч токенов). Грубую интуицию можно получить даже без нейросети — на простой статистике. Посчитаем, какое слово чаще шло следом за данным в маленьком тексте.
from collections import defaultdict, Counter
corpus = (
"я люблю котов я люблю собак я люблю писать код "
"ты любишь котов ты любишь чай"
).split()
# Биграммная модель: для каждого слова считаем, какое слово шло следом.
bigram = defaultdict(Counter)
for a, b in zip(corpus, corpus[1:]):
bigram[a][b] += 1
def predict(word):
if word not in bigram:
return None, []
options = bigram[word]
total = sum(options.values())
ranked = [(w, c / total) for w, c in options.most_common()]
return ranked[0][0], ranked
for w in ("я", "люблю", "ты"):
best, ranked = predict(w)
dist = ", ".join(f"{x}={p:.2f}" for x, p in ranked)
print(f"после '{w}' -> вероятнее всего '{best}' ({dist})")
Вывод:
после 'я' -> вероятнее всего 'люблю' (люблю=1.00) после 'люблю' -> вероятнее всего 'котов' (котов=0.33, собак=0.33, писать=0.33) после 'ты' -> вероятнее всего 'любишь' (любишь=1.00)
Видно главное: ответ — это не «то самое правильное слово», а ранжированный список кандидатов с вероятностями. После «люблю» в нашем тексте три равновероятных продолжения. Большая модель делает то же самое, только опираясь не на пару фраз, а на закономерности из триллионов слов.
Откуда берётся «понимание»
Чтобы хорошо предсказывать следующий токен в произвольном тексте, модели приходится неявно выучить очень многое: грамматику, факты о мире, логические связи, стиль, даже умение продолжать рассуждение. Предсказание следующего токена — это лишь цель обучения. А чтобы её достичь на гигантском разнообразии текстов, модель вынуждена построить внутри себя богатое представление языка и мира. Отсюда и возникает то, что мы воспринимаем как «понимание».
Итог
- Языковая модель оценивает вероятность каждого следующего токена по предыдущему тексту.
- Текст генерируется авторегрессивно: токен за токеном, каждый раз заново.
- На выходе — распределение вероятностей по словарю, а не единственный ответ.
- «Понимание» — побочный продукт того, что хорошо предсказывать текст без него невозможно.