pimenov.ai

Qwen3.8 на Mac mini M4 Pro: сначала всё сломалось, потом он написал эту статью

Я установил Qwen3.8 на Mac mini M4 Pro, подключил его к полному Codex, затем собрал тонкий MLX-контур — и модель написала черновик этой статьи.

ИИПрактикаИИ-агентыCodex

Небольшое интро от меня. В работе с локальными моделями я пока новичок. Но это как раз тот случай, когда мне интереснее взяться, установить, соединить всё руками, что-нибудь сломать в разрешённых пределах и уже по фактам разобраться, как оно устроено. Иду вперёд примерно так: сначала появляется рабочая гипотеза, потом терминал, затем новые вопросы — и в конце всё-таки понимание.

На этот раз я взял Qwen3.8 27B, установил его на Mac mini с Apple M4 Pro и 48 GB объединённой памяти и подключил к Codex через Codex Router как ещё одну модель. Дальше совершил вполне понятный новичковый манёвр: предложил локальному Qwen работать почти в том же окружении, что и полноценная модель Codex, с общей историей, системными инструкциями и большим каталогом инструментов. Qwen честно написал «Думаю» и, кажется, решил сделать это своей постоянной профессией.

Ничего полезного из первых запросов не получилось. Зато после разбора журналов стало понятно, где именно сломалась схема. Для Qwen выделили отдельную роль, убрали из его входа MCP и всю историю Codex, подняли отдельный MLX-процесс и передали ему компактный пакет проверенных фактов. Ирония в том, что после этого Qwen получил задание написать статью о собственной установке. Исходный технический черновик этого текста действительно написал локальный Qwen3.8. Затем его утверждения были сверены с журналами и официальными источниками, а текст отредактирован.

Эксперимент показал мне ещё одну важную вещь: нужно отдельно оптимизировать работу Codex с инструментами и контекстом. Большие цифры ниже описывают не случайную свалку переписки, а результат попытки подключить локальную модель к полной агентной среде без предварительного сокращения её служебного пакета. Этот опыт превратился в аудит. Сейчас я разбираю, какие инструменты действительно нужны каждой сессии, что должно загружаться постоянно и что лучше передавать только отдельным задачам.

Первый проверочный запуск дал ложную уверенность

Рабочая конфигурация уже связывала два компьютера. Codex Desktop и Codex Router находились на MacBook, Ollama — на Mac mini с Apple M4 Pro и 48 GB объединённой памяти. Запросы шли через локальный SSH-туннель. В Ollama оставались Qwen3.6 и новая Qwen3.8; для последней был создан отдельный псевдоним с контекстом 131 072 токена. Старый маршрут сохранили для отката, маршрут по умолчанию не меняли.

Первичные проверки выглядели убедительно: API отвечал, модель возвращала короткий текст, потоковая выдача начиналась. Но такой тест доказывает только доступность процесса. Он ничего не говорит о том, успеет ли сервер обработать реальный агентный префикс до тайм-аута клиента.

Разница проявилась в журналах. Простейший пользовательский вопрос в полной сессии превратился в запрос на 196 784 входных токена. В других попытках фиксировались 218 060–221 808 токенов. В исследованной среде было 586 инструментов, 553 из них — MCP; их метаданные занимали около 1,3 млн символов. Эти цифры стали результатом намеренно широкой интеграционной попытки и одновременно подсветили самостоятельную задачу: полный каталог инструментов нельзя автоматически считать нормальным входом для каждой модели и каждой сессии.

Ollama остановил запрос через десять минут

Один из воспроизводимых запусков дошёл до обработки 55 296 токенов примерно за 9,5 минуты. Затем сработала десятиминутная граница ожидания: Ollama записал `context canceled` и вернул `HTTP 500`, клиентская сторона получила `502` и `UND_ERR_HEADERS_TIMEOUT`. Увеличенный до 600 секунд тайм-аут не исправил ситуацию. Он только заставил дольше ждать тот же исход.

