Project NOMAD 社区插件指南:用 ZIM 内容包扩展离线知识库
本文基于 Project NOMAD 官方文档 Community Add-Ons 编写,讲解社区构建的 ZIM 内容包如何接入 NOMAD 的 Kiwix 离线资料库,包括两个典型内容包(美军野战手册、W3Schools 编程档案)的规格、标准的四步安装流程,以及 NOMAD 底层的 library mode 是如何自动发现并注册新 ZIM 文件的。读完本文,你可以独立完成一次社区 ZIM 插件的构建与部署,并理解「装完为什么能自动出现在 Information Library」背后的实现机制。
什么是社区插件(Community Add-Ons)
Project NOMAD 内置了一套经过官方筛选的工具与内容,但社区已经开始构建插件(add-ons),为平台扩展专业领域的离线内容包。需要明确其定位:
- 这些插件是第三方项目,不由 NOMAD 团队维护;
- 安装与否由使用者自行决定(at your own discretion);
- 任何 bug 或功能请求都应提交到插件自己的仓库,而不是 Project NOMAD。
如果你自己也构建了 NOMAD 插件,可以向 Project NOMAD 团队提交 issue 或通过官网联系表单告知,官方会评估是否将其收录到这篇文档中。
ZIM 内容包:社区插件的主流形态
ZIM 内容包(ZIM Content Packs)会把额外的离线参考资料合并进你现有的 Kiwix 资料库。从源码结构看,这类插件通常遵循同一套构建-部署范式:
- 插件仓库附带一个
install.sh脚本; - 脚本先下载原始素材(PDF、网页镜像等);
- 使用
zimwriterfs(zim-tools 提供的 ZIM 构建器)把素材构建成一个可检索的 ZIM 文件; - 将 ZIM 注册到你正在运行的 Kiwix 容器中。
由于 NOMAD 的 Kiwix 运行在 library mode(见下文原理部分),新 ZIM 只要落盘到资料库目录并被写入 kiwix-library.xml,就会在 Information Library 中被列出,无需修改 Kiwix 的启动参数。
U.S. Military Field Manuals(美军野战手册)
- 仓库:
jrsphoto/ZIM-military-field-manuals(社区第三方仓库) - 内容:约 180 本公有领域(public domain)的美军野战手册,涵盖战地医学、生存技能、战伤急救、地图判读等主题;
- 形态:构建为可全文检索的 ZIM,直接放入 Kiwix 资料库即可浏览;
- 体积参考:最终 ZIM 约 2 GB;构建过程中会从 archive.org 下载约 2 GB 的源 PDF,因此构建机需要能访问外网且预留足够磁盘。
W3Schools Programming Archive(W3Schools 编程档案)
- 仓库:
kennethbrewer3/ZIM-w3schools-offline(社区第三方仓库) - 内容:W3Schools 编程教程的完整离线副本,覆盖 HTML、CSS、JavaScript、Python、SQL 等语言;适合学习编程、查语法,或在无互联网环境(教学点、野外部署等)中开展编程教学;
- 体积参考:最终 ZIM 约 700 MB;构建过程中会从某个 GitHub 镜像下载约 6 GB 的源文件——注意源下载量远大于产物体积,规划磁盘空间时要以源下载量为上限。
安装社区插件:四步标准流程
每个插件都有自己的安装说明,但绝大多数 ZIM 包遵循相同的流程。以下参数与 NOMAD 的实际部署路径完全对应:
-
通过 SSH 克隆插件仓库到 NOMAD 宿主机,例如:
git clone <插件仓库地址> /tmp/zim-add-on -
查看插件 README,确认构建依赖。大多数插件需要
git、python3、unzip和zim-tools(后者提供zimwriterfs构建工具)。 -
运行插件附带的
install.sh,带上--deploy参数,将插件指向两个 NOMAD 侧的关键信息:- Kiwix 资料库路径:
/opt/project-nomad/storage/zim - Kiwix 容器名:
nomad_kiwix_server
这两个值不是凭空约定的:NOMAD 在 fs.ts 中定义
ZIM_STORAGE_PATH = '/storage/zim',而 docker_service.ts 中DEFAULT_HOST_STORAGE_ROOT = '/opt/project-nomad/storage',拼起来正是宿主机上的/opt/project-nomad/storage/zim;容器名则定义在 service_names.ts 的KIWIX: 'nomad_kiwix_server'。 - Kiwix 资料库路径:
-
脚本完成四件事:构建 ZIM → 复制进你的 Kiwix 资料库目录 → 注册进 Kiwix(写入资料库 XML)→ 重启 Kiwix 容器。
脚本结束后,新内容会在你下一次加载 Information Library(Kiwix Web 界面,NOMAD 默认映射到宿主机 8090 端口)时出现。
构建耗时预期:从几分钟到一小时以上不等,取决于插件体积和宿主机 CPU 性能。以 2 GB 的美军手册包为例,下载 2 GB 源文件加上 zimwriterfs 压缩索引,在没有外网带宽限制的情况下仍可能需要较长时间,建议放在空闲时段执行。
原理深潜:NOMAD 如何自动「捡起」新装的 ZIM
这一步是理解整个机制的关键,也是排查「装了插件但 Information Library 里看不到」问题的依据。
Kiwix 以 library mode 启动
NOMAD 的 Kiwix 服务使用 ghcr.io/kiwix/kiwix-serve:3.8.1 镜像,启动命令定义在 kiwix.ts:
export const KIWIX_LIBRARY_CMD = '--library /data/kiwix-library.xml --monitorLibrary --address=all'
--library /data/kiwix-library.xml:不直接指定某个 ZIM 文件,而是读取一份资料库清单 XML,其中登记了所有 ZIM 的路径与元数据;--monitorLibrary:让 kiwix-serve 监控该清单文件的变化,清单更新后自动重新加载。
这条命令由 迁移脚本 从早期的通配符模式(*.zim --address=all)升级而来——library mode 正是为了让「插件装一个新 ZIM」变成一次清单追加而非改容器启动参数。在 service_seeder.ts 中可以看到对应的容器配置:宿主机 ${NOMAD_STORAGE_ABS_PATH}/zim 绑定到容器内 /data,端口 8080/tcp 映射到宿主机 8090。因此 kiwix-library.xml 在宿主机上的实际位置就是 /opt/project-nomad/storage/zim/kiwix-library.xml,与插件安装脚本要求的资料库路径一致。
kiwix-library.xml 由 KiwixLibraryService 管理
NOMAD 侧对这份清单的读写实现在 kiwix_library_service.ts,几个与插件安装直接相关的能力:
addBook(filename):为某个 ZIM 追加一条<book>记录。它会先用@openzim/libzim打开 ZIM 文件校验有效性(isValidZimFile),读取内部 UUID、Title、Description、语言、作者、文章数/媒体数以及 48px favicon(base64 编码进 XML,供 Kiwix 的 OPDS 目录和/catalog/v2/illustration/{uuid}使用);若文件损坏则跳过并记录错误日志;rebuildFromDisk():扫描资料库目录下的所有.zim文件并整体重建清单。这正是「把 ZIM 复制进/opt/project-nomad/storage/zim后重新生成 XML」这一动作的官方实现——插件脚本重启容器后,清单中就会出现新书;ensureLibraryXmlHealthy():启动时的安全网。如果kiwix-library.xml缺失或损坏(例如写入被中断、文件被误删),会自动从磁盘上的 ZIM 文件重建,避免 Kiwix 拿着坏清单启动后「无书可服务」且无法自愈。清单文件通过临时文件 +rename原子写入,就是为了防这种半截文件;- 幂等保护:
addBook会先检查<book>的path是否已存在,已存在则跳过,所以插件脚本重复执行--deploy不会造成重复条目。
排障边界:谁的问题找谁
文档 A Note on Support 明确了支持边界,结合上述机制可以这样定位故障:
- 插件侧问题(install.sh 报错、源下载失败、ZIM 内容缺失/错乱):到插件自己的仓库开 issue;
- NOMAD 侧问题(例如:ZIM 已经在
/opt/project-nomad/storage/zim里、kiwix-library.xml里也有对应<book>记录,但 Information Library 就是不显示):这是 NOMAD 可以协助排查的范围。此时应优先检查:容器是否真的重启过、kiwix-serve是否仍在以--library ... --monitorLibrary启动、清单文件是否因异常写入而损坏(可参考rebuildFromDisk的重建逻辑手动重建)。
小结
社区 ZIM 内容包扩展 NOMAD 的方式非常克制:不改容器启动参数、不动 NOMAD 代码,只在 /opt/project-nomad/storage/zim 目录和 kiwix-library.xml 清单上「追加一本书」,再借助 --monitorLibrary 与容器重启让 Kiwix 生效。这套机制由 KiwixLibraryService 在 NOMAD 内部统一维护(元数据读取、原子写、损坏自愈),因此第三方插件只需按「构建 → 落盘 → 注册 → 重启」四步走即可可靠接入;而第三方内容的质量与 bug 则由插件作者自行负责。
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 StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00