Перейти к содержимому
arckep.ru — все нейросети в одном месте без VPN Перейти
>AISTUDY_
Поддержать
AUTHORСвежий выпуск №024 → Куда внедрять агентов: фронт или тыл
Авторская колонка · своя модель дороже APIСЕРИЯ 014
Авторская колонка · выпуск №014

Своя модель
дороже API

Как я поднял локальную модель прямо на сервере, чтобы не платить за облако — и почему через сутки снёс её обратно, хотя она работала.

У меня есть фоновый сторож, который следит за сервером и пишет в Telegram, когда что-то выглядит подозрительно. Полезная штука с одной болезнью: он поднимал тревогу на собственные служебные процессы, и за день столько шума, что настоящую угрозу в этом потоке уже было не заметить.

Решение напрашивалось: поставить между сторожем и Telegram умного фильтра, который отделит «это мы сами» от «это правда чужой». Маленькая классификация — на вход описание события, на выход одно слово: реальная угроза или ложняк. Ровно та работа, под которую языковая модель создана.

И тут была развилка. Можно дёрнуть облачный API — пара копеек, минута настройки. А можно поднять модель прямо на сервере: никакого внешнего провайдера, ничего не уходит наружу, и — как тогда казалось — бесплатно. У меня было требование держать как можно больше на своём железе, плюс соблазн сэкономить: фильтр — первая ласточка, за ним маячил целый выводок фоновых агентов. Сторож, разбор автоматических банов от CrowdSec, ещё с десяток мелких задач. Если у всех будет один общий локальный «мозг» — зачем вообще платить облаку?

Через сутки я этот локальный мозг снёс и вернулся на облачный API. Не потому что он не завёлся — он работал, и работал правильно. А потому что «бесплатно» на общем сервере оказалось самой дорогой опцией из всех. Вот эта история целиком — что ставил, на какие грабли наступил, и почему в итоге арифметика «экономии» перевернулась.

Схема 1Две цены одного решения
Раздел 01

Что я поднимал

Связка простая и популярная: Ollama (это менеджер локальных моделей — качаешь модель одной командой, он поднимает её как локальный сервис, к которому ходишь по сети) плюс модель от Google семейства Gemma 4.

Сначала взял лёгкую версию — около 4 миллиардов параметров. Завелась, отвечала за 7–12 секунд. Но мне хотелось запаса по качеству на будущие задачи, и я переехал на старшую — 26-миллиардную, с архитектурой MoE. Сразу оговорюсь, чтобы не строить интригу на пустом месте: для моей задачки — выбор из двух вариантов — это был перебор, младшая модель справлялась не хуже. Старшую я брал на вырост, под будущий парк агентов, который так и не случился. Так что да, оверкилл — но именно на нём и вылезли все интересные грабли.

Тут стоит пояснить, потому что выбор был осознанный. MoE (mixture of experts, «смесь экспертов») — это когда в модели формально 26 миллиардов параметров, но на каждое слово работает не вся сеть, а маленькая её часть, около 4 миллиардов. Идея красивая: платишь за качество большой модели, а считаешь по цене маленькой. На практике, как выяснилось, «по цене маленькой» — это про вычисления, а не про память: все 26 миллиардов всё равно должны лежать в оперативке целиком. 17 гигабайт на диске. В памяти модель держалась постоянно — около 18 гигабайт, — а в момент ответа раздувалась до 23,7 гигабайта: на время вычисления она разворачивает поверх себя временные буферы. Запомните оба числа, к ним вернёмся — память тут и есть главный герой развязки.

Раздел 02

Где пришлось повозиться

Прежде чем фильтр заработал как надо, я собрал три грабли. Рассказываю не для красоты — на каждую я потратил время, и каждая повторится у любого, кто пойдёт этим путём.

Первая: модель молчала. Шлю запрос — в ответ пусто. Не ошибка, не таймаут, просто пустой ответ с пометкой «закончились токены». Оказалось, современные модели по умолчанию сначала «думают» про себя, и только потом отвечают. Я выдал ей крошечный бюджет на ответ, она весь его потратила на невидимое мне размышление, и до собственно ответа дело не дошло.

