Skip to main content
Glama

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.

PyPI Python License: MIT

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:

  1. 🔒 Enrutamiento de privacidad que falla de forma cerrada. Una llamada que marcas sensitive=True se 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.

  2. 🤝 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)

pydantic-settings

router.decide(...) — enrutamiento puro, sin llamadas

openai

openai

ejecutar llamadas en un servidor local compatible con OpenAI (o OpenAI en la nube)

anthropic

anthropic

el respaldo en la nube predeterminado / modelo reason (Claude)

mcp

mcp

llm-localfirst mcp (exponer el enrutador a través de MCP)

pydantic-ai

pydantic-ai-slim

la integración manager-worker attach_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 path
from 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

sensitive=True

local

lanza LocalUnavailable (falla de forma cerrada)

model="<cloud>" explícito + sensitive=True

lanza PrivacyViolation

kind="reason"

nube

nube

kind="bulk" / "auto" (predeterminado)

local

respaldo en la nube (fell_back=True)

model="<nombre>" explícito

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 hook

El 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 stdio

Tope 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 logs

Dale 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 tokens

Las 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.00

Dos 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.00 y nunca dispararse. max_cloud_tokens y max_cloud_calls son 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 priced

Có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. etiquetas una llamada sensitive=True (o eliges un kind). 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

LF_LOCAL_BASE_URL

http://localhost:11434/v1

endpoint local compatible con OpenAI

LF_LOCAL_MODEL_ID

qwen2.5:7b

id del modelo local

LF_FALLBACK_MODEL

haiku

modelo de nube para respaldo no sensible

LF_REASON_MODEL

haiku

modelo de nube para kind="reason"

LF_SENSITIVE_FAIL_CLOSED

true

mantener las llamadas sensibles de filtrarse nunca

LF_PROBE_TTL

30.0

segundos para cachear el sondeo de alcanzabilidad

LF_PRICES

{}

{"haiku": [in, out]} por millón de tokens

LF_MAX_CLOUD_CALLS

sin definir

tope de llamadas a la nube por proceso

LF_MAX_CLOUD_TOKENS

sin definir

tope de tokens de nube por proceso

LF_MAX_CLOUD_COST

sin definir

tope de gasto en la nube (necesita LF_PRICES)


Desarrollo

uv venv && uv pip install -e '.[dev]'
ruff check . && pytest

El 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.

A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
4wRelease cycle
3Releases (12mo)
Commit activity

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

  • A
    license
    Not graded
    quality
    B
    maintenance
    A self-hostable MCP server that routes prompts to multiple LLM providers using declarative policies, with multi-role orchestration for independence and verification.
    MIT

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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