claude-code ai

Claude Context offline — Ollama, lokalny Milvus, zero ruchu na zewnątrz

Konfiguracja Claude Context bez OpenAI i bez Zilliz Cloud. Lokalne embeddingi przez Ollamę, Milvus w Dockerze, pełna prywatność kodu. Krok po kroku.

MO Maciej Olszewski ·

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)

Dla wielu kontraktów (health, finance, defense, public sector) to wyklucza taki przypadek użycia. 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 = zero (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 serwuje kilka modeli embeddingów. Dla Claude Context rekomendowane:

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

Domyślnie wybieram nomic-embed-text — najlepszy kompromis jakości do rozmiaru, trzyma się <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 trzyma dane w volumie. 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

Kluczowe zmienne:

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

Globalny config (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 to ważne — 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 kontekstu: 5000 plików TypeScript indeksuje się u mnie ~8 minut na M2, głównie czeka na Ollamę (embedding jest wąskim gardłem, 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.

Troubleshooting

DEADLINE_EXCEEDED na gRPC

Najczęściej w trybie Zilliz Cloud Free tier (mamy opcję offline, więc nie dotyczy). Ale jeśli trafisz 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.

Orphaned merkle files

Merkle trees służą do inkrementalnego reindexowania. Jeśli skasujesz kolekcję w Milvusie ręcznie, zostają puste pliki śledzące. Fix:

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

Ollama timeout podczas indeksowania

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

SPLITTER_MAX_CHUNK_SIZE=2000
SPLITTER_CHUNK_OVERLAP=200

To wymusza mniejsze chunki (2000 chars z 200 overlappingu). 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+ — 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 vs OpenAI

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

  • Retrieval F1 niższe o ~5-10% (ale wciąż w zakresie użyteczności)
  • Embeddingi szybsze lokalnie (brak dodatkowego opóźnienia sieciowego)
  • Większy 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

Milvus lokalnie trzyma 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 robi osobną kolekcję. Jeśli skończyłeś 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 update modelu trzeba reindex — stare embeddingi nie są kompatybilne 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 — 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.