llmfit 深度拆解:Rust 写就的本地大模型选型神器——一行命令把"显存够不够跑"从玄学变成算术
选题来源:GitHub Trending 2026-08-17 | AlexsJones/llmfit 32k Stars**
前言:选模型这件事,为什么让人头疼
如果你曾经在本地跑大模型,一定经历过这个困境:
打开 Hugging Face,搜索 "Qwen 3.5",看到 9B、14B、32B、72B 四个版本;再看 "Gemma 4",有 2B、7B、12B 三个变体;接着是 Llama 4、DeepSeek、Mistral……每个模型都标注了参数规模,但没有一个地方告诉你:在你的这台机器上,到底能跑哪个、能跑多快、哪个体验最好。
于是你开始猜:8GB 显存跑 7B 应该没问题吧?跑不起来就量化,Q4 不行就 Q2……结果跑起来慢得像 PPT,或者直接 OOM(显存溢出)。反复折腾两三个小时,最后还是回到 API 调用,省心但费钱。
llmfit 就是来解决这个问题的。 它是一个 Rust 编写的终端工具,核心功能只有一个:告诉你当前硬件能跑什么模型,以及哪个模型最适合你。 一行命令,自动检测 CPU、内存、GPU 显存,结合模型元数据库,输出一个带 Fit 评分的推荐列表——Perfect、Good、Marginal、Too Tight,四档清晰。
第一章:为什么是 Rust——从 TUI 性能到跨平台硬件检测
1.1 为什么选 Rust 而不是 Go 或 Python
llmfit 的核心代码全部用 Rust 写就,这是一个值得玩味的技术决策。
做一个本地硬件检测 + 模型推荐系统,Go 和 Python 都能完成,生态库也足够丰富。那 Rust 的优势在哪?
第一,硬件检测必须快。 sysinfo 是 Rust 生态里最成熟的系统信息库,能在毫秒级拿到 CPU 核心数、内存总量、GPU 型号和显存大小。Python 的 psutil 也能做到,但启动 Python 解释器本身就要几十毫秒,在 TUI 交互场景里这个延迟是明显可感知的。Rust 编译成单个可执行文件,冷启动时间 < 5ms,硬件检测本身 < 50ms,用户感知到的是"秒响应"。
第二,TUI 渲染的性能瓶颈不在 UI 层,在数据层。 llmfit 用 ratatui(Rust 生态的 ncurses 替代品)渲染表格,模型数据库里有 113 个模型 × 多个量化版本 × 多个运行时,渲染时需要对每一行计算 Fit 评分、显存占用、速度估算。如果这部分逻辑用 Python 写,GIL 会导致多核无法利用;用 Go 写,GC 暂停在交互式 TUI 里偶发卡顿。Rust 没有 GC,内存分配是显式且零开销的,数据处理完全并行化。
第三,发行版打包简洁。 cargo build --release 产出单个静态链接二进制,sysinfo + ureq + serde 几个依赖全在标准库生态内,不需要用户装运行时。Homebrew、Scoop、Docker 三行安装命令,用户拿到的是一个 10MB 左右的可执行文件,开箱即用。
1.2 硬件检测:sysinfo + GPU 探测的工程细节
打开 llmfit 的源码,src/hardware.rs 是整个工具的感知层。这段代码的核心任务是:拿到这台机器真实的硬件能力,而不是用户"以为"的能力。
// src/hardware.rs 核心结构(重构自源码逻辑)
use sysinfo::{System, Disks, CpuRefreshKind, MemoryRefreshKind};
pub struct HardwareProfile {
pub cpu_cores: usize,
pub total_ram_bytes: u64,
pub gpu_profiles: Vec<GPUProfile>,
pub has_nvidia: bool,
pub has_amd: bool,
pub has_metal: bool, // Apple Silicon
}
pub struct GPUProfile {
pub name: String,
pub vram_bytes: u64,
pub vendor: GPUVendor,
}
#[derive(Clone, Copy)]
pub enum GPUVendor {
Nvidia,
AMD,
AppleMetal,
Unknown,
}
检测流程分三层:
CPU + 内存层:通过 sysinfo 的 System::new_all() 一次性获取。cpu_cores 取物理核心数(cpus_online()),total_ram 是 get_total_memory()。这里有个坑:Windows 上 sysinfo 拿到的是系统总内存,而 Llama.cpp/Ollama 等运行时能访问的显存受 CUDA 可寻址内存限制,两者不完全等价,所以需要单独处理 GPU 层。
GPU 层:sysinfo 本身不直接暴露 GPU 信息,所以需要平台特异代码:
#[cfg(target_os = "macos")]
fn detect_gpus() -> Vec<GPUProfile> {
// macOS:通过系统调用读取 Metal 设备信息
use std::process::Command;
let output = Command::new("system_profiler")
.args(["SPDisplaysDataType", "-json"])
.output()
.ok()?;
// 解析 JSON,提取 VRAM
// Apple Silicon 的统一内存就是系统内存
let total_mem = System::new_all().get_total_memory();
vec![GPUProfile {
name: "Apple Silicon".into(),
vram_bytes: total_mem, // 统一内存共享
vendor: GPUVendor::AppleMetal,
}]
}
#[cfg(target_os = "linux")]
fn detect_gpus() -> Vec<GPUProfile> {
// Linux:尝试读取 nvidia-smi 输出
let output = Command::new("nvidia-smi")
.args(["--query-gpu=name,memory.total", "--format=csv,noheader"])
.output()
.ok()?;
// 解析 "RTX 4090, 24576 MB"
// 同时检测 AMD GPU(通过 /sys/class/drm/)
}
#[cfg(target_os = "windows")]
fn detect_gpus() -> Vec<GPUProfile> {
// Windows:通过 Windows API (DXGI) 或 nvidia-smi
}
这段代码的巧妙之处在于渐进降级:如果 nvidia-smi 不存在,就认为没有 NVIDIA GPU;如果 Apple Silicon 上 system_profiler 拿不到 VRAM,就回退到总系统内存。最坏情况也能给出一个"保守估计"。
用户手动覆盖机制:llmfit 支持 --memory=24G 参数,允许用户强制指定显存大小。这个参数在 Docker 容器内尤其有用——容器 cgroup 限制的显存和宿主机独立显卡的显存是两回事,必须能覆盖。
// 命令行参数处理
pub struct CliArgs {
#[arg(long, help = "Override total RAM/VRAM in bytes, e.g. 24G")]
memory: Option<String>,
#[arg(long, help = "Max context length for estimation")]
max_context: Option<usize>,
// ...
}
// 解析 "24G" -> 24 * 1024 * 1024 * 1024
fn parse_memory(s: &str) -> u64 {
let s = s.trim();
let multiplier = match s.ends_with('G') {
true => 1_073_741_824u64,
false => 1_048_576u64,
};
let num: u64 = s[..s.len()-1].parse().unwrap();
num * multiplier
}
第二章:模型数据库——113 个模型的量化与显存数学
2.1 模型元数据 schema
llmfit 维护了一个本地模型数据库 data/hf_models.json,里面记录了每个模型的:
{
"name": "Qwen/Qwen2.5-14B-Instruct",
"display_name": "Qwen 2.5 14B Instruct",
"family": "Qwen",
"params_billions": 14.0,
"architecture": "dense", // 或 "moe"
"moe_total_params": null, // MoE 专用:总参数量
"moe_active_params": null, // MoE 专用:激活参数量
"recommended_quantizations": [
"Q4_K_M", "Q5_K_M", "Q8_0", "F16"
],
"context_window": 32768,
"use_cases": ["coding", "general", "math"],
"quality_score": 82, // 0-100 主观质量评分
"provider_hints": ["ollama", "llama.cpp", "lm-studio"]
}
这个数据库是"精选"而非"穷举"——llmfit 团队手动维护,只收录有明确参数规模、经过社区验证的模型。这和 Hugging Face 的海量模型不同:llmfit 的推荐必须建立在精确的显存计算上,如果不知道一个模型的精确参数规模和推荐量化,就无法给出 Fit 评分。
2.2 显存占用的精确计算
这是 llmfit 最重要的工程核心:把"能跑哪个模型"从经验判断变成算术题。
稠密模型(Dense Model)显存计算公式:
显存占用 (bytes) = 参数规模 × 量化字节数 + 上下文开销 + KV Cache
其中量化字节数是关键:
| 量化格式 | 每参数字节数 | 适用场景 |
|---|---|---|
| F16 (BF16) | 2 bytes | 精度基准 |
| Q8_0 | 1 byte | 高质量量化,接近 F16 |
| Q5_K_M | ~0.7 bytes | 中等质量,推荐首选 |
| Q4_K_M | ~0.56 bytes | 性价比最优 |
| Q3_K_M | ~0.44 bytes | 低显存设备 |
| Q2_K | ~0.28 bytes | 极致压缩 |
Q4_K_M 是目前最主流的量化格式,因为它在 F16 精度和显存占用之间取得了最好平衡。llmfit 对每个模型默认展示 Q4_K_M 的 Fit 评分,同时允许用户切换到其他量化版本看评分变化。
上下文开销:处理长上下文时,KV Cache 的显存占用随上下文长度线性增长:
KV Cache (bytes) = 2 × num_layers × hidden_size × batch_size × seq_len × bytes_per_param
对于 14B Q4_K_M 模型,单层 KV Cache 约 80MB。处理 8192 token 上下文时,KV Cache 本身就要占用 ~1.5GB 显存——这往往是用户忽略的部分,也是"明明模型能加载,跑起来却 OOM"的根本原因。
MoE 模型特殊处理:Mixtral、Qwen2.5-MoE 等 MoE(Mixture of Experts)架构的总参数量很大(如 Qwen2.5-72B-MoE 总参 720 亿),但每次推理只激活一小部分专家(如 8/57)。llmfit 的 moe_total_params 和 moe_active_params 字段专门处理这种情况:
fn calculate_vram_estimate(model: &ModelMeta, quantization: &str) -> u64 {
let active_params = model.moe_active_params
.unwrap_or(model.params_billions * 1_000_000_000.0);
let bytes_per_param = match quantization {
"Q4_K_M" if model.architecture == "moe" => 0.56, // MoE 用更多 KV Cache
"Q4_K_M" => 0.56,
"Q5_K_M" => 0.70,
"Q8_0" => 1.0,
"F16" => 2.0,
_ => 0.56,
};
// MoE: 权重只算激活参数,KV Cache 算总参数
let weight_bytes = active_params * bytes_per_param;
let kv_cache_overhead = model.params_billions * 1_000_000_000.0
* model.context_window as f64
* 0.000_001; // 经验系数
(weight_bytes + kv_cache_overhead) as u64
}
2.3 Fit 评分:四档背后的决策逻辑
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum FitRating {
Perfect, // 显存占用 < 70% 可用内存,留足上下文和 KV Cache 空间
Good, // 显存占用 70-85%,能跑但体验受限
Marginal, // 显存占用 85-95%,勉强能跑,可能卡顿或上下文受限
TooTight, // 显存占用 > 95%,大概率 OOM,不推荐
}
pub fn compute_fit(
model_vram: u64,
available_vram: u64,
context_window: usize,
max_context: Option<usize>,
) -> FitRating {
let effective_context = max_context.unwrap_or(context_window) as f64;
let context_ratio = effective_context / context_window as f64;
// 上下文越长,KV Cache 预留越多,可用显存折扣越大
let headroom = 1.0 - (context_ratio * 0.3); // 0.7 ~ 1.0
let usable_vram = (available_vram as f64 * headroom) as u64;
let ratio = model_vram as f64 / usable_vram as f64;
match ratio {
r if r <= 0.70 => FitRating::Perfect,
r if r <= 0.85 => FitRating::Good,
r if r <= 0.95 => FitRating::Marginal,
_ => FitRating::TooTight,
}
}
为什么用 70% 而非 100% 作为 Perfect 的边界? 因为运行时除了模型权重,还需要显存:
- KV Cache(随上下文长度动态增长)
- 激活值(forward pass 时的临时张量)
- CUDA context 和库开销(~500MB-1GB)
留 30% 余量是工程经验值,确保"能加载"和"能跑"是两件都被满足的事。
第三章:多运行时支持——Ollama、llama.cpp、LM Studio 的统一抽象
3.1 为什么需要多运行时集成
llmfit 的推荐必须针对具体运行时,因为不同运行时对显存的管理策略完全不同:
Ollama:运行时完全托管,按需加载,按需卸载。Ollama 0.5+ 支持分页内存(paged memory),相同模型在 Ollama 上往往比 llama.cpp 省 10-20% 显存。llmfit 对 Ollama 有专门折扣系数。
llama.cpp server:直接加载模型到 GPU,不做分页内存管理。显存估算最准确,但容易 OOM。
LM Studio:提供动态量化(Dynamic Quantization),可以在加载后调整量化精度。llmfit 对 LM Studio 的估算更保守,因为它的加载策略最不可预测。
MLX(Apple Silicon):MLX 使用统一内存,无需单独计算 GPU 显存,模型加载量 = 量化后模型大小,估算最简单。
3.2 运行时检测逻辑
pub fn detect_available_providers() -> Vec<RuntimeProvider> {
let mut providers = Vec::new();
// Ollama:检查 11434 端口是否响应
if std::process::Command::new("curl")
.args(["-s", "-o", "/dev/null", "-w", "%{http_code}",
"http://localhost:11434/api/tags"])
.output()
.map(|o| o.stdout)
.and_then(|s| String::from_utf8(s).ok())
.map(|s| s.trim() == "200")
.unwrap_or(false)
{
providers.push(RuntimeProvider::Ollama);
}
// llama.cpp:检查 llama-cli 或 llama-server 是否在 PATH
if which("llama-cli").is_ok() || which("llama-server").is_ok() {
providers.push(RuntimeProvider::LlamaCpp);
}
// LM Studio:检查 1234 端口
// MLX:检查是否 macOS + 是否有 mlx 命令
// Docker Model Runner:检查 docker 命令可用性
providers
}
检测到哪些运行时可用,就只在这些运行时上给 Fit 评分。如果 Ollama 没启动,llmfit 就不会推荐"需要 Ollama"才有的模型配置。
第四章:TUI 设计——ratatui 的实战艺术
4.1 三种交互模式的架构
llmfit 提供了三种使用模式,对应三个不同的代码路径:
TUI 交互模式(默认):通过 ratatui 渲染全屏终端界面,用户用键盘导航、搜索、过滤、对比。这是最核心的用户体验。
CLI 批处理模式:llmfit --cli,输出表格或 JSON,适合脚本集成和 CI/CD 流水线。
REST API 服务模式:llmfit serve,启动本地 HTTP 服务,支持 curl 调用和第三方 UI 对接。
fn main() {
let args = Cli::parse();
match (args.tui, args.serve, args.cli) {
(true, false, false) => run_tui(args),
(false, true, false) => run_server(args),
(false, false, true) | (false, false, false) => run_cli(args),
_ => eprintln!("Cannot combine --tui, --serve, --cli"),
}
}
4.2 搜索和过滤的交互设计
TUI 里的核心交互:
/或f:进入过滤模式,输入关键词(模型名、参数规模、量化格式、使用场景)a:按使用场景过滤(coding / general / math / creative)s:切换排序(评分 / 速度 / 上下文长度 / 显存占用)j/k:上下移动选择Enter:查看模型详情(显示所有量化版本的 Fit 评分、速度估算)m或c:多选对比模式,Visual 或 Select 模式勾选多个模型p:Plan 模式,估算给定配置需要的硬件
搜索算法:过滤不是简单的字符串包含匹配,而是加权评分搜索:
fn score_match(model: &ModelMeta, query: &str) -> f64 {
let query_lower = query.to_lowercase();
// 模型名精确匹配权重最高
let name_score = if model.name.to_lowercase().contains(&query_lower) {
1.0
} else if model.family.to_lowercase().contains(&query_lower) {
0.6
} else {
return 0.0;
};
// 参数规模匹配(如 "8b" 精确匹配 8B 模型)
let params_score = if let Some(params) = extract_billion_params(&query_lower) {
(model.params_billions - params).abs() / model.params_billions
} else {
0.5
};
name_score * 0.7 + params_score * 0.3
}
第五章:速度估算——不只是"能跑",还要"跑得快不快"
5.1 Token/s 估算模型
"能跑"和"跑得快"是两件事。llmfit 在 Fit 评分之外,还给出了速度估算(tokens/s),让用户不只知道"能不能",还知道"等不等得住"。
速度估算依赖一个经验模型:
tokens/s = f(CPU性能, GPU算力, 显存带宽, 模型参数规模, 量化精度)
pub fn estimate_throughput(
profile: &HardwareProfile,
model: &ModelMeta,
quantization: &str,
) -> f64 {
// 基础吞吐量(假设 F16 全速运行)
let base_tflops = match profile.primary_gpu() {
Some(gpu) => gpu.compute_tflops(), // 从 GPU 型号查表
None => 0.0,
};
// 量化折扣:Q4_K_M 比 F16 快约 2.5-3 倍(因为显存带宽需求更低)
let quant_discount = match quantization {
"F16" => 1.0,
"Q8_0" => 1.4,
"Q5_K_M" => 1.8,
"Q4_K_M" => 2.5,
"Q3_K_M" => 3.2,
_ => 2.5,
};
// 参数规模折扣:参数越多,显存带宽瓶颈越严重
let scale_discount = (model.params_billions / 7.0).sqrt();
// CPU 回退折扣(无 GPU 时)
let runtime_discount = if profile.has_nvidia || profile.has_amd || profile.has_metal {
1.0
} else {
// CPU 推理极慢,给出真实估算
let cpu_tflops = profile.cpu_single_core_tflops();
cpu_tflops / base_tflops.max(1.0) * 0.1 // CPU 通常比 GPU 慢 10 倍
};
base_tflops * quant_discount / scale_discount * runtime_discount
}
5.2 实测数据对照
根据 llmfit 社区反馈,估算模型在常见配置下的准确度:
| 配置 | 实测 Token/s | 估算 Token/s | 误差 |
|---|---|---|---|
| RTX 4090 + Qwen2.5-7B Q4_K_M | ~45-60 t/s | ~52 t/s | <15% |
| Mac M3 Pro 36GB + Llama3-8B Q4_K_M | ~30-40 t/s | ~35 t/s | <15% |
| RTX 3060 12GB + Mistral-7B Q4_K_M | ~20-28 t/s | ~24 t/s | <20% |
| 无 GPU + AMD 5950X + Qwen2.5-7B Q4_K_M | ~3-6 t/s | ~4 t/s | <25% |
估算在有 GPU 的场景最准确,CPU 回退场景误差较大(因为 CPU 推理速度还取决于内存带宽和 SIMD 指令集支持)。
第六章:代码实战——从安装到推荐
6.1 安装(5 分钟上手)
# macOS / Linux
brew install llmfit
# 或一键脚本(无需 Homebrew)
curl -fsSL https://llmfit.axjns.dev/install.sh | sh
# Windows
scoop install llmfit
# Docker(无需本地安装)
docker run ghcr.io/alexsjones/llmfit
# 源码编译(需要 Rust 1.75+)
git clone https://github.com/AlexsJones/llmfit.git
cd llmfit
cargo build --release
./target/release/llmfit
6.2 TUI 交互演示
# 启动 TUI(默认)
llmfit
# 搜索 "qwen" 相关模型
/ → 输入 qwen → Enter
# 只看 coding 场景的推荐
f → 输入 coding → Enter
# 查看 Fit = Perfect 的所有模型
# 在 TUI 中按 a 选择 use_case → coding
# 然后按 s 排序 → fit
# 对比多个模型(Visual 模式)
v → 用 j/k 选中多个 → m 进入多选对比
# 估算给定配置需要的硬件(Plan 模式)
p → 选择 Qwen2.5-72B-Instruct Q4_K_M 32768 context
# 输出:
# Recommended VRAM: 48GB
# Run path: GPU only (MLX not available on x86)
# Compatible runtimes: Ollama, llama.cpp
6.3 CLI 模式(适合脚本集成)
# 查系统硬件信息
llmfit system
# Output:
# CPU: Apple M3 Pro (11 cores)
# RAM: 36 GB
# GPUs: Apple M3 Pro GPU (36 GB unified)
# Runtimes: Ollama detected
# 搜索特定模型
llmfit search "gemma 12b"
# Output:
# NAME PARAMS QUANT FIT SPEED CONTEXT
# Gemma 4 12B 12.0B Q4_K_M Perfect ~32 t/s 32k
# Gemma 3 12B 12.0B Q4_K_M Good ~28 t/s 128k
# Gemma 2 9B 9.0B Q4_K_M Perfect ~38 t/s 8k
# 获取推荐(JSON 格式,适合程序调用)
llmfit recommend --json --use-case coding --limit 5
# 获取完美 Fit 的模型
llmfit fit --perfect -n 10
# 指定显存大小(Docker 容器场景)
llmfit --memory=16G recommend --json
# 限制上下文长度
llmfit --max-context 4096 fit --perfect
6.4 REST API 模式(服务化)
# 启动 API 服务
llmfit serve --host 0.0.0.0 --port 8787
# 健康检查
curl http://localhost:8787/health
# {"status":"ok","version":"0.9.4"}
# 获取系统信息
curl http://localhost:8787/api/v1/system
# 获取推荐模型
curl "http://localhost:8787/api/v1/models/top?limit=5&min_fit=good&use_case=coding"
# 获取特定模型详情
curl "http://localhost:8787/api/v1/models/Qwen2.5-14B-Instruct"
6.5 自定义模型扩展
llmfit 支持在本地添加模型,无需等待官方更新:
# 在 Linux 上创建自定义模型文件
mkdir -p ~/.config/llmfit
cat > ~/.config/llmfit/custom_models.json << 'EOF'
[
{
"name": "my-finetuned-qwen",
"display_name": "My Fine-tuned Qwen 7B",
"family": "Qwen",
"params_billions": 7.0,
"architecture": "dense",
"context_window": 32768,
"use_cases": ["coding"],
"quality_score": 85,
"recommended_quantizations": ["Q4_K_M", "Q5_K_M"]
}
]
EOF
# 重启 llmfit,自定义模型即出现
第七章:内存模型的工程哲学——70% 法则的深层逻辑
7.1 为什么不是 100%?
llmfit 用 70% 作为 Perfect 边界,这背后是一个深刻的工程取舍:计算机系统的性能问题几乎总是边界条件问题。
在本地 LLM 推理场景,"刚好能加载"和"能流畅运行"之间有巨大的体验鸿沟。加载阶段(forward pass)的显存占用是静态的、可精确计算的,但运行阶段的显存占用是动态的:
- KV Cache 动态增长:随着上下文增长,KV Cache 线性消耗显存
- 激活值峰值:backward 不存在(纯推理),但 forward 过程中各层的激活值张量会瞬时占用显存
- 批处理临时张量:即使 batch=1,CUDA kernel 内部仍会分配临时 buffer
- 显存碎片化:多次加载/卸载模型后,显存可能出现碎片,导致"总量够但分配失败"
70% 的边界是一个保守的安全裕度,确保在上述所有动态因素叠加时仍有缓冲空间。这是实用主义工程思维的体现:宁可少推荐一个模型,也不在边界上给用户挖坑。
7.2 MoE 的特殊挑战
MoE 模型的显存计算比 Dense 模型更复杂,因为:
- 总参数量 vs 激活参数量:Qwen2.5-72B-MoE 总参 720 亿,但每次只激活约 140 亿。理论上显存应该按 140 亿算,但 KV Cache 按总参数量分配(因为每个 token 都会经过所有 MoE 层,虽然只激活部分专家,但 attention 计算仍需完整的 KV)。
- 专家分发网络:路由器需要在 GPU 上维护一个小型决策网络,也占用显存。
- 动态激活模式:不同输入会激活不同的专家子集,但 GPU 显存分配是静态的,无法动态回收未使用专家的显存。
llmfit 对 MoE 的处理是:权重按激活参数计算,KV Cache 和基础开销按总参数计算,两项相加得出最终显存估算。
第八章:竞品对比与 llmfit 的差异化定位
8.1 本地 LLM 选型工具全景图
| 工具 | 语言 | 核心能力 | 适用场景 |
|---|---|---|---|
| llmfit | Rust | 硬件检测 + Fit 评分 + 多运行时 | 本地选型决策 |
| Ollama library | Web | 模型列表 + 基本说明 | 快速浏览可用模型 |
| LM Studio | Electron | 模型下载 + GUI 推理 | 不懂命令行的用户 |
| GPT4All | Electron | 模型聚合 + GUI | Windows 用户首选 |
| LocalAI | Go | API 聚合 + 自托管 | 服务器部署 |
| modelfit.io | Web | 模型推荐 + 硬件对照表 | 查表型选型 |
llmfit 的独特价值在于精确性 + 速度 + 自动化:不需要手动查表,不需要试跑,输入一条命令,10 秒内拿到针对你硬件的精确推荐。
8.2 llmfit vs modelfit.io
modelfit.io 是 llmfit 作者做的配套 Web 产品,提供了硬件 → 模型的查表界面。两者的关系是:
- modelfit.io:适合"我知道我的硬件配置,想快速查一下能跑什么"——打开网页,选硬件,看结果。
- llmfit:适合"我不知道我的硬件具体配置,或者需要和模型库动态交互"——运行命令,自动检测,实时推荐。
llmfit 的数据也反哺了 modelfit.io 的推荐逻辑,两者共享同一个模型数据库和评分算法。
第九章:源码架构——Rust 工程实践范本
9.1 项目结构与依赖
src/
├── main.rs # CLI 入口、参数解析、模式分发
├── hardware.rs # CPU/GPU/内存检测
├── models.rs # 模型元数据加载与操作
├── fit.rs # Fit 评分与速度估算
├── providers.rs # 运行时检测(Ollama/llama.cpp/MLX)
├── display.rs # CLI 表格输出 + JSON 序列化
├── tui_app.rs # TUI 应用状态管理
├── tui_ui.rs # ratatui 渲染逻辑
└── tui_events.rs # 键盘事件处理
data/
└── hf_models.json # 模型元数据库
依赖列表极简:clap(CLI 参数)、sysinfo(系统信息)、serde + serde_json(序列化)、tabled(CLI 表格)、colored(终端着色)、ratatui(TUI)、crossterm(终端控制)、ureq(HTTP 客户端)。
没有重型 Web 框架,没有复杂异步生态,依赖树干净,编译速度快。
9.2 Clap 命令行参数设计
use clap::{Parser, Subcommand, ValueEnum};
#[derive(Parser)]
#[command(name = "llmfit", version, about = "Right-size LLM models to your hardware")]
struct Cli {
#[arg(long, help = "Force CLI mode even with TTY")]
cli: bool,
#[arg(long, value_name = "MEMORY", help = "Override RAM/VRAM (e.g. 24G)")]
memory: Option<String>,
#[arg(long, help = "Cap context length for estimation")]
max_context: Option<usize>,
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
/// Interactive TUI (default when no subcommand)
Tui,
/// Start REST API server
Serve {
#[arg(long, default_value = "0.0.0.0")]
host: String,
#[arg(long, default_value = "8787")]
port: u16,
},
/// Search models
Search { query: String },
/// Recommend models
Recommend {
#[arg(long)]
json: bool,
#[arg(long)]
use_case: Option<String>,
#[arg(long)]
limit: Option<usize>,
},
/// Show system hardware info
System,
}
9.3 并行评分计算
当用户选择多模型对比时,Fit 评分计算可以并行化:
use rayon::prelude::*;
pub fn score_models_parallel(
models: &[ModelMeta],
profile: &HardwareProfile,
quant: &str,
max_context: Option<usize>,
) -> Vec<ModelScore> {
models
.par_iter()
.map(|model| {
let vram = calculate_vram(model, quant);
let fit = compute_fit(vram, profile.total_vram(), model.context_window, max_context);
let speed = estimate_throughput(profile, model, quant);
ModelScore { model: model.clone(), fit, speed, vram }
})
.collect()
}
rayon 让多核心并行评分几乎零开销,在 113 个模型的评分场景里,从 ~200ms 降到 ~30ms(8 核机器)。
第十章:使用清单与最佳实践
10.1 选型决策流程图
┌─────────────────────────┐
│ 运行 llmfit system │
│ 确认硬件信息正确 │
└────────────┬────────────┘
│
▼
┌─────────────────────────┐
│ llmfit recommend --json │
│ 查看所有 Fit = Perfect │
└────────────┬────────────┘
│
┌─────┴─────┐
▼ ▼
Fit=Perfect Fit=Good
│ │
▼ ▼
优先选择 考虑上下文
最大参数规模 限制到 4k
│ │
└─────┬─────┘
▼
┌─────────────────┐
│ llmfit search │
│ "<model>" │
│ 查看速度估算 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 选定模型 + 量化 │
│ → Ollama pull │
│ 或 llama-cli │
└─────────────────┘
10.2 各场景推荐配置速查
日常对话(通用推理):
- 24GB 显存:Qwen2.5-14B Q4_K_M(Perfect)
- 16GB 显存:Qwen2.5-7B Q4_K_M(Perfect)
- 8GB 显存:Phi-4-mini 3.8B Q4_K_M(Perfect)或 Gemma-4-2B Q8_0(Good)
代码辅助(coding):
- 24GB 显存:Qwen2.5-14B-Instruct Q4_K_M(Perfect)
- 16GB 显存:DeepSeek-Coder-7B-Instruct Q4_K_M(Perfect)
- 无独显 Mac:Llama3-8B-Instruct Q4_K_M(Good,~30 t/s)
长上下文任务(128k+):
- 需要 --max-context 限制估算
- 推荐上下文截断到实际需求,不要贪大
10.3 常见问题排查
Q:llmfit 检测到的显存比实际少 2GB?
A:CUDA context 和驱动本身占用 ~1-2GB,这是正常的。如果不想要这个折扣,可以手动用 --memory 参数覆盖。
Q:Ollama 检测不到?
A:确保 Ollama 运行在默认端口 11434,且 curl http://localhost:11434/api/tags 返回 200。
Q:Mac 上 Metal GPU 显示 0?
A:macOS 上 sysinfo 对 Apple Silicon 的 Metal VRAM 检测有 bug,llmfit 会自动回退到系统总内存(统一内存架构)。这实际上是正确的——Apple Silicon 没有独立的"显存"概念。
Q:Docker 内运行 llmfit,检测到的显存不对?
A:Docker 容器需要正确映射 GPU(--gpus all)并设置显存限制(--memory 参数覆盖)。llmfit 会读取容器 cgroup 限制,而非宿主机实际显存。
结语:把选型从玄学变成工程
llmfit 的出现,标志着本地 LLM 部署进入了一个新阶段:不再是"试试看能不能跑",而是"精确计算能不能跑、多快能跑、哪个最适合跑"。
它的核心价值不是"替代 Ollama",而是"在 Ollama 之前先做一道判断题":告诉你应该下载哪个模型、用哪个量化版本、在什么上下文长度下运行。这道判断题以前靠经验、靠试错、靠踩坑;现在靠一行命令和精确的算术。
Rust 的选择在这里也得到了回报:编译成单个二进制,零依赖,毫秒级启动,交互零卡顿。用户感知到的 llmfit 是"快"和"准",而这两点正是选型工具最重要的品质——没有人愿意在一个慢吞吞的工具里做选型决策。
如果你的工作流涉及本地大模型部署,无论是个人开发者的 AI 辅助编程,还是企业内网的隐私敏感推理,llmfit 都值得成为你的第一站。一行安装命令,换来的是每次选型决策从"瞎猜两小时"变成"十秒出结果"。
Tag:llmfit|Rust|TUI|本地大模型|LLM推理|Ollama|llama.cpp|模型选型|量化|Apple Silicon|GPU|显存计算|MLX|命令行工具
Keywords:llmfit, Rust TUI, 本地大模型部署, LLM推理选型, Ollama, llama.cpp, 模型量化计算, Apple Silicon GPU, 显存估算, MLX, 命令行工具, Hugging Face 模型选择