Такое поведение совпадает с публичным отчётом в репозитории Ollama о десятиминутном тайм-ауте у MLX runner: запрос завершается `context canceled`, хотя обработка ещё идёт. В других issues описаны отдельные проблемы длинного контекста и удержания KV cache. Эти отчёты помогают увидеть класс ограничений, но не доказывают, что причиной конкретного запуска был именно KV cache. По локальным данным подтверждены большой вход, медленная обработка его префикса и отмена около десятиминутной границы.

Название `qwen3.8:27b-mlx` уже указывало на MLX runner внутри Ollama. Поэтому формула «перейти с Ollama на MLX» слишком грубая. Архитектура модели осталась прежней, изменился путь обслуживания запросов: вместо Ollama с его жизненным циклом появился отдельный `mlx-vlm` server для одного узкого процесса написания текста.

Большой агентный префикс не успевал пройти обработку до десятиминутной отмены запроса.
Большой агентный префикс не успевал пройти обработку до десятиминутной отмены запроса.

Полный агентный пакет оказался лишним

У Qwen3.8 была заявлена большая контекстная ёмкость, а псевдоним Ollama настроили на 128K. Однако реальный запрос в 196 784 токена уже превышал этот предел. Даже если поднять лимит выше, модель должна сначала вычислить весь префикс. На локальной машине это минуты работы до первого содержательного токена и большой KV cache.

Для статьи Qwen не нужны файловая система, терминал, Notion, браузер и сотни MCP-схем. Нужны проверенные факты, редакционный контракт и чёткий формат ответа. Безопаснее сформировать отдельный пакет задания и вызвать модель как ограниченного исполнителя без инструментов. Основной Codex сохраняет роль оркестратора: собирает доказательства, проверяет источники, создаёт визуалы и отвечает за итоговый текст.

Такой подход не облегчает всю сессию Codex. Она по-прежнему получает системные инструкции и доступные инструменты. Компактность появляется на отдельной границе передачи задачи: основной агент сам выбирает факты и отправляет Qwen только то, что относится к статье.

Большой контекст создаёт ложное ощущение, будто в модель можно без разбора отправить весь рабочий стол. Для авторской задачи это ухудшает проверяемость. Когда пакет содержит хронологию, измерения, ссылки и редакционные правила, происхождение каждого утверждения видно сразу. Если черновик сообщает новую цифру или уверенно называет причину сбоя, которой нет в пакете доказательств, основной агент обязан удалить или перепроверить её. Локальная генерация остаётся черновиком, она не становится новым источником правды.

Отдельный MLX-процесс для авторских задач

На Mac mini создана изолированная среда `~/.local/share/qwen-author-mlx` на Python 3.12 через `uv`. В ней зафиксированы `mlx-vlm==0.6.13`, `mlx==0.32.0` и `mlx-lm==0.31.3`. Используется публичная модель `mlx-community/Qwen3.8-27B-4bit` с ревизией `3e6447f082e89cc7f0bc6e5441afd38dfce760ff`. Три файла весов занимают 16 081 490 933 байта, около 14,98 GiB.

LaunchAgent `ai.pimenov.qwen-author-mlx` запускает mlx_vlm.server и слушает только `127.0.0.1:18080`. Параметр `--max-kv-size 65536` ограничивает размер KV cache; KV-квантование, prefix caching и speculative decoding не включены. Режим рассуждений по умолчанию выключен.

На MacBook работает второй LaunchAgent — `ai.pimenov.qwen-author-tunnel`. Он привязывает локальный `127.0.0.1:18080` к тому же loopback-порту Mac mini через существующее SSH-соединение. Сервер не публикуется на сетевом интерфейсе Mac mini, клиент обращается к совместимому с OpenAI API.

Команда `qwen-author` задаёт границу задачи. Она принимает Markdown через стандартный ввод и отказывается от пакетов больше 80 000 байт UTF-8. В теле запроса отсутствует поле `tools`, выставлено `enable_thinking=false`, включена потоковая выдача и задано не более 8192 выходных токенов. Файловая блокировка допускает только один запрос одновременно. Простые шаблоны защищают от случайной передачи учётных данных, журнал содержит размер входа, время и статус без текста запроса и ответа.

