OpenClaw шлюз Ollama vLLM локальная сеть тайм-ауты doctor status удалённый Mac

Когда агент OpenClaw ходит не в облако поставщика, а в локальную или внутрисетевую LLM, половина инцидентов — это не «плохая модель», а несостыковка контрактов: шлюз говорит на языке OpenAI-совместимых путей, а Ollama и vLLM слушают разные базовые URL, разные лимиты одновременных запросов и разные профили задержки при длинном префилле. Вторая половина — тайм-ауты на трёх уровнях: клиент SDK, reverse-proxy и сам upstream, где vLLM может держать очередь KV-кэша, а Ollama — сериализовать загрузку модели в RAM. Инженеры часто проверяют только «curl с ноутбука», забывая, что сервисный аккаунт на сервере видит другой резолвер DNS и другой набор корневых сертификатов для mTLS; симптом выглядит как «плавающий» 502 без единой строчки в логах модели. Ниже — воспроизводимый каркас: как сопоставить эндпоинты, как нарезать параллелизм без взаимных столов, и как закрыть поставку одним прогоном doctor плюс status, чтобы не смешивать косметические предупреждения с реальными разрывами RPC. Для периметра без публичных входов и согласованного TLS в tailnet полезно свериться с материалом OpenClaw в Docker и Tailscale: sidecar, шлюз и токены без публичной экспозиции.

1. Маппинг эндпоинтов: один фасад шлюза — два разных бэкенда

На практике удобно держать для клиентов один base URL шлюза и внутри переключать маршрут на /v1/chat/completions и /v1/models к нужному провайдеру. Ollama обычно отдаёт совместимый слой на отдельном порту или подпрефиксе; vLLM чаще поднимают как отдельный сервис OpenAI-API с иным хостом. Зафиксируйте в репозитории таблицу «внешний путь → внутренний upstream → версия образа», иначе через месяц никто не вспомнит, какой location в nginx отрезал /v1. Проверка приёмки начинается с GET /v1/models через шлюз и прямой вызов upstream с той же сетевой ролью, что у демона — расхождение здесь дешевле ловить, чем на стриминговом completions. Если шлюз добавляет нормализацию имён моделей, документируйте правила подстановки: агенты часто шлют «красивый» тег, а vLLM ждёт полный идентификатор чекпойнта. Отдельно проверьте заголовки, которые прокси выкидывает по умолчанию: часть стеков удаляет нестандартные поля трассировки, и тогда теряется связка между запросом в шлюзе и записью в журнале inference. Для команд, которые параллельно держат несколько моделей на одной физической ноде, полезно явно развести профили «интерактив» и «пакет» на уровне маршрутов, чтобы случайный A/B-тест клиента не переключал трафик на экспериментальный тег без изменения DNS.

Правило: smoke-тест /v1/models с теми же заголовками, что и у /v1/chat/completions, обязателен до нагрузочного прогона.

2. Тайм-ауты: клиент, ingress и «длинный хвост» генерации

Локальные модели не гарантируют низкую задержку: большой контекст и широкие логиты удлиняют первый токен. Выставите три независимых тайм-аута: connect/TLS на клиенте, proxy_read_timeout (или аналог) на балансировщике и внутренний deadline на стороне шлюза к upstream. Для stream: true критичен именно idle между чанками — типичный обрыв на 60–120 секунд без трафика. Снимите трассу с метками времени между чанками на loopback, затем через ingress; если разрыв совпадает с кратным лимиту провайдера, меняйте политику прокси, а не параметры модели. Помните, что некоторые HTTP-клиенты применяют отдельный read-timeout ко всему ответу, а не к idle-окну; в логах это выглядит как обрыв «ровно через N минут» даже при непрерывном потоке мелких чанков. На стороне шлюза имеет смысл логировать только интервалы между чанками и коды закрытия сокета, не сохраняя полный текст — иначе вы удвоите нагрузку на диск в пике. Паттерны публичных вебхуков с подписью и дедлайнами хорошо иллюстрирует разбор вебхука шлюза и GitHub: публичный callback, 401 и тайм-ауты — те же классы ошибок всплывают и у LLM-ingress, особенно когда внешний балансировщик не различает длинные SSE и обычные POST.

3. Concurrency: нарезка на шлюзе и лимиты vLLM / Ollama

Одновременные агенты легко переполняют очередь планировщика vLLM или вызывают конкуренцию за загрузку весов в Ollama на одной ноде. Задайте верхнюю границу параллельных запросов на шлюзе чуть ниже, чем max_num_seqs и бюджет памяти GPU, и оставьте запас для коротких служебных вызовов. На уровне процесса закрепите отдельный пул для «длинных» задач с большим контекстом, чтобы они не вытесняли интерактивные короткие диалоги. В runbook выпишите целевые p95 по очереди и по времени до первого токена; при росте очереди сначала режьте параллелизм на шлюзе, а не лимиты в самом vLLM — так проще откатиться без рестарта inference. Для Ollama учитывайте, что одновременная подгрузка нескольких крупных GGUF на одну машину может сдвинуть p99 даже при умеренном числе активных чатов; планируйте окно обслуживания или заранее прогретые модели. Для vLLM фиксируйте политику preemption: если она включена агрессивно, интерактивные запросы «мигают» готовностью, а телеметрия очереди выглядит здоровой при субъективно плохом UX. Наконец, синхронизируйте лимиты с бэкендами аутентификации: иногда первый лишний запрос отклоняется по квоте раньше, чем inference успевает вернуть понятную ошибку, и винят сеть.

