如果你已经在一台 Mac 上认真玩过开源大模型,大概率经历过这个瞬间:磁盘空间告急,打开终端翻目录,发现~/.ollama下躺着十几个模型文件,~/models里还散落着一堆.gguf文件,同一个模型有Q4_K_M、Q5_K_S好几个量化版本,已经完全想不起来哪个是当前正在用的。这不是个别现象。本地大模型的使用成本,正在从“下载模型”转移到“管理模型”。
这个判断听起来有点反直觉。过去大家讨论本地 LLM,重点都在显卡、内存、量化精度、推理速度。可等你真正下载了几十个模型之后会发现:找模型、识别模型、清理旧版本所花的时间,可能比写调用代码还多。而 macOS 上的模型存放路径又特别分散:Ollama 有自己的一套目录,Hugging Face 缓存有一套目录,LM Studio 还有另一套目录。它们之间互不感知,磁盘却在同一块硬盘上竞争。
What the Model 这个针对 macOS 的本地 LLM 盘点工具,瞄准的正是这个被人忽略的夹层问题。它不是又一个推理框架,也不是又一个模型下载器,而是一个本地模型资产清单工具:帮你搞清楚这台机器上到底有哪些模型、每种格式多大、每个文件在哪个路径、哪些可以放心删除。本文会先拆解这类工具为什么必要,再讲清楚 GGUF、Safetensors、MLX 这些格式在盘点时要怎么识别,然后给出一套不依赖特定 GUI 的模型盘点方案,用 macOS 自带的命令行和一段 Python 脚本,你就能自己实现 What the Model 的核心逻辑。读完至少能解决三件事:知道模型存在哪、知道怎么识别、知道怎么安全清理。
1. 为什么需要模型盘点:本地 LLM 的管理困境
1.1 模型文件散落在多个目录
只要在 Mac 上用过两个以上的本地推理工具,模型文件就注定是分散的。Ollama 把模型放在~/.ollama/models,Hugging Face 的huggingface-cli download会把模型缓存到~/.cache/huggingface/hub,LM Studio 默认在~/.lmstudio/models,如果你从 GitHub Release 手动下载过 GGUF 文件,可能又随手扔进了~/Downloads或者某个工作目录。更麻烦的是,同一个模型可能被 Ollama 导入一份,又被 LM Studio 下载一份,两边的文件内容几乎一样,磁盘占用却算了两遍。
这种分散带来的直接结果就是“看不见”。你只知道当前正在用的那个模型在哪儿,永远不知道这台机器上一共存了多少模型资产。当磁盘被塞满时,你甚至没法快速回答“哪个模型最大”“哪个模型能删”。这就是模型盘点工具存在的第一个理由:把所有分散的模型文件统一纳入一份清单。
1.2 命名混乱与量化版本难以区分
本地模型的命名通常带有完整的技术标识,例如Qwen2.5-7B-Instruct-Q4_K_M.gguf。这个命名算友好的,至少能看出系列、参数量、量化方式。但很多模型文件名其实是乱码、哈希值,或者只有缩写。同一个模型还有不同量化等级:Q4_K_M、Q5_K_S、Q6_K、F16,参数量不变,文件体积和推理效果却有差异。
如果只靠文件名去管理,很容易出现两个问题。第一,看到Q4_K_M和Q5_K_S不知道差异有多大,不敢删;第二,以为自己只有一个模型,实际有四个不同量化版本,白白占了二三十 GB。盘点工具的价值恰恰在于把量化等级、参数量、文件大小这些分散信息提取出来,让“重复资产”直接暴露在清单里。
1.3 磁盘占用失控,而且工具之间互相不知道
7B 模型的 GGUF 量化文件通常在 4 到 5 GB 左右,13B 模型差不多 8 到 10 GB,70B 模型即使量化也常常超过 40 GB。几个模型叠加,一块 512 GB 的 Mac 硬盘很轻松就会被吃掉大半。更隐蔽的是,macOS 的文件系统可能还有快照、克隆文件等机制,删除文件后磁盘空闲空间不一定马上恢复,这会让“空间去哪里了”变得更加难以追踪。
如果缺少一个统一的资产清单,面对磁盘告警时只能凭记忆和du命令到处翻。而有了一份模型清单,你至少能在五分钟内回答:最大的十个模型文件分别是什么,哪些属于同一个模型的重复下载,哪些已经不再被任何工具引用。
2. What the Model 是什么:本地模型清单工具的功能定位
从项目标题来看,What the Model 的核心职责是给 macOS 上的本地 LLM 做 Inventory,也就是模型资产盘点。一个典型的 Inventory 工具,至少要完成三层工作:发现、识别、展示。
发现层负责扫描本地目录,找到所有可能的模型文件。它需要覆盖常见工具的默认路径,也允许用户手动添加自定义目录。识别层负责判断文件格式、读取模型元数据、计算文件大小、尝试推断参数量和量化等级。展示层则把识别结果整理成可读的列表或者详情页,让用户一眼看清全局。
这里要特别注意边界。这类工具和 Ollama、LM Studio 并不是替代关系。Ollama 是运行时,负责加载和推理;LM Studio 是图形化推理环境。而 What the Model 做的是“资产管理”:它不关心怎么跑模型,只关心你的机器上到底有什么模型。你可以把它理解为电脑里的“设备资产台账”:Ollama 是进程管理器,What the Model 是仓库管理员。
这种设计有个显而易见的好处:它不绑定具体的推理框架。只要磁盘上存在模型文件,不管你是用 Ollama 导入的,还是从 Hugging Face 手动下载的,它都能统一收进同一份清单。对于同时使用多个工具的开发者来说,这才是真正能解决痛点的产品形态。
如果你还没有使用这类工具,也完全可以用脚本自己实现同样的逻辑。接下来三节,我会先把本地模型常见的格式和目录讲清楚,再给出一套可以直接运行的盘点方案。
3. 本地 LLM 常用格式与关键概念
3.1 GGUF、Safetensors、MLX 到底有什么区别
做模型盘点之前,必须能识别三种常见的模型文件格式。它们的使用场景和技术特点完全不同。
GGUF是 llama.cpp 生态的单文件格式,通常一个.gguf文件就是一个完整的模型,包含权重、分词器和元数据。它的好处是部署简单,拷贝一个文件就能用,所以很多本地推理工具和 GUI 应用都支持它。Safetensors是 Hugging Face 社区主流的权重格式,通常是目录里的一组.safetensors分片文件,配合config.json、tokenizer.json等描述文件一起使用。MLX是 Apple 针对自家芯片优化过的格式,常见于 mlx-lm 生态,同样是以目录为单位,里面包含.safetensors 权重和配置文件。
三种格式的差异直接影响了盘点逻辑。GGUF 的元数据内嵌在文件二进制头部,可以靠读取文件内容来识别;Safetensors 和 MLX 则依赖周边配置文件,盘点时需要把整个目录当作一个模型单元,而不是只看单个权重文件。
| 格式 | 常见扩展名 | 使用生态 | 盘点时怎么看 |
|---|---|---|---|
| GGUF | .gguf | llama.cpp、Ollama、LM Studio | 单文件,读取二进制头部元数据 |
| Safetensors | .safetensors | Transformers、Hugging Face | 目录 + 配置文件,按目录识别 |
| MLX | .safetensors + config.json | mlx-lm、Apple 生态 | 目录 + 配置文件,按目录识别 |
3.2 量化等级为什么是盘点重点
量化等级直接决定了模型文件的大小和推理时所需内存。相同参数量的模型,F16版本可能是Q4_K_M版本的两到三倍大小。对于开发者来说,量化版本是一个非常重要的决策信息:部署到内存有限的 Mac 上,通常优先选小量化;追求生成质量,会选高精度版本。
模型文件名里的Q4_K_M、Q5_K_S、Q6_K这些标识,就是量化方式的简写。盘点工具要做的不是去判断哪个量化等级更好,而是把这些标识从文件名或元数据里原样提取出来,并按照参数量聚合同一模型的不同版本。这样你才能一眼看出:“哦,这个 7B 模型我下了四个版本,留两个就够了。”
3.3 模型元数据藏在文件头部还是配置文件
GGUF 的元数据在文件二进制头部。文件开头先是魔数GGUF,然后是版本号、张量数量、键值对数量,接着是一连串的元数据键值对,包括模型名称、架构、文件类型、上下文长度等。所以解析 GGUF 必须按二进制格式读取。
Safetensors 和 MLX 模型的元数据则在 JSON 配置里,比如config.json里的architectures、hidden_size、num_hidden_layers等字段。盘点这类模型时,通常以目录为单位,读取目录里的config.json来推断模型信息。理解了这一点,后面的脚本逻辑就很清晰了。
4. 环境准备:macOS 下的模型目录分布
macOS 本身没有“模型目录”这样的标准概念,但几个主流工具默认都有固定位置。盘点时可以从这些路径开始扫描。
| 工具/来源 | 常见目录 | 说明 |
|---|---|---|
| Ollama | ~/.ollama/models | 内部按 blobs 存放,文件名为哈希 |
| Hugging Face Cache | ~/.cache/huggingface/hub | 按模型仓库名组织 |
| LM Studio | ~/.lmstudio/models | 通常直接存放 GGUF 文件 |
| 手动下载 | ~/Downloads、~/models、~/Documents | 无固定规律 |
需要提醒的是,这些路径在不同版本的工具中可能发生变化,实际以你机器上的目录为准。另外,部分目录可能位于外置磁盘或自定义路径下,盘点时要把自定义目录也纳入扫描范围。
环境要求方面,本文的脚本只需要 macOS 自带的环境:bash 命令、Python 3。macOS 自带的 Python 在较新版本中可能不再是系统预装组件,如果没有,可以通过 Homebrew 安装,命令是brew install python3。脚本本身不需要第三方依赖,用标准库即可跑通。
5. 盘点流程拆解:扫描、识别、清单、清理
模型盘点看起来复杂,拆开就是四个步骤:扫描目录、识别文件、生成清单、辅助清理。
扫描目录是第一步。用一个递归遍历脚本,把指定目录下所有文件过一遍,过滤出感兴趣的扩展名。这一步的关键是扫描范围要覆盖全面,否则漏掉路径等于白跑。识别文件是第二步。对.gguf文件,读取二进制头获取元数据;对其他格式,优先找目录中的config.json或*.safetensors文件。识别之后,把结果整理成结构化的清单,包含文件名、路径、格式、大小、量化标识、可能的参数量。最后才是清理决策。
清理是整个流程里最需要谨慎的一步。我的建议是:盘点阶段永远只做只读操作,不要自动删除任何文件。工具可以给出“疑似重复模型”的提示,但删除动作必须由用户确认。因为模型文件可能正被某个推理进程占用,也可能被多个工具引用,直接删文件很容易破坏 Ollama 等工具的模型索引。
下面我用命令行和 Python 脚本,一步步把这个流程跑通。
6. 完整示例:命令行与 Python 实现模型盘点
6.1 第一步:定位模型目录并查看磁盘占用
先用命令行快速定位常见模型目录,并统计它们各自占用了多少磁盘空间。在 macOS 终端中执行:
# 统计常见模型目录的磁盘占用 du -sh ~/.ollama/models 2>/dev/null du -sh ~/.cache/huggingface 2>/dev/null du -sh ~/.lmstudio/models 2>/dev/null du -sh ~/models 2>/dev/null # 在 home 目录下查找可能是模型目录的位置 find ~ -maxdepth 3 -type d \( -name "models" -o -name "*gguf*" \) 2>/dev/null | head -20第一条命令分别输出每个目录的总大小。如果某个目录不存在,会通过2>/dev/null静默跳过。第二条命令用find在用户目录下搜索名为models或包含gguf的文件夹,帮助定位自定义路径。
这一段的目的是先把“模型到底放在哪”搞清楚。看到输出后,把实际存在的目录记下来,作为后续 Python 脚本的扫描根目录。
6.2 第二步:用 Python 解析 GGUF 元数据
GGUF 文件的二进制头部包含模型关键信息。下面这个脚本可以读取一个.gguf文件的魔数、版本、张量数量和常见元数据字段。把它保存为gguf_meta.py:
#!/usr/bin/env python3 # 文件路径:gguf_meta.py import struct import sys GGUF_MAGIC = 0x46554747 # 即字符串 "GGUF" 的小端整数 GGUF_TYPE_MAP = { 0: "uint8", 1: "int8", 2: "uint16", 3: "int16", 4: "uint32", 5: "int32", 6: "float32", 7: "bool", 8: "string", 9: "array", 10: "uint64", 11: "int64", 12: "float64", } def read_string(f): length = struct.unpack("<Q", f.read(8))[0] data = f.read(length) return data.decode("utf-8", errors="replace") def read_value(f, vtype): if vtype == 8: return read_string(f) if vtype == 0: return struct.unpack("<B", f.read(1))[0] if vtype == 1: return struct.unpack("<b", f.read(1))[0] if vtype == 2: return struct.unpack("<H", f.read(2))[0] if vtype == 3: return struct.unpack("<h", f.read(2))[0] if vtype == 4: return struct.unpack("<I", f.read(4))[0] if vtype == 5: return struct.unpack("<i", f.read(4))[0] if vtype == 6: return struct.unpack("<f", f.read(4))[0] if vtype == 7: return struct.unpack("<?", f.read(1))[0] if vtype == 10: return struct.unpack("<Q", f.read(8))[0] if vtype == 11: return struct.unpack("<q", f.read(8))[0] if vtype == 12: return struct.unpack("<d", f.read(8))[0] if vtype == 9: elem_type = struct.unpack("<I", f.read(4))[0] count = struct.unpack("<Q", f.read(8))[0] return [read_value(f, elem_type) for _ in range(count)] raise ValueError(f"未知 GGUF 值类型: {vtype}") def read_gguf_metadata(path): with open(path, "rb") as f: magic = struct.unpack("<I", f.read(4))[0] if magic != GGUF_MAGIC: return None version = struct.unpack("<I", f.read(4))[0] tensor_count = struct.unpack("<Q", f.read(8))[0] kv_count = struct.unpack("<Q", f.read(8))[0] meta = {} for _ in range(kv_count): key = read_string(f) vtype = struct.unpack("<I", f.read(4))[0] value = read_value(f, vtype) meta[key] = value return { "version": version, "tensor_count": tensor_count, "metadata": meta, } if __name__ == "__main__": if len(sys.argv) < 2: print("用法: python3 gguf_meta.py <model.gguf>") sys.exit(1) info = read_gguf_metadata(sys.argv[1]) if info is None: print("不是有效的 GGUF 文件") sys.exit(1) print("GGUF 版本:", info["version"]) print("张量数量:", info["tensor_count"]) meta = info["metadata"] for key in ["general.name", "general.architecture", "general.file_type", "general.size_label"]: if key in meta: print(f"{key}: {meta[key]}")这段代码的逻辑分三层。第一层是头部读取,魔数不对就直接判定不是 GGUF。第二层是键值对遍历,每个键是字符串,值有固定类型编号,脚本根据类型编号读取对应字节。第三层是字段提取,general.name是模型显示名,general.architecture是模型架构,比如llama、qwen2。注意,并不是每个 GGUF 文件都会写入全部字段,所以用了条件判断。
6.3 第三步:遍历目录生成模型资源清单
有了单文件解析能力,就可以把它扩展到整个目录,生成一份 JSON 清单。新建model_inventory.py,代码如下:
#!/usr/bin/env python3 # 文件路径:model_inventory.py import json import os import sys from pathlib import Path from gguf_meta import read_gguf_metadata MODEL_EXTENSIONS = {".gguf", ".safetensors", ".bin", ".pt", ".onnx"} def scan_models(root: str): items = [] for dirpath, dirnames, filenames in os.walk(root): for name in filenames: ext = Path(name).suffix.lower() if ext not in MODEL_EXTENSIONS: continue full_path = os.path.join(dirpath, name) stat = os.stat(full_path) info = {"name": name, "path": full_path} if ext == ".gguf": gguf = read_gguf_metadata(full_path) if gguf: info["model_name"] = gguf["metadata"].get("general.name") info["architecture"] = gguf["metadata"].get("general.architecture") info["size_bytes"] = stat.st_size info["size_mb"] = round(stat.st_size / 1024 / 1024, 2) info["extension"] = ext items.append(info) items.sort(key=lambda x: x["size_bytes"], reverse=True) return items if __name__ == "__main__": root = sys.argv[1] if len(sys.argv) > 1 else os.path.expanduser("~/.ollama/models") items = scan_models(root) print(json.dumps(items, indent=2, ensure_ascii=False)) total_mb = sum(i["size_bytes"] for i in items) / 1024 / 1024 print(f"\n总计 {len(items)} 个文件,共 {round(total_mb, 2)} MB")这里有一点要注意:from gguf_meta import read_gguf_metadata要求gguf_meta.py和model_inventory.py放在同一目录下,或者在 Python 的模块搜索路径中。脚本当前只针对.gguf做了元数据解析,对 Safetensors 目录只识别文件本身。更完整的方案,可以把同目录下的一组.safetensors文件合并成一个模型单元,并读取config.json,但作为最小盘点方案,当前输出已经足够你定位大文件和重复文件。
6.4 运行与验证
分别执行以下命令:
python3 gguf_meta.py ~/.ollama/models/blobs/你的模型文件 python3 model_inventory.py ~/.ollama/models如果一切正常,第一条命令会输出模型的版本、张量数量、名称和架构;第二条命令会输出一个按文件大小降序排列的 JSON 数组,末尾是文件总数和总大小。判断成功的标准是:能解析出general.name、general.architecture字段,且清单中的文件大小与实际磁盘占用一致。
如果第一个脚本报索引错误或者输出乱码,优先怀疑文件不是标准 GGUF,或者文件下载不完整。可以用file 模型文件命令先验证文件类型。如果第二个脚本扫出来全是.safetensors文件,说明这台机器主要用 Transformers 或 MLX,可以进一步对目录做聚合解析。
7. 运行结果与效果验证
7.1 预期输出示例
正常情况下,gguf_meta.py的输出大概长这样:
GGUF 版本: 3 张量数量: 291 general.name: Qwen2.5-7B-Instruct general.architecture: qwen2 general.file_type: 15其中general.file_type是一个整数,对应 llama.cpp 内部的量化类型编号。不同的编号代表不同量化方式,如果脚本显示的是 15,通常对应Q8_K;但不同版本的 GGUF 规范可能略有差异,遇到具体型号时建议以模型发布页说明为准。model_inventory.py的输出以一个 JSON 数组开始,每个对象代表一个模型文件,数组末尾是统计行。
7.2 如何判断盘点是否成功
成功与否有三个判断标准。第一,扫描范围是否完整:前面用du找到的目录,最终都应该在清单里出现。第二,识别结果是否准确:.gguf文件的名称、架构、大小三个字段能对应上。第三,总大小是否合理:把清单里的size_bytes加起来,再和du的目录总占用对比,如果差距过大,说明还有模型文件没有被纳入扩展名过滤规则。
如果只看到部分文件进入清单,最常见的原因是模型扩展名不在MODEL_EXTENSIONS集合里。比如有些 GGUF 文件会被命名成model.bin,有些旧版本使用.ggml后缀。遇到这种情况,把后缀加入集合重新运行即可。另外,Hugging Face 缓存里的大量文件是分片和辅助文件,真正需要关注的.safetensors文件会被识别,但一个模型会输出多行,后续可以按目录聚合成模型单元。
7.3 失败时的排查顺序
运行失败时,先看报错发生在哪一层。如果是module not found,检查两个 Python 文件是否在同一目录。如果是Permission denied,说明当前用户没有读取该目录的权限,特别是系统目录下的模型。如果是解析到一半中断,优先怀疑文件被占用或下载不完整。总体排查顺序是:路径是否正确、权限是否足够、文件是否是标准格式、扩展名是否在过滤集合中。
8. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 扫描结果为空 | 扫描路径错误 | 用ls确认目录是否存在 | 修正路径,加入自定义目录 |
| 只扫描到少量文件 | 扩展名不在过滤集合 | 查看目录里的实际文件名 | 把.bin、.ggml等后缀加入集合 |
| GGUF 解析报错 | 文件损坏或下载未完成 | 用file 文件检查类型,对比文件大小 | 重新下载模型 |
| 识别出乱码 | 元数据使用了非标准字段 | 打印原始 KV 键值对检查 | 以general.name等标准字段为准 |
| 清单总大小与 du 不一致 | 有目录未纳入扫描 | 逐目录对比 du 输出 | 扩大扫描根目录范围 |
| 删除文件后 Ollama 列表异常 | 直接删除了 Ollama 的 blob 文件 | 在 Ollama 中执行ollama list | 通过ollama rm删除模型,不要手动删 blob |
| 磁盘空闲空间没有立刻恢复 | APFS 本地快照或文件被进程占用 | 检查lsof 文件路径和快照列表 | 关闭占用进程,等待快照过期或手动清理快照 |
这里尤其要强调最后两类问题。Ollama 的模型目录内部是哈希命名的 blob 文件,直接删除文件会让ollama list的索引与实际文件不一致。删模型要用ollama rm,而不是在文件管理器里删除。另外,macOS 的 APFS 文件系统存在本地快照机制,删除大文件后空闲空间不一定立刻体现,这是正常现象。
9. 最佳实践与工程建议
9.1 建立统一的模型目录规范
不要在每个项目目录里都放一份模型文件。建议在固定位置建一个~/Models目录,按格式分子目录,比如~/Models/GGUF、~/Models/MLX、~/Models/Safetensors。下载新模型时统一放到对应目录,盘点脚本只需要扫描这一个根目录即可。对 Ollama 和 LM Studio 独占的模型,保留在它们的默认目录,但要在清单文档里注明来源。
9.2 用符号链接聚合多工具目录
如果你既用 Ollama,又用 LM Studio,还希望所有模型能在同一个盘点工具里出现,可以在统一目录里建软链接。例如:
ln -s ~/.ollama/models/blobs ~/Models/ollama-blobs ln -s ~/.cache/huggingface/hub ~/Models/hf-cache这样盘点工具扫描~/Models时,就能间接覆盖所有工具的默认目录。注意软链接本身不复制文件,不增加磁盘占用,只是给盘点提供统一入口。
9.3 删除模型前必须确认引用关系
无论使用工具还是脚本,删除模型前都要回答三个问题:这个模型是否还在被某个推理服务引用?是否存在于 Ollama 或 LM Studio 的索引中?是否有其他量化版本可以替代?建议先用lsof检查有没有进程打开模型文件,再决定是否删除。
lsof 模型文件路径 ollama list如果文件正被占用,删除操作会失败或者导致运行中的服务崩溃。最稳妥的方式是按工具推荐的删除流程操作:Ollama 用ollama rm,其他手动下载的文件直接移到废纸篓,并保留一段时间再清空。
9.4 把许可证信息纳入清单
很多本地模型采用了特殊的开源许可证,是否允许商用、是否允许二次分发,每家的规定不一样。盘点工具展示模型名称和路径的同时,最好在清单文档中记录许可证信息。这一步和磁盘管理无关,但和项目交付、企业使用直接相关,越早记录越省事。
9.5 用 launchd 定时盘点
手动跑脚本容易忘记,macOS 自带的 launchd 可以设定固定时间自动执行盘点。下面是一个每日 9:30 运行的 LaunchAgent 配置示例,保存为~/Library/LaunchAgents/com.example.model-inventory.plist:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.model-inventory</string> <key>ProgramArguments</key> <array> <string>/usr/bin/python3</string> <string>/Users/yourname/scripts/model_inventory.py</string> <string>/Users/yourname/Models</string> </array> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>9</integer> <key>Minute</key> <integer>30</integer> </dict> <key>StandardOutPath</key> <string>/tmp/model-inventory.log</string> <key>StandardErrorPath</key> <string>/tmp/model-inventory.err</string> </dict> </plist>加载方式在较新的 macOS 上推荐使用:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.model-inventory.plist自动盘点不会立刻释放磁盘,但可以让“模型资产持续可见”。每次生成清单后,对比上一次清单,就能看出新增了什么、删除了什么、哪些模型长期没被使用。长期不用的模型单独存放在外置硬盘,比一直放在系统盘里更合理。
10. 总结与后续学习方向
本地大模型的管理难题是真实存在的:目录分散、命名混乱、量化版本重复、磁盘占用失控。What the Model 这类工具的价值不在于推理速度,而在于把“你有哪些模型资产”这件事变得清晰可见。本文没有停留在概念层面,而是用命令行和 Python 脚本完整实现了盘点流程的核心部分:定位目录、解析 GGUF、生成 JSON 清单。跑通这套流程之后,你已经具备了管理本地模型资产的基本能力。
下一步可以从三个方向继续深入。第一,用 Python 读取 Safetensors 的config.json,把目录级模型聚合逻辑补全;第二,做一份可视化的模型清单页面,或者把 JSON 导入表格工具;第三,研究 Ollama 的模型索引机制,搞清楚如何避免误删文件导致的索引异常。
最后提醒一句:盘点脚本永远是只读的,删除动作永远要手动确认。工具可以帮你把决定做得更准,但最终按下删除键的责任,还是在你自己手里。建议先跑一遍只读扫描脚本,把当前机器的模型清单打印出来,再决定下一步怎么清理。