Основной Codex собирает компактный пакет, а локальный Qwen возвращает только Markdown-черновик.
Основной Codex собирает компактный пакет, а локальный Qwen возвращает только Markdown-черновик.

Первый токен за секунды вместо минут

После загрузки процесса его RSS составлял около 15,5 GiB. `memory_pressure` показывал 56% свободной памяти. Подкачка на машине была ненулевой, но между загрузкой модели и проверочными запусками не выросла; признаков нарастающего давления на память в этом окне не наблюдалось.

Проверка состояния через туннель вернула `healthy` за 0,048 секунды. В коротком запросе с потоковой выдачей первый токен появился через 6,464 секунды, весь ответ завершился за 6,671 секунды. Репрезентативный пакет размером 1720 байт дал первый токен через 4,289 секунды и закончил ответ за 33,009 секунды. Это укладывается в заданный предел пяти минут до первого токена с большим запасом.

Затем Qwen получил полный пакет доказательств для этой статьи. В него вошли хронология, локальные журналы, параметры новой среды, официальные источники и редакционные запреты. Модель вернула Markdown статьи и самопроверку без MCP, файловой системы и общей истории Codex. Черновик потребовал фактологической правки: в нём причинная связь с KV cache была сформулирована увереннее, чем позволяли журналы, а несколько сетевых и производительных выводов оказались слишком широкими. Поэтому исходный ответ сохранён как подтверждение происхождения текста, технические утверждения итоговой версии сверены отдельно.

Границы безопасности и эксплуатации

Изоляция нужна не только ради скорости. Сервер слушает loopback, пакет проходит локальную проверку размера и простых шаблонов учётных данных, а содержание не попадает в служебный журнал. Это снижает риск случайно превратить локальный процесс в общую сетевую точку доступа или записать исходный материал в журнал. При этом фильтр регулярных выражений нельзя считать полноценной системой поиска секретов: перед передачей задачи основной Codex всё равно отвечает за отбор и очистку контекста.

У отдельного процесса нет прав на Notion и другие внешние действия. Он возвращает текст в стандартный вывод; дальнейшая сборка пакета материала, проверка визуалов и проверочный запуск выполняются основным процессом. Если Qwen ошибается или API недоступен, запрещён автоматический переход на Ollama либо платный облачный маршрут. Ошибка ограничивается одним авторским вызовом и не меняет остальную конфигурацию.

Сервис также не становится универсальной основой для всех задач Codex. Ограничение 65 536 для KV cache, лимит 80 000 байт на пакет и один одновременный запрос выбраны для этого контура. Их нельзя переносить на другие модели и машины без нового измерения памяти, времени до первого токена и размера реального входа.

Локальная модель получила узкую роль

Ollama, его модели, старые маршруты Router и маршрут по умолчанию не менялись. Новый контур существует параллельно и решает одну задачу: ограниченная генерация текста из заранее собранного пакета. Он не появляется в списке моделей Codex Desktop и не пытается заменить полноценную агентную модель.

Практический вывод прост: большой контекст модели не делает локальную модель готовой к полной агентной среде. Сначала нужно измерить фактический вход и время до первого токена. Если для задачи не требуются инструменты, лучше вынести её в отдельный процесс и передать минимально достаточный контекст. Это снижает нагрузку, делает границу данных понятной и не ломает рабочий маршрут.

Откат нового решения тоже изолирован: достаточно выгрузить `ai.pimenov.qwen-author-tunnel` на MacBook и `ai.pimenov.qwen-author-mlx` на Mac mini. Модель, виртуальное окружение, Ollama и конфигурация Router при этом остаются на месте. Такой откат не требует перезапуска Codex Desktop и не затрагивает прежний Qwen3.6.


Следующий шаг

Если хотите повторить схему с самого начала, сначала разберите базовую установку и подключение локальной модели: Как поднять свою LLM и подключить к Codex.

Связанные материалы

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

Если захотите обсудить, как это применить у себя или в команде — пишите в Telegram @pimenov