Claude Code avec Ollama : backends local et cloud

Table des matières

Version originale : English

1. Vue d'ensemble

Claude Code accepte un endpoint compatible avec l'API Anthropic. Ollama est l'un de ces backends.

  1. Ollama local : les modèles tournent sur votre machine (Mac, Linux, etc.).
  2. Ollama Cloud : les modèles hébergés par Ollama, via son API.

1.1. Pourquoi un autre backend

Cas Effet
Confidentialité Les données restent sur le réseau local
Coût Pas de facturation au token pour les modèles locaux
Hors ligne Fonctionne sans Internet
Expérimentation Tester d'autres modèles (Qwen, Llama, etc.)
Limites de débit Éviter le throttling de l'API

2. Architecture

Diagramme Graphviz. Claude Code CLI se connecte à trois backends : l'API Anthropic (par défaut, vert), Ollama local sur le LAN, port 11434 (bleu, modèles qwen3-coder, codellama, nomic-embed), Ollama Cloud sur ollama.com (violet, modèles qwen3:480b, glm-4.7, minimax). Les variables d'environnement choisissent le chemin actif.

Figure 1 : Claude Code et trois chemins : l'API Anthropic (par défaut), Ollama local sur le LAN, Ollama Cloud. Chaque chemin a ses variables d'environnement. Le binaire CLI est le même.

3. Prérequis

3.1. Installer Ollama (usage local)

# macOS
brew install ollama

# Linux
curl -fsSL https://ollama.com/install.sh | sh

# Récupérer un modèle de code
ollama pull qwen3-coder:latest
ollama pull nomic-embed-text:v1.5

3.2. Installer pass pour stocker les clés chiffrées

# macOS
brew install pass gnupg

# Linux (Debian/Ubuntu)
apt install pass gnupg

# Initialiser (clé GPG requise)
pass init "your-gpg-key-id"

3.3. Stocker la clé API Ollama Cloud

La clé API se trouve sur https://ollama.com/settings/keys.

pass insert OLLAMA_API_KEY
# Coller la clé à l'invite

4. Configuration

4.1. Configuration du shell

Créer $HOME/.config/ollama/ollama.sh :

# Configuration Claude Code + Ollama
# À sourcer : source ~/.config/ollama/ollama.sh

# Clé API Ollama Cloud (depuis pass)
export OLLAMA_API_KEY="$(pass OLLAMA_API_KEY 2>/dev/null)"

# Serveur Ollama local (mettre votre hostname/IP)
export OLLAMA_LOCAL_HOST="${OLLAMA_LOCAL_HOST:-localhost}"
export OLLAMA_LOCAL_PORT="${OLLAMA_LOCAL_PORT:-11434}"
export OLLAMA_LOCAL_URL="http://${OLLAMA_LOCAL_HOST}:${OLLAMA_LOCAL_PORT}"

# Répertoire de config isolé (évite le conflit d'auth claude.ai)
export CLAUDE_OLLAMA_CONFIG="${XDG_DATA_HOME:-$HOME/.local/share}/claude-ollama"
[ -d "$CLAUDE_OLLAMA_CONFIG" ] || mkdir -p "$CLAUDE_OLLAMA_CONFIG"

# ============================================================
# Alias de backend
# ============================================================

# Anthropic par défaut (abonnement claude.ai)
alias cc-default='claude'

# Ollama local
alias claude-local='CLAUDE_CONFIG_DIR=$CLAUDE_OLLAMA_CONFIG \
  ANTHROPIC_AUTH_TOKEN=ollama \
  ANTHROPIC_BASE_URL=$OLLAMA_LOCAL_URL claude'

# Ollama Cloud (auth par Bearer token)
alias claude-ollama='CLAUDE_CONFIG_DIR=$CLAUDE_OLLAMA_CONFIG \
  ANTHROPIC_BASE_URL=https://ollama.com \
  ANTHROPIC_AUTH_TOKEN=${OLLAMA_API_KEY} \
  ANTHROPIC_API_KEY="" claude'

# ============================================================
# Raccourcis de modèle
# ============================================================

# Modèles locaux
alias cc-local='claude-local --model qwen3-coder:latest'
alias cc-local-llama='claude-local --model codellama:latest'
alias cc-local-embed='claude-local --model nomic-embed-text:v1.5'

# Modèles cloud
alias cc-cloud='claude-ollama --model glm-4.7:cloud'
alias cc-cloud-fast='claude-ollama --model minimax-m2.1:cloud'
alias cc-cloud-coder='claude-ollama --model qwen3-coder:480b'

