Skip to main content
Glama

llm-localfirst

Маршрутизация LLM по принципу local-first: держите чувствительные данные и массовую текстовую работу на собственных моделях, а облако используйте только для действительно сложной части.

PyPI Python License: MIT

Большинство LLM-роутеров оптимизируют выбор облачного провайдера ради стоимости или отказоустойчивости. llm-localfirst меняет поведение по умолчанию: сначала он запускает вашу собственную локальную модель (Ollama / vLLM / LM Studio) и обращается к облаку только тогда, когда работа действительно этого требует. Он добавляет две возможности, которых нет у типовых роутеров:

  1. 🔒 Приватная маршрутизация в режиме fail-closed. Вызов, помеченный вами sensitive=True, закрепляется за локальной моделью и никогда не может переключиться на облако. Если локальная модель недоступна, вызов выбрасывает исключение — он не отправляет ваш промпт стороннему API незаметно.

  2. 🤝 Делегирование «менеджер–исполнитель». Дайте облачному агенту-«директору» готовый инструмент, который перекладывает затратную по токенам и низкорисковую текстовую работу (резюмирование / черновик / перевод / переформатирование / извлечение / классификация) на быстрого локального исполнителя — сокращая расходы на облако и удерживая массовые данные на вашем оборудовании. (Взято из продакшн-агента на Pydantic AI.)

Плюс защита списком разрешённых моделей (произвольные строки моделей отклоняются — контроль радиуса поражения SSRF и расходов), кэшируемая проверка доступности, обёртка MCP-сервера и CLI.


Гарантия конфиденциальности в пяти строках

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 означает эти данные не должны покидать машину. Роутер скорее завершится ошибкой, чем допустит утечку. Эта асимметрия — чувствительные вызовы закрываются при отказе, обычные массовые вызовы уходят в облако — и есть продукт.


Related MCP server: OpenAI-Compatible MCP Gateway

Установка

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)

Дополнительно

Добавляет

Нужно для

(нет)

pydantic-settings

router.decide(...) — чистая маршрутизация, без вызовов

openai

openai

запуск вызовов на локальном OpenAI-совместимом сервере (или облачном OpenAI)

anthropic

anthropic

облачный запасной вариант по умолчанию / модель reason (Claude)

mcp

mcp

llm-localfirst mcp (доступ к роутеру через MCP)

pydantic-ai

pydantic-ai-slim

интеграция делегирования «менеджер–исполнитель» через attach_worker

Путь принятия решения (decide()) не импортирует SDK провайдеров, поэтому вы можете изучать маршрутизацию — и запускать весь набор тестов — имея установленным только ядро.


Быстрый старт за 60 секунд (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)

Или из командной строки:

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)

Как маршрутизация принимает решение

decide() проверяет, доступна ли ваша локальная модель (с кэшированием), а затем применяет следующие правила по порядку:

Вызов

Локальная модель доступна

Локальная модель недоступна

sensitive=True

локальная

выбрасывает LocalUnavailable (fail-closed)

явный model="<cloud>" + sensitive=True

выбрасывает PrivacyViolation

kind="reason"

облако

облако

kind="bulk" / "auto" (по умолчанию)

локальная

запасной вариант — облако (fell_back=True)

явный model="<name>"

эта модель из списка разрешённых (облако блокируется только для чувствительных вызовов)

Любой явный model должен быть именем из списка разрешённых; произвольная строка (или случайный URL) вызывает исключение ModelNotAllowed. Этот список — защита от SSRF и расходов: вызывающий код никогда не сможет направить роутер на новый эндпоинт или на дорогую модель, с которой роутер не был сконфигурирован.


Делегирование «менеджер–исполнитель» (Pydantic AI)

Позвольте облачному директору заниматься планированием и вызовами инструментов, а черновую текстовую работу отдайте локальному исполнителю:

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

Директор вызывает delegate_to_worker для резюме, черновиков, переводов, переформатирования и извлечения; эти задачи выполняются на вашем GPU, не сжигая облачные токены. См. examples/manager_worker.py.


Нативная поддержка MCP

Предоставьте роутер любому MCP-клиенту (Claude Desktop, IDE, агентам) в виде трёх инструментов — route (пробное решение), complete и usage (сколько потрачено за эту сессию):

pip install "llm-localfirst[mcp]"
llm-localfirst mcp        # serves over stdio

Потолок расходов на облако

Гарантия конфиденциальности отвечает на вопрос может ли этот вызов покинуть машину?. Другой вопрос, на который должна ответить local-first система: сколько уже стоило покидание машины?

Каждое завершение (completion) учитывается автоматически — без настройки и без флагов:

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

Задайте потолок — и он остановится, а не перерасходует: тот же режим fail-closed, что и защита конфиденциальности, но применённый к деньгам:

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