Это не баг одной модели, а общий трендРежим скрытого рассуждения сейчас включён по умолчанию у большинства свежих моделей, и ведёт он себя одинаково противно: пустой ответ с пометкой «закончились токены». У Gemma выключается флагом «не думать» плюс запас токенов побольше. У DeepSeek — отдельным параметром в теле запроса. У Claude — настройкой расширенного мышления. Симптом один на всех, поэтому, если получаете пустоту, первым делом проверяйте не свой код, а режим рассуждения.

Вторая: модель дралась сама с собой. Сервер — 12 ядер. Я выделил рантайму половину, 6 ядер, через системные лимиты. А Ollama эти лимиты проигнорировала и запустила 12 рабочих потоков — по числу всех ядер в системе. В итоге 12 потоков дрались за 6 ядер, и это замедляло работу. Когда я вручную сказал «ровно 6 потоков», скорость обработки промпта выросла на 43%.

Было: 12 потоков на 6 ядер
как Ollama выставила сама — потоки дерутся за ядра: 21 токен/с на обработке промпта
Стало: 6 потоков под 6 ядер
выставил вручную — те же ядра, потоки перестали толкаться: 30 токенов/с, +43%

Третья — самая ехидная: модель будила сама себя. Помните, фильтр работал внутри сторожа, который ловит скачки нагрузки? А языковая модель на процессоре во время ответа сама грузит процессор на 300–600%. Дальше — петля: сторож видит скачок нагрузки, зовёт фильтр; фильтр будит модель; модель грузит процессор; сторож видит новый скачок — уже от самой модели; зовёт фильтр снова. Сам себя кусающий за хвост дятел. Лечится тем, что процессы самого движка модели просто вычёркиваешь из наблюдения, чтобы сторож на них не реагировал, — но додуматься до этого можно только напоровшись.

Схема 2Петля самозапуска

После всех трёх фиксов фильтр прошёл мой тест-набор начисто: 12 кейсов из 12, семь ложных тревог отсеяны, пять реальных угроз пропущены дальше. Модель работала корректно. Можно было оставлять. Я снёс её на следующий день.

Раздел 03

Почему я всё равно ушёл на API

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

Память. Те самые 23,7 гигабайта. На сервере всего 43 гигабайта, и на нём же живёт ещё десяток сервисов — база данных, кэш, графовая база, несколько бэкендов, боты. Когда модель встала в память постоянно (а для скорости она должна быть всегда наготове, иначе каждый запрос — это лишние секунды на её загрузку с нуля), свободной памяти на пиках оставалось около 400 мегабайт. Сервер начинал залезать в своп — это когда оперативки не хватает и система сбрасывает часть данных на медленный диск, отчего подтормаживает всё подряд. Любая тяжёлая операция — большая переиндексация, активная сессия — упиралась в потолок. Запас прочности стал нулевым. Модель не просто заняла память: она отобрала её у всего остального.

Скорость. Локально один запрос — 5–12 секунд, тот же запрос через облачный API — меньше полутора. Уже в несколько раз быстрее на каждом обращении. А на полном прогоне разрыв ещё шире: весь мой тест-набор локальная модель молотила две с половиной минуты — запросы вставали в очередь друг за другом, процессор-то один; API тот же набор отдал за одиннадцать секунд, потому что обрабатывал их разом, не упираясь в одно железо. Для единственного фильтра 5–12 секунд ещё терпимо. Для той самой мечты про десяток фоновых агентов это уже очередь на минуты.

Деньги — и вот тут переворот. Я считал, что экономлю. Посчитал честно. Мой фильтр гонит около четверти миллиона токенов в месяц (токен — это примерно три четверти слова). Через облако это стоит меньше десяти центов в месяц. Даже весь воображаемый парк агентов — это единицы долларов. А «бесплатная» локальная модель стоила 23,7 гигабайта оперативки и 20 гигабайт диска — ресурсов, которые на общем сервере были нужнее десяти другим сервисам. Я экономил копейки, расплачиваясь самым дефицитным, что есть на машине. Это не экономия, это размен рубля на копейку.