# ============================================================
# Fonctions utilitaires
# ============================================================

ollama-init() {
    local config_dir="$CLAUDE_OLLAMA_CONFIG"
    mkdir -p "$config_dir"

    cat > "$config_dir/settings.json" << 'EOF'
{
  "apiKeyHelper": "pass OLLAMA_API_KEY"
}
EOF

    cat > "$config_dir/.claude.json" << 'EOF'
{
  "primaryAccountType": "apiKey",
  "hasCompletedOnboarding": true
}
EOF

    echo "Initialized ollama config at $config_dir"
}

ollama-status() {
    echo "Local Ollama ($OLLAMA_LOCAL_URL):"
    curl -s "$OLLAMA_LOCAL_URL/api/tags" 2>/dev/null \
      | jq -r '.models[].name' 2>/dev/null \
      || echo "  Not reachable"
    echo ""
    echo "Ollama Cloud API Key:"
    if [ -n "$OLLAMA_API_KEY" ]; then
        echo "  Set (${#OLLAMA_API_KEY} chars)"
    else
        echo "  Not set (run: pass insert OLLAMA_API_KEY)"
    fi
}

ollama-host() {
    if [ -n "$1" ]; then
        export OLLAMA_LOCAL_HOST="$1"
        export OLLAMA_LOCAL_URL="http://${OLLAMA_LOCAL_HOST}:${OLLAMA_LOCAL_PORT}"
        echo "Switched to: $OLLAMA_LOCAL_URL"
    else
        echo "Current: $OLLAMA_LOCAL_URL"
        echo "Usage: ollama-host <hostname|ip>"
    fi
}

4.2. Ajouter au RC du shell

# Ajouter à ~/.zshrc ou ~/.bashrc
[ -f "$HOME/.config/ollama/ollama.sh" ] && source "$HOME/.config/ollama/ollama.sh"

4.3. Initialiser la configuration

source ~/.config/ollama/ollama.sh
ollama-init

5. Utilisation

5.1. Référence rapide

Commande Backend Modèle Notes
cc-default claude.ai claude-sonnet Abonnement requis
cc-local localhost qwen3-coder GPU/CPU local
cc-cloud ollama.com glm-4.7 API cloud
cc-cloud-coder ollama.com qwen3-coder:480b Gros modèle de code

5.2. Exemple de session

# Vérifier les backends disponibles
ollama-status

# Ollama local
cc-local
> Help me write a Python function to parse JSON

# Passer au cloud pour un modèle plus gros
cc-cloud-coder
> Refactor this code for better error handling

5.3. Changer d'hôte

# Par défaut : localhost
cc-local

# Une autre machine du LAN
ollama-host mac.local
cc-local

# Par adresse IP
ollama-host 192.168.1.50
cc-local

6. Détails techniques

6.1. Authentification

Ollama attend une authentification par Bearer token :

Authorization: Bearer <token>

Utiliser ANTHROPIC_AUTH_TOKEN (Bearer), pas ANTHROPIC_API_KEY (X-Api-Key).

# Correct (Bearer token)
ANTHROPIC_AUTH_TOKEN=ollama claude

# Faux (en-tête X-Api-Key)
ANTHROPIC_API_KEY=ollama claude

6.2. Isolation de la config

CLAUDE_CONFIG_DIR évite le conflit avec l'authentification claude.ai :

~/.claude.json              # auth claude.ai (ne pas toucher)
~/.local/share/claude-ollama/  # config du backend ollama

6.3. Variables d'environnement

Variable Rôle Exemple
ANTHROPIC_BASE_URL Endpoint de l'API http://localhost:11434
ANTHROPIC_AUTH_TOKEN Bearer token ollama ou clé API
CLAUDE_CONFIG_DIR Répertoire de config ~/.local/share/claude-ollama

7. Lancer le serveur Ollama

7.1. Installation locale

# Démarrer le serveur (localhost seulement)
ollama serve

# Démarrer le serveur (accessible depuis le LAN)
OLLAMA_HOST=0.0.0.0 ollama serve

7.2. En service (macOS)

brew services start ollama

# Pour écouter sur toutes les interfaces, éditer :
# ~/Library/LaunchAgents/homebrew.mxcl.ollama.plist
# Ajouter : <key>OLLAMA_HOST</key><string>0.0.0.0</string>

7.3. En service (Linux systemd)

# Créer l'override
sudo mkdir -p /etc/systemd/system/ollama.service.d
sudo tee /etc/systemd/system/ollama.service.d/override.conf << EOF
[Service]
Environment="OLLAMA_HOST=0.0.0.0"
EOF

sudo systemctl daemon-reload
sudo systemctl restart ollama

8. Tests

8.1. Script de test de connexion

Enregistrer sous test-ollama-backends.sh :

#!/bin/sh
# Tester les connexions de Claude Code aux backends Ollama

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

PASS=0
FAIL=0
SKIP=0

result() {
    local name="$1" status="$2" msg="$3"
    case "$status" in
        pass) echo "${GREEN}PASS${NC}: $name"; PASS=$((PASS + 1)) ;;
        fail) echo "${RED}FAIL${NC}: $name - $msg"; FAIL=$((FAIL + 1)) ;;
        skip) echo "${YELLOW}SKIP${NC}: $name - $msg"; SKIP=$((SKIP + 1)) ;;
    esac
}

echo "Testing Claude Code + Ollama Backends"
echo "======================================"
echo ""

# Prérequis
echo "Prerequisites:"
command -v claude >/dev/null 2>&1 \
    && result "claude installed" pass \
    || result "claude installed" fail "not found"

command -v pass >/dev/null 2>&1 \
    && result "pass installed" pass \
    || result "pass installed" fail "not found"

command -v curl >/dev/null 2>&1 \
    && result "curl installed" pass \
    || result "curl installed" fail "not found"

echo ""

# Ollama local
echo "Local Ollama:"
OLLAMA_URL="${OLLAMA_LOCAL_URL:-http://localhost:11434}"
if curl -s --connect-timeout 5 "$OLLAMA_URL/api/tags" >/dev/null 2>&1; then
    MODELS=$(curl -s "$OLLAMA_URL/api/tags" | jq -r '.models | length' 2>/dev/null)
    result "connection ($OLLAMA_URL)" pass
    result "models available: $MODELS" pass
else
    result "connection ($OLLAMA_URL)" fail "not reachable"
fi

echo ""

# Ollama Cloud
echo "Ollama Cloud:"
API_KEY=$(pass OLLAMA_API_KEY 2>/dev/null || echo "")
if [ -n "$API_KEY" ]; then
    result "API key configured" pass
    RESP=$(curl -s --connect-timeout 10 \
        -H "Authorization: Bearer $API_KEY" \
        "https://ollama.com/api/tags" 2>&1)
    if echo "$RESP" | grep -q "models"; then
        result "connection (ollama.com)" pass
    elif echo "$RESP" | grep -q "unauthorized"; then
        result "connection (ollama.com)" fail "invalid API key"
    else
        result "connection (ollama.com)" skip "could not verify"
    fi
else
    result "API key configured" skip "not set"
fi

echo ""

# Résumé
echo "Summary:"
echo "  Passed: $PASS"
echo "  Failed: $FAIL"
echo "  Skipped: $SKIP"

[ $FAIL -eq 0 ] && exit 0 || exit 1

8.2. Lancer les tests

chmod +x test-ollama-backends.sh
./test-ollama-backends.sh

9. Dépannage

9.1. "Connection refused" vers Ollama local

# Vérifier qu'ollama tourne
pgrep ollama || echo "Not running"

# Vérifier le port d'écoute
netstat -an | grep 11434

# S'il écoute seulement sur 127.0.0.1, relancer avec :
OLLAMA_HOST=0.0.0.0 ollama serve

9.2. "Unauthorized" depuis Ollama Cloud

# Vérifier que la clé API est définie
echo "Key length: ${#OLLAMA_API_KEY}"

# Tester directement
curl -H "Authorization: Bearer $OLLAMA_API_KEY" \
     https://ollama.com/api/tags

9.3. Conflit d'auth avec claude.ai

Les alias isolent la config ollama avec CLAUDE_CONFIG_DIR. Si le conflit persiste :

# Voir la config utilisée (valeurs tronquées : aucune clé ne fuit dans la sortie)
env | grep -i claude | cut -c1-20
env | grep -i anthropic | cut -c1-20

# Vérifier que les alias sont chargés
type cc-local

9.4. Modèle introuvable

# Lister les modèles locaux
curl -s localhost:11434/api/tags | jq -r '.models[].name'

# Récupérer le modèle manquant
ollama pull qwen3-coder:latest

11. Références