Эта статья — про то, как превратить Claude Code в «терминальный агент‑интерфейс», а выбор моделей вынести в отдельный слой маршрутизации. В реальности Claude Code умеет работать через кастомный ANTHROPIC_BASE_URL, а значит его можно направить на локальный прокси и дальше — куда угодно: в OAuth‑аккаунты, OpenAI‑совместимые API и локальные рантаймы.
Ключевые выводы по практике (в рамках одной видеокарты RTX 3060 с двенадцатью гигабайтами памяти):
В локальном Ollama‑наборе для ежедневного кодинга оставлены только qwen2.5-coder:7b и qwen2.5:7b — они дают лучший баланс скорости/качества на типовых промптах. Более тяжёлый deepseek-coder-v2:16b-lite-instruct-q4_K_M оказался заметно медленнее без выигрыша, который оправдывал бы задержку. (Это мои замеры и выбор под конкретный сценарий, ниже — таблица.)
Локальная llama3.1:8b по публичным измерениям на RTX 3060 даёт порядка 60 токенов/сек и около 0.9 секунды до первого токена (TTFT) — но для роли «дефолтного» кодового ассистента она обычно проигрывает специализированным кодовым моделям в качестве (и/или в удобстве поведения агента).
Почему здесь вообще работает замена «мозгов»
Claude Code официально поддерживает настройку через переменные окружения — можно изменить базовый URL и токен, а также назначить «модели по умолчанию» (opus/sonnet/haiku или их аналоги). Эти переменные можно задавать в shell, либо один раз прописать в ~/.claude/settings.json в секции env.
Смысл архитектуры такой:
Claude Code остаётся тем же инструментом (чтение/правка/запуск кода в рабочей директории), но исходящие запросы уезжают не на «родной» SaaS‑endpoint, а на локальный роутер.
В этой роли удобен CLIProxyAPI: он заявлен как прокси‑сервер с интерфейсами, совместимыми с OpenAI/Gemini/Claude/Codex, поддержкой OAuth‑логина для нескольких провайдеров и балансировкой round‑robin между аккаунтами.
Отдельная важная деталь для локалок: с начала 2026 года Ollama поддерживает Anthropic‑совместимый API для Claude Code (то есть Claude Code можно направлять на Ollama напрямую), но для «сборки всего в одном месте» удобнее держать единый роутер и подключать Ollama как upstream.
Архитектура маршрутизации
Ключевая идея — один вход (Claude Code) и несколько «мозгов» за ним. CLIProxyAPI при этом может быть и «переводчиком протоколов», и балансировщиком аккаунтов, и точкой, где вы вводите алиасы под свои сценарии.
flowchart LR
A[Claude Code] -->|Anthropic Messages API\nANTHROPIC_BASE_URL| B[CLIProxyAPI]
B -->|OAuth| C[Codex / GPT модели]
B -->|OAuth| D[Qwen Chat / Qwen Code]
B -->|OpenAI-compat upstream| E[Ollama локально]
E --> F[qwen2.5-coder:7b]
E --> G[qwen2.5:7b]
E --> H[другие локальные модели\n(по необходимости)]
Практический смысл этой схемы:
Вы можете настроить «логические роли» моделей: fast для быстрых ответов, code для повседневного кода, brain для тяжёлых задач и длинных агентных прогонов. Алиасы в CLIProxyAPI существуют явно: есть oauth-model-alias, флаг fork (оставить оригинальное имя и добавить алиас как дополнительное), и правила, как избегать неоднозначности пересечений имён между провайдерами.
Установка и базовая настройка CLIProxyAPI
Установка CLIProxyAPI
Официальный «быстрый старт» у CLIProxyAPI есть для нескольких способов установки.
Для macOS через Homebrew: brew install cliproxyapi и запуск как сервис.
Для Linux есть one‑click installer script, также отдельные инструкции для Arch (AUR) и systemd‑юнита.
Сборка из исходников поддерживается через go build -o cli-proxy-api ./cmd/server.
Важно: конфиг обязателен до старта сервиса; типовой путь — ~/.cli-proxy-api/config.yaml, а директория авторизации по умолчанию — ~/.cli-proxy-api.
Минимальный config.yaml
Ниже — практичный «минимум, который не стыдно держать» для локального роутера: ограничение на localhost, простая авторизация по dummy‑ключу, round‑robin стратегия, базовые политики retry/quota.
host: "127.0.0.1"port: 8317# где CLIProxyAPI хранит OAuth-токены/учёткиauth-dir: "~/.cli-proxy-api"# ключи, которыми будут пользоваться клиенты (например, Claude Code)api-keys:- "sk-dummy"force-model-prefix: falserequest-retry: 3max-retry-interval: 30quota-exceeded:switch-project: trueswitch-preview-model: truerouting:strategy: "round-robin"
Поля host, port, auth-dir, api-keys, force-model-prefix, request-retry, quota-exceeded и routing.strategy задокументированы в базовой конфигурации CLIProxyAPI.
Запуск сервера с явным путём к конфигу выглядит так:
./cli-proxy-api --config ~/.cli-proxy-api/config.yaml
OAuth‑логины для Codex и Qwen
В актуальной документации CLIProxyAPI логин к провайдерам делается командами самого cli-proxy-api.
Codex (OpenAI via OAuth):
./cli-proxy-api --codex-login
Qwen (Qwen Chat via OAuth device flow):
./cli-proxy-api --qwen-login
Для OAuth‑логинов у CLIProxyAPI явно указан флаг --no-browser (чтобы не открывать браузер, а вывести URL), и что callback‑порт для Codex фиксированный (1455), а для Claude Code — другой (54545).
Если вы используете отдельный Codex CLI, то в его документации тоже есть codex login (OAuth через ChatGPT) и альтернативный вход через API‑key. Это полезно понимать, если вы хотите «развести» способы авторизации или отлаживать токены независимо от CLIProxyAPI.
Алиасы и routing под «роли» моделей
CLIProxyAPI умеет переименовывать модели (для списка /v1/models и для роутинга запросов) через oauth-model-alias. По документации это алиасы «по каналу», а fork: true оставляет оригинальное имя и добавляет алиас как дополнительное.
Пример, близкий к рабочему «сетапу для программиста»:
oauth-model-alias:
codex:
- name: "gpt-5.4"
alias: "brain"
fork: true
- name: "gpt-5.4-mini"
alias: "fast"
fork: true
- name: "gpt-5.4-mini"
alias: "code"
fork: true
qwen:
- name: "coder-model"
alias: "code"
fork: true
Два практических нюанса из примера конфигурации CLIProxyAPI:
Алиасы глобальные и могут пересекаться между провайдерами — это потенциально создаёт неоднозначность. Для строгого «прибивания к backend» лучше использовать уникальные алиасы/префиксы или не пересекать имена.
Для failover‑пула (когда один alias «смотрит» на несколько upstream‑моделей) в примере конфига описано поведение: запросы round‑robin’ятся по пулу, а если выбранный upstream падает до выдачи вывода — прокси пробует следующий. Это ровно та механика, которая нужна для «Qwen как основной, GPT как запасной».
Подключение локального Ollama как upstream
CLIProxyAPI поддерживает «OpenAI‑совместимые upstream‑провайдеры» через конфиг: задаётся base-url и набор ключей. Это тот крючок, которым удобно подключить Ollama, потому что у Ollama есть OpenAI‑совместимые эндпоинты (/v1/chat/completions, /v1/responses и др.).
Минимальный пример (локальный Ollama по умолчанию использует порт 11434; здесь важен суффикс /v1 для OpenAI‑совместимого API):
openai-compatibility:
- name: "ollama"
prefix: "local"
base-url: "http://127.0.0.1:11434/v1"
api-key-entries:
- api-key: "sk-local-anything"
Сам CLIProxyAPI прямо приводит структуру блока openai-compatibility (включая name, prefix, base-url, api-key-entries).
Подключение Claude Code
Через переменные окружения
Документация CLIProxyAPI для Claude Code сводится к простому: запустите CLIProxyAPI и установите ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN и переменные выбора моделей.
Пример (под «версии 2.x» Claude Code, где есть отдельные defaults для opus/sonnet/haiku):
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
export ANTHROPIC_AUTH_TOKEN=sk-dummy
export ANTHROPIC_DEFAULT_SONNET_MODEL=code
export ANTHROPIC_DEFAULT_OPUS_MODEL=brain
export ANTHROPIC_DEFAULT_HAIKU_MODEL=fast
Альтернатива для старых версий, где используются ANTHROPIC_MODEL и ANTHROPIC_SMALL_FAST_MODEL, тоже описана в документации CLIProxyAPI.
Через settings.json
В официальных документах Claude Code отдельно сказано:
Переменные окружения можно «забить» в settings.json под ключом env, чтобы они применялись ко всем сессиям или распространялись командой.
Пользовательские настройки лежат в ~/.claude/settings.json, а проектные — в .claude/settings.json и .claude/settings.local.json.
Практичный пример ~/.claude/settings.json:
{
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8317",
"ANTHROPIC_AUTH_TOKEN": "sk-dummy",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "code",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "brain",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "fast"
}
}
Дальше — просто запускаете:
claude
Проверка, что роутер реально виден
Для CLIProxyAPI логично начать с проверки списка моделей (OpenAI‑совместимый эндпоинт). В сценарии «локально на localhost» это обычно выглядит так:
curl http://127.0.0.1:8317/v1/models \
-H "Authorization: Bearer sk-dummy" | jq
Если алиасы настроены корректно, они должны светиться как клиент‑видимые имена моделей. Механика «показать модели» и «переименовать модели алиасами» прямо описана у CLIProxyAPI в части oauth-model-alias (алиас влияет и на listing, и на routing).
Локальные модели в Ollama: замеры и практический выбор
Что именно тестировалось и как мерить воспроизводимо
Чтобы локальные замеры могли жить в статье (а не только «на ощущениях»), удобнее всего измерять через Ollama API, потому что Ollama возвращает тайминги (total_duration, prompt_eval_duration, eval_duration, а также количества токенов). Эта структура ответа показана в официальном api.md проекта Ollama.
Минимальный измерительный запрос (не потоковый, чтобы получить единый JSON с таймингами):
curl -s http://127.0.0.1:11434/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5-coder:7b",
"prompt": "Сгенерируй PHP-функцию, которая валидирует email и возвращает нормализованное значение. Коротко.",
"stream": false
}' | jq '{total_duration, prompt_eval_duration, eval_duration, prompt_eval_count, eval_count}'
Дальше вы сравниваете:
- «время отклика» на фиксированный промпт (как wall‑clock, так и
total_duration), - плотность вывода (сколько токенов генерируется),
- и отдельно «prompt eval» (который сильно растёт при длинном контексте).
Реальные замеры на RTX 3060 с двенадцатью гигабайтами памяти
Ниже — практические замеры «русский prompt» и «PHP prompt» для локальных моделей (Ollama). Сценарий — повседневный кодинг, где важны задержка и «адекватность по русскому».
Для llama3.1:8b добавлены публичные технические метрики на RTX 3060 в формате Ollama‑таймингов и отдельный синтетический бенчмарк (TTFT + throughput). Эти две метрики полезны, когда вы хотите понять «где прячется время» (prompt‑eval vs генерация) и насколько модель будет быстрой при коротких/длинных ответах.
| Модель (Ollama) | Русский prompt: время отклика | PHP prompt: время отклика | Комментарий по итогу теста |
|---|---|---|---|
| qwen2.5-coder:7b | ~5.39s | ~4.95s | Основной локальный кодовый помощник (лучший баланс скорости/качества в повседневном кодинге). |
| qwen2.5:7b | ~5.09s | ~4.59s | Основной «русский/общий» помощник; на практике быстрее и стабильнее для текста, чем более тяжёлые варианты. |
| deepseek-coder-v2:16b-lite-instruct-q4_K_M | ~9.71s | ~8.34s | Удалён после тестов: на этой видеокарте не даёт выигрыша, который оправдывает задержку. |
| llama3.1:8b | ~4.3s на коротком текстовом промпте (публичный замер, 165 токенов, Q4_K_M) | оценку лучше снимать PHP‑промптом | Публично на RTX 3060: ~60 ток/с + около 0.9с TTFT; как «универсал» — норм, но в роли дефолтного кодового ассистента обычно проигрывает специализированным кодовым моделям. |
Пояснение по последней строке:
Публичный замер для llama3.1:8b-instruct-q4_K_M на RTX 3060 показывает total_duration около 4.295 секунды при генерации 165 токенов (и очень быстрый prompt‑eval, порядка 0.037 секунды) — это иллюстрирует «потолок скорости» для компактной 8B‑модели при коротком промпте.
Отдельно LocalScore даёт для RTX 3060 метрики «time to first token» и скорости генерации для Meta Llama 3.1 8B Instruct (TTFT около 879ms и generation speed около 52.2 tok/s в их бенчмарке). Это полезно именно как «латентность движка», а не как замена прикладным промптам.
Почему именно эти две локальные модели остаются дефолтом
Логика выбора «qwen2.5-coder:7b + qwen2.5:7b» хорошо ложится на официальные свойства семейства Qwen:
Qwen2.5‑Coder — отдельная линейка под код, с несколькими размерами (включая 7B), и заявленными улучшениями в генерации/исправлении/рассуждении по коду.
Qwen2.5 как базовая модельная серия заявляет мультиязычность и длинный контекст (в т.ч. на 7B‑уровне), но в зависимости от конкретной сборки/рантайма реальный «дефолтный» контекст часто меньше и расширяется режимами вроде YaRN. Это прямо отражено в model card’ах: конфиг для 7B‑Instruct обычно выставлен на 32768 токенов, а расширение выше делается через YaRN.
Для DeepSeek Coder V2 Lite важно понимать архитектуру: это MoE‑модель с 16B параметров (и малым числом активных параметров на инференсе), большим контекстом и фокусом на код. Но на «домашней» видеокарте задержка может вырасти из‑за совокупности факторов (включая размер, шаблоны, KV‑cache). В официальном описании DeepSeek Coder V2 подчёркивается 128K контекст и расширение поддержки языков программирования, но это не отменяет реальности «в повседневном кодинге мне важнее отклик».
Таблица сравнения локальных моделей для этой конфигурации
Таблица ниже намеренно «прикладная»: она не обещает точных VRAM‑цифр для каждого промпта (они зависят от контекста и квантизации), но фиксирует главное: размер, контекстные возможности по документации, наблюдаемую скорость и стоимость эксплуатации.
| Модель | Параметры и тип | Контекст по документации | Типичный VRAM‑класс (Q4, короткий контекст) | Скорость/латентность (как наблюдается) | Качество: код | Качество: русский текст | Цена |
|---|---|---|---|---|---|---|---|
| qwen2.5-coder:7b | 7B, dense | базово 32K; расширение через YaRN/варианты до 128K (зависит от рантайма) | «влезает» в одну карту этого класса | ~5s на типовом запросе | высокая для повседневного кода (для размера) | средняя | локально «почти бесплатно» (электричество) |
| qwen2.5:7b | 7B, dense | базово 32K; расширение через YaRN/варианты до 128K | «влезает» в одну карту этого класса | ~4.6–5.1s на типовом запросе | средняя | высокая (как основной «русский/общий») | локально «почти бесплатно» |
| deepseek-coder-v2:16b-lite | 16B total, MoE, ~2.4B active | до 128K | выше требования к памяти/контексту | ~8–10s на типовом запросе | потенциально выше на сложных задачах | средняя | локально «почти бесплатно» |
| llama3.1:8b | 8B, dense | 128K | ~6 GB VRAM под модель + запас (зависит от контекста) | ~60 tok/s в публичном Ollama‑замере; TTFT порядка секунды | средняя | средняя | локально «почти бесплатно» |
Ключевой практический вывод именно для этой видеокарты и сценария «быстрый ежедневный кодинг»: если модель становится «чуть умнее», но вдвое медленнее, она перестаёт быть дефолтом и превращается в «вызывать по необходимости».
Ограничения локалок и советы по боевому роутингу
Ограничение по агентности и tool-calling
Claude Code — агент, который читает/меняет/запускает код в директории. Для этого нужны стабильные ответы в нужном формате и адекватная работа с tool calling. Ollama прямо пишет, что «open models can be used with Claude Code» через Anthropic‑совместимый API, но это не гарантирует, что любая open‑модель будет одинаково хорошо выполнять агентные паттерны.
Если вы пытаетесь «вставить локалку» и видите деградацию поведения агента, обычно проблема не в «не умеет думать», а в комбинации факторов: шаблоны диалога, длительность контекста, стабильность tool calling, а также то, насколько модель хорошо держит системные инструкции внутри длинного промпта. Поэтому практичный паттерн — держать локалку на «мелких» задачах (черновики, переписывание, быстрые пояснения), а «настоящую агентность» (многошаговые изменения по репозиторию) отдавать в более сильный удалённый backend. Контекст и скорость: почему одна и та же модель бывает «быстрой и медленной»
Скорость и память на инференсе зависят не только от параметров модели, но и от длины входного контекста и выходной генерации. Qwen публикует отдельные speed/memory бенчмарки с прогоном разных длин входа (вплоть до очень длинных) — из них следует главная практическая мысль: длинный контекст резко меняет и память, и latency.
В Claude Code это особенно заметно: сам инструмент склонен «набивать» большой контекст (код, патчи, вывод команд). В одном из практических гайдов по интеграции Claude Code с другими backend’ами прямо рекомендуют ориентироваться на очень большой контекст (порядка десятков тысяч токенов) как на нормальную рабочую реальность.
Из этого вытекают два практических правила:
Не ставьте локальную модель как единственный дефолт, если она «не держит» типичный объём контекста. Гораздо лучше — локалка как быстрый раннер для коротких задач.
Ограничивайте контекст там, где это возможно (особенно для локальных моделей): иначе KV‑cache начинает съедать память и вы получаете рост prompt eval time и иногда уход в RAM, что убивает отзывчивость.
OpenAI‑совместимый API не всегда «сессионный»
Ещё один подводный камень: если вы используете OpenAI‑совместимый endpoint (например, Ollama /v1/responses), некоторые интерфейсы могут быть «не stateful» — то есть не поддерживают диалог как единый объект на стороне сервера. В документации Ollama по OpenAI compatibility прямо сказано, что Responses API implementation «non‑stateful» и не поддерживает conversation/контекст как сущность.
Для Claude Code это не всегда критично (сам клиент может пересылать историю), но для некоторых внешних интеграций и агентных обвязок может неожиданно всплыть — особенно если вы привыкли к «серверной сессии».
Практические советы по алиасам и стратегии
Если цель — экономия без боли, то рабочая схема обычно выглядит так:
fast — дешёвая/быстрая модель для коротких ответов и «шумовых» задач.
code — профильная модель под код (локальная или облачная), основная в ежедневной работе.
brain — более дорогой и сильный backend для задач, где цена ошибки выше цены токенов (сложные рефакторинги, агенты на несколько часов, миграции).
В CLIProxyAPI это логически оформляется через oauth-model-alias и (при необходимости) alias‑pool с failover‑поведением, описанным в примере конфига.