Локальные вызовы никогда не ограничиваются. Их лимитирование лишило бы смысла локальный запуск — потраченный облачный бюджет означает лишь, что облако закрыто, а массовая работа продолжается.

Или по стоимости, для чего нужны цены:

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

Чего эта система намеренно не делает:

  • Она не поставляет таблицу цен. Цены меняются, и устаревшее число, зашитое в код, хуже, чем никакого. Цены задаёте вы — и потолок расходов отказывается запускаться, если хотя бы у одной облачной модели из списка разрешённых нет цены, вместо того чтобы молча оставаться на $0.00 и никогда не срабатывать. max_cloud_tokens и max_cloud_calls точны и вообще не требуют настройки.

  • Она не ограничивает отдельный вызов. Количество токенов существует только после ответа провайдера, поэтому потолок блокирует следующий облачный вызов после того, как лимит превышен. Он ограничивает перерасход одним вызовом; ограничить же один вызов он не может.

Учётная книга хранится в памяти и привязана к экземпляру Router. Это защитное ограждение для процесса, а не биллинг: если вам нужно контролировать расходы между процессами, сохраняйте ledger.snapshot() в своё хранилище.

llm-localfirst complete "..." --usage    # tally on stderr, completion on stdout
llm-localfirst doctor                    # shows the budget and which models are priced

Сравнение с аналогами

llm-localfirstне универсальный шлюз для многих провайдеров и не стремится им быть. Для ясности и объективности: LiteLLM и Bifrost уже умеют маршрутизировать к локальным моделям (Ollama, vLLM) — локальная возможность не является отличительной чертой. Отличия — это принудительная защита конфиденциальности в режиме fail-closed, инструмент делегирования «менеджер–исполнитель» и поведение local-first по умолчанию.

Возможность

llm-localfirst

LiteLLM

OpenRouter

llmrouter-lib

Маршрутизация к локальным моделям (Ollama/vLLM)

По умолчанию — local-first

❌ (облачный прокси)

Чувствительные вызовы закрываются при отказе — никогда не уходят в облако

Инструмент делегирования «менеджер–исполнитель» (облако→локально)

Защита списком разрешённых (отклонение произвольных строк моделей)

Много облачных провайдеров / балансировка нагрузки / кэширование

➖ (намеренно)

Если вам нужен широкий облачный шлюз с десятками провайдеров — используйте LiteLLM. Если вы хотите, чтобы ваши приватные данные по построению оставались локальными, а массовая работа выполнялась на вашем оборудовании, — это эта библиотека.


Чем это НЕ является

  • Не мультиоблачный шлюз. Он поставляется с одним локальным бэкендом + Claude (+ опционально OpenAI). Добавляйте другие, регистрируя их в списке разрешённых; он не обрастёт сотней адаптеров провайдеров.

  • Не классификатор контента. Вы помечаете вызов sensitive=True (или выбираете kind). Он не угадывает, приватный ли ваш текст, — он обеспечивает соблюдение того, что вы декларируете.

  • Не балансировка нагрузки и не семантическое кэширование. Это функции шлюза; здесь же — политика маршрутизации с гарантией конфиденциальности.

  • Не аналитика расходов и не биллинг. Потолок расходов — это защитный механизм внутри процесса, а не дашборд: счётчики сбрасываются при завершении процесса, и он сообщает то, что сообщил провайдер. За реальными цифрами читайте счёт провайдера.

  • Не файрвол для промптов. Он управляет тем, где выполняется вызов, а не тем, что в нём.


Конфигурация

Все настройки читаются из переменных окружения (префикс LF_) или из файла .env. См. .env.example. Основные:

Переменная

По умолчанию

Значение

LF_LOCAL_BASE_URL

http://localhost:11434/v1

локальный OpenAI-совместимый эндпоинт

LF_LOCAL_MODEL_ID

qwen2.5:7b

идентификатор локальной модели

LF_FALLBACK_MODEL

haiku

облачная модель для нечувствительного запасного варианта

LF_REASON_MODEL

haiku

облачная модель для kind="reason"

LF_SENSITIVE_FAIL_CLOSED

true

не допускать утечки чувствительных вызовов

LF_PROBE_TTL

30.0

сколько секунд кэшировать проверку доступности

LF_PRICES

{}

{"haiku": [in, out]} за миллион токенов

LF_MAX_CLOUD_CALLS

не задано

потолок облачных вызовов на процесс

LF_MAX_CLOUD_TOKENS

не задано

потолок облачных токенов на процесс

LF_MAX_CLOUD_COST

не задано

потолок расходов на облако (нужны LF_PRICES)


Разработка

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

Логика маршрутизации (политика, реестр, роутер, доступность) на 100% покрыта офлайн-тестами — не требуются ни сеть, ни SDK провайдеров. Вклад приветствуется; см. CONTRIBUTING.md.

Лицензия

MIT © Shaxzodbek Qambaraliyev / Blaze. См. 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