CNN TürkDronların korkulu rüyası: TOLGA!The Jerusalem PostInmate killed in northern Israel after leaving prison as part of rehabilitation programInquirerLTO suspends license of SUV driver linked to cellphone seller’s deathSky TG24Sinner, trofei e vittorie in carriera: i record del primo italiano campione a WimbledonPunchUAE sponsors mass wedding for 250 Palestinian couplesZDF heuteAktuelle Pressemitteilungen des ZDFWirtualna PolskaKryzys wokół Trybunału Konstytucyjnego. Miażdżąca ocena PolakówIl Fatto QuotidianoAAA cercasi agenti segreti: 40mila candidature in 24 ore per il primo concorso pubblico per diventare “007”, ecco i requisiti richiesti e come candidarsiNHK 社会プロボウラーの中山律子さんが死去 一大ブームをけん引 84歳Daily MailDolly Parton's new SongTeller hotel and museum in Nashville is pitch-perfect tribute to Queen of Country - but the footage she recorded before her death is hard to watchХабрЧто там с китайским авиапромомMyJoyOnlineWas TrafficTech-GH designed to raise revenue for gov’t? – Fiifi Boafo questions 60% share of fines
The Daily Newsstand · Free, Always
Saturday, November 7, 2026

Claude Code без Anthropic: заводим агента на GLM-5.3 и Qwen через свой шлюз и собираем грабли

Translate

Из Беларуси Claude Code официально не работает: Anthropic не обслуживает регион, а белорусской картой не оплатить ни подписку, ни API. Мы делаем ZuBrIQ — шлюз к моделям с оплатой в BYN — и за последние месяцы заставили Claude Code, Codex и OpenCode работать на открытых моделях — GLM-5.3 у провайдера и Qwen3.8-27B на собственных V100. Ниже — схема и пять граблей, на каждую из которых мы наступили сами.

Зачем вообще подменять модель под Claude Code

Claude Code — хороший агент, и он умеет ходить не только к Anthropic. Достаточно ANTHROPIC_BASE_URL и токена — и он шлёт запросы по протоколу Anthropic Messages куда угодно. Про это недавно был хороший обзор на Хабре — «Чем заменить Claude или Gemini после блокировки». Там подменяли модель на DeepSeek и MiniMax.

У нас задача шире. Нужны не один клиент и не одна модель, а десяток клиентов и несколько моделей за одним адресом и одним ключом. Плюс учёт расходов, резервные маршруты и модель, данные которой не покидают страну. Поэтому между агентами и моделями стоит шлюз на LiteLLM.

Схема

Claude Code ── /v1/messages ─────────┐
Codex ──────── /v1/responses ────────┤
OpenCode, Zed, Cursor, SDK ──────────┤
  /v1/chat/completions               │
                                     ▼
                         ┌───────────────────────┐
                         │   LiteLLM (2 пода)    │
                         │ ключи, бюджеты, логи  │
                         │ имя модели → маршруты │
                         └───────────┬───────────┘
              ┌──────────────────────┼───────────────────────┐
              ▼                      ▼                       ▼
     vLLM, 4×V100 16 ГБ      GLM-5.3 у провайдера    DeepSeek V4 Pro
     Qwen3.8-27B AWQ INT4    (основной маршрут)      (резерв)
     имя: zubr               имя: zubr-coder         под тем же именем

Главное правило — клиенты знают только стабильные имена: zubr, zubr-flash, zubr-coder. За каждым именем стоит список маршрутов с порядком и резервом. Сменились веса или упал провайдер — интеграции этого не замечают.

Грабля 1. Тихий уход в резерв на /v1/messages

Сначала мы завели GLM-5.3 как обычный OpenAI-совместимый бэкенд — провайдером openai/ с нужным api_base. Чат и SDK работали. А Claude Code и Codex получали ответы… от резервной модели.

Оказалось, LiteLLM для openai/ переводит /v1/messages (Claude Code) и /v1/responses (Codex) в OpenAI Responses API. Провайдер отвечает на /responses 404, и роутер молча уходит на следующий маршрут. В логах ошибки нет, ответ есть — просто не от той модели.

Выдаёт это только заголовок ответа:

x-litellm-attempted-fallbacks: 1

Лечится нативным провайдером LiteLLM для этого вендора: он переводит Messages и Responses в chat/completions, который у провайдера есть. Переменная LITELLM_USE_CHAT_COMPLETIONS_URL_FOR_ANTHROPIC_MESSAGES чинит только /v1/messages, Codex с ней всё равно уходит в резерв.

Вывод: порядок маршрутов LiteLLM соблюдает всегда. Если отвечает «не та» модель — смотрите на fallback, а не на order.

Грабля 2. Claude Code сам просит Haiku, Sonnet и Opus

Подменить ANTHROPIC_MODEL мало. Claude Code отдаёт служебные подзадачи — заголовки, сжатие контекста, субагентов — моделям классов Haiku, Sonnet и Opus по их именам. У ключа без доступа к Anthropic такие запросы падают с 403, причём посреди работы.

Рабочий ~/.claude/settings.json выглядит так:

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.zubriq.ai",
    "ANTHROPIC_AUTH_TOKEN": "sk-…",
    "ANTHROPIC_MODEL": "zubr-coder[1m]",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "zubr-coder[1m]",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "zubr-flash[1m]",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "zubr",
    "CLAUDE_CODE_MAX_CONTEXT_TOKENS": "262144",
    "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
  }
}

Ключ выпускается в личном кабинете zubriq.ai, а zubrcode connect claude записывает этот файл сам. Три детали, каждая стоила нам вечера:

  • ANTHROPIC_BASE_URL — без /v1. Claude Code сам дописывает /v1/messages, и с /v1 получается /v1/v1/messages.

  • Суффикс [1m] говорит Claude Code, что у модели окно 1M, и отрезается до отправки: на шлюз уходит чистое zubr-coder. Без него агент считает окно по своим правилам и сжимает контекст слишком рано.

  • Для модели без [1m] окно задаёт CLAUDE_CODE_MAX_CONTEXT_TOKENS. На модели с [1m] эта переменная не влияет.

Грабля 3. Нулевые расходы

С нативным провайдером запросы пошли куда надо, но расход по ключам стал равен нулю. Для этого провайдера LiteLLM не берёт цену из model_info. Spend ноль — бюджеты ключей не срабатывают, отчёт по марже врёт.

Решение — продублировать цены прямо в litellm_params записи модели:

litellm_params:
  model: <provider>/glm-5.3
  input_cost_per_token: 0.0000012
  output_cost_per_token: 0.000004
  cache_read_input_token_cost: 0.00000022

Цифры условные — важно место, где они лежат. И ещё: правка модели через PATCH /model/{id}/update доезжает до второго пода не сразу, а через минуту-две. Не спешите считать, что не сработало.

Грабля 4. Модель, которая не видит картинок

GLM-5.3 силён в коде, но изображения не принимает. Причём ведёт себя по-разному в зависимости от входа:

Вход

Что происходит с картинкой

chat/completions провайдера

400: allowed values: ['text']

Anthropic-совместимый эндпоинт провайдера

молча выкидывается, модель «угадывает» по тексту

резерв DeepSeek V4 Pro

отвечает, что изображения нет

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

В нашем агенте ZubrCode мы сделали подмену. Если у модели в каталоге нет зрения, картинка заменяется текстовым описанием от быстрой модели со зрением — GLM-5.3 Flash. Тонкость: агент переигрывает всю историю на каждом ходе. Без кеша одно и то же фото описывалось бы заново каждый раз. Поэтому описание кешируется по sha256 картинки на диске.

Отдельная мелочь в каталоге: supports_vision: null из /model/info у нас трактовался как явное false ((bool) null). Из-за этого зрение пропало и у модели, которая видит. Правильно — «не знаю, спроси выше по цепочке». И учтите: если под одним именем несколько маршрутов, флаги берутся с первого по порядку.

Грабля 5. Своя модель на V100

Для данных, которые не должны уходить за границу, у нас Qwen3.8-27B на собственных 4×V100 по 16 ГБ. Карты 2017 года, без bf16 и без FP8. Поэтому квант AWQ INT4 с вычислениями в FP16, vLLM с тензорным параллелизмом на 4 карты и форк vLLM с поддержкой SM70.

Что всплыло:

  • KV-кеш нужно задавать явно. Форк считает бюджет KV как total × gpu_memory_utilization − активации и не вычитает веса модели: загрузчик для SM70 отдаёт их размер почти нулём. Итог — KV съедает больше, чем можно, и соседу на тех же картах памяти не остаётся. Мы задаём --kv-cache-memory-bytes явно, а --gpu-memory-utilization оставили только как проверку свободной памяти при старте.

  • Два инстанса нельзя стартовать одновременно. Летом рядом с основной моделью жила отдельная VL-модель. Пик инициализации двух процессов был больше 16 ГБ — один воркер ловил OOM. Дальше хуже: основной инстанс зависал на NCCL watchdog. systemd показывал active, а порт был закрыт. Лечили так: второй юнит ждал health первого в ExecStartPre.

  • Dense против MoE. До сентября под этим именем была MoE 35B-A3B: около 3 млрд активных параметров, первый токен за ~0,6 с. Плотная 27B умнее и видит картинки сама, без отдельной VL-модели. Но первый токен теперь ~1,3 с. Для агента, который делает десятки вызовов, это заметно. Мы оставили её как «Haiku-слот»: фоновые подзадачи и всё, что нельзя отдавать наружу.

Текущие параметры: контекст 262 144 токена, max-num-seqs 24, KV ~4,6 ГБ на карту, tool calling через парсер qwen3_xml.

Что в итоге

  • Claude Code, Codex и OpenCode работают через один шлюз на GLM-5.3 и Qwen, без патчей клиентов — только конфиг.

  • Модель в ключе стабильна по имени, а маршруты и веса под ней меняются без участия пользователей.

  • Самые неприятные ошибки здесь молчаливые: уход в резерв, нулевой spend, выброшенная картинка. Мониторьте заголовки fallback и сверяйте расход, а не только коды ответов.

Шлюз из статьи — часть нашей платформы ZuBrIQ: там же готовые настройки для Claude Code и других клиентов. В следующих статьях цикла — подробно про vLLM на V100 и маскирование персональных данных до отправки в модель. Делитесь в комментариях, какие клиенты и модели вы связываете и на какие грабли наступали.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.