Головна / Статті / Як спрямувати Claude Code на GPT і локальні моделі Ollama через проксі

Як спрямувати Claude Code на GPT і локальні моделі Ollama через проксі

Перенаправте ANTHROPIC_BASE_URL на проксі-транслятор, перевірте на платному бекенді, перейдіть на безкоштовні локальні моделі й дізнайтеся, що ламається і як розумно розподіляти задачі.

1911 слів

Якщо ви платите за кілька ШІ-підписок, то напевно ловили себе на тому, що відкриваєте ще один термінал чи вкладку браузера лише для того, щоб віддати задачу іншій моделі, адже Claude Code говорить тільки з Claude. Вибір моделі всередині виглядає багатообіцяльно, але у випадному списку лише моделі самої Anthropic. Дехто написав невеликі плагіни-шлюзи, які тихо спрямовують його трафік іншим провайдерам, і виявилося, що трюк за ними зовсім не екзотичний. Ось що потрібно для налаштування, що зламалося дорогою і яка схема зрештою прижилася.

Чому це не хак

Claude Code, як і більшість консольних агентів на Anthropic SDK, не зашиває в код api.anthropic.com. Він читає ANTHROPIC_BASE_URL, а ключ — з ANTHROPIC_AUTH_TOKEN, і надсилає кожен запит на цю адресу. Налаштування існує для компаній, які пускають інструмент через внутрішній шлюз, аудит-проксі чи дзеркало у своєму регіоні. Воно не задумувалося як перемикач моделей, але поводиться саме так, щойно помічаєш, що сервіс на іншому кінці зовсім не мусить бути Anthropic. Йому досить приймати формат Anthropic Messages і відповідати в тій формі, якої чекає Claude Code, включно з подіями стримінгу та блоками викликів інструментів.

Тож уся ідея — невеликий HTTP-сервіс. Він перекладає схему запитів і відповідей Anthropic на те, чим говорить справжній бекенд, зазвичай формат OpenAI chat completion, бо майже всі провайдери, зокрема локальні, зійшлися на ньому, а потім перекладає відповідь назад:

Claude Code  --Anthropic Messages format-->  local proxy  --OpenAI format-->  GPT-5 / Grok / Ollama / whatever
Claude Code  <--Anthropic Messages format--  local proxy  <--OpenAI format--  (response, tool calls, streaming deltas)

З такого погляду питання, чому Claude Code просто не підтримує інші моделі, перестає бути цікавим. Він уже підтримує, опосередковано, якщо хтось посередині займається перекладом.

Доступні інструменти

Очевидного переможця немає. Натомість є жменька невеликих проєктів, переважно одноосібних, які розв'язують ту саму задачу перекладу з різним охопленням. Ось ті, які варто порівняти:

+---------------------------+--------+------------------------------+------------------------------------------+
| Project                    | Stack  | Backends                      | Notes                                     |
+---------------------------+--------+------------------------------+------------------------------------------+
| claude-code-proxy           | Go     | OpenAI, OpenRouter, Ollama    | Single binary, pattern-based model        |
| (nielspeter)                 |        |                                | mapping (*opus*/*sonnet*/*haiku*),        |
|                              |        |                                | full streaming + tool call support        |
+---------------------------+--------+------------------------------+------------------------------------------+
| claude-code-ollama-proxy    | Python | Ollama, OpenAI (fallback),    | Built specifically for local-first use,   |
| (mattlqx)                    | / uv   | Gemini                        | uses LiteLLM under the hood for format    |
|                              |        |                                | translation                               |
+---------------------------+--------+------------------------------+------------------------------------------+
| claude-code-router          | Node   | OpenAI, Anthropic, Gemini,    | The most feature-complete option, ships   |
| (musistudio)                 |        | DeepSeek, Kimi, custom        | a UI, rule-based routing (background /    |
|                              |        | endpoints                     | think / longContext), retries, failover   |
+---------------------------+--------+------------------------------+------------------------------------------+
| LiteLLM proxy               | Python | 100+ providers                | Not built for Claude Code specifically,   |
| (generic)                    |        |                                | but exposes an Anthropic-compatible route |
|                              |        |                                | so it works the same way                  |
+---------------------------+--------+------------------------------+------------------------------------------+

Усі під ліцензією MIT, за замовчуванням слухають localhost і роблять ту саму основну роботу. Різняться вони тим, скільки логіки маршрутизації накручено поверх шару перекладу. Починати з найпростішого розумно: так ви розберетеся у формі запитів і відповідей до того, як довірите рішення рушію правил якогось роутера.

Перший підхід: платний бекенд

Перш ніж тягти туди локальну модель, переконайтеся, що вся обв'язка працює. Тому перший запуск використав OpenAI як бекенд через claude-code-proxy, програму на Go:

# clone and build (Go toolchain required)
git clone https://github.com/nielspeter/claude-code-proxy.git
cd claude-code-proxy
go build -o claude-code-proxy cmd/claude-code-proxy/main.go

Налаштування лежать у звичайному env-файлі, де рівні моделей Claude зіставляються з тим, за що ви насправді платите:

# ~/.claude/proxy.env
OPENAI_API_KEY=sk-...
OPENAI_BASE_URL=https://api.openai.com/v1

# map Claude's model tiers to whatever you're actually paying for
ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5
ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5
ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5-mini

Запустіть проксі, потім спрямуйте на нього Claude Code замість ендпоінта Anthropic:

./claude-code-proxy &            # listens on localhost:8082 by default
export ANTHROPIC_BASE_URL=http://localhost:8082
claude

От і все. Claude Code запускається як завжди, інтерфейс не змінюється, але кожне повідомлення тепер іде через GPT-5. Виклики інструментів, правки файлів і весь цикл агента працювали без змін у власній конфігурації Claude Code.

Один сюрприз: цей патерн із проксі з'явився раніше за хвилю плагінів для маршрутизації моделей, про які пишуть. Та сама ідея лежить у власній документації Anthropic щодо корпоративних шлюзів, тільки тут усе у себе й спрямоване в неофіційний бік.

Справжня мета: безкоштовна локальна модель

Платити за GPT за спиною Claude Code — означає втратити половину сенсу. Краща мета — віддати нудні 80% сесії чомусь безкоштовному й локальному: правки форматування, механічний рефакторинг, очевидний тест для функції, — а платні й якісніші моделі лишити для роботи, де потрібне судження.

Ollama робить це майже непристойно простим: свіжі версії віддають OpenAI-сумісний ендпоінт за адресою /v1 без жодних адаптерів:

# install Ollama if you don't have it: https://ollama.com/download
ollama pull qwen2.5-coder:14b
ollama serve

Потім спрямуйте той самий проксі на нього замість OpenAI:

# ~/.claude/proxy.env
OPENAI_BASE_URL=http://localhost:11434/v1
# no API key needed for local Ollama, the field just needs to be non-empty
OPENAI_API_KEY=ollama
ANTHROPIC_DEFAULT_SONNET_MODEL=qwen2.5-coder:14b
ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen2.5-coder:7b

Запускайте точно так само, як раніше:

./claude-code-proxy &
export ANTHROPIC_BASE_URL=http://localhost:8082
claude

Ні API-ключа, ні дашборда з білінгом, і нічого не залишає машину. Якщо не хочеться ставити Ollama нативно, Docker-версія — та сама конфігурація в контейнері:

# docker-compose.yml
services:
  ollama:
    image: ollama/ollama:latest
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
volumes:
  ollama_data:

Потім завантажте модель усередині нього:

docker compose up -d
docker exec -it $(docker compose ps -q ollama) ollama pull qwen2.5-coder:14b

OPENAI_BASE_URL лишається http://localhost:11434/v1, і більше нічого не змінюється.

Що пішло не так

Не все запрацювало з першого разу. Ці сценарії збоїв пояснюють, чому «просто спрямуй на проксі» применшує зусилля:

+-------------------------------------+--------------------------------------------------------------+
| What broke                            | Why, and what fixed it                                        |
+-------------------------------------+--------------------------------------------------------------+
| Tool calls silently stopped mid-task  | Smaller local models (7B/8B) don't reliably emit well-formed   |
|                                        | tool-call JSON under Claude Code's system prompt, which is     |
|                                        | dense and multi-step. Bumping to a 14B code-tuned model fixed  |
|                                        | most of it, not all of it.                                     |
+-------------------------------------+--------------------------------------------------------------+
| Streaming responses arrived as one     | The proxy has to translate each OpenAI streaming delta into a  |
| big chunk instead of token-by-token    | matching Anthropic streaming event. If it buffers instead of   |
|                                        | forwarding incrementally, you lose the live-typing feel, it    |
|                                        | still works, it just feels laggy.                              |
+-------------------------------------+--------------------------------------------------------------+
| Claude Code's /model picker didn't     | The simple proxies don't hook into the picker UI at all, model |
| show my local model as an option       | selection happens entirely through the env file mapping, not   |
|                                        | inside Claude Code itself. Only the router-style tools with a   |
|                                        | UI (claude-code-router) actually inject entries into /model.    |
+-------------------------------------+--------------------------------------------------------------+
| Context got truncated on long          | Local models running through Ollama default to a much smaller  |
| sessions                               | context window than the model card advertises unless you        |
|                                        | explicitly set `num_ctx` when pulling or running the model.     |
+-------------------------------------+--------------------------------------------------------------+

Ситуація з контекстним вікном найпідступніша. Ollama спокійно завантажить модель, заявлену зі 128k токенів, а потім мовчки обмежить реальний контекст до 2048 чи 4096, якщо цього не перевизначити. Довга сесія Claude Code тоді деградує до того, що модель забуває початок розмови, і жодної помилки при цьому. Якщо ви робите щось складніше за швидкий разовий запит, задайте значення явно:

ollama run qwen2.5-coder:14b --keepalive 30m
# or, more durably, in a Modelfile:
# PARAMETER num_ctx 32768

Що куди відправляти

Змусити обв'язку працювати — це легкі 20%. Складніше вирішити, яка робота йде якій моделі, і тут допомагає перестати думати бінарно «локально чи платно» й думати про форму задачі:

+----------------------------------+-------------------------------+---------------------------+
| Task type                          | What I route it to             | Why                        |
+----------------------------------+-------------------------------+---------------------------+
| Mechanical edits, renames,          | Local Ollama model              | Free, fast enough, doesn't |
| boilerplate, formatting fixes       | (qwen2.5-coder:14b)             | need real judgment          |
+----------------------------------+-------------------------------+---------------------------+
| Everyday feature work, most         | Mid-tier hosted model           | Good enough reasoning at a  |
| refactors, writing tests            | (gpt-5-mini class)               | fraction of top-tier cost   |
+----------------------------------+-------------------------------+---------------------------+
| Architecture decisions, gnarly      | Whatever your best model is     | This is where model quality |
| bugs, anything security-adjacent    | (Claude Opus, GPT-5, etc.)       | differences actually show    |
+----------------------------------+-------------------------------+---------------------------+

Маршрутизація лише за принципом «дешево чи безкоштовно» призводить до того, що 14B-модель локально просять про те, чого вона надійно робити не вміє, і ви витрачаєте на налагодження її впевнено хибних викликів інструментів більше часу, ніж зекономили на інференсі. Проксі робить маршрутизацію технічно можливою. Рішення за вас він не ухвалює, і в жодному з перевірених інструментів це не стало простіше. Простіше стало лише тоді, коли я перестав чекати, що плагін вирішить усе автоматично, і почав вручну міняти env-файл залежно від того, що збирався спитати.

Попередження про безпеку

Тримайте проксі на localhost. Якщо змінити адресу прив'язки на 0.0.0.0, щоб достукатися з іншої машини, у вашій мережі з'явиться ендпоінт без автентифікації, який може витрачати реальні гроші на налаштований платний бекенд для будь-кого, хто до нього дістанеться. Жоден із випробуваних проксі не вмикає автентифікацію за замовчуванням. Якщо потрібен віддалений доступ, поставте перед ним щось, що справді перевіряє облікові дані. Не відкривайте порт просто так.

Що лишилося в роботі

Переміг найпростіший варіант: claude-code-proxy і два env-файли для перемикання. Один вказує на платну модель для всього, де потрібне справжнє міркування, інший — на локальну Ollama для механічної роботи. Повноцінний роутер з інтерфейсом не знадобився, бо реальне рішення грубе — два кошики, а не п'ять, — і поміняти конфіг простіше, ніж опановувати рушій правил.

Головний урок стосується не лише Claude Code. Агент для програмування й модель за ним розділені сильніше, ніж підказує інтерфейс, і варто один раз пройти проксі-транслятор від початку до кінця, як це розділення перестає здаватися трюком і починає виглядати як архітектура, що лежить в основі більшості таких інструментів. Claude Code — просто той, яким я користуюся щодня, тому його й варто було підключити.

Якщо пробуватимете, почніть із платного бекенда. Набагато простіше зрозуміти, чи зламане налаштування проксі, чи модель просто замала для задачі, коли не налагоджуєш одне й друге одночасно.