llmfit 社区基准全解:一条 `llmfit bench --all --share` 把你的硬件实测数据贡献回开源仓库
导读:llmfit 的核心能力是"告诉我你的硬件,我告诉你什么模型跑得动"——而这背后的底气,来自一个不断壮大的社区基准数据库。本文围绕仓库中的 社区基准说明文档,完整讲解 llmfit 社区基准数据的产生、提交、校验与回流闭环:你会掌握 llmfit bench --share 的完整使用姿势、理解 PR 自动提交的免 gh 授权机制、读懂每一条 JSON 提交的 schema 契约,以及看懂一次 merge 之后你的实测数据是如何"嵌入二进制、进入每一个新安装"的。
一、community/ 目录是什么:一台台真实机器攒出来的测量数据库
在 llmfit 仓库中,llmfit-core/data/community/ 是一个只存放"基准测试结果"的目录:每个子目录以硬件命名(如 nvidia-geforce-rtx-7900-xt、apple-m5-pro、amd-radeon-rx-6800),目录里是若干条 JSON 提交,每条对应一次真实的基准跑分。
这些数据不是维护者手工录入的,而是由全球 llmfit 用户通过同一条命令贡献:
llmfit bench --all --share
--all 表示对所有模型做一次完整基准扫描,--share 表示把这次扫描的结果贡献回上游仓库。用一句话概括这条命令的行为链:跑基准 → 组装成标准的 JSON payload → 让你确认 → 自动 fork 仓库并打开一个 Pull Request,把文件添加进 community/ 目录——整个过程完全不需要安装 gh CLI,也不需要任何自建服务器。
核心机制在于认证方式:共享流程使用 GitHub OAuth device flow(也就是 gh auth login 内部采用的同一套机制),llmfit 二进制的客户端 ID 是公开的、非机密,因此可以直接打进二进制里。若环境变量中存在 GITHUB_TOKEN / GH_TOKEN,llmfit 会自动优先使用它,从而在 CI 等无交互环境中也能直接跑通共享流程。
共享不等于丢数据:先本地暂存,随时可补交
README 特别强调一个设计原则:"拒绝共享绝不会丢弃数据"。不带 --share 的基准运行同样会被完整记录到用户机器的本地存储中;之后某次执行 llmfit bench --share(即使此刻已没有新模型可测)也会把本地积压的旧结果一次性打包进一个 PR 提交上去。
从源码看,这个机制落地在 share.rs:
- 每次成功的基准运行先经
store_local序列化成"待上传 payload"写入本地 pending 存储,文件名与最终上传到仓库的文件名完全一致(时间戳 + 内容哈希); - 共享成功后,
mark_shared再把文件从pending/移动到shared/——文件保留作为本地历史,但永远不会被发送第二次; - 本地存储根目录由
dirs库的data_local_dir()决定(Linux 上通常即~/.local/share/llmfit/benchmarks),并可通过环境变量LLMFIT_BENCH_STORE覆盖,便于测试或将存储放到共享卷上。
需要说明适用前提:这套共享闭环以 GitHub 为上游托管方(上游仓库、main 分支等常量在 share.rs 中定义),因此文档描述的 PR 流程均针对当前上游仓库的 GitHub 托管环境。
二、先预览再提交:--dry-run 让你不碰 GitHub 也能看到完整 payload
在真正联系 GitHub 之前,你完全可以用 dry-run 模式预览将要提交的内容:
llmfit bench --all --share --dry-run
dry-run 模式的行为在 share.rs 的 share_all_pending 中实现:
- 列出本地 pending 存储中全部待贡献结果(一行一条,格式为
model via provider — N tok/s); - 逐条打印将要上传的完整 JSON payload(对应源码中的
--- <本地文件路径> ---分隔块); - 明确提示
--dry-run: nothing was submitted.后退出,全程不发任何网络请求。
CLI 层把 --dry-run 解析为 ShareOptions.dry_run(对应结构体定义见 share.rs,命令行组装见 llmfit-tui/src/main.rs);另有 assume_yes 字段用于跳过交互式确认。值得注意的是,dry-run 与正常的 --share 相比还省去了预检:真实共享时程序会在基准开跑之前先做凭证预检(preflight_auth),把"token 缺失/过期"这类问题提前暴露,而不是等跑完几分钟基准才报错。
--share 的提示、进度等所有人可读的输出统一走 stderr,绝不会污染 bench --json 写到 stdout 的结构化结果。
三、目录布局:为什么文件能被安全地并发提交
community/ 的布局是一套约定,而非随意堆放:
community/
<hardware-slug>/
<unix-timestamp>-<hash>.json
其中:
<hardware-slug>:硬件标识的规范化 slug。payload 中 GPU 机取 GPU/加速器名、纯 CPU 机取 CPU 名,转为小写并只保留字母数字、其余字符替换为-(实现见 share.rs 的payload_slug)。例如真实目录 amd-radeon-rx-7900-xt、apple-m5-pro、intel-arc-graphics-130v-140v-integrated。校验器要求 slug 匹配^[a-z0-9]+(-[a-z0-9]+)*$。<unix-timestamp>-<hash>.json:提交时间戳 + 8 位十六进制内容哈希。哈希基于 FNV-1a 64 位算法混入墙钟时间生成(short_hash),即使内容相同的重复运行也会得到不同文件名,同时保持稳定可复现。
这套命名有两个直接收益:
- 并发提交永不冲突:文件按硬件命名空间 + 内容哈希隔离,不同用户、不同批次的结果天然不重叠;
- 幂等性:仓库内文件名与贡献者本地存储条目一一对应。当贡献者已有打开的 benchmark PR 时,新结果会被追加进同一个 PR 而不是再开一个;部分失败后重试时,已经落地(landed)的文件会被跳过而非重复提交。
共享失败与恢复路径在 submit_stored 中有清晰实现:先检查该用户是否已有打开的 bench PR,有则追加;否则以 bench/<slug>-<hash> 为分支名新建分支并开新 PR。若所有文件都已在远端(例如此前 PR 已合并但本地 mark_shared 失败),则返回"无需开 PR"的结果,避免 GitHub 拒绝空 diff。上传后的文件若硬件身份不可识别(如 ROCm/libdrm 探测不到 GPU 名而显示为 N/A)会被过滤并保留在本地——原因正如代码注释所言:社区排行榜按硬件身份分组,占位符身份只会制造无意义的桶。
四、合并之后会发生什么:一次提交 = 下个版本里所有人的"默认校准"
这是整个社区基准闭环的"回报"设计。README 明确指出:
Submissions are aggregated by
llmfit-core/build.rsand embedded into the binary, so every merged submission ships in the next release.
构建期聚合逻辑见 llmfit-core/build.rs:它递归扫描 data/community/ 下所有 <slug>/*.json,按确定性顺序排序后聚合成单一 JSON 数组,写入 OUT_DIR/community_benchmarks.json,并通过 include_str! 嵌入二进制(对应 benchmarks.rs 中被 build.rs 聚合的注释与 cargo:rerun-if-changed=data/community 的重建声明)。一个坏文件只会产生 cargo:warning 并跳过,绝不会破坏整个构建——因为 CI 在 PR 阶段就已经校验过了。
只要用户跑在相同硬件(同一 CPU + GPU)上,你的提交就会带来三类可见收益:
| 收益 | 说明 |
|---|---|
| 你的实测进入对方 benchmark 页面 | 数据来源标注为 llmfit community |
| measured ✓ tok/s 出现在对方 fit 表中 | 出现在用户自己的本地实测之下、localmaxxing 中位数与公式估算之上——你测过的那些模型将优先显示真实测速而非估算 |
| 其余每个模型获得校准后的估算 | 以你的实测为锚点修正估算曲线;一台全新安装的机器在用户还没跑过任何基准之前,就已经因为你的提交而受益 |
数据消费侧的排序逻辑,可以在 benchmarks.rs 中看到对应类型:MeasuredSource 区分本地实测、嵌入式社区提交等来源;community_submissions() 读取构建期嵌入的社区提交;community_results_for_specs(specs) 会先按硬件(CPU/GPU)过滤出与当前机器匹配的提交(过滤逻辑同时被本地存储复用,见 StoredBenchmark::matches_hardware);LocalBenchIndex 则负责索引用户自己在本机跑过的实测,供 fit 表做本地优先命中。测试 benchmarks.rs 里 community_embed_parses_and_is_seeded 断言嵌入聚合非空、community_results_filter_by_hardware 断言结果确实按硬件匹配过滤。
五、合并前的守门人:每条 PR 都要过的校验关卡
README 明确:每一条触及该目录的 PR 都会运行 Community Benchmarks workflow,调用 scripts/validate_community_benchmarks.py。本地也可以直接运行同一脚本:
python3 scripts/validate_community_benchmarks.py # 校验全部文件
python3 scripts/validate_community_benchmarks.py FILE... # 只校验指定文件
脚本需要 jsonschema(pip install jsonschema),退出码 0 表示全部通过,1 表示有问题。手写(hand-crafted)的提交同样欢迎,前提是能通过与自动生成提交相同的全部检查。具体检查分四层:
1. 路径与命名约定:文件必须直接位于 community/<hardware-slug>/ 之下;slug 必须是小写字母数字加连字符;文件名必须匹配 ^\d{9,12}-[0-9a-f]{8}(-\d+)?\.json$(其中 (-\d+)? 兼容早期构建产生的后缀,仓库中确有这样的文件,例如 intel-arc-graphics-130v-140v-integrated/1783676393-792a24b6-0.json)。
2. 体积上限:单文件不得超过 64 KB、单文件结果数不得超过 100 条——一条正常提交只有几 KB,体积异常大就意味着它不是基准数据。
3. schema 符合性:逐条用 schema.json(draft-07)校验,错误会精确到 JSON path 并逐条输出。
4. 跨字段合理性(schema 表达不了的部分):
minTps <= avgTps <= maxTps,且avgTps > 0;- 硬件物理边界:
ramGb ≤ 8192、vramGb ≤ 2048、cpuCores ≤ 1024、gpuCount ≤ 64(刻意留得很宽,只拦"4 TB 显卡 / 百万核 CPU"这类无意义数据,不拦真实存在的冷门硬件); - 提交时间合理性:
submittedAtUnix既不能早于共享功能上线的 2026-07-01(1782864000),也不能超过当前时间 + 24 小时容差。
六、提交格式:从顶层到字段级的完整契约
每个文件都符合 schema.json。README 给出的标准示例:
{
"schemaVersion": 1,
"submittedAtUnix": 1752127200,
"tool": { "name": "llmfit", "version": "1.0.0" },
"hardware": {
"hwClass": "DISCRETE_GPU",
"hardwareName": "NVIDIA GeForce RTX 4090",
"memTierGb": 24,
"vramGb": 24.0,
"gpuCount": 1,
"unifiedMemory": false,
"cpu": "AMD Ryzen 9 7950X",
"cpuCores": 32,
"ramGb": 64.0,
"os": "linux"
},
"results": [
{
"model": "llama3.1:8b",
"provider": "ollama",
"numRuns": 3,
"avgTps": 128.4,
"minTps": 121.0,
"maxTps": 133.7,
"avgTtftMs": 41.2,
"avgTotalMs": 812.5,
"avgOutputTokens": 104.0
}
]
}
schema 设置 additionalProperties: false,意味着每个对象都不允许出现未列出的多余字段。逐层拆解如下。
6.1 顶层字段(五个全必填)
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
schemaVersion |
integer | const: 1 |
契约版本,当前唯一合法值 |
submittedAtUnix |
integer | ≥ 0 | 提交的 Unix 时间戳,由 CLI 在上传前重新盖章(见后文) |
tool |
object | 必填 name、version |
生成工具标识 |
hardware |
object | 见 6.2 | 运行硬件描述 |
results |
array | minItems: 1 |
本次扫描的模型结果列表 |
6.2 tool 对象
| 字段 | 类型 | 约束 |
|---|---|---|
name |
string | 当前即 "llmfit" |
version |
string | 取自 CARGO_PKG_VERSION(构建时版本) |
6.3 hardware 对象
必填字段为 hwClass、gpuCount、unifiedMemory、cpu、cpuCores、ramGb、os;其余可空。
| 字段 | 类型 | 约束 | 语义 |
|---|---|---|---|
hwClass |
string | 枚举 DISCRETE_GPU / UNIFIED / CPU_ONLY |
硬件类别,由统一内存 / 是否有 GPU 推导(见 share.rs 的 build_submission) |
hardwareName |
string / null | — | GPU/加速器型号名;GPU 机与 UNIFIED 机的分组键 |
memTierGb |
integer / null | ≥ 0 | 声明式"内存层级":将实测容量就近取整到粗粒度阶梯(declared_mem_tier,当前阶梯为 2/3/4/6/8/12/16/24/32/48/64/80/96/128/192/256 GB),精确相等时向下取整——刻意低估比高估安全,因为它是对机器真实配置的声明;源码注释特别提醒它不要与 benchmarks.rs 中用途不同的 lookup_mem_tier 混淆 |
vramGb |
number / null | ≥ 0 | GPU 显存总量(统一内存机为空,改走 memTierGb) |
gpuCount |
integer | ≥ 0,必填 | GPU 数量 |
unifiedMemory |
boolean | 必填 | 是否统一内存架构 |
cpu |
string | 必填 | CPU 型号名;CPU-only 机以此作为分组键与 slug |
cpuCores |
integer | ≥ 1,必填 | CPU 总核数 |
ramGb |
number | ≥ 0,必填 | 内存总量 |
os |
string | 枚举 linux / macos / windows,必填 |
由 cfg!(target_os) 推导(os_name) |
所有数值在序列化前都会被 round2 保留两位小数(share.rs)。
6.4 results[] 对象
必填字段为 model、provider、numRuns、avgTps、minTps、maxTps、avgTotalMs、avgOutputTokens。
| 字段 | 类型 | 约束 | 语义 |
|---|---|---|---|
model |
string | minLength: 1 |
模型标识。llamacpp 场景下会做 GGUF 绝对路径剥离,只保留文件名(见下文隐私处理) |
provider |
string | 枚举 ollama / vllm / mlx / llamacpp |
后端运行器 |
numRuns |
integer | ≥ 1 | 取平均的重复运行次数 |
avgTps / minTps / maxTps |
number | 0 ~ 100000 | 生成吞吐(tok/s)的平均 / 最小 / 最大;且跨字段必须满足 min ≤ avg ≤ max |
avgTtftMs |
number / null | ≥ 0 | 平均首 token 延迟(毫秒),部分后端不可测则为 null |
avgTotalMs |
number | ≥ 0,必填 | 平均总耗时(毫秒) |
avgOutputTokens |
number | ≥ 0,必填 | 平均输出 token 数 |
6.5 仓库里的真实样例
README 的示例是理想化的 ollama 模型标签。仓库里真实存在的提交则能让你看到 llama.cpp / GGUF 场景下的实际形态,例如 amd-radeon-rx-7900-xt/1785258762-ee642f2d.json:一台 i9-10900X + RX 7900 XT 的 Linux 机器,hwClass 为 DISCRETE_GPU,一条提交内包含 40 个模型的实测(Llama-3.2-1B-Instruct-Q4_K_M.gguf 约 375.97 tok/s,逐级递减到 Qwen2.5-Coder-32B-Instruct-Q4_K_M.gguf 的约 31.13 tok/s),numRuns 均为 3、avgTtftMs 为 null——这就是 llamacpp 提交的真实剖面。全仓目前已有覆盖 AMD 独显/核显、Apple M 系列、Intel Arc/Xe、NVIDIA 各代显卡等大量硬件目录,每条文件都是一台真实机器的指纹。
6.6 隐私与数据卫生:路径会被先"清洗"
一个容易被忽略的细节:llamacpp 的 llama-server 在 /v1/models 里报告的模型 id 往往是 -m/--model 的绝对文件路径,其中可能带着用户名等机器特定信息。为此 share.rs 内置了两层防护:
- 新 payload 构建时通过
strip_gguf_path规范化:只有以/、\或盘符开头的绝对路径且以.gguf结尾时,才剥离为裸文件名;而hf.co/org/repo/file.gguf这类带命名空间的 Hub 引用会原样保留(它们不含机器特定信息); - 旧版二进制写入的本地存储仍可能残留路径,加载时由
sanitize_stored_payload统一在共享前清洗,保证共享预览、dry-run 与实际上传三方一致,机器特定路径永远不出本机。
七、常见运行场景与边界行为
结合 README 与源码,把几个高频场景的行为讲清楚,可以避免踩坑:
1. 本地还没有任何基准结果
share_all_pending 直接报错提示:先运行 llmfit bench <model> 或 llmfit bench --all(错误文案见 share.rs)。
2. 硬件无法被识别
若 GPU 名是 N/A/unknown 之类的占位符,提交会被过滤并给出明确提示:结果保留在本地,不会污染社区排行榜。占位符判定集合与原因见 share.rs。
3. token 失效
先查 GITHUB_TOKEN / GH_TOKEN,再查上次 device flow 登录缓存的 token(默认缓存在配置目录的 llmfit/github_token,权限 0600)。环境变量中的 token 无效属于硬错误(用户显式设置过,必须指出来);缓存的 token 失效则被静默丢弃并重新走交互式登录。若不希望任何交互登录发生(如受限 CI),可把 LLMFIT_GH_CLIENT_ID 显式设为空字符串来禁用 device flow(oauth_client_id)。
4. 多轮共享
上传成功后 mark_shared 会把 pending 清空;但已打开的 PR 是"可续写"的——下次共享会检测到已存在 open bench PR 并继续追加,而不是制造一堆碎片 PR。
八、小结:这条数据管线的设计哲学
回看整条链路,llmfit 的社区基准之所以能持续壮大,靠的是三组刻意设计的取舍:
- 贡献门槛降到最低:无
gh、无自建服务器,device flow 几分钟授权一次即可;共享失败绝不丢数据,本地暂存 + 幂等文件命名让"事后补交"与"失败重试"都变得廉价; - 数据质量交给自动化守门:CI 校验 + schema 严格封闭(
additionalProperties: false)+ 物理边界合理性检查,让"合并即可信"成立,也让手写提交与工具生成提交遵循同一套标准; - 激励闭环内置在产品里:合并即嵌入二进制、随下个版本发布,硬件相同的用户立刻在自己的 benchmark 页面、fit 表和模型估算中受益——贡献者与使用者的利益在数据上合流,而排序优先级(本地实测 > 社区实测 > 中位数 > 估算)保证每个人看到的最准确数据永远来自最近的真实测量。
如果你也想让社区看到你那台机器的真实跑分,随时运行:
llmfit bench --all --share --dry-run # 先看会提交什么
llmfit bench --all --share # 确认无误后正式贡献
一次运行,就是给所有同款硬件用户的一份开箱校准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00