CPU внутри LLM: как RISC-V-ядро живёт в весах Qwen3.5
Спросите Qwen3.5, сколько будет 123 456 789 × 987 654 321, и модель начнёт угадывать. Qwenputer на том же вопросе не угадывает. Внутри её весов работает 32-битное RISC-V-ядро, и ответ приходит из регистров, а не из распределённых вероятностей.
Автор эксперимента Дивьянш Агравал выложил модель, код и разбор 22 октября 2026 года. Главное в этой работе не арифметика. Главное, что точность перестала быть свойством модели и стала свойством адресации.
Что такое Qwenputer
Qwenputer это стоковая Qwen3.5 4B, в веса которой добавлен RISC-V CPU общего назначения. Ядро исполняет программы прямо в прямом проходе модели, а оперативной памятью ему служат те же слои Gated DeltaNet, которые модель использует для внимания. Ни плагина, ни песочницы, ни вызова внешнего инструмента.
Формально это не дообучение и не файнтюн. Веса исходной модели остаются нетронутыми, компьютерные слои добавлены сверху отдельными измерениями. Компилятор расставляет значения весов вручную, без градиентов и без единого шага обучения.
Почему рекуррентное состояние годится на роль оперативной памяти
В Qwen3-Next и Qwen3.5 три из четырёх слоёв внимания используют Gated DeltaNet, линейную рекуррентную архитектуру. У каждой головы есть матрица состояния, которая обновляется на каждом токене. Сначала состояние умножается на гейт, число от нуля до единицы, и это способ забывания: гейт 0,9 стирает всё понемногу, гейт 1 не стирает ничего.
Дальше голова сдвигает одно направление состояния к новому значению, а сила записи beta задаёт, насколько далеко. При beta равной единице старое значение заменяется целиком, без смешивания. Если добавить one-hot кодирование ключей, вектор из нулей с единственной единицей, каждая запись попадает ровно в одну строку состояния. Тогда one-hot запрос читает ровно то, что было записано.
Получается настоящая RAM с адресами, а не сжатая ассоциативная память, которая «примерно помнит». И стоит она дешевле, чем использовать под ту же задачу обычное внимание: состояние головы Gated DeltaNet не растёт с длиной диалога, тогда как KV-кэш растёт линейно и в какой-то момент перестаёт помещаться в память.
Сама идея не новая. Шлаг, Ири и Шмидхубер ещё в 2021 году показали, что линейное внимание с дельта-правилом работает как ассоциативная память, «быстрые веса». Новое здесь в том, что память сделали точной и адресуемой внутри продакшн-модели, и этого хватило, чтобы запустить на ней целый процессор.
Важная деталь: в обычной Qwen3.5 состояние Gated DeltaNet не хранит точные значения. Гейт и beta там обучаемые и плавают, поэтому запись размывается. Автор выставил их в единицу принудительно и получил детерминированное поведение вместо статистического.
Почему нельзя обойтись обычным вниманием? Технически можно, и эксперименты с «RAM на attention» существуют. Но там память это KV-кэш, который растёт с каждым токеном, а извлечение идёт по мягкому совпадению ключей. Чем больше пар ключ-значение, тем сильнее интерференция: похожие адреса конкурируют, и точное чтение деградирует. Gated DeltaNet снимает оба ограничения сразу, потому что состояние фиксированного размера обновляется по адресу, а не смешивается со всей историей.
Компилятор вместо обучения
CPU описывается как схема, длинный список мелких шагов: прочитать регистр, сложить два числа, перейти если ноль. Компилятор превращает каждый шаг в кусок трансформерного слоя. Головы внимания отвечают за поиск по адресу, feed-forward блоки считают арифметику, головы DeltaNet держат память.
Во время генерации каждая инструкция превращается в несколько токенов. Один токен называет строку памяти для записи, следующий несёт значение, третий закрывает инструкцию. Эти токены и есть трейс исполнения: пока модель их генерирует, процессор действительно работает.
Отсюда неожиданное следствие для всех, кто следит за интерпретируемостью. Вычисления модели не спрятаны в суперпозиции признаков, они вынесены в видимую последовательность адресов и значений. Если хочется понять, что модель сделала с числом, можно прочитать её трейс как лог процессора.
Что умеет это ядро
Ядро 32-битное, набор инструкций RV32IM плюс расширение Zba и небольшой блок для больших чисел. Оно занимает 11 слоёв перед 32 слоями Qwen. По словам автора, ядро проходит официальные riscv-tests, программы совпадают с результатами qemu, а 18 миллионов инструкций оно отработало автономно, без эталонной машины, которая поправляла бы его по ходу, и без единой ошибки.
На этом ядре уже работает код на C и MicroPython, хотя и медленно. До Linux-класса не хватает памяти и скорости, но полный набор RV32IM реализован.
Как Qwen вызывает свой процессор
Самое практичное решение в проекте: никакого дообучения не понадобилось. Автор использовал формат tool call, на котором модели уже хорошо натренированы. Qwen отправляет инструкции и читает ответ в том же синтаксисе, что и при вызове внешней функции, только вместо внешнего рантайма срабатывают компьютерные слои внутри модели.
Есть служебный драйвер RvChat. Он загружает прошивку в состояние Gated DeltaNet и не даёт токенам трейса утекать в обычные слои Qwen. Без него модель начало бы «проговаривать» машинный код в ответе.
Почему не просто вызвать Python
У обычной модели инструмент уже есть, и на простых задачах он работает лучше любого внутреннего ядра. Проблема в цене удобства. Вызов инструмента требует песочницы, отдельного процесса, прав и сетевого хопа, а в агентном цикле добавляет задержку на каждом шаге. Если вычисление нужно внутри длинной цепочки рассуждений, десятки таких вызовов складываются в секунды ожидания.
Есть аргумент менее очевидный: детерминизм. Внешний исполнитель это ещё одна система, которая может обновиться, упасть или повести себя иначе. Вкомпилированное ядро живёт в том же чекпоинте, что и модель, и на одинаковом входе даёт одинаковый трейс. Для воспроизводимых экспериментов и для аудита это разница принципиальная.
Проверка на цифрах
Арифметические наборы DeepMind дают такую картину. На div_big Qwenputer набирает 97,5% против 95% у Qwen с Python-инструментом и 72,5% у базовой модели. На mul_big результат 97,5% против 100% с Python и 55% у базовой. На mul_div_multiple_longer Qwenputer даёт 100%, Python-инструмент 97,5%, базовая модель 90%. На add_or_sub_big 97,5%, столько же, сколько с Python, и 87,5% у базовой.
Стоит понимать, что именно проверяли. Наборы DeepMind и NUPA состоят из длинных целых чисел, которые не помещаются в мантиссу float и требуют поразрядной арифметики. Базовая модель решает их вероятностно: она видела похожие примеры и продолжает последовательность цифр, поэтому ошибается тем чаще, чем длиннее число. Процессор внутри весов считает их так, как это сделал бы компилятор на обычной машине.
На длинной целочисленной арифметике NUPA разрыв ещё заметнее: 48,6% у базовой модели превращаются в 100%. Ровно столько же даёт Python-инструмент.
Смысл не в том, что Qwenputer обошёл Python. Смысл в том, что он сравнялся с ним, не выходя за пределы модели. Никакого сервера инструментов, никакой песочницы, никакой сетевой задержки. Для сценариев, где внешний вызов запрещён или нежелателен, это принципиально другая инженерия.
Отдельно автор проверил, не врёт ли процессор. Около 230 000 позиций вывода он сверил с эталонной машиной и не нашёл ни одного расхождения. Речь модели при этом не пострадала: расхождение с базовой Qwen по KL-дивергенции 6e-4 при уровне шума 5e-4, то есть в пределах погрешности.
Файловая система в состоянии RNN
Раз RAM уже есть, автор добавил к ней дисковую подсистему, и это самая странная часть проекта. Модель получает внутренние операции put, append, get, list и delete, снова без внешних вызовов. Имя файла хешируется в один из 1024 слотов каталога, каталог лежит в состоянии DeltaNet, а текст хранится в других головах по восемь токенов в строке, связанных в цепочку. При коллизии имён берётся следующий слот.
Поиск файла занимает два-три шага вместо полного перебора. Влезает до 512 файлов, примерно 53 000 токенов текста. Состояние можно сохранить в конце разговора и загрузить в следующий, файлы останутся на месте.
И это не игрушка для демонстрации. На вопросах, ответы на которые изменились между чатами, модель с такой файловой системой отвечает верно в 90% случаев против 30% при вставке старых чатов в промпт. С Python-инструментами памяти получается 83,3% против 78,9% у Qwenputer, то есть внутренняя файловая система как минимум не хуже внешней.
Где ломается
Чекпоинт весит 18,8 ГБ, примерно вдвое больше базовой модели, хотя большая часть прироста это нулевой паддинг. Нулевой паддинг появился потому, что компьютерные слои шире базовых: под адреса и значения выделены дополнительные измерения, и в конкретной прошивке большая их часть не используется. Для запуска нужен драйвер RvChat, обычный generate() не подойдёт: прошивку надо загрузить в состояние, а трейс-токены удержать от вывода. Запускается всё на одной GPU с 24 ГБ.
Скорость остаётся главным ограничением. Каждая инструкция процессора стоит нескольких декодированных токенов, поэтому крупное вычисление занимает секунды вместо миллисекунд. Пакетный исполнитель, на котором гоняли бенчмарки, выдаёт около 3200 процессорных токенов в секунду на L4.
Дальше автор планирует дать модели инструмент python(), который исполнял бы MicroPython на этом же ядре, и ускорить процессор. Второе важнее: пока цена инструкции измеряется токенами, нишу таких моделей составляют точные, но редкие вычисления, а не замена обычному коду.
Зачем это, кроме арифметики
Точный контроль над рекуррентным состоянием открывает тему, которая к арифметике отношения не имеет. Гибридные модели вроде Qwen3.5 могут научиться прятать рассуждение в состоянии RNN, и тогда мониторинг по chain-of-thought перестаёт что-либо видеть: модель рассуждает в памяти, а в тексте выдаёт только вывод. Автор разобрал этот сценарий отдельно.
Обратная сторона той же медали выглядит полезнее. Скомпилированные веса работают как встроенный монитор, который модель не может отключить, и как «ключи ответов» для интерпретируемости: если вычисление вынесено в адреса и значения, его можно проверить снаружи, не полагаясь на самоотчёт модели.
Именно это делает Qwenputer интересным для безопасности, а не для калькулятора. Мы привыкли, что интерпретируемость добывается постфактум, обучением зондов и подбором промптов. Здесь её проектируют заранее, на этапе компиляции, и она не зависит от того, что модель «решила» показать.
Часто задаваемые вопросы
Qwenputer это tool call или настоящий CPU внутри модели?
Настоящий CPU, но вызванный через привычный формат tool call. Внешнего рантайма нет: инструкции исполняются слоями модели, а памятью служит состояние Gated DeltaNet. Формат tool call использован только как интерфейс, к которому Qwen уже привыкла, чтобы не дообучать модель.
Можно ли так же вкомпилировать что-то крупнее, например Linux?
Пока нет. Ядро занимает 11 слоёв, чекпоинт вырос до 18,8 ГБ, а каждая инструкция стоит нескольких токенов. Для Linux нужны контроллер прерываний, таймеры и на порядки большая память. Автор называет ускорение процессора главной следующей задачей.
Проблема арифметики LLM решается масштабом?
Нет, и это главный вывод. Базовая Qwen3.5 4B ошибается на длинных числах не потому, что мало параметров, а потому что у неё нет адресуемой памяти. Как только появились точные запись и чтение по адресу, точность выросла до уровня Python-инструмента без единого шага обучения.
Итог
Qwenputer показывает, что внутри языковой модели можно собрать вычислитель с гарантированной точностью, если относиться к её рекуррентному состоянию как к памяти, а не как к сжатому контексту. Компилятор расставляет веса, RISC-V-ядро проходит официальные тесты, 18 миллионов инструкций отрабатывают без ошибок, арифметика догоняет Python-инструмент. CPU внутри LLM перестаёт быть метафорой.
Самое ценное здесь даже не бенчмарк, а трейс. Вычисления модели становятся видимыми, потому что каждое действие оставляет адрес и значение в последовательности токенов. Если вам интересно, где проходит граница между «модель умеет» и «модель исполняет», начните с этой границы: она теперь проходит по слоям Gated DeltaNet.