Как устроены языковые модели
Клиент пишет в поддержку: «Деньги списались, но подписка не открылась». Ранее в учебном цикле мы обучали модель определять тему такого обращения. Она могла вернуть одну из заданных меток: оплата, доставка или доступ.
Теперь задача шире. Нужно подготовить оператору краткое резюме ситуации, указать, чего пока нельзя утверждать, и предложить черновик ответа клиенту. Заранее перечислить все возможные формулировки нельзя. Здесь пригодится языковая модель: она может сформировать новый текст с учётом заявки и переданного ей контекста.
Но как из чисел внутри модели получается связный ответ? Что означает «модель учитывает контекст»? Почему она иногда верно связывает списание денег с неактивной подпиской, а иногда уверенно придумывает правило возврата, которого никто ей не сообщал?
Разберём один тип распространённых генеративных моделей: авторегрессионную языковую модель на основе Transformer. «Авторегрессионная» означает, что она создаёт продолжение по частям, используя уже полученный текст. Это объяснение покрывает основной механизм генерации многих LLM, но конкретные реализации могут различаться архитектурой, способом обучения и дополнительными компонентами. Базовая работа о Transformer ввела механизм attention; позже авторегрессионные модели показали, как использовать подобную архитектуру для генерации текста по запросу, в том числе с примерами внутри него (исследование GPT-3).
Главная задача модели: выбрать продолжение
Если модели передали начало фразы:
«После оплаты подписка не...»
она вычисляет оценки возможных продолжений. Среди вариантов могут оказаться «активировалась», «открылась» и другие единицы текста. Один вариант выбирается, добавляется к уже имеющемуся тексту, после чего модель повторяет расчёт для следующей позиции.
Этот цикл можно записать так:
Имеющийся текст -> оценки следующих токенов -> выбор токена -> обновлённый текст -> новый расчёт.
Токен - единица, с которой работает модель. Он не обязан совпадать со словом: токеном может быть слово, часть слова, знак препинания или последовательность байтов. Подробно разберём это ниже.
Механизм «предскажи следующий токен» на первый взгляд кажется слишком простым для объяснения резюме, ответов на вопросы или работы с кодом. Однако для точного продолжения большого разнообразия текстов модели приходится учитывать грамматику, связи между частями текста, формат документа и множество закономерностей, встречавшихся при обучении. Дополнительная настройка затем помогает использовать эти возможности для выполнения инструкций.
Здесь важна граница: модель обучается формировать подходящее продолжение, а не напрямую проверять истинность каждого утверждения по актуальной базе компании. Связный ответ и проверенный ответ - разные результаты.
Вывод раздела
- Языковая модель формирует ответ последовательно, выбирая очередной токен с учётом уже доступного контекста.
- Способность продолжать текст не даёт встроенной гарантии фактической точности.
Почему текст сначала превращают в токены
Модель выполняет вычисления над числами. Поэтому входной текст сначала проходит через токенизатор: он разбивает его на единицы из своего словаря и заменяет каждую единицу числовым идентификатором.
Условно фраза «подписка не открылась» могла бы превратиться в последовательность вроде:
«подпис» -> «ка» -> « не» -> « открылась»
Это иллюстрация принципа, а не фактическое разбиение конкретного токенизатора. Другой словарь разделит ту же фразу иначе. У разных моделей число токенов для одного и того же русского текста может отличаться. В открытой документации токенизатора tiktoken показан один из подходов: часто встречающиеся последовательности получают собственные токены, а новые слова можно представить более мелкими частями.
Зачем нужны части слов, если можно сделать токеном каждое слово? Словарь целых слов был бы огромным и плохо справлялся бы с редкими фамилиями, опечатками и новыми названиями. Части слов позволяют собрать незнакомое слово из знакомых элементов. Цена такого решения - длина последовательности становится зависимой от языка, написания и конкретного словаря.
После токенизации наше обращение выглядит для модели не как строка символов, а как список идентификаторов:
Текст заявки -> токены -> идентификаторы токенов.
В этом списке уже есть порядок, но сами идентификаторы пока не говорят модели, какие элементы похожи по употреблению. Идентификатор 128 не «ближе по смыслу» к идентификатору 129 только потому, что числа соседние.
Справка. Токенизация влияет на размер запроса, доступную длину контекста и объём вычислений. Поэтому при проектировании приложения считают токены фактическим токенизатором выбранной модели, а не переводят количество слов в токены по постоянному коэффициенту.
Вывод раздела
- Токен - техническая единица текста, а не обязательное целое слово.
- Токенизатор преобразует текст в числа, но связь между частями текста модель ещё должна вычислить.
Эмбеддинги: как токены получают числовое представление
Каждому идентификатору токена сопоставляется эмбеддинг - вектор из обучаемых чисел. Если упростить для рисунка, вектор можно представить как три числа, например [0,2; −0,7; 0,4]. В реальной модели измерений гораздо больше.
Во время обучения значения векторов меняются вместе с другими параметрами. Токены, участвующие в похожих контекстах, могут получить представления, позволяющие модели использовать их сходным образом. Но отдельную координату такого вектора обычно нельзя надёжно подписать человеческим словом вроде «оплата» или «срочность». Смысл возникает из совместной работы множества координат и слоёв.
Одинаковый токен в разных предложениях начинает с одного и того же базового представления, но после обработки контекста его внутреннее представление меняется. Сравним:
«После оплаты подписка не открылась».
«Нужна подписка на новости».
Слово одно и то же, а его роль в задаче поддержки разная. Эмбеддинг даёт отправную точку; дальнейшие слои должны учесть соседние слова.
Модели также нужна информация о порядке. Набор токенов «клиент отменил платёж» отличается от «платёж отменил клиент», даже если сами слова совпадают. Поэтому к представлению токенов добавляют сведения о позиции. Способ кодирования порядка различается между архитектурами; для понимания здесь важно назначение: модель должна отличать, какой токен где находится.
Последовательность на этом этапе выглядит так:
Идентификатор токена -> начальный вектор + информация о позиции -> обработка в слоях модели.
Не путать два вида эмбеддингов. Здесь речь о внутренних векторах токенов, участвующих в генерации. В системах поиска по документам также используют эмбеддинги целых фрагментов текста, чтобы находить похожие документы. Они решают другую задачу. Доступ к документам через такой поиск подробно рассматривается в главе о RAG.
Вывод раздела
- Эмбеддинг переводит идентификатор токена в обучаемый числовой вектор.
- Позиционная информация помогает учитывать порядок.
- Контекстный смысл возникает после обработки вектора другими слоями, а не хранится целиком в одном числе токена.
Attention: как модель связывает части контекста
Представим запрос оператору:
«Клиент оплатил подписку. Она не открылась. Составь краткое резюме».
Чтобы написать разумное резюме, модели полезно связать «она» с «подпиской». Если ориентироваться только на соседние слова, связь можно пропустить. Для этого в Transformer используется self-attention, или внимание внутри одной последовательности.
На одном из шагов каждый токен получает три вычисленных из его текущего представления вектора:
- Query (Q), запрос: какую информацию этот токен ищет.
- Key (K), ключ: по каким признакам другие токены могут к нему обратиться.
- Value (V), значение: какую информацию токен передаст, если на него обратят внимание.
Это технические роли в вычислении, а не три отдельные человеческие мысли модели. Для текущего токена его Q сравнивают с K доступных токенов. Чем выше результат сравнения, тем больший вес может получить соответствующий V.
Упрощённо расчёт записывается так:
Оценка связи = скалярное произведение Q и K / √d.
Здесь d - размерность ключевого вектора. Скалярное произведение складывает произведения соответствующих координат двух векторов. Деление на √d удерживает масштабы оценок при увеличении числа координат; именно такая нормировка используется в исходной работе о Transformer.
Затем функция softmax превращает оценки в неотрицательные веса с суммой 1. Результат attention для текущей позиции получается как взвешенная сумма векторов V:
Новая информация для позиции = сумма (вес связи × V доступного токена).
Маленький числовой пример
Предположим, для слова «она» после сравнения с двумя более ранними фрагментами получились условные оценки:
- связь с «подписка»: 2;
- связь с «клиент»: 0.
Softmax возводит математическую константу e в степень каждой оценки и нормирует результаты:
Вес «подписка» = exp(2) / [exp(2) + exp(0)] ≈ 0,88.
Вес «клиент» = exp(0) / [exp(2) + exp(0)] ≈ 0,12.
В этом игрушечном расчёте представление «она» получит больше информации от «подписка». Настоящая модель использует много токенов, координат, слоёв и отдельных механизмов внимания. Из одного показанного веса нельзя сделать вывод, что модель «доказанно поняла», к чему относится местоимение.
Для авторегрессионной генерации действует ещё одно правило: токен не должен смотреть на будущие токены. При обучении будущий текст известен из исходного документа, но разрешать на него смотреть означало бы подсказать правильный ответ. Причинная маска закрывает такие связи. Позиция видит себя и предшествующий текст, но не продолжение, которое ей предстоит предсказать.
Вывод раздела
- Attention вычисляет, от каких доступных частей последовательности текущая позиция получит информацию.
- Числовые веса возникают из сравнения обучаемых векторов, а не из заранее написанных правил о словах.
- Причинная маска не позволяет подсмотреть будущий токен во время обучения генерации.
Почему одного attention недостаточно
Один расчёт внимания не составляет всю языковую модель. Обработка повторяется в нескольких слоях. В типичном блоке Transformer информация проходит через attention, затем через позиционную нейронную сеть, которая преобразует представление каждого токена. Между компонентами используются связи, сохраняющие часть прежнего представления, и нормировка, помогающая устойчивому вычислению.
Зачем нужны эти части?
- Attention переносит информацию между позициями. Например, связывает проблему «не открылась» с объектом «подписка».
- Преобразование внутри позиции комбинирует полученные признаки и создаёт новые внутренние представления.
- Повторение слоёв позволяет строить более сложные зависимости на основе результатов предыдущих слоёв.
- Сохранение части предыдущего представления и нормировка помогают проводить сигнал через глубокую сеть и обучать её.
У модели обычно несколько голов внимания внутри слоя. Каждая выполняет подобный расчёт со своими обученными преобразованиями Q, K и V. Это даёт возможность одновременно учитывать разные виды связей, но не следует ожидать, что каждая голова получит простое постоянное название вроде «голова грамматики» или «голова фактов».
Для нашего обращения после нескольких слоёв модель получает контекстное представление всей доступной последовательности. Последняя позиция используется для вычисления оценок токенов, которые могут идти следующими.
Граница объяснения. Схема «attention нашёл связанное слово -> модель поняла смысл» полезна как первая интуиция, но слишком упрощает работу сети. Ответ зависит от многих слоёв, параметров и токенов. Показать один высокий вес внимания недостаточно, чтобы объяснить причину конкретного утверждения модели.
Как языковую модель обучают продолжать текст
В главе об обычной ML-модели мы видели примеры вида «признаки заявки -> правильная тема». Для базового обучения языковой модели разметка устроена иначе: следующий токен уже присутствует в самом тексте.
Возьмём условную последовательность:
«После» -> «оплаты» -> «подписка» -> «открылась».
Из неё можно получить несколько обучающих задач:
| Доступное начало | Токен, который нужно предсказать |
|---|---|
| «После» | «оплаты» |
| «После оплаты» | «подписка» |
| «После оплаты подписка» | «открылась» |
Это схематичные токены для объяснения; фактический токенизатор может разбить слова иначе.
На каждой позиции модель выдаёт оценки всего словаря. Обучение увеличивает оценку действительно следующего токена. Для одной позиции часто используют логарифмическую потерю:
Потеря позиции = −ln(вероятность правильного следующего токена).
Если правильный токен получил вероятность 0,8, потеря равна примерно 0,22. Если он получил 0,02, потеря возрастёт примерно до 3,91. При обучении потери по позициям объединяют, вычисляют градиенты и меняют параметры токенных представлений и слоёв сети.
Здесь проявляется важное различие между обучением и генерацией. При обучении правильное продолжение известно из текста, поэтому потери можно вычислять сразу для многих позиций одной последовательности, закрывая каждой позиции будущие токены маской. При обычной генерации следующий токен неизвестен: модель должна выбрать его, добавить к контексту и только тогда перейти к следующему шагу.
Такой способ базового обучения создаёт модель, способную продолжать самые разные тексты. Чтобы она лучше отвечала на запросы пользователя и соблюдала инструкции, применяют дополнительные этапы настройки на примерах желаемых ответов и, в некоторых подходах, на человеческих предпочтениях. Один исследованный вариант описан в работе об обучении моделей следовать инструкциям с обратной связью от людей. Конкретный набор этапов зависит от модели.
Вывод раздела
- При базовом обучении правильный следующий токен берут из самого обучающего текста.
- Модель меняет параметры, чтобы снижать потерю на множестве таких предсказаний.
- Настройка на инструкции влияет на поведение помощника, но не превращает генерацию в проверку фактов.
Что происходит при создании одного ответа
Проследим путь нашего обращения через готовую модель.
Приложение передаёт запрос:
Заявка клиента: «Деньги списались, но подписка не открылась». Составь для оператора краткое резюме. Не утверждай, что причина уже известна.
Далее выполняются шаги:
- Токенизация. Весь запрос превращается в идентификаторы токенов.
- Начальные представления. Токены получают эмбеддинги и информацию о позиции.
- Слои Transformer. Модель вычисляет контекстные представления, учитывая доступные предыдущие токены.
- Оценки продолжений. Для следующего токена вычисляются числовые оценки по словарю.
- Выбор токена. Правило генерации выбирает один из вариантов.
- Повторение. Выбранный токен добавляется к ответу, и модель рассчитывает продолжение.
Результатом может стать: «Клиент сообщает о списании средств при неактивной подписке. Причина пока не подтверждена». Это возможный ответ, а не гарантированный текст модели. Он отвечает задаче, поскольку отделяет сообщение клиента от проверенного факта.
При генерации система может хранить уже рассчитанные внутренние представления ключей и значений прошлых токенов, чтобы не пересчитывать весь предыдущий текст с нуля на каждом шаге. Такой кеш K/V ускоряет продолжение, но не расширяет доступный модели контекст сам по себе.
Почему ответы на один запрос различаются
На каждом шаге модель выдаёт не единственный неизбежный токен, а набор оценок. Правило выбора может брать наиболее вероятный вариант или допускать выбор среди нескольких.
Температура меняет распределение вероятностей перед выбором. Упрощённо, если оценки токенов обозначить z, их преобразуют по правилу:
Вероятность токена = exp(z / T) / сумма exp(оценок всех токенов / T).
Здесь T - температура. При меньшей положительной T различия между оценками становятся резче; при большей распределение становится ровнее.
Для трёх условных оценок [2; 1; 0] получим примерно:
| Температура | Вероятности трёх вариантов |
|---|---|
| 0,5 | 0,87; 0,12; 0,02 |
| 1 | 0,67; 0,24; 0,09 |
| 2 | 0,51; 0,31; 0,19 |
Числа показывают механизм, а не настройку, подходящую для любой задачи. Более низкая температура часто делает ответы менее разнообразными, но не проверяет их истинность. Если самый вероятный вариант содержит неверное утверждение, усиление его преимущества не исправит факт.
Вывод раздела
- Генерация повторяет вычисление и выбор следующего токена.
- Настройки выбора влияют на вариативность формулировок.
- Более предсказуемая формулировка не равна более надёжному содержанию.
Что такое контекстное окно и почему оно ограничивает ответ
Контекст - доступная модели последовательность токенов текущего запроса: инструкции, сообщение клиента, переданные документы, примеры и уже сгенерированная часть ответа. Модель использует их при расчёте продолжения.
Контекстное окно ограничивает объём последовательности, который можно обработать в одном запросе. Оно измеряется токенами. Конкретный предел зависит от модели и среды её использования. Если приложение не поместило в запрос внутреннее правило возврата, модель не сможет прочитать именно этот документ только потому, что он существует в компании.
Контекст также расходуется на разные части задачи. Если передать длинную переписку, несколько инструкций и множество документов, для продолжения может остаться меньше места. Приложению приходится выбирать полезные фрагменты, сокращать историю или отдельно получать нужные сведения.
Есть и вычислительная причина внимательно относиться к длине. В обычном полном attention каждая из n позиций сравнивается с множеством других позиций. Число пар растёт примерно как n × n: если удвоить длину последовательности, число таких сравнений в этой упрощённой оценке вырастет примерно в четыре раза. Реальное время и память зависят от архитектуры и оптимизации реализации, но длинный контекст не бывает бесплатным.
Наконец, вместить сведения не означает использовать их одинаково хорошо. В исследовании Lost in the Middle для проверенных задач качество извлечения информации снижалось, когда нужный фрагмент оказывался в середине длинного контекста. Это не универсальное правило для каждой модели и запроса, но важная причина тестировать фактическое использование длинных документов.
Контекст не следует путать с изменением параметров. Если показать модели новое правило компании в текущем запросе, она может опереться на него в этом запросе. Это не означает, что её базовые веса тут же переобучились и правило стало постоянной частью модели.
Вывод раздела
- Контекст ограничивает сведения, доступные модели при конкретном ответе.
- Длина запроса влияет на стоимость вычисления и не гарантирует одинакового внимания ко всем фрагментам.
- Переданное в запросе правило и знание, закреплённое в параметрах при обучении, существуют по-разному.
Почему модель придумывает правдоподобные детали
Вернёмся к заявке: «Деньги списались, но подписка не открылась». Допустим, в запросе нет статуса платежа в базе компании и нет правил возврата. Модель всё же может написать:
«Подписка активируется в течение 15 минут; если этого не произойдёт, деньги автоматически вернутся».
Такой ответ выглядит как знакомый шаблон поддержки. Но откуда взялись «15 минут» и автоматический возврат? Из переданного запроса эти сведения не следуют.
Причину ошибки можно проследить по устройству системы. Модель выбирает продолжение, которое кажется подходящим с точки зрения выученных закономерностей и последующей настройки. Внутри описанного механизма нет обязательного шага «сверить утверждение с текущим правилом этой компании». Поэтому правдоподобная фраза может появиться без достаточного основания.
Это не означает, что любой ответ модели неверен. Это означает, что убедительный стиль не служит подтверждением факта. Для прикладной системы нужны отдельные решения:
- передать модели актуальные данные или документы, если ответ должен от них зависеть;
- отделить найденный факт от предположения;
- проверять обязательные поля и ограничения результата программно;
- отправлять рискованные решения на проверку человеку.
Позднее в цикле мы отдельно разберём подключение LLM к приложению, доступ к знаниям через RAG и вызов инструментов. Здесь важно увидеть причину этих компонентов: они дополняют генерацию тем, чего один только механизм продолжения текста не обеспечивает.
Разбираем заявку целиком: какие данные нужны на каждом шаге
Пусть система должна помочь оператору с обращением о списании денег и неактивной подписке. Безопасный для анализа набор входных сведений может выглядеть так:
| Сведение | Откуда берётся | Что можно утверждать |
|---|---|---|
| «Деньги списались» | Текст клиента | Клиент сообщает о списании |
| «Подписка не открылась» | Текст клиента | Клиент сообщает о проблеме с доступом |
| Статус платежа: успешно | Проверенная запись платёжной системы, если приложение её получило | Платёж зарегистрирован успешно |
| Статус подписки: не активирована | Проверенная запись системы подписок, если приложение её получило | Подписка пока не активна |
| Причина расхождения | Пока не установлена | Причину нельзя сообщать как факт |
| Правила возврата | В запрос не переданы | Конкретный срок возврата утверждать нельзя |
Языковая модель полезна для составления понятного резюме и черновика ответа из предоставленных сведений. Но само приложение отвечает за получение актуальных статусов, выбор документов и проверку результата.
Теперь виден полный путь:
Заявка и проверенные сведения -> токены -> контекстные представления в Transformer -> последовательная генерация черновика -> проверка утверждений -> решение оператора или системы.
Если из этого пути убрать проверенные сведения, модель не сможет надёжно восстановить их по формулировке клиента. Если убрать проверку результата, она может придать предположению вид установленного факта.
Типичные сбои и способы их диагностировать
| Что наблюдаем | Возможная причина | Что проверить |
|---|---|---|
| Модель уверенно называет срок возврата, которого нет во входных данных | Правдоподобное продолжение принято за подтверждённый факт | Какие документы и статусы действительно были переданы в запрос |
| Ответ игнорирует важное правило внутри длинного документа | Нужный фрагмент затерялся в контексте или конфликтует с другой инструкцией | Размещение правила, длину запроса, проверку на разных документах |
| Одинаковая заявка получает разные формулировки | Вариативный выбор токенов | Настройки генерации и допустимость вариаций для задачи |
| Модель путает сообщение клиента с состоянием системы | В запросе не разделены источник и статус сведений | Явные поля «со слов клиента» и «проверено системой» |
| Ответ звучит хорошо, но нарушает обязательный формат | Генерация текста сама по себе не гарантирует структуру | Проверку схемы ответа и обработку невалидного результата |
| Модель плохо справляется с новым внутренним правилом | Правило не было передано или оказалось неясным | Источник актуального документа, его версию и тестовые случаи |
Когда нужен классификатор, а когда языковая модель
Сквозной пример позволяет сравнить два подхода без противопоставления их друг другу.
Если задача строго состоит в выборе одной из трёх известных тем, отдельный классификатор может быть проще: у него определённые выходные классы, понятный набор метрик и ограниченный результат. Если нужно составить резюме свободного текста, извлечь неодинаково сформулированные обстоятельства или подготовить черновик ответа, языковая модель даёт более гибкий механизм.
В одной системе они могут работать вместе. Например, классификатор предлагает маршрут заявки, приложение получает проверенные данные по нужной теме, а языковая модель составляет оператору краткое резюме. Затем программные проверки и сотрудник решают, можно ли использовать подготовленный текст.
Главная идея устройства LLM укладывается в последовательность:
Токенизация -> начальные векторы и позиции -> слои attention и преобразований -> оценки следующего токена -> выбор токена -> повторение до завершения.
Во время обучения параметры этой системы меняются так, чтобы улучшать продолжение текстов; дополнительные этапы помогают следовать инструкциям. Во время ответа модель использует доступный ей контекст, но не получает автоматически доступ к действующим правилам, данным компании и проверке истинности. Понимание этого механизма позволяет осмысленно решать, что поручить модели, какие сведения ей передать и где результат необходимо проверить.