# 🔌 Providers — Multi-proveedor en klaude-proxy
## 🤔 ¿Qué hago? ¿Cómo lo hago? ¿Y para qué lo hago?
**Qué hago:** klaude-proxy soporta múltiples proveedores de LLM — Anthropic API y Ollama (modelos locales). El enrutamiento es transparente para el cliente: Klaus Code CLI (u cualquier cliente compatible con la Anthropic Messages API) simplemente especifica el modelo que quiere usar y el proxy lo dirige al backend correcto.
**Cómo lo hago:** El campo `model` del request determina el proveedor. Si el modelo contiene `:` (convención de Ollama para tags), va a Ollama vía su endpoint OpenAI-compatible. Si es `claude-*` o está vacío, va a Anthropic. El adaptador de Ollama traduce el formato Anthropic ↔ OpenAI de forma transparente, por lo que el cliente siempre recibe respuestas en formato Anthropic.
**Para qué lo hago:** Permite usar modelos locales especializados (`kdev:latest`, `kitil:latest`) sin coste por token, manteniendo la misma interfaz que Anthropic. La caché semántica funciona igual para ambos proveedores.
---
## 🗺️ Regla de routing
| Campo `model` en el request | Provider | Modelo resuelto |
| --- | --- | --- |
| Vacío / `null` | Anthropic | `claude-haiku-4-5-20251001` |
| `claude-haiku-4-5-20251001` | Anthropic | tal cual |
| `claude-opus-4-8` | Anthropic | tal cual |
| `kdev:latest` | Ollama | tal cual |
| `kitil:latest` | Ollama | tal cual |
| Cualquier string con `:` | Ollama | tal cual |
La regla es simple: **si el modelo lleva `:` es Ollama; todo lo demás es Anthropic**.
---
## 🔄 Flujo de una petición
```mermaid
flowchart TD
C([Cliente\nKlaus Code CLI]) -->|POST /v1/messages| P[klaude-proxy]
P --> R{router.py\nresolve_provider}
R -->|model vacío| D[default_model\nclaude-haiku-4-5]
R -->|model claude-*| A[Anthropic]
R -->|model contiene :| O[Ollama]
P --> CACHE{Caché\nQdrant}
CACHE -->|HIT| RESP([Respuesta cacheada])
CACHE -->|MISS| R
A -->|Anthropic format| P
O -->|OpenAI format → traducción → Anthropic format| P
P -->|Anthropic format| C
P -->|Store si es end_turn| CACHE
```
---
## ⚙️ Configuración
### Variables de entorno
| Variable | Default | Descripción |
| --- | --- | --- |
| `ANTHROPIC_API_KEY` | `""` | API key de Anthropic. Opcional si solo usas Ollama. |
| `OLLAMA_BASE_URL` | `http://localhost:11434` | URL base de Ollama (sin `/v1`). |
| `OLLAMA_TIMEOUT_SECONDS` | `120` | Timeout en segundos para llamadas a Ollama. |
| `DEFAULT_MODEL` | `claude-haiku-4-5-20251001` | Modelo usado cuando el cliente no especifica ninguno. |
### `.env` mínimo para Ollama-only
```env
# No hace falta ANTHROPIC_API_KEY
OLLAMA_BASE_URL=http://192.168.1.50:11434
DEFAULT_MODEL=kdev:latest
```
### `.env` mínimo para Anthropic-only (configuración previa)
```env
ANTHROPIC_API_KEY=sk-ant-...
```
### `.env` para uso mixto
```env
ANTHROPIC_API_KEY=sk-ant-...
OLLAMA_BASE_URL=http://localhost:11434
DEFAULT_MODEL=claude-haiku-4-5-20251001
```
---
## 🤖 Modelos Ollama conocidos
| Modelo | Propósito |
| --- | --- |
| `kdev:latest` | Desarrollo — código, refactoring, revisión |
| `kitil:latest` | ITIL / operaciones — gestión de incidentes, cambios |
Cualquier modelo disponible en tu instancia Ollama es válido: el proxy no valida la lista en tiempo de arranque. Si el modelo no existe, Ollama devolverá error 404 que el proxy propagará al cliente.
---
## 🔌 Adaptador Ollama (`proxy/ollama_client.py`)
El adaptador usa el endpoint OpenAI-compatible de Ollama (`/v1/chat/completions`), disponible desde Ollama ≥ 0.1.24.
### Traducción request (Anthropic → OpenAI)
```
Anthropic: OpenAI (Ollama):
{ {
"model": "kdev:latest", "model": "kdev:latest",
"system": "Eres un experto", → "messages": [
"messages": [ {"role": "system", "content": "Eres un experto"},
{"role": "user", {"role": "user", "content": "¿Qué hace este código?"}
"content": "¿Qué hace..."} ],
], "max_tokens": 4096
"max_tokens": 4096 }
}
```
### Traducción response (OpenAI → Anthropic)
```
OpenAI (Ollama): Anthropic:
{ {
"choices": [{ "type": "message",
"message": { "role": "assistant",
"role": "assistant", → "content": [{"type": "text", "text": "..."}],
"content": "La función hace..." "stop_reason": "end_turn",
}, "usage": {
"finish_reason": "stop" "input_tokens": 150,
}], "output_tokens": 80
"usage": { }
"prompt_tokens": 150, }
"completion_tokens": 80
}
}
```
---
## 🔍 Identificar el provider en los logs
El dashboard y los logs de contenedor muestran `provider=` en cada petición:
```
CACHE MISS hash=a1b2c3d4 stream=True model=kdev:latest provider=ollama
FORWARD hash=a1b2c3d4 model=kdev:latest provider=ollama text=...
RESPONSE hash=a1b2c3d4 in=150 out=80 model=kdev:latest source=ollama
```
El header de respuesta HTTP incluye `X-Provider: ollama` o `X-Provider: anthropic`.
---
## 🔗 Documentos relacionados
- [proxy.md](proxy.md) — endpoints y configuración general
- [cache.md](cache.md) — estrategia de caché semántica (válida para todos los providers)
- [analytics.md](analytics.md) — tracking de costes (el campo `source` refleja el provider)