Как я собрал на DGX Spark приватный AI-сервер, и теперь рассказываю, что туда вошло

Страницы:  1

Ответить
 

Professor Seleznov


У меня на столе стоит небольшая золотистая коробочка размером чуть больше Mac mini. Внутри — приватный AI-сервер: чат с локальной 26B-моделью, поисковая индексация моих документов с GPU-парсингом, конструктор агентов в Dify, RAGFlow для тяжёлого парсинга PDF, мониторинг, бэкапы, опциональный кластер из двух машин по QSFP 200G. Тридцать контейнеров, пять минут на установку черезsudo bashinstall.sh, ноль обращений к внешним API.
Я делал это не как pet-project, а под себя — мне нужна была машина для работы с корпоративными документами, договорами и регламентами, которые ни при каких условиях нельзя отдавать в облачные ассистенты. Сборка получилась самостоятельным дистрибутивом — назвал его AGmind, выложил на GitHub под Apache 2.0.
В статье разберу:
— из чего собран стек и зачем там каждый компонент; — почему RAGFlow пришлось пересобрать с нуля и что я туда добавил; — как устроен кластер из двух Spark'ов; — пять конкретных грабель GB10, которые я ловил вечерами; — почему Claude Code за месяц превратил один из этих компонентов в работающий продукт, но при этом не заменил собственно программиста.
Зачем мне понадобился свой AI-сервер
Облачные ассистенты — OpenAI, Anthropic, Gemini — прекрасно работают с тем, что не страшно отдавать наружу. Как только речь заходит про корпоративные документы, юридические договоры, медкарты, внутренние регламенты — каждый второй compliance-офицер заворачивает SaaS, и совершенно справедливо. Это не вопрос того, насколько хорош TLS у вендора. Это вопрос того, что данные физически уходят на чужие серверы, и дальше доверять можно только бумажкам.
Self-hosted-альтернатив я перебрал руками. Open WebUI — нормальный чат, но с документами работает плохо. Dify — мощный workflow-конструктор и приличный фронт, но встроенный парсер PDF слабый: таблицы плывут, картинки пропадают, многоколоночные тексты разваливаются. RAGFlow — наоборот, сильный парсер, но UI и оркестрация уступают Dify. AnythingLLM, FlowiseAI, LangFlow — у каждого своя специализация и свой набор пропусков.
Мне нужно было одно: чтобы я мог положить в папку 200 PDF-документов, задавать по ним вопросы, ходить в это через нормальный чат, собирать агентов через drag-n-drop, и чтобы всё это поднималось одной командой и так же одной командой бэкапилось. Кубики для этого в open-source есть, дистрибутива — нет. Так появился AGmind.
Железо: что такое DGX Spark в двух словах
DGX Spark — это компактный AI-десктоп от NVIDIA на чипе GB10 Grace Blackwell. Анонсировали в марте 2025 как Project DIGITS, продавать начали 15 октября 2025. Стартовая цена $3999, в феврале 2026 из-за дефицита LPDDR5x подняли до $4699.
Внутри одного SoC сидят:
— 20-ядерный ARM-процессор (10 высокопроизводительных Cortex-X925 + 10 энергоэффективных Cortex-A725, спроектированы NVIDIA совместно с MediaTek); — Blackwell GPU c compute capability sm_121: 48 SM, 6144 CUDA-ядра, 192 тензорных ядра пятого поколения; — 128 ГБ памяти LPDDR5x с пропускной способностью 273 ГБ/с — единый когерентный пул, который видят и CPU, и GPU без всякого PCIe-копирования; — два QSFP-порта на 200 Гбит каждый (NVIDIA ConnectX-7), через которые два Spark'а склеиваются в кластер.
По чистой GPU-производительности это что-то между RTX 5070 и 5070 Ti. Сенсация не в FLOPs, а именно в 128 ГБ unified memory: на одной коробке за $4 тысячи я могу инферить 70B-модель в FP4 без всякого шардирования, чего на потребительском железе обычно не сделать.
Что у этой коробки болит — драйверы. Spark официально живёт на ветке 580.x; на 590+ NVIDIA словила три независимые регрессии, специфичные для unified memory GB10:
— vLLM зависает на CUDAGraph capture при первом инференсе. Воспроизведено независимо в репозитории eugr/spark-vllm-docker, там в README прямо стоит требование «driver 580.x, на 590.x deadlock»; — утечка памяти в драйвере 590.48.01: после нормального завершения CUDA-процесса в системе пропадает порядка 80 ГБ, которых не видно ни в AnonPages, ни в Slab, ни в PageTables; лечится только перезагрузкой; — TMA-баг в драйвере 595.58.03 валит NVFP4-квантизацию с illegal memory access.
В моём install.sh поэтому стоит apt-mark hold nvidia-driver-580-open — это не паранойя, а защита от unattended-upgrades, которые рано или поздно подтянут 590, и человек, поставивший систему вечером, утром получит мёртвую vLLM.
Архитектура: что входит в стек и зачем
Стек у меня живёт в докере и состоит примерно из тридцати контейнеров.
Dify — фронтенд и оркестратор workflow
Dify (langgenius/dify-api:1.13.3) — основной интерфейс, через который я живу. Это open-source-аналог LangChain Studio плюс ChatGPT-like чат, плюс drag-n-drop конструктор агентов. У них есть workflow-редактор, в котором можно нодами собрать что-нибудь типа «получи документ → распарси через RAGFlow → суммаризируй gemma-4 → отправь в Telegram», и это собирается за пять минут без кода.
Я использую Dify как primary frontend (agmind-dify.local), а внутри он умеет ходить в локальную vLLM, в RAGFlow через плагин из marketplace и в любой OpenAI-compatible endpoint. Сам Dify — это пять контейнеров: api, worker, web, sandbox, plugin_daemon.
RAGFlow — пересобранный с нуля под Spark
Здесь надо отдельно. Upstream-RAGFlow в коробке не работает на DGX Spark — там и x86-only зависимости, и устаревшие ONNX-рантаймы, и куча мелочей. Готового образа под arm64 + sm_121 + CUDA 13 в природе нет.
Поэтому я взял базу из патчей HendrikSchoettle/ragflow-dgx-spark (там сделана работа по переезду на ARM), накатил поверх свои cherry-pick'и из upstream main и собрал собственный образ ar2r223/ragflow-spark:v0.24.1-spark, запиннил по SHA256, выложил в DockerHub.
В сборке:
Базовая ветка v0.24.0 + патчи Hendrik: cascade-OCR на Latin / Cyrillic / Chinese (важно — в upstream был только английский), file metadata в ES-чанках, поддержка AVIF, фиксы IMAP и WebDAV mtime, ONNX Runtime GPU 1.25.0 под aarch64 + CUDA 13 + sm_121; — Cherry-pick из upstream main (от 27 апреля): TokenChunker (атомарные таблицы + image_context), TitleChunker (5 уровней regex-иерархии для книг, законов, мануалов), pdf_chunk_metadata.py, extract_pdf_outlines, 7 ingestion-шаблонов (book / general / laws / manual / one / paper / resume); — Мои runtime-патчи: русский prompt для image describe в cv_model.py (когда у KB language=Russian, vision-модель получает русскоязычный prompt вместо захардкоженного английского), русские заголовки и описания в 10 ingestion-шаблонах, плюс лечение бага Pipeline.globals в Hendrik fork v0.24, где Pipeline не наследовал от Canvas и валился с AttributeError на первом же чанке.
В результате RAGFlow умеет на моём железе разбирать русскоязычные PDF с таблицами, схемами и иллюстрациями, описывать картинки русским текстом через vision-модель и индексировать всё это в Elasticsearch 9.x. Образ ~13.3 ГБ, тянется один раз.
Apropos — тэг :latest в моём versions.env запрещён, все образы пинятся либо по версии, либо по digest. Это правило в CI: галлюцинирующие LLM любят предлагать «правдоподобные» теги, которых не существует в registry. Об этом подробнее в разделе про Claude Code.
vLLM — три инстанса под разные задачи
На GB10 у меня крутится три инстанса vLLM:
vLLM (LLM)vllm/vllm-openai:gemma4-cu130, запускает google/gemma-4-26B-A4B-it. Это NVIDIA playbook-сборка под arm64 и sm_121, единственная, на которой gemma-4 нормально живёт на Spark. По умолчанию gpu_memory_utilization=0.60 — оставляю запас для docling-serve, у которого пиковое потребление до 16 ГБ; — vLLM (embeddings)nvcr.io/nvidia/vllm:26.02-py3, поднимает deepvk/USER-bge-m3. Это, кстати, не стандартный bge-m3, а файнтюненная под русский вариант от deepvk, на наших корпоративных текстах работает заметно лучше; — vLLM (reranker) — то же базовое NGC-изображение, поднимает BAAI/bge-reranker-v2-m3 для финальной сортировки кандидатов.
Почему 26.02-py3, а не 26.03? Потому что 26.03 требует драйвер 595.45+, а у нас 580.142, и поднимать драйвер мы не можем (см. выше). Маленький пример того, как один gotcha тянет за собой выбор всех остальных версий.
Атеншн-бэкенд я фиксирую VLLM_ATTENTION_BACKEND=TRITON_ATTN, потому что FlashInfer FP8 на sm_121 валится с kernel only supports sm120 — это известный баг под новый compute capability.
Docling — парсер документов с GPU OCR
Docling-serve (docling-serve-cu130:v1.16.1) — это GPU-ускоренный конвертер документов от IBM. Принимает PDF / DOCX / PPTX / XLSX, отдаёт Markdown с сохранённой структурой таблиц, заголовками и описаниями картинок.
В стеке у меня три preset'а под разные типы документов:
FAST — для текстовых PDF с готовым text layer (Word/LaTeX export). Отключает OCR и table-structure recognition, на 5-страничной arxiv-статье даёт 4.05 секунды против 6.01 в default; — BALANCED (default) — полный pipeline, OCR включается автоматически если text layer неполный, TableFormer работает в accurate-режиме; — SCAN — для отсканированных страниц без text layer. Принудительный easyocr с lang=[ru, en] и picture_description через vLLM gemma-4 vision с concurrency=8, по моим замерам у каждого значимого изображения получается осмысленное русскоязычное описание, которое попадает в индекс.
Docling делит GPU с vLLM, отсюда и gpu_memory_utilization=0.60 у LLM-инстанса.
Базы и хранение
Тут без сюрпризов:
PostgreSQL 16-alpine — метаданные Dify, состояние плагинов; — Redis 7.4 — task queue, кэш плагинов, pub/sub для celery; — Weaviate 1.37 — векторное хранилище под эмбеддинги (есть toggle на Qdrant, но дефолт Weaviate); — MinIO — S3-совместимое объектное хранилище под загруженные документы (agmind-storage.local); — Elasticsearch 9.x — нужен RAGFlow, в нём чанки + полнотекстовый индекс. RAGFlow жёстко завязан на ES, Postgres он не умеет; — MySQL 8.0 — тоже под RAGFlow, у них в схеме MySQL захардкожен.
Мониторинг и операционка
Без мониторинга стек из тридцати контейнеров — это слепая лошадь. У меня:
Prometheus + Grafana 3001 с десятью собственными дашбордами (общий обзор, контейнеры, GPU master, GPU worker, peer-worker, логи, алерты, аудит, RAG-метрики, RAGFlow). Отдельная боль: на GB10 unified memory dcgm-exporter не работает совсем, а NVML возвращает N/A на половину запросов. Пришлось писать свой textfile collector, который парсит nvidia-smi и отдаёт agmind_gpu_* метрики через node-exporter; — Loki + Grafana Alloy — логи всех контейнеров, в апреле перевёл с Promtail на Alloy (это уже официально рекомендуемый агент); — Alertmanager — каналы в Telegram и webhook; — Portainer 2.39 — визуальное управление контейнерами на master + автодеплой агента на peer Spark с одним и тем же PORTAINER_AGENT_SECRET (чтобы переустановки не ломали привязку); — fail2ban + UFW — firewall LAN-only по умолчанию, защита от bruteforce.
Безопасность
Из коробки:
— все секреты лежат в /opt/agmind/credentials.txt с правами 600, root-only; — у каждого контейнера в compose сдропано 30+ Linux-capabilities; — Dify Sandbox изолирован в отдельной Docker-сети ssrf-network, наружу ходит через Squid-прокси (защита от SSRF в плагинах); — опциональная Authelia с TOTP/WebAuthn на Grafana и Portainer; — agmind rotate-secrets перегенерирует все пароли и ключи одной командой.
Кластер из двух Spark'ов
Если у вас две Spark-машины, AGmind их склеивает в кластер по QSFP 200G DAC. Это не просто «увеличить память» — это разнесение нагрузок: vLLM получает выделенный GPU без оглядки на парсер.
┌─────────────────────┐                        ┌─────────────────────┐
│ spark-master │ QSFP 200G DAC │ spark-peer │
│ (frontend + БД + │ ◄──── direct link ────►│ (только vLLM, │
│ Dify + RAGFlow + │ 192.168.100.0/24 │ выделенный GPU, │
│ monitoring) │ │ 128K context) │
│ WAN: ethernet │ │ WAN: NAT через │
│ iptables MASQUERADE│ ─────── default gw ───►│ master по QSFP │
└─────────────────────┘ └─────────────────────┘
Что важно понимать:
На single-Spark vLLM делит GPU с docling, поэтому в визарде задаётся вопрос про контекст (32K / 64K / 128K) — на 128K при активном парсинге уже впритык; — На dual-Spark этот вопрос пропускается: peer крутит только vLLM, GPU выделен полностью, 128K контекст по умолчанию без компромиссов; — NAT-on-demand — peer выходит в WAN через QSFP master'а только когда нужно (тянет образы или модели), потом командой agmind nat off WAN отрезается, и intent air-gap сохраняется. Полезно, если железо стоит в защищённой сети, а интернет нужен раз в неделю на апдейт; — Симметричная установкаsudo bashinstall.sh на обеих нодах, визард сам определяет роль через LLDP, при отсутствии — fallback на ping. Для CI можно задать --mode=master или --mode=worker явно; — Passwordless SSH между нодами визард настраивает сам, мониторинг показывает обе машины в Grafana отдельными дашбордами gpu-master и gpu-worker.
Что я с этим всем делаю в реальной жизни
Открываю agmind-dify.local в браузере — и:
Чат с локальной 26B-моделью. TTFT 183 миллисекунды, генерация 23–24 токена в секунду на одиночном запросе, до 50 токенов агрегированно на трёх параллельных. Контекст 65K с FP8 KV-кэшем, до 45 параллельных запросов на одной коробке. Никаких лимитов, ничего не уходит наружу.
Загружаю папку с PDF — задаю по ним вопросы. Под капотом RAGFlow парсит каждый документ, выдирает таблицы и картинки, прогоняет картинки через vision-модель (gemma-4 vision описывает каждое изображение русским текстом), нарезает на чанки, эмбеддинги в Weaviate. Когда я спрашиваю — bge-m3 ищет похожие чанки, bge-reranker сортирует, gemma-26B пишет ответ со ссылками на источник.
Конструктор агентов. Нужен агент, который раз в день забирает определённые письма из Gmail, классифицирует их, важные складывает в Notion, остальные суммаризирует в дайджест и отправляет в Telegram, — собирается в Dify за десять минут на drag-n-drop, без единой строчки кода.
Бэкап. sudo agmind backup — снимок Postgres, Redis, всех volume'ов и конфигов. Опционально шифрование age, опционально upload по SSH на peer-машину.
Производительность на честных бенчмарках
Без чисел разговор про self-hosted AI бессмысленный.
Метрика gemma-4-26B-A4B-it (MoE)
TTFT (streaming) 183 мс
TPS (1 запрос) 23–24 ток/с
TPS (3 параллельных) ~50 ток/с агрегированно
Контекст 65K (FP8 KV-cache)
Max concurrency @ 65K 45 запросов
Память: веса 48.5 GiB (bfloat16)
Память: KV-cache 41.7 GiB (FP8)
Total footprint ~95 GiB

Docling (5-page arxiv PDF) Время
Cold start 6.04 с
Warm 1.6 с
Per-page (warm) 0.32 с
284-page PDF, без VLM 88 с
Тот же PDF, с VLM concurrency=8 191 с

Прочее
Полный install.sh на чистой системе ~30 минут (включая 52 ГБ весов)

Установка
bash
git clone https://github.com/botAGI/AGmind.git
cd AGmind
sudo bash install.sh
Визард задаёт 10–15 вопросов: single-Spark или dual-Spark, какую LLM (по умолчанию gemma-4, либо curated-список Qwen / Llama / Mistral / phi-4, либо custom HuggingFace), какой контекст, какие опциональные сервисы (RAGFlow, Open WebUI, LiteLLM, SearXNG, DB-GPT, Crawl4AI, Authelia 2FA), куда бэкапиться. Через ~25 минут стек живой, все credentials лежат в /opt/agmind/credentials.txt с правами 600.
Day-2-операции:
bash
agmind status              # сервисы, GPU, модели, эндпоинты
agmind doctor # системная диагностика
agmind logs # тейл логов
agmind ragflow status # три ragflow-контейнера + ES health
agmind docling bench # cold/warm/per-page тайминг
agmind upgrade --diff # что устарело относительно pinned-версий
agmind backup # Postgres + Redis + volumes
agmind rotate-secrets # перегенерировать пароли и ключи
Пять грабель GB10, на которые я наступил
Часы потерь честные. Каждая история — это вечер, который вместо «допилить фичу» превратился в «понять, почему это вообще не работает».
1. 502 на каждый запрос после force-recreate (потерял два дня)
Я писал nginx-конфиг по привычке нулевых: upstream agmind_api { server api:5001; } плюс proxy_passhttp://agmind_api. Через неделю мне понадобилось рестартнуть Dify api с обновлённым .env через docker compose up -d --force-recreate api. Получил 502 на каждый запрос. Логи api здоровы, сам api отвечает на curl по новому IP, nginx — 502.
Оказалось, новый api получил новый IP (был .5, стал .7), а nginx upstream-блок закешировал старый IP при старте. Добавил resolver 127.0.0.11 valid=10s; (Docker embedded DNS) — не помогло. Ещё час дебага: resolver влияет только на proxy_pass $variable, а на upstream-блоки и на статический proxy_passhttp://name — нет. Это в документации nginx написано, но мелким шрифтом.
Решение — переписать всё через variable form:
nginx
location /api {
set $u_dify_api http://api:5001;
proxy_pass $u_dify_api;
}
И полностью убрать upstream {}-блоки. Сейчас в templates/nginx.conf.template действует жёсткое правило при ревью: ни одного proxy_pass http:// без $. Регрессионный тест проверяет, что после force-recreate api сервис отвечает 200 без ручного рестарта nginx.
2. Зомби-задачи в Redis после force-recreate (потерял два часа)
Запустил большой PDF на 280 страниц через docling, висит в processing десять минут. Подумал — worker завис, сделал docker compose up -d --force-recreate worker. Вернулся через час — задача всё ещё processing. Перезапустил весь стек. Та же история. Любая новая загрузка стабильно висит в waiting, GPU idle.
Реальная причина оказалась в моих же force-recreate'ах, которые оставили в Redis stale-state: ключи generate_task_belong: (TTL 1800), pub/sub-каналы /1.celeryev привязаны к hostname celery@OLDID, новый worker их не читает. Recreate = новый контейнер с новым hostname. Redis ничего об этом не знает.
Лечится так:
bash
redis-cli -a $PW -n 0 --scan --pattern 'generate_task_belong:*' | \
xargs redis-cli -a $PW -n 0 DEL
redis-cli -a $PW -n 1 --scan --pattern 'celery-task-meta-*' | \
xargs redis-cli -a $PW -n 1 DEL
FLUSHDB блокируется ACL даже для default user — это security hardening, разрешён только DEL by key. Правильный путь дальше — менять env через docker restart api worker, а не через recreate.
3. mDNS self-collision (потерял час)
Хотел, чтобы agmind-dify.local, agmind-rag.local, agmind-storage.local резолвились в одну машину. Положил три алиаса в /etc/avahi/hosts на один и тот же IP. Avahi пишет в журнал: Local name collision. С другого хоста алиасы не резолвятся.
Час дебага. Оказалось, это self-collision внутри avahi: демон при старте регистрирует $(hostname).local → 192.168.1.42 как primary address record, и когда я добавляю alias на тот же IP, avahi видит конфликт между двумя record'ами для одного IP — и даже не отправляет probe в сеть.
Фикс — использовать avahi-publish-address -R name.local IP через systemd-обёртку, по одному юниту на алиас. /etc/avahi/hosts оставить только для имён с другим IP.
Бонус-баг к этой истории: второй mDNS-respond'ер на UDP/5353 ломает avahi молча. NoMachine с EnableLocalNetworkBroadcast 1, iTunes/Bonjour и прочие занимают порт. Проверяется через sudo ss -ulnp | grep 5353 — там должен быть только avahi.
4. Distroless-контейнеры без shell (потерял полчаса)
Loki, redis_exporter, nginx-prometheus-exporter — distroless-образы. У них нет /bin/sh. Healthcheck через CMD-SHELL wget ... выдаёт stat /bin/sh: no such file or directory, и контейнер навечно висит unhealthy, хотя метрики отдаются нормально. Если у вас в compose depends_on: { redis_exporter: { condition: service_healthy } } — стек никогда не поднимется.
Правило простое: для distroless-образов здоровье проверяется через Prometheus up{job=...}, а не через docker healthcheck.
5. APT и truncated downloads (потерял вечер)
Это уже не про AGmind, а про инфраструктуру. Но без этой истории картина неполная.
apt-get install -y linux-firmware (это 603-мегабайтный deb для arm64) — dpkg -i падает с «неожиданный конец файла или потока». SHA256 не совпадает. --reinstall не помогает, apt-get clean не помогает. stat показывает 632 МБ, curl -sI возвращает Content-Length 634 МБ. Файл обрезается на ~2 МБ до конца.
Curl по HTTP принимает truncated body как успех — HTTP 200, Connection closed до конца Content-Length, для curl это валидный финал. Где-то между моим хостом и upstream-зеркалом сидит прозрачный прокси или CDN, который режет соединение.
Решение — везде HTTPS. TLS требует close_notify alert при завершении, и если он не пришёл, клиент знает, что body неполный. После замены http://ports.ubuntu.com на https:// всё стало качаться чисто.
Я узнал это случайно, когда уже хотел переустанавливать систему. Сидел и думал — это что, я железо при распаковке покалечил?
Месяц с Claude Code: что это на самом деле
Самое интересное в этой истории — не какой стек я собрал, а как я его собирал. Я не писал код руками. Точнее, писал, но в объёме одной-двух строк, чтобы что-то быстро поправить. Все 88 КБ install.sh, все 16 lib-модулей, все nginx-шаблоны, все Python-скрипты для генерации манифестов сгенерировал Claude Code.
Это не «ChatGPT, дай сниппет». Claude Code — это CLI-агент, который читает файлы в репозитории, делает правки, гоняет тесты, открывает PR. Он сам видит мой проект, сам помнит, что в каком модуле. Я формулирую задачу человеческим языком, он её делает.
О себе для контекста: учился на программиста, лет 12–15 назад писал в продакшене, потом ушёл в бизнес и десять лет руки до кода почти не доходили. Архитектурное мышление осталось, диффы я читать не разучился, но сесть и накатать тысячу строк bash с идемпотентным wizard'ом — давно не садился. Тем интереснее было собрать что-то целиком, имея AI-агента в роли младшего разработчика на рутине.
Что у меня работало хорошо: bash-скрипты с edge-case'ами (в install.sh сейчас покрыто около тридцати возможных состояний хоста — частичная установка после прерывания, существующие credentials, сломанный peer, занятый порт 5353, битый apt-cache); регрессионные тесты под mock'и для cluster-mode; документация (этот пост — я диктую содержание, Claude формулирует, я вычитываю).
Что работало плохо. LLM врут, и это не лечится. Самый болезненный случай — Claude как-то предложил minio/minio:RELEASE.2026-02-01T00-00-00Z как стабильный пин MinIO. Тэг выглядит правдоподобно: timestamp в правильном формате, паттерн совпадает с реальными релизами. docker compose config принимает его как валидный. При docker compose up падает с manifest unknown, и установка валится на 9-й фазе из 11.
После этого случая я в CLAUDE.md (это файл с правилами проекта, его Claude автоматически читает в начале каждой сессии) написал жирно: «LLM не знает, какие тэги существуют в registry. Никаких "выглядит правдоподобно". Только docker manifest inspect перед commit». И добавил автотест tests/compose/test_image_tags_exist.sh, который проверяет каждый image:tag в registry. Теперь галлюцинации ловятся в CI.
Контекст забывается между сессиями. Каждая новая сессия — чистый лист. Если я не зафиксирую правило «не делай force-recreate во время RAG-индексации, это ломает Redis-state, я уже терял два часа», он через неделю это снова предложит. Без CLAUDE.md ничего не работает. Сейчас у меня там 200 с лишним строк правил, и каждое — выстраданное факапом. Раздел называется «Learned the hard way».
Иногда не понимает приоритеты. Говоришь «поправь баг в OCR» — попутно отрефакторит три соседних модуля, потому что заметил code smell. Иногда полезно, иногда я просто хочу патч, а не PR на восемьсот строк. Лечится через тот же CLAUDE.md: «не правь то, о чём тебя не просили».
Что я вынес про AI-разработку
Главное наблюдение, которое стоит написать прямым текстом: AI-агент не делает тебя умнее. Он делает тебя быстрее в том, в чём ты уже хоть как-то разбираешься.
Если я не понимаю, почему proxy_passhttp://name ломается на force-recreate, а proxy_pass $variable — нет, никакой Claude мне это сам не объяснит. Он сгенерирует код, я его поставлю, оно сломается, и я не пойму, почему. Если же я понимаю — Claude напишет nginx-конфиг с правильным паттерном за минуту вместо часа.
То же самое со всем остальным. Без общего понимания, как устроен Docker, что такое systemd-юнит, как работает HTTP, я бы не отличил рабочий код от рабочего-с-виду. Claude — не замена программиста. Это сильно ускоренный младший разработчик, на которого можно скинуть рутину, при условии, что архитектор у тебя есть. И если этого архитектора нет — никакая модель его не заменит, хоть она и пишет код в десять раз быстрее тебя.
Где это реально меняет уравнение: в задачах, где у тебя есть видение, опыт читать чужой код, понимание предметной области — но нет команды и нет физического времени. Раньше один человек с такими исходными мог сделать MVP за пару месяцев. Сейчас — production-grade продукт за 30 дней. У меня в репозитории 86 коммитов, 32 тысячи строк, 30 контейнеров, и это не маркетинговая фраза, а git log. Дисциплина простая:
— чёткое видение продукта (не «дай мне умную систему», а «wizard на 10 вопросов, идемпотентность, откат при ошибке, конкретные SLO»); — CLAUDE.md с правилами проекта, который пополняется после каждого факапа; — железо под рукой для проверки на живом стенде — эмуляция врёт, форумы устаревают, документация по умолчанию отстаёт от реальности.
Если у вас есть DGX Spark — забирайте install.sh, гоняйте на чистой системе, в issue-tracker'е расскажите, что сломалось. Если Spark'а нет, но интересно, как устроен private RAG end-to-end — lib/ и templates/docker-compose.yml читаются как самодокументация: я писал их так, чтобы через год самому помнить, почему именно gpu_memory_utilization=0.60, а не 0.70.
Во второй части расскажу про мониторинг unified memory без NVML — там пришлось довольно изобретательно костылить — и про supply-chain hardening для Dify-плагинов в air-gap-сценариях. Подписывайтесь, если интересно.
github.com/botAGI/AGmind-Источник
 
Loading...
Error