Железо как потолок. И это не докрутить. На сервере нет видеокарты, а процессор — без специальных инструкций для быстрых вычислений (того, что в больших моделях даёт основной разгон). Без этого упираешься в жёсткий предел скорости, который не сдвинуть никакими настройками — только сменой железа. Я даже проверил, не станет ли быстрее, если убрать Ollama и взять более низкоуровневый движок напрямую: разница в пределах нескольких процентов. Узкое место не в обвязке, а в самом процессоре.

Когда я снёс локальную модель, сервер вернул себе 18,5 гигабайта оперативной памяти (ровно столько она держала постоянно) и 20 гигабайт диска. А облачный фильтр на том же тест-наборе показал ровно ту же точность — 12 из 12. Для выбора из двух вариантов — свой или чужой — качество неотличимо. Я отдал кучу ресурсов и скорости ради приватности, которая этой конкретной задаче была не нужна: сами-то тревоги и так уходили в Telegram, секретов в них нет. Заплатил ресурсами за сейф, в котором нечего прятать.

Раздел 04

Что у сторожа внутри — и что на самом деле поменялось

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

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

Первый рубеж — дешёвый текстовый фильтр, без всякого ИИ. У сторожа есть список заведомо своих процессов и портов — то, что на машине крутится легально. Каждое событие сначала прогоняется через этот список простым сопоставлением текста. Очевидно «своё» отсекается мгновенно и бесплатно, и так уходит большая часть потока. Звать модель на каждый чих — дорого и незачем; она нужна только для того, что простой список не разрулил.

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

Схема 3Два рубежа фильтрации

И две вещи, без которых ИИ в охранной задаче ставить нельзя. Fail-open: если модель почему-то не ответила (таймаут, пустота, не разобрался формат) — сторож шлёт тревогу без фильтрации. Лучше лишний пуш в Telegram, чем пропущенное вторжение, пока ИИ молчит. Обходные категории: для самого опасного — новый SSH-ключ, новый незнакомый сервис — ИИ не зовётся вообще. Такое уходит в тревогу всегда: цена пропуска тут слишком высока, чтобы доверять её вероятностной модели.

А теперь — собственно разница между «было» и «стало».

Было: Ollama, локально
Запрос уходил по локальному адресу к модели на том же сервере. Модель висела в памяти постоянно, с выключенным «думаньем» и вручную выставленными потоками. Ни ключей, ни интернета — всё внутри машины. И 23,7 ГБ оперативки под это всё.
Стало: облачный API
Тот же системный промпт, тот же грубый разбор ответа, тот же fail-open, те же обходные категории — всё нетронуто. Поменялся ровно транспорт: вместо локального вызова — обращение к провайдеру в стандартном, OpenAI-совместимом формате, а адрес, ключ и имя модели лежат в защищённом конфиге. Ноль гигабайт под саму модель.

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

И это ещё один довод в пользу облака, которого не видно в таблице со стоимостью: уйти на API почти ничего не стоит, и — что важнее — вернуться обратно тоже. Локальная модель привязывает тебя к железу; вызов по стандартному формату оставляет дверь открытой в обе стороны.

Раздел 05

Когда локальная модель всё-таки оправдана

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

ПодходЦена в месяцЗадержкаКогда брать
Облачный API
(что выбрал)
меньше $50,7–1,5 спо умолчанию, пока данные не запрещено слать наружу
Локальная модель
на общем CPU-сервере
$0 деньгами,
но 23,7 ГБ памяти
5–12 с,
очереди на пиках
почти никогда: память дороже денег
Свой сервер
с видеокартой
порядка $2000,5–2 сесли данные по закону нельзя в облако

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

Второй — если облачные провайдеры резко подорожают или закроются. Маловероятно на горизонте года, но это реальный риск, который стоит держать в уме.

Третий — если объём вырастет в сотню раз и копейки за API превратятся в ощутимые суммы. На моём масштабе фоновых задач этого не случится, но на чужом — запросто.

Пока ни один из трёх не сработал — остаюсь на API.

Итог

Что я с этого унёс

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

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

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

Серия 014 · выпуск опубликован · 2026-06-19
Авторская колонка · выпуск №014 · своя модель дороже API

// Обсуждение

Можно писать анонимно. Укажите email, чтобы получать уведомления об ответах.