Skip to main content
Glama

llm-localfirst

本地优先的 LLM 路由 — 让敏感数据和批量文本处理留在你自己的模型上,只在真正困难时才调用云端。

PyPI Python License: MIT

大多数 LLM 路由器优化的是调用哪家云提供商以降低成本或实现故障转移。llm-localfirst 则反转了这个默认设定:它首先在你的本地模型(Ollama / vLLM / LM Studio)上运行,只有工作确实需要时才会触达云端。它额外提供了主流路由器没有的两项能力:

  1. 🔒 失败即关闭的隐私路由。 你标记为 sensitive=True 的调用会固定到本地模型,绝不允许回退到云端。如果本地模型不可用,该调用会抛出异常——它不会悄悄把你的提示词发送给第三方 API。

  2. 🤝 Manager-worker 委派。 为云端“director”代理提供一个即插即用的工具,把 token 密集、低风险的文本处理(摘要 / 起草 / 翻译 / 重排版 / 提取 / 分类)卸载给快速的本地 worker——从而削减云端开销并把批量数据留在你的硬件上。(提炼自一个生产环境 Pydantic AI 代理。)

此外还有一个模型允许列表保护(拒绝任意模型字符串——这是 SSRF/成本爆炸半径的控制)、可达性探测缓存、一个 MCP server 包装器,以及 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)

Extra

Adds

Needed for

pydantic-settings

router.decide(...) — 纯路由决策,不发起调用

openai

openai

在本地 OpenAI 兼容服务器(或云端 OpenAI)上执行调用

anthropic

anthropic

默认云端回退 / reason 模型(Claude)

mcp

mcp

llm-localfirst mcp(通过 MCP 暴露路由器)

pydantic-ai

pydantic-ai-slim

manager-worker 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)

或者从 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)

路由如何决策

decide() 会探测你的本地模型是否可达(带缓存),然后按顺序应用以下规则:

调用

本地可用

本地不可用

sensitive=True

本地

抛出 LocalUnavailable(失败即关闭)

显式指定 model="<cloud>" + sensitive=True

抛出 PrivacyViolation

kind="reason"

云端

云端

kind="bulk" / "auto"(默认)

本地

云端回退(fell_back=True

显式指定 model="<name>"

该允许列表中的模型(仅敏感调用时阻止云端)

任何显式的 model 必须是允许列表中的名称;任意字符串(或一个游离 URL)会抛出 ModelNotAllowed。该允许列表就是 SSRF / 成本守卫——调用方永远无法让路由器指向一个未配置的新端点或昂贵模型。


Manager-worker 委派(Pydantic AI)

让云端 director 保留规划和工具调用,把繁重的文本工作转交给本地 worker:

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

director 调用 delegate_to_worker 来处理摘要、起草、翻译、重排版和提取;这些任务在你的 GPU 上运行,而不是消耗云端 token。参见 examples/manager_worker.py


原生 MCP

将路由器以三个工具的形式暴露给任何 MCP 客户端(Claude Desktop、IDE、代理)——route(只做决策)、completeusage(本次会话已花费):

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

云端费用上限

隐私保证回答的是这次调用可以离开机器吗?。本地优先设置还必须回答另一个问题:离开机器已经花了多少钱?

每次 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

给它一个上限,它就会停止而不是超支——与隐私固定相同的失败即关闭姿态,现在应用于金钱:

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_tokensmax_cloud_calls 是精确的,完全不需要配置。

  • 它不限制单次调用。 Token 计数只有在提供商响应之后才存在,因此上限是在被突破后阻止下一次云端调用。它把超支限制在一次调用以内;它无法限制某一次调用。

账本保存在内存中,作用域为 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)——本地能力并不是差异点。差异在于失败即关闭的隐私固定manager-worker 委派工具,以及本地优先的默认姿态

能力

llm-localfirst

LiteLLM

OpenRouter

llmrouter-lib

路由到本地模型(Ollama/vLLM)

默认姿态为本地优先

❌(云代理)

敏感调用失败即关闭——绝不回退到云端

Manager-worker 委派工具(云端→本地)

允许列表保护(拒绝任意模型字符串)

多云供应商 / 负载均衡 / 缓存

➖(设计使然)

如果你想要一个拥有数十个提供商的大规模云网关,请使用 LiteLLM。如果你想让私有数据在结构上就留在本地,让批量工作在自有的硬件上运行,那么这个库就是为你准备的。


这不是什么

  • 不是多云网关。 它自带一个本地后端 + Claude(+ 可选的 OpenAI)。更多后端可通过在允许列表上注册来添加;它不会长出上百个提供商 shim。

  • 不是内容分类器。 将调用标记为 sensitive=True(或选择一个 kind)。它不会猜测你的文本是否私密——它只执行你所声明的内容。

  • 不是负载均衡或语义缓存。 那些是网关功能;这是一个带有隐私保证的路由策略

  • 不是成本分析或计费。 费用上限 是进程内的护栏,而不是仪表盘:进程结束时计数归零,并且它报告的是提供商报告的数字。要真实数字,请阅读你的提供商账单。

  • 不是提示词防火墙。 它控制的是调用在哪里运行,而不是调用里包含什么。


配置

所有设置都从环境变量(前缀 LF_)或 .env 文件读取。参见 .env.example。要点如下:

变量

默认值

含义

LF_LOCAL_BASE_URL

http://localhost:11434/v1

本地 OpenAI 兼容端点

LF_LOCAL_MODEL_ID

qwen2.5:7b

本地模型 ID

LF_FALLBACK_MODEL

haiku

非敏感回退使用的云端模型

LF_REASON_MODEL

haiku

kind="reason" 使用的云端模型

LF_SENSITIVE_FAIL_CLOSED

true

确保敏感调用永不泄露

LF_PROBE_TTL

30.0

可达性探测的缓存秒数

LF_PRICES

{}

每百万 token 的 {"haiku": [in, out]} 价格

LF_MAX_CLOUD_CALLS

未设置

每进程云端调用次数的上限

LF_MAX_CLOUD_TOKENS

未设置

每进程云端 token 数的上限

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