Claude Context domyślnie kieruje cię do OpenAI za embeddingi i Zilliz Cloud jako magazyn wektorów. Dla firm z wymaganiami zgodności albo po prostu z awersją do wysyłania kodu na zewnątrz obie decyzje da się cofnąć. Tu opisuję pełną konfigurację offline: Ollama lokalnie, Milvus w Dockerze, żadnych kluczy API.

Wracamy do głównego artykułu: Claude Code: jak przestać palić tokeny.

Dlaczego offline

Kod, który indeksujesz Claude Contextem, idzie do modelu embeddingów. Domyślnie to OpenAI (text-embedding-3-small albo -large), który:

  • Wysyła fragmenty twojego kodu poza sieć firmową
  • Wymaga klucza API, który musi być rotowany
  • Kosztuje (niedużo, ale notuje zużycie)
  • Podlega polityce retencji OpenAI (30 dni logów domyślnie)

W wielu kontraktach (ochrona zdrowia, finanse, obronność, sektor publiczny) to wyklucza takie użycie. Konfiguracja offline rozwiązuje wszystkie cztery problemy naraz.

Architektura stosu offline

graph LR A[Claude Code] -->|MCP| B[claude-context-mcp] B -->|embed request| C[Ollama localhost:11434] B -->|vector write/search| D[Milvus localhost:19530] C -->|nomic-embed-text| E[model file na dysku] D -->|pliki kolekcji| F[Docker volume]

Trzy komponenty, wszystkie lokalne. Ruch sieciowy zerowy (po jednorazowym pobraniu obrazu Dockera i modelu Ollama).

Krok 1: Ollama i model embeddingów

Instalacja

# macOS:
brew install ollama
brew services start ollama

# Linux:
curl -fsSL https://ollama.com/install.sh | sh
systemctl --user enable --now ollama

# Weryfikacja:
curl http://localhost:11434/api/tags
# powinno zwrócić {"models": []}

Wybór modelu

Ollama udostępnia kilka modeli embeddingów. Dla Claude Context polecane:

ModelWymiarRozmiarJakośćKomenda pull
nomic-embed-text768274 MBdobraollama pull nomic-embed-text
mxbai-embed-large1024670 MBbardzo dobraollama pull mxbai-embed-large
bge-m310241,2 GBflagowaollama pull bge-m3

Domyślnie wybieram nomic-embed-text: najlepszy kompromis między jakością a rozmiarem, mieści się w <300 MB. mxbai-embed-large bierzesz, gdy masz dużą bazę kodu (>10k plików) i zależy ci na semantyce.

ollama pull nomic-embed-text

# Weryfikacja że działa:
curl http://localhost:11434/api/embed \
  -d '{"model": "nomic-embed-text", "input": "test embedding"}'
# powinno zwrócić {"embeddings": [[...768 liczb...]]}

Krok 2: Milvus w Dockerze

Milvus to ten sam silnik co w Zilliz Cloud, tylko lokalnie. Najprostsza konfiguracja to tryb standalone przez docker-compose.

Pobranie i uruchomienie

mkdir -p ~/milvus && cd ~/milvus
curl -L https://github.com/milvus-io/milvus/releases/download/v2.4.15/milvus-standalone-docker-compose.yml -o docker-compose.yml
docker compose up -d

Standalone startuje trzy kontenery: milvus-standalone, milvus-etcd, milvus-minio. Razem ~2 GB pamięci w spoczynku, ~500 MB dysku per 100k embeddingów.

Weryfikacja

# Health check:
curl http://localhost:9091/healthz
# powinno zwrócić 200 OK

# Port 19530: główne API gRPC
docker compose ps
# wszystkie trzy powinny być (healthy)

Utrwalenie danych

Domyślny docker-compose.yml zapisuje dane w wolumenie. Jeśli skasujesz kontenery, dane zostają. Jeśli chcesz reset:

docker compose down -v    # -v usuwa też volumes

Krok 3: Claude Context z lokalnym backendem

Instalacja

claude mcp add claude-context \
  -e EMBEDDING_PROVIDER=ollama \
  -e EMBEDDING_MODEL=nomic-embed-text \
  -e OLLAMA_HOST=http://localhost:11434 \
  -e MILVUS_ADDRESS=localhost:19530 \
  -e MILVUS_TOKEN= \
  -e HYBRID_MODE=true \
  -- npx @zilliz/claude-context-mcp@latest

Najważniejsze zmienne:

  • EMBEDDING_PROVIDER=ollama wyłącza domyślne OpenAI
  • EMBEDDING_MODEL=nomic-embed-text musi wskazywać model, który ściągnął ollama pull
  • OLLAMA_HOST to domyślnie http://localhost:11434, ale lepiej ustawić jawnie
  • MILVUS_ADDRESS=localhost:19530 to lokalny port Milvusa
  • MILVUS_TOKEN= zostaje pusty (lokalny Milvus nie wymaga tokena)
  • HYBRID_MODE=true włącza BM25 + wyszukiwanie wektorowe zamiast samego wektorowego

Globalna konfiguracja (alternatywa)

Zmienne można trzymać w ~/.context/.env zamiast w linii komend:

EMBEDDING_PROVIDER=ollama
EMBEDDING_MODEL=nomic-embed-text
OLLAMA_HOST=http://localhost:11434
MILVUS_ADDRESS=localhost:19530
MILVUS_TOKEN=
HYBRID_MODE=true
CUSTOM_IGNORE_PATTERNS=node_modules,dist,build,.planning,archives,.next,target
SPLITTER_TYPE=ast

CUSTOM_IGNORE_PATTERNS jest ważne, bo domyślnie Claude Context indeksuje wszystko. Wyklucz katalogi, które nie mają wartości semantycznej (artefakty builda, cache, archiwa).

Krok 4: pierwsze indeksowanie

W sesji Claude Code:

Zaindeksuj tę bazę kodu używając claude-context.

Claude wywoła index_codebase przez MCP. W zależności od wielkości repo to od kilku minut do pół godziny. Postęp można śledzić:

# W drugim terminalu:
docker compose -f ~/milvus/docker-compose.yml logs -f milvus-standalone | grep -i "inserted"

Dla porównania: 5000 plików TypeScript indeksuje się u mnie ~8 minut na M2, głównie w oczekiwaniu na Ollamę (wąskim gardłem jest embedding, nie Milvus).

Po zakończeniu weryfikacja:

Jaki jest status indeksowania?

Albo bezpośredni test:

Znajdź funkcje, które obsługują uwierzytelnianie użytkownika.

Jeśli semantyka działa, zwróci trafne fragmenty kodu bez czytania plików. To ten moment, kiedy widzisz oszczędność tokenów w akcji.

Rozwiązywanie problemów

DEADLINE_EXCEEDED na gRPC

Najczęściej w trybie Zilliz Cloud Free tier (mamy opcję offline, więc nie dotyczy). Ale jeśli trafisz na to lokalnie, Milvus nie wstał do końca. Sprawdź:

docker compose logs milvus-standalone | tail -50

Typowa przyczyna: kontener jeszcze się inicjalizuje (pierwszy start trwa do 2 minut). Odczekaj.

Osierocone pliki merkle

Drzewa Merkle służą do przyrostowego reindeksowania. Jeśli skasujesz kolekcję w Milvusie ręcznie, zostają puste pliki śledzące. Rozwiązanie:

rm -rf ~/.context/merkle/<nazwa-projektu>/
# w sesji Claude:
# "Zaindeksuj tę bazę kodu od zera"

Przekroczony czas odpowiedzi Ollamy podczas indeksowania

Duże pliki (>100 KB) bywają za ciężkie dla Ollamy w jednym żądaniu. W ~/.context/.env:

SPLITTER_MAX_CHUNK_SIZE=2000
SPLITTER_CHUNK_OVERLAP=200

To wymusza mniejsze fragmenty (2000 znaków z zakładką 200). Ollama radzi sobie z tym od ręki.

Niekompatybilny Node.js

Claude Context wymaga Node.js 20.x lub 22.x. Nie 24.0.0+, bo pakiet @zilliz/claude-context-mcp nie kompiluje się na 24. Jeśli masz nvm:

nvm install 22
nvm use 22
claude mcp add ...   # świeża rejestracja

Benchmark jakości: offline a OpenAI

Claude Context oficjalnie benchmarkował konfigurację z OpenAI. Z Ollamą nomic-embed-text otrzymasz:

  • F1 wyszukiwania niższe o ~5-10% (ale wciąż w użytecznym zakresie)
  • Embeddingi szybsze lokalnie (brak dodatkowego opóźnienia sieciowego)
  • Dłuższy zimny start (pierwszy embedding ~2 s na Apple Silicon, potem ~50-100 ms)

Dla większości zastosowań różnica jakości jest niezauważalna. Jeśli widzisz, że Claude często nie znajduje funkcji, które powinien, przesiądź się na mxbai-embed-large. To wyraźnie lepszy model, kosztem 670 MB dysku.

Monitorowanie i konserwacja

Miejsce na dysku

Lokalny Milvus zapisuje dane w ~/milvus/volumes/ (domyślnie). Dla średniego projektu:

  • 1000 plików ≈ 50 MB
  • 10 000 plików ≈ 500 MB
  • 100 000 plików ≈ 5 GB

Sprawdzenie:

du -sh ~/milvus/volumes/

Czyszczenie starych kolekcji

Każdy projekt ma osobną kolekcję. Jeśli skończyłeś pracę z jakimś repo:

docker exec milvus-standalone attu-cli --help
# lub wejście do Python API:
python -c "from pymilvus import connections, utility; connections.connect('default', host='localhost', port='19530'); print(utility.list_collections())"

Aktualizacje Ollamy i modeli

ollama pull nomic-embed-text    # zaktualizuje jeśli jest nowsza wersja
brew upgrade ollama              # update samej Ollamy

Po aktualizacji modelu trzeba reindeksować, bo stare embeddingi nie są zgodne z nową wersją (inna skala, często inny wymiar).

Kiedy ta konfiguracja się nie opłaca

Offline ma koszt stały:

  • ~2 GB RAM dla Milvusa
  • ~300 MB-1 GB dla Ollamy (zależnie od modelu)
  • Docker Desktop / Docker Engine

Jeśli pracujesz na małym projekcie (<500 plików), hobbystycznie, bez wymagań zgodności, to prostsza konfiguracja z OpenAI + Zilliz Cloud Free tier działa od razu, w 2 minuty, i kosztuje cię ~$0 miesięcznie. Offline to decyzja dla kontekstu firmowego albo mocnego przywiązania do prywatności.


Wracając do głównego artykułu: Claude Code: jak przestać palić tokeny. Dla terminala zamiast bazy kodu: RTK: pełna konfiguracja.