Моя домашняя сеть уже давно перестала быть просто «вайфаем в квартире». Сейчас этот зоопарк состоит из: нескольких роутеров, прошитых под на OpenWrt, NAS, МФУ, а также IoT-устройств (робот-пылесос, умные лампочки, бризер, кондиционер, три канарейки, черепаха, золотые рыбки и старый глупый хомяк). А на роутерах ещё куча сервисов крутятся (например, https-over-dns и сервис-который-нельзя-называть).
В какой-то момент я поймал себя на мысли, что трачу кучу времени на рутину: копаться в заметках, вспоминать команды для OpenWrt, вручную проверять сервисы; понял, что выступаю для своей сети сисадмином на побегушках. Так я и решил настроить локально Qwen3.6-35B-A3B + несколько инструментов.
В этой статье я расскажу о MVP моего домашнего Skynet-а: настроенный агент умеет сам ходить по SSH на роутеры, проверять статус сервисов — и сам поддерживает документацию по сети (на основе подхода llm wiki). Чтобы не бояться, что LLM случайно уронит сеть, я выстроил строгие правила: все деструктивные действия требуют моего подтверждения, а любые скрипты, которые агент напишет, я запускаю только после ручного ревью (не самый оптимальный вариант — но для MVP хватило).
Итак, далее вас ждёт пошаговая инструкция для новичков, как поднять подобную систему в вашем контуре. И пример, как с её помощью поднять себе РКН следить за состоянием принтера по протоколу SNMP.
И сразу скажу: я фанат Powershell, так как эта командная оболочка работает и под Windows, и под Linux и построена на основе горячо любимого мною .NET. Поэтому все дальнейшие действия (и генерируемые скрипты) будут приведены для кроссплатформенного Powershell.
Шаг 1. Устанавливаем Node.js и Qwen CLI — даём ИИ-сисадмину «тело»
Зачем это делать: Сам по себе LLM-бэкенд (будь то локальный llama.cpp или облачный API) — это просто мощный, но изолированный «мозг в колбе». Он умеет только думать и генерировать текст. Чтобы наш будущий ИИ-сисадмин начал работать с файлами, выполнять команды и вообще взаимодействовать с внешним миром, ему нужен механизм контролируемого взаимодействия с компьютером. У меня в системе данную роль выполняет Qwen CLI (он ещё упоминается под названием Qwen Code). Это консольная утилита, которая превращает LLM в полноценного агента, способного вызывать внешние инструменты (в моём случае — ходить по SSH через MCP).
Для её работы нам понадобится среда выполнения JavaScript — Node.js. Мне нужна была версия под Windows - поэтому я скачал установщик LTS-версии с сайта Node.js (он, ко всему прочему, поставит и пакетный менеджер npm).
Теперь открываем консоль (я открыл PowerShell) и ставим Qwen CLI через npm:
npm install -g @qwen-code/qwen-cli
После успешной установки просто вводим команду qwen. Утилита выведет красивый ASCII-логотип, проверит окружение и запустит мастер первоначальной настройки.
Важно: не торопитесь проходить мастер настройки! Почему — будет описано далее.