4. Doctor и status: один прогон приёмки перед релизом конфигурации

Согласуйте с командой минимальный чеклист: openclaw doctor для структурных проблем окружения, затем openclaw gateway status --require-rpc для живого RPC-контура, затем короткий curl к /v1/models с продовыми заголовками. Если RPC «зелёный», а HTTP пустой, ищите расслоение TLS или разных пользователей окружения между интерактивной оболочкой и launchd-юнитом. Сохраните в тикете оба вывода и версию образов upstream — это сокращает эскалации втрое. Отдельно проверьте DNS во внутренней сети: split-horizon часто ломает только ночные job, когда резолвер отличается от дневного ноутбука инженера. Doctor полезен для ранних сигналов о правах, путях и версиях Node, но не заменяет проверку реального трафика; status с флагом require-rpc как раз закрывает этот разрыв. Если в организации принят «зелёный» дашборд по health-check на /ping, не подменяйте им полноценный вызов models: такие пробы часто не несут тех же заголовков Authorization и дают ложное чувство безопасности. Наконец, заведите короткий перечень запрещённых изменений в проде без повторного прогона чеклиста — например, правка только тайм-аута nginx без сопроводительного теста стрима.

  • Один и тот же Authorization на /v1/models и короткий non-stream completions.
  • Снимок status --require-rpc до и после изменения ingress.
  • Логи прокси с upstream_response_time для стриминговых location.
  • Таблица лимитов: шлюз, vLLM, Ollama и максимальная длина контекста.

5. Воспроизводимый мини-сценарий из тикета

Зафиксируйте переменные GATEWAY_BASE, MODEL и TOKEN. Шаг A: curl -sS "$GATEWAY_BASE/v1/models" -H "Authorization: Bearer $TOKEN" с машины CI. Шаг B: короткий chat/completions без потока. Шаг C: поток с записью меток времени чанков в файл — сравните с idle-тайм-аутом балансировщика. Шаг D: повторите B и C с роли того же пользователя, что у systemd/launchd — расхождение здесь почти всегда объясняет «у дежурного работает, у робота нет». Приложите к задаче только заголовки без секрета и первые десять строк тела ответа. Шаг E: добавьте искусственную паузу между чанками на тестовом стенде, чтобы убедиться, что прокси не закрывает соединение на «тишине» модели; в бою такая пауза возникает при сложных рассуждениях или при конкуренции за GPU. Шаг F: зафиксируйте размер контекста и повторите C с удвоенным prompt, чтобы увидеть сдвиг p95 до первого токена — это ранний индикатор, что пора переносить нагрузку на более памятную ноду. Если CI не может хранить секреты напрямую, используйте тот же механизм подстановки, что и в проде, иначе вы отладите «не тот» токен с лишним переводом строки.

6. Кейс: «переполнение» длинного контекста на удалённый высокопамятный Mac

Когда контекст агента раздувается до десятков тысяч токенов, ноутбук команды упирается в RAM и swap, разумный вынос — постоянный удалённый Mac с большим объёмом памяти как выделенный inference-хост за тем же шлюзом. Шлюз остаётся лёгким и ближе к агенту, а тяжёлый префилл и длинные стримы выполняются на ноде с запасом по ОЗУ и предсказуемым launchd. Закрепите фиксированный hostname во внутреннем DNS, единые тайм-ауты curl, как в прод-интеграции, и отдельный секрет ротации; иначе снова появится класс «локально быстро, из офиса рвёт». Раз в неделю снимайте vm_stat и график сети в минуты пикового стрима, чтобы отличить нехватку памяти от исчерпания uplink. На практике полезно развести роли: одна пара «шлюз + короткие вызовы инструментов», вторая — «длинные рассуждения и свёртка контекста», чтобы сбой тяжёлой сессии не уводил в рестарт весь входной периметр. Если агент подмешивает большие вложения, заранее ограничьте их размер на стороне клиента шлюза, иначе даже высокопамятная нода упрётся в дисковый I/O при логировании. Такой профиль хорошо сочетается с корпоративными практиками изоляции рабочих областей на общих CI-нодах, см. FAQ по пулу Mac CI: Keychain, профили и изоляция как образец дисциплины окружения.

Почему для шлюза, локальной LLM и длинных сессий удобны Mac mini и macOS

Инференс и стриминг нагружают память, сеть и таймеры ОС сильнее, чем «голый» CPU. Mac mini на Apple Silicon даёт высокую пропускную способность памяти и низкий простой по энергии — удобная база для круглосуточного шлюза рядом с командой или в периметре малого ЦОД. macOS сочетает привычный launchd, нативный TLS-стек и инструменты наблюдаемости без лишнего гипервизора. Gatekeeper, SIP и FileVault снижают класс риска «случайно подменили бинарь в PATH того же пользователя, что и демон», а компактный корпус и тишина упрощают соседство с рабочими местами. Если вы хотите закрепить OpenClaw, Ollama или vLLM на надёжном железе с запасом по ОЗУ под длинный контекст, Mac mini M4 — практичная стартовая точка по совокупной стоимости владения. Чтобы подобрать выделенную облачную машину под такой профиль, откройте главную страницу Macstripe и согласуйте регион и объём памяти с командой.