llm-localfirst
llm-localfirst
Маршрутизация LLM по принципу local-first: держите чувствительные данные и массовую текстовую работу на собственных моделях, а облако используйте только для действительно сложной части.
Большинство LLM-роутеров оптимизируют выбор облачного провайдера ради стоимости или отказоустойчивости. llm-localfirst меняет поведение по умолчанию: сначала он запускает вашу собственную локальную модель (Ollama / vLLM / LM Studio) и обращается к облаку только тогда, когда работа действительно этого требует. Он добавляет две возможности, которых нет у типовых роутеров:
🔒 Приватная маршрутизация в режиме fail-closed. Вызов, помеченный вами
sensitive=True, закрепляется за локальной моделью и никогда не может переключиться на облако. Если локальная модель недоступна, вызов выбрасывает исключение — он не отправляет ваш промпт стороннему API незаметно.🤝 Делегирование «менеджер–исполнитель». Дайте облачному агенту-«директору» готовый инструмент, который перекладывает затратную по токенам и низкорисковую текстовую работу (резюмирование / черновик / перевод / переформатирование / извлечение / классификация) на быстрого локального исполнителя — сокращая расходы на облако и удерживая массовые данные на вашем оборудовании. (Взято из продакшн-агента на 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)Дополнительно | Добавляет | Нужно для |
(нет) |
|
|
|
| запуск вызовов на локальном OpenAI-совместимом сервере (или облачном OpenAI) |
|
| облачный запасной вариант по умолчанию / модель |
|
|
|
|
| интеграция делегирования «менеджер–исполнитель» через |
Путь принятия решения (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 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)Или из командной строки:
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() проверяет, доступна ли ваша локальная модель (с кэшированием), а затем применяет следующие правила по порядку:
Вызов | Локальная модель доступна | Локальная модель недоступна |
| локальная | выбрасывает |
явный | — | выбрасывает |
| облако | облако |
| локальная | запасной вариант — облако ( |
явный | эта модель из списка разрешённых (облако блокируется только для чувствительных вызовов) |
Любой явный 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. Основные:
Переменная | По умолчанию | Значение |
|
| локальный OpenAI-совместимый эндпоинт |
|
| идентификатор локальной модели |
|
| облачная модель для нечувствительного запасного варианта |
|
| облачная модель для |
|
| не допускать утечки чувствительных вызовов |
|
| сколько секунд кэшировать проверку доступности |
|
|
|
| не задано | потолок облачных вызовов на процесс |
| не задано | потолок облачных токенов на процесс |
| не задано | потолок расходов на облако (нужны |
Разработка
uv venv && uv pip install -e '.[dev]'
ruff check . && pytestЛогика маршрутизации (политика, реестр, роутер, доступность) на 100% покрыта офлайн-тестами — не требуются ни сеть, ни SDK провайдеров. Вклад приветствуется; см. CONTRIBUTING.md.
Лицензия
MIT © Shaxzodbek Qambaraliyev / Blaze. См. 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