Развилка: Облако или локальный сервер?
Здесь вам нужно принять решение, где будет «думать» ваш сисадмин.
Вариант А — Облачная модель. Если вы планируете просто подключить недорогую облачную модель (DeepSeek, Qwen, Anthropic, OpenAI и т.п.) — тогда пройдите мастер настройки до конца: выберите провайдера, введите API-ключ, и сразу переходите к Шагу 3, пропуская установку llama.cpp.
Вариант Б — Локальная модель (мой выбор). Если вы строите полностью автономного и приватного сисадмина, который ничего не отправляет в облако — ничего не вводите в мастере. Нажмите дважды Ctrl+C, чтобы выйти из Qwen CLI. затем переходите к Шагу 2.
Итак, по итогам первого шага у вас либо полностью настроенный облачный агент, либо установленный CLI-клиент, готовый к подключению локальных «мозгов».
Шаг 2. Устанавливаем llama.cpp и запускаем модель — локальные «сердце» и «мозг»
Зачем это делать: Если на прошлом шаге вы выбрали путь приватности и автономности, то сейчас понадобится «мозг» (локальная модель) и «сердце» (то, в чём запускаем). Для запуска модели я использовал llama.cpp. Llama.cpp написана на C++ (язык сам по себе низкоуровневый) плюс содержит множество оптимизаций, что позволяет позволяет запускать модели с минимальным оверхедом.
Для начала эксперимента нам не нужно хардкора и сборки llama.cpp из исходников. Идём на страницу релизов llama.cpp, качаем свежий прекомпилированный архив, в моём случае для Windows с поддержкой CUDA, и просто распаковываем его. Я создал папку C:\llama.cpp и скинул всё туда.
Скачиваем и запускаем модель локально
Не стану долго рассказывать о всех тонкостях — ибо сам пользовался инструкцией уважаемого хабровчанина @rAnto из его статьи про локальный запуск Qwen3.6 35B-A3B на RTX 4070. Добавлю лишь, что в моём случае пришлось смириться с контекстом ~ 240к (вместо 262к) из-за «всего лишь» 8Гб видеопамяти.
Я использовал 4-битный квант MXFP4 (от unsloth) и запускал модель с помощью следующей команды:
C:\llama.cpp\llama-server -m '.\Qwen3.6-35B-A3B-MXFP4_MOE.gguf' --host 127.0.0.1 --port 8080 --no-mmap -ngl 99 -ncmoe 99 -fa 1 -ctk q8_0 -ctv q8_0 -b 2048 -ub 512 --cache-ram 0 -t 12
Личный опыт: Если вам понравится вариант с локальным агентом, в дальнейшем обязательно соберите llama.cpp из исходников (можно проконсультироваться с любой OpenSource LLM касательно параметров сборки под ваше железо). В моём случае компиляция под себя оправдалась. Для запуска тяжёлой Qwen3.6-35B-A3B квантованием MXFP4 на ноутбуке c с характеристиками AMD Ryzen 9 7845HX/32Гб RAM/RTX 5070 Mobile 8Gb стоковый llama.cpp выдавал до 170 токенов/сек входных и 12 выходных. А скомпилированный из исходников (в стоковом не было оптимизации под Ryzen) ускорился до 200 и 20 токенов/сек соответственно.
Проверяем работу
Если запуск прошёл без ошибок, у вас в терминале замелькают логи загрузки. Как только сервер отрапортует о готовности, открывайте браузер, введите в строке адреса http://127.0.0.1:8080/ и пробуйте задать модели вопрос:

Если в браузере модель вам отвечает, осталось лишь связать её с Qwen CLI, чтобы агент наконец-то начал понимать нас.
Снова запустите Qwen CLI, далее пошаговая инструкция для актуальной на момент написания статьи версии Qwen CLI (0.21.10):
[Шаг 1/6] Выберите "Custom Provider", затем "OpenAI-compatible";
[Шаг 2/6] Введите http://localhost:8080/ (или иной адрес, который вы указали в команде запуска llama.cpp);
[Шаг 3/6] В качестве API key введите любой ключ (в моей команде запуска настройки API-ключа нет, поэтому сервер будет отвечать что бы вы не ввели на этом шаге);
[Шаг 4/6] Укажите имя модели (у меня это
Qwen3.6-35B-A3B);[Шаг 5/6] Пока пропустите, нажав Enter
[Шаг 6/6] У вас получится примерно такой файл:
{ "ui": { "autoModeAcknowledged": true }, "env": { "QWEN_CUSTOM_API_KEY_OPENAI_HTTP_LOCALHOST_8080_AA9A3524234A": "1" }, "modelProviders": { "openai": [ { "id": "Qwen3.6-35B-A3B", "name": "Qwen3.6-35B-A3B", "baseUrl": "http://localhost:8080/", "envKey": "QWEN_CUSTOM_API_KEY_OPENAI_HTTP_LOCALHOST_8080_AA9A3524234A" } ] }, "security": { "auth": { "selectedType": "openai" } }, "model": { "name": "Qwen3.6-35B-A3B", "baseUrl": "http://localhost:8080/" } }
Как закончите его изучение, нажмите Enter чтобы Qwen CLI перешёл в режим диалога. Спросите модель о чём-нибудь для проверки и убедитесь, что она также корректно отвечает:

Первое ручное изменение конфигурации
Важно: размер контекстного окна у модели Qwen3.6 262 тысячи токенов, по умолчанию же Qwen CLI считает, что контекстное окно у модели 1 миллион токенов. измените эту настройку прямо в файле конфигурации Qwen.
Закройте Qwen CLI, затем откройте в текстовом редакторе, поддерживающем подсветку форматирования JSON файл %USERPROFILE%\.qwen\settings.json - туда сохранилась конфигурация с шага 6. Добавьте в параметры модели размер её контекста и увеличенный timeout (на моем железе модель думала по нескольку минут прежде, чем начать отвечать):

Не забудьте про выделенную запятую!
Если вы где-то ошибетесь в файле конфигурации, при следующем запуске Qwen CLI пересоздаст файл с параметрами по умолчанию, а изначальное содержимое переместит в файл settings-backup.json. Тогда снова закройте Qwen CLI, исправьте ошибку, затем сохраните файл под именем settings.json.
Если же вы всё сделали правильно — поздравляю! У вас уже есть локальный агент, способный взаимодействовать с файлами на вашем компьютере. Остальсь лишь научить его работать с другими устройствами.
Шаг 4. Настраиваем SSH MCP Sessions — тянем «руки» агента к роутерам
Зачем это делать: Теперь, когда у нас есть локальный агент, нужно научить его выполнять команды на роутерах. Сам по себе он этого не сумеет (надеюсь), поэтому мы научим его с помощью инструмента ssh-mcp-sessions. Это локальный сервер, который даёт Qwen CLI возможность подключаться к устройствам, поддерживающим SSH.
ssh-mcp-sessions умеет:
хранить профили хостов, к которым возможно подключение (в
%USERPROFILE%\.ssh-mcp\hosts.json);открывать постоянные SSH-сессии (при переключении между диалогами сохраняются открытая директория и переменные окружения);
выполнять команды и возвращать результат обратно агенту.
Устанавливаем:
Открываем PowerShell и ставим пакет ssh-msp-sessions:
npm install -g ssh-mcp-sessions
После установки выполните команду
npx ssh-mcp-sessions
Если вы видите текст SSH MCP Server running on stdio, то сервер запустился успешно, нажмите Ctrl+C чтобы остановить его, затем откройте (или создайте, если его нет) файл %USERPROFILE%\.ssh-mcp\hosts.json.
Пример файла с параметрами подключения к основному роутеру (в файле я его назвал Router-Main) с IP-адресом 192.168.1.1, доступом по ssh по ключу (приватный ключ без пароля):
{ "hosts": [ { "id": "Router-Main", "host": "192.168.1.1", "port": 22, "username": "root", "keyPath": "~/.ssh/openwrt.id_rsa" } ] }
Теперь снова отредактируем конфиг-файл Qwen CLI чтобы добавить вы него информацию об ssh-mcp-sessions:

И снова внимательно проверьте структуру JSON и не теряйте запятые!
Проверяем работу: запускаем qwen и вводим в нём команду /mcp. Если в ответе появилась утилита ssh-mcp-sessions, значит Qwen CLI «видит» инструмент и теперь сможет отправлять команды на роутеры:

Шаг 5. Краткое описание LLM Wiki и моя адаптация под домашнюю сеть
Зачем это делать: Теперь пришло время рассказать, как организованы знания о локальной сети. Объяснять каждый раз досконально что делать — муторно и неудобно. И тут на помощь приходит концепция llm wiki, которую в апреле 2026 года опубликовал Андрей Карпатый (сооснователь OpenAI, бывший глава AI в Tesla).
Идея llm wiki в виде трёх пунктов
Пишем основную информацию, с которой мы работаем, в формате Markdown.
Далее просим LLM построить по этим данным уже свою структурированную коллекцию Markdown-файлов.
И затем, при выполнении запросов, пусть LLM аккумулирует в этой базе знаний полученную в процессе работы информацию.
Приведу пример как это работает у меня:
В изначальном описании своей сети я перечисляю все устройства (кроме основного роутера) указывая только их MAC-адреса.
Далее я даю команду агенту узнать на роутере IP-адреса всех устройств - и прошу запомнить информацию о том, как это сделать. Агент записывает это в отдельный Markdown-файл.
И далее я могу обращаться к устройствам лишь по именам. А агент, в созданной им карточке устройства посмотрит по имени MAC адрес, а по известному ему алгоритму узнает IP-адрес устройства.
В общем и целом подход llm wiki — это процесс постоянного накопления агентом знаний, их извлечение при необходимости, а также поддержание знаний в актуальном состоянии в виде набора текстовых файлов: с перекрёстными ссылками и зафиксированными противоречиями (при их наличии).
Архитектура LLM Wiki — три слоя
Raw-слой (исходники) — ваши исходные документы: статьи, конфиги, инструкции. Эти файлы читаются, но никогда не изменяются LLM. Это — источник информации для модели.
Схема — файл
QWEN.mdилиAGENTS.md, который объясняет LLM, как устроена вики, какие правила именования и какие рабочие процессы. Это ключевой файл — именно он превращает LLM из обычного чат-бота в дисциплинированного редактора вики.Wiki-слой — сгенерированные LLM Markdown-файлы:
Как llm wiki работает у меня
Я слегка адаптировал эту идею под свою домашнюю сеть. Вот структура папок, которую использую:
llm-wiki\ ├── raw\ # неизменяемые исходники (READ ONLY для AI) │ ├── devices\ # ПОСТОЯННЫЕ атрибуты устройств │ │ ├── router-main.md # hostname, MAC, тип ОС, способ доступа │ │ └── ... │ ├── services\ # информация о сервисах │ │ ├── https-dns-proxy.md # название, описание, на каком устройстве запущен │ │ └── ... │ ├── manuals\ # инструкции по работе с ОС/сервисами │ │ ├── Справка по командам OpenWRT.md │ │ └── ... │ └── checkups\ # описания проверок работы сети │ ├── Ежедневная проверка.md │ └── ... ├── compiled\ # wiki-страницы (AI пишет сюда) │ ├── index.md # каталог всех страниц │ ├── devices\ # ДИНАМИЧЕСКОЕ состояние устройств │ │ ├── router-main.md # IP-адрес, дата последней проверки │ │ └── ... │ ├── backups\ # резервные копии настроек устройств или сервисов │ │ └── ... │ └── log.md # журнал всех действий └── QWEN.md # инструкция для LLM по структуре вики
Три основные операции
1. Ingest (поглощение). Если я создаю новый Markdown-файл в папке raw\ (или правлю существующий), то после даю команду агенту через Qwen CLI:
Выполни Ingest.
LLM сама найдёт новые и изменённые файлы в папке raw\, выделит ключевые факты, создаст или обновит страницы в compiled\, обновит index.md и log.md, а затем выполнит qmd embed для обновления поискового индекса (об индексе расскажу чуть позже).
2. Change (изменение). Команда, когда нужно внести изменения в сети (или в wiki):
Change. Собери все статически назначенные IP-адреса (данные находятся на роутере router-main) и сохрани их в wiki
Агент сначала проверяет уже записанную в wiki информацию, затем подключается по SSH к указанному роутеру, выполняет команды и сохраняет результат в compiled\.
3. Lint (проверка). Периодически после изменений следует просить агента проверить согласованность данных в вики:
Выполни Lint.
Агент ищет противоречия между страницами, находит страницы без входящих ссылок, обнаруживает устаревшие утверждения и предлагает исправления.
[СКРИНШОТ 6: Пример структуры папок llm-wiki в проводнике Windows]
Шаг 6. Установка qmd - локального поисковика по Markdown-заметкам
Зачем это делать: при описанном выше подходе нас ждет неочевидная проблема: в некоторый момент данных в llm wiki может оказаться настолько много, что они перестанут помещаться в контекст агента. Плюс для каждого запроса агенту придётся читать все файлы, которые связаны с поставленной задачей, целиком.
Чтобы этого избежать, мы можем добавить в систему утилиту qmd — для полнотекстового поиска по указанным markdown‑файлам. С её помощью агент сможет быстро определить, в каком файле находится нужная ему информация, — или даже получить только её, не читая весь файл.
Для установки открываем PowerShell и устанавливаем пакет qmd через npm:
npm install -g @tobilu/qmd
Затем, там же в powershell, создадим папку, в которой будет находиться наша llm wiki, и добавим ее в индексируемую коллекцию:
mkdir "C:\HabrLlmWiki" qmd collection add "C:\HabrLlmWiki" --name HabrLlmWiki
далее переходим в папку с llm wiki и вызываем первое построение индекса:
cd "C:\HabrLlmWiki" qmd embed
При первом запуске qmd скачает несколько GGUF-моделей (эмбеддинг-модель, реранкер) — это займёт пару минут и потребует интернета.
Модели qmd кэшируются в
%USERPROFILE%\.cache\qmd\models\и занимают примерно 2 ГБ. Если места на диске мало — можно отключить реранкинг, выполнив в powershell команду$env:QMD_RERANK_MODE = "off"перед запускомqmd embedиqwen. Подробнее смотрите в документации к qmd.
Так как наша база знаний пока пуста, в выводе команды qmd embed должно быть указано, что проиндексировано 0 документов. Это нормально — далее мы наполним вики содержимым.
Для информации: изначально я настраивал qmd в режиме mcp сервера (также, как ssh-mcp-sessions). Однако на практике оказалось, что моей модели использовать qmd проще через вызов команды в консоли, чем через MCP, так как при использовании mcp постоянно были какие-то проблемы с относительными путями. И плюс команды qmd не меняют содержимого файлов, поэтому я разрешил их безусловное исполнение в папке с wiki.
Шаг 7. Промпты
Самые нетерпеливые могут скачать сразу весь архив с примером, о котором поведаю дальше, из моего репозитория на github.
Файл QWEN.md
Этот файл должен находиться в корне llm wiki; если вы используете не Qwen CLI, переименуйте его в AGENTS.md или иначе, как требует ваше ПО. Этот
файл загружается при каждом запуске Qwen CLI и определяет, как агент должен себя вести. В нём описана уже известные вам структура папок (речь про raw/ и compiled/), список действий (Ingest, Lint, Change). А также общие правила работы, к примеру:
1. Прежде чем менять конфигурацию устройства, читай его карточку из `raw/devices/` и извлекай необходимые данные из соответствующего ОС manual-а (оптимально через qmd, но также можно и полным прочтением файла). 2. Для поиска исторических данных (например, какие IP уже используются) используй `qmd search` по `compiled/`. 3. При изменении состояния (IP, установка пакета, включение сервиса) – **обязательно** обновляй `compiled/devices/` и пиши запись в `compiled/log.md`. 4. При Ingest обновляй `compiled/index.md`, сверяй фактические данные с карточками и создавай страницы для новых устройств. 5. При обнаружении неизвестной ОС – создавай в `compiled/` страницу `unknown-os.md` с перечнем устройств и запроси у пользователя добавление мануала по ней.
Шаг 8. Практическая задача: получаем состояние МФУ через SNMP
Зачем этот шаг: Вся ИИ-система нужна мне в первую очередь для повышения автономности локальной сети, чтобы я мог быстро получить её состояние, знать, что сломалось и, может быть, оперативно починить, переподнять, поменять настройки того-о-чем-нельзя-говорить.
Для примера расскажу, как, не обладая глубокими познаниями в работе принтеров по сети, я вместе с ИИ научился следить за состоянием моего домашнего лазерного МФУ через протокол SNMP.
Сразу спойлер — процесс потребовал одновременной работы двух облачных бесплатных LLM (ИИ-поиск Google и Qwen3.8-Max), потому что локальная модель на этом этапе ещё не справлялась.

Задача казалась несложной:
Поиск в гугле способов опроса состояния принтера: уровня картриджей, статуса печати (готов, печатаю, ошибка) и прочей основной информации.
В результате было найдено решение — опрос принтера по протоколу SNMP v2c, и ИИ выдал код, как через COM-объект в Windows PowerShell выполнить такой опрос:
$snmp = New-Object -ComObject olePrn.OleSNMP $PrinterIP = "192.168.1.10" # IP-адрес принтера $Community = "public" # Укажите SNMP Community (по умолчанию public) $OidSysName = ".1.3.6.1.2.1.1.5.0" # Базовый OID для имени устройства # Проверяем SNMP v2c (версия = 2) try { $snmp.Open($PrinterIP, $Community, 2, 3000) $result = $snmp.Get($OidSysName) $snmp.Close() Write-Host "Принтер поддерживает SNMP v2c. Имя устройства: $result" -ForegroundColor Green return } catch { $snmp.Close() }
Запомните этот код. И особенно комментарии к нему!
Я проверил — код успешно работал и выводил имя принтера.
Дальше попробовал найти .NET-библиотеку, не привязанную к Windows, которая умеет работать по протоколу SNMP — нашлась Lextm.SharpSnmpLib.
Отдав облачному Qwen 3.8 ссылку на код библиотеки и информацию о производителе модели моего принтера, я получил краткую инструкцию с основными OID для запроса и примеры скриптов на PowerShell, как получить значение по OID (get) и как получить список доступных значений OID (walk).
Скопировав этот список уже в локальный md-файл, я попросил модель выполнить Ingest и затем опросить принтер (его IP-адрес уже был записан в compiled-части wiki).
Локальная LLM успешно прочла новый документ, собрала скрипт, запустила — и он не сработал. Покрутившись некоторое время, она сообщила, что «принтер не отвечает потому что нет связи с ним по сети» (это была неправда). При этом запросы данных через COM-объект продолжали отлично работать!
Дальше в течение нескольких часов я, а также обе облачные модели, изучали исходный код библиотеки Lextm.SharpSnmpLib, ругали Windows Firewall, искали проблему в вызовах библиотеки C# из PowerShell, так и сяк «крутили» код — и в итоге ИИ-поиск Google таки разобрался в проблеме.
Причина проблемы была в том, что мой принтер … (барабанная дробь) … всё это время общался со мной по SNMP 1 версии! Объект olePrn.OleSNMP то ли сам как-то это понимал, то ли просто игнорировал указание, что общаться надо по 2 версии протокола. Но в результате пакеты через него шли в формате SNMPv1, и тогда всё работало. А библиотека Lextm.SharpSnmpLib отправляла, как её и просили, пакеты 2 версии — и принтер их тупо игнорировал.
В итоге я заменил справку по общению с принтером по SNMP и примеры скриптов. После этого локальная модель обновила скрипт мониторинга — и тут он сработал уже без ошибок.

Заключение
Раньше поддержкой устройств и сервисов приходилось заниматься вручную — и это занимало слишком много времени. Использование агента сначала требовало больше времени, но сейчас, с учётом накопленных в llm wiki скриптов автоматизации, экономия уже налицо: система по сути начала следить сама за собой.
Смог бы я пройти путь самостоятельного написания того же домашнего скрипта мониторинга принтера? 100% нет, у меня не хватило бы времени на изучение кода библиотеки или протокола SNMP. Если бы это была рабочая задача — там, конечно, выбора бы не было. Но именно упорство LLM помогло разработать мне это и многие другие домашние скрипты.
О дальнейшем развитии системы я расскажу в следующей статье (надеюсь, уже в хабе DIY) — пока писалась эта, в системе уже появились новые устройства.
Если у вас будут вопросы — пишите, буду рад на них ответить. Ещё раз приведу ссылку на репозиторий с примером моей llm wiki.
Всем хорошего дня!

