llm-localfirst
llm-localfirst
Enrutamiento de LLM local-first: mantén los datos sensibles y el trabajo de texto masivo en tus propios modelos, y llama a la nube solo para la parte difícil.
La mayoría de los enrutadores de LLM optimizan qué proveedor de nube llamar por costo o conmutación por error. llm-localfirst invierte el valor predeterminado: se ejecuta primero en tu propio modelo local (Ollama / vLLM / LM Studio) y recurre a la nube solo cuando el trabajo realmente lo necesita. Añade dos cosas que los enrutadores convencionales no tienen:
🔒 Enrutamiento de privacidad que falla de forma cerrada. Una llamada que marcas
sensitive=Truese fija a un modelo local y nunca se le permite recurrir a la nube. Si el modelo local está caído, la llamada lanza una excepción — no envía silenciosamente tu prompt a una API de terceros.🤝 Delegación manager–worker. Dale a un agente "director" en la nube una herramienta integrable que descarga el trabajo de texto de alto consumo de tokens y bajo riesgo (resumir / redactar / traducir / reformatear / extraer / clasificar) a un worker local rápido — reduciendo el gasto en la nube y manteniendo los datos masivos en tu hardware. (Extraído de un agente Pydantic AI de producción.)
Además, una guardia de lista de permitidos de modelos (las cadenas de modelo arbitrarias se rechazan — un control de SSRF/radio de explosión de costos), sondeo de alcanzabilidad con caché, un servidor MCP envolvente y una CLI.
La garantía de privacidad, en cinco líneas
from llm_localfirst import Router, LocalUnavailable
router = Router.from_env()
try:
out = router.complete("Redact all PII from this record.",
source=customer_record, sensitive=True)
except LocalUnavailable:
# Local model is down. We did NOT send the record to the cloud. You decide.
...sensitive=True significa estos datos no deben salir de la caja. El enrutador prefiere fallar antes que filtrar. Esa asimetría — las llamadas sensibles fallan de forma cerrada, las llamadas masivas ordinarias recurren a la nube — es el producto.
Related MCP server: OpenAI-Compatible MCP Gateway
Instalación
pip install llm-localfirst # the routing brain — zero provider SDKs
pip install "llm-localfirst[openai]" # + talk to local Ollama/vLLM/LM Studio (and cloud OpenAI)
pip install "llm-localfirst[anthropic]" # + Claude (the default cloud fallback / reason model)
pip install "llm-localfirst[all]" # everything (also: mcp, pydantic-ai)Extra | Añade | Necesario para |
(ninguno) |
|
|
|
| ejecutar llamadas en un servidor local compatible con OpenAI (o OpenAI en la nube) |
|
| el respaldo en la nube predeterminado / modelo |
|
|
|
|
| la integración manager-worker |
La ruta de decisión (decide()) no importa ningún SDK de proveedor, por lo que puedes inspeccionar el enrutamiento — y ejecutar toda la suite de pruebas — con solo el núcleo instalado.
Inicio rápido en 60 segundos (Ollama)
ollama pull qwen2.5:7b # any OpenAI-compatible local server works
pip install "llm-localfirst[openai,anthropic]"
export ANTHROPIC_API_KEY=sk-ant-... # only needed for the cloud fallback / reason pathfrom llm_localfirst import Router, Kind
router = Router.from_env()
# 1) Inspect routing WITHOUT spending a token.
print(router.decide(kind=Kind.BULK)) # -> local (cheap + private)
print(router.decide(kind="reason")) # -> cloud (the hard part)
print(router.decide(sensitive=True)) # -> local (pinned; never cloud)
# 2) Actually run it. Bulk work prefers local, and falls back to cloud only if local is down.
print(router.complete("Summarize this in one sentence.",
source=long_text, kind=Kind.BULK).text)O desde la shell:
llm-localfirst doctor # show config, the allowlist, and local up/down
llm-localfirst route "summarize this" --kind bulk
llm-localfirst route "redact this" --sensitive # exits non-zero if local is down (fail-closed)Cómo decide el enrutamiento
decide() sondea si tu modelo local es alcanzable (con caché) y luego aplica estas reglas en orden:
Llamada | Local disponible | Local no disponible |
| local | lanza |
| — | lanza |
| nube | nube |
| local | respaldo en la nube ( |
| ese modelo de la lista de permitidos (la nube se bloquea solo cuando es sensible) |
Cualquier model explícito debe ser un nombre en la lista de permitidos; una cadena arbitraria (o una URL suelta) lanza ModelNotAllowed. Esa lista de permitidos es la guardia de SSRF / costo: un llamador nunca puede apuntar el enrutador a un nuevo endpoint o a un modelo costoso con el que no fue configurado.
Delegación manager–worker (Pydantic AI)
Deja que un director en la nube mantenga la planificación y las llamadas a herramientas, y descarga el trabajo de texto pesado a un worker local:
from pydantic_ai import Agent
from llm_localfirst import Router
from llm_localfirst.integrations.pydantic_ai import attach_worker
router = Router.from_env()
director = Agent("anthropic:claude-haiku-4-5", system_prompt="...")
# Adds a `delegate_to_worker(task, source)` tool that routes to your LOCAL model.
# attach_worker REFUSES a non-local worker, so delegated source text can't leak.
attach_worker(director, router, worker_model="local",
on_delegate=lambda task, result: ...) # optional observability hookEl director llama a delegate_to_worker para resúmenes, borradores, traducciones, reformateo y extracción; esos se ejecutan en tu GPU en lugar de quemar tokens de la nube. Ver examples/manager_worker.py.
Nativo de MCP
Expón el enrutador a cualquier cliente MCP (Claude Desktop, IDEs, agentes) como tres herramientas — route (decisión en seco), complete y usage (lo que esta sesión ha gastado):
pip install "llm-localfirst[mcp]"
llm-localfirst mcp # serves over stdioTope de gasto en la nube
La garantía de privacidad responde ¿puede esta llamada salir de la máquina?. La otra pregunta que una configuración local-first debe responder es ¿cuánto ha costado ya salir de la máquina?
Cada finalización se contabiliza automáticamente — sin configuración, sin bandera:
router = Router.from_env()
router.complete("summarise this", source=long_document)
router.ledger.calls("cloud") # 1
router.ledger.tokens("local") # Usage(input_tokens=..., output_tokens=...)
router.ledger.snapshot() # JSON-safe, for logsDale un tope y se detiene en lugar de gastar de más — la misma postura de fallo cerrado que el pin de privacidad, aplicada al dinero:
from llm_localfirst import Budget, Router
router = Router(..., budget=Budget(max_cloud_tokens=200_000))
...
llm_localfirst.BudgetExceeded: cloud token budget spent: 203_400/200_000 tokensLas llamadas locales nunca se limitan. Limitarlas anularía el propósito de ejecutar local — un presupuesto de nube gastado solo significa que la nube está cerrada, y el trabajo masivo sigue fluyendo.
O por costo, que necesita precios:
export LF_PRICES='{"haiku": [0.8, 4.0], "sonnet": [3.0, 15.0], "opus": [15.0, 75.0]}'
export LF_MAX_CLOUD_COST=5.00Dos cosas que esto deliberadamente no hace:
No incluye una tabla de precios. Los precios cambian, y un número fijo obsoleto es peor que ningún número. Tú los proporcionas — y un tope de costo se niega a iniciar si cualquier modelo de nube en la lista de permitidos carece de precio, en lugar de quedarse silenciosamente en
$0.00y nunca dispararse.max_cloud_tokensymax_cloud_callsson exactos y no necesitan configuración alguna.No limita una sola llamada. Los conteos de tokens solo existen una vez que el proveedor ha respondido, por lo que el tope bloquea la siguiente llamada a la nube después de que se supere. Limita el exceso a una llamada; no puede limitar una sola llamada.
El libro mayor vive en memoria, con alcance a un Router. Es una barandilla para un proceso, no facturación — si necesitas gasto aplicado entre procesos, persiste ledger.snapshot() en tu propio almacenamiento.
llm-localfirst complete "..." --usage # tally on stderr, completion on stdout
llm-localfirst doctor # shows the budget and which models are pricedCómo se compara
llm-localfirst no es una pasarela general de múltiples proveedores, y no intenta serlo. Para ser claro y justo: LiteLLM y Bifrost ya pueden enrutar a modelos locales (Ollama, vLLM) — la capacidad local no es el diferenciador. Los diferenciadores son el pin de privacidad de fallo cerrado, la herramienta de delegación manager-worker y una postura predeterminada local-first.
Capacidad | llm-localfirst | LiteLLM | OpenRouter | llmrouter-lib |
Enrutar a modelos locales (Ollama/vLLM) | ✅ | ✅ | ❌ | ➖ |
La postura predeterminada es local-first | ✅ | ❌ (proxy de nube) | ❌ | ➖ |
Las llamadas sensibles fallan de forma cerrada — nunca recurren a la nube | ✅ | ❌ | ❌ | ❌ |
Herramienta de delegación manager-worker (nube→local) | ✅ | ❌ | ❌ | ❌ |
Guardia de lista de permitidos (rechaza cadenas de modelo arbitrarias) | ✅ | ➖ | ➖ | ➖ |
Muchos proveedores de nube / balanceo de carga / caché | ➖ (por diseño) | ✅ | ✅ | ➖ |
Si quieres una pasarela de nube amplia con docenas de proveedores, usa LiteLLM. Si quieres que tus datos privados permanezcan locales por construcción y que tu trabajo masivo se ejecute en tu propio hardware, esa es esta biblioteca.
Lo que esto NO es
No es una pasarela multi-nube. Incluye un backend local + Claude (+ OpenAI opcional). Añade más registrándolos en la lista de permitidos; no crecerá con cien adaptadores de proveedores.
No es un clasificador de contenido. Tú etiquetas una llamada
sensitive=True(o eliges unkind). No adivina si tu texto es privado — hace cumplir lo que declaras.No es balanceo de carga ni caché semántica. Esas son características de pasarela; esto es una política de enrutamiento con una garantía de privacidad.
No es análisis de costos ni facturación. El tope de gasto es una barandilla en proceso, no un panel: los conteos se reinician cuando el proceso lo hace, y reporta lo que el proveedor reportó. Para números reales, lee la factura de tu proveedor.
No es un firewall de prompts. Controla dónde se ejecuta una llamada, no qué contiene.
Configuración
Todas las configuraciones se leen del entorno (prefijo LF_) o de un archivo .env. Ver .env.example. Destacados:
Variable | Predeterminado | Significado |
|
| endpoint local compatible con OpenAI |
|
| id del modelo local |
|
| modelo de nube para respaldo no sensible |
|
| modelo de nube para |
|
| mantener las llamadas sensibles de filtrarse nunca |
|
| segundos para cachear el sondeo de alcanzabilidad |
|
|
|
| sin definir | tope de llamadas a la nube por proceso |
| sin definir | tope de tokens de nube por proceso |
| sin definir | tope de gasto en la nube (necesita |
Desarrollo
uv venv && uv pip install -e '.[dev]'
ruff check . && pytestEl cerebro de enrutamiento (política, registro, enrutador, alcanzabilidad) está cubierto 100% sin conexión — sin red y sin SDKs de proveedor. Las contribuciones son bienvenidas; ver CONTRIBUTING.md.
Licencia
MIT © Shaxzodbek Qambaraliyev / Blaze. Ver LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseCqualityDmaintenanceAn MCP server that routes LLM requests across multiple providers and orchestrates other MCP servers, with a focus on local privacy for embeddings and memory.283
- FlicenseNot gradedqualityDmaintenanceLocal MCP server that exposes fixed tools for GPT, Claude, and Gemini while routing to any OpenAI-compatible chat completions backend with independent configuration per target.1
- AlicenseNot gradedqualityBmaintenanceA self-hostable MCP server that routes prompts to multiple LLM providers using declarative policies, with multi-role orchestration for independence and verification.MIT
- AlicenseNot gradedqualityCmaintenancePrivacy-first local MCP hub for coordinating multiple AI providers from Claude Code, supporting local Ollama seats and cloud providers with safety routing.MIT
Related MCP Connectors
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/shaxzodbek-uzb/llm-localfirst'
If you have feedback or need assistance with the MCP directory API, please join our Discord server