一条命令启动本地离线 AI 聊天
MIT 开源项目 Unmuzzled 可通过 npx 启动浏览器聊天界面,基于 llama.cpp 在本机运行 GGUF 模型,聊天记录仅保存在浏览器。支持硬件加速、流式输出和模型下载断点续传,示例笔记本实际生成速度为 1.7 token/s。
AI 深度解读
Unmuzzled 想把本地 AI 聊天的门槛压到一条命令:运行 npx unmuzzled,打开浏览器,下载模型,然后在自己的设备上聊天。作者的结论很明确:离线和隐私可以做成开箱即用,但速度仍由硬件决定。
这篇最有参考价值的,是作者如何把模型下载、流式输出、本地服务安全和 Android 适配拼成一个完整产品,以及哪些地方并没有想象中省事。
一条命令省掉了什么,又没省掉什么
Unmuzzled 以 MIT 协议开源。桌面端不要求安装 Python、Docker,也不用手写配置文件。首次启动会展示模型、文件大小、机器内存和剩余磁盘,用户点击 Download 后才开始下载,支持暂停和续传。
下面两条命令分别解决默认启动和使用自备模型的问题:
npx unmuzzled # setup screen, then chat
npx unmuzzled --model ./model.gguf # bring your own model
留意第二行的 --model:默认模型只是入口,应用也支持加载其他 GGUF 模型。
推理由 node-llama-cpp 调用 llama.cpp,硬件允许时使用 Vulkan、CUDA 或 Metal。一次性下载完成后,应用可以在飞行模式下工作,没有账号和遥测;聊天记录只存在浏览器中,并提供编辑、重新生成和历史搜索。
这里的「没有服务器」指不依赖远端服务。桌面版仍会启动本机 HTTP 服务,供浏览器界面调用。
默认模型是 9B,来源链条需要认真看:
- 基础模型是 Qwen3.5-9B。
- Jackrong/DeepSeek-V4-Pro-Qwen3.5-9B 使用 DeepSeek-V4-Pro 生成的约 25 万条推理样本微调。
- xtools-at/…-UNCENSORED-heretic 通过 Heretic 移除拒答行为。
- mradermacher/…-i1-GGUF 再将模型量化为 Q4_K_M,文件大小为 5.63 GB。
作者称这些环节均采用 Apache-2.0 协议,权重直接从 Hugging Face 下载,Unmuzzled 不重新分发。原文后两项使用了省略名称,没有给出完整标识。
名称里有 DeepSeek,不代表运行的是 DeepSeek 原版模型。
它仍是一个小型 Qwen 模型,学习了 DeepSeek 的推理风格。移除拒答行为也不等于提高准确率。作者提醒它仍可能自信地答错,同时允许用户换用保留安全训练的模型。
流式聊天不复杂,本地服务的边界更容易漏
桌面端没有框架,也没有构建步骤:bin/unmuzzled.js 负责 CLI、初始化和下载;src/server.js 提供 HTTP、静态文件与聊天接口;src/engine.js 封装推理;src/models.js 管理模型和续传;public/ 使用普通 HTML、CSS 和 ES modules。
浏览器把对话 POST 到 /api/chat,服务端通过 Server-Sent Events(SSE)依次发送思考片段、正文片段,最后以 done 事件返回 token 数和 tokens/second。
这里更值得借鉴的是流式解析。node-llama-cpp 能把部分模型的推理内容分段;模板不支持时,作者用小型状态机识别 <think>…</think>。标签可能被拆到不同数据块里,因此不能只在每个 chunk 内做一次字符串替换。
界面也为离线运行做了配套:IBM Plex Sans 和 Mono 字体从本地加载,回答支持 Markdown 与代码高亮,思考过程放进可折叠、带计时的面板。模型输出按不可信内容处理,原始 HTML 会被转义,远程图片不会被请求。
更关键的问题出在 127.0.0.1。网页虽然运行在远端站点,仍可能尝试访问用户的本地服务。作者处理了两类攻击:
一类是类似 CSRF 的请求。恶意页面可以发送 text/plain POST,绕过 CORS 预检。Unmuzzled 要求 application/json,让跨域请求触发预检,而服务端不批准预检。
另一类是 DNS rebinding:恶意域名在页面加载后改为解析到本机地址,让浏览器把本地服务视为同源。应用因此检查 Host,拒绝不属于本地名称的请求。初始化接口也应用相同防护,避免网页擅自触发约 5 GB 的下载。
部署在 localhost,只改变了访问位置,没有自动消除网页带来的攻击入口。
离线已经跑通,速度和手机适配仍有成本
作者给出的实测机器是 Intel i5-1135G7、Iris Xe 集成显卡、Vulkan 和 16 GB RAM。9B 模型加载约需 40–50 秒,生成速度约为每秒 2 tokens,多次运行范围为 1.7–2.7 tokens/second。
这张演示图加速了 8 倍,末尾展示的真实速度是 1.7 tok/s。推理模型还要先生成思考内容,正文出现得更晚。作者称独立显卡和 Apple Silicon Mac 会快很多,但没有提供对应设备的对照测试。
Android beta 同样在手机上运行模型,不依赖电脑转发。应用会检查内存和存储,默认 9B 模型约需 12 GB RAM;下载界面标注约 5.6 GB,提供进度、速度、剩余时间、暂停和恢复,离开应用后也能保留进度。用户还可以从手机存储导入 .gguf 文件,用 Think 开关选择深度推理或即时回答。
移动端采用 React Native(Expo)和 llama.rn,包含针对 ARM 的 dotprod/i8mm 优化,并支持在 Adreno GPU 上选择 OpenCL 卸载。
作者在 Windows 构建时遇到的坑也很具体:IPv6 网络故障导致 Gradle 下载失败,需要强制 Java 使用 IPv4;Markdown 库依赖 Node 内置 punycode,需要安装独立包;Windows 的 260 字符路径限制,又撞上最长 297 字符的生成 C++ 路径和不支持长路径的 Ninja 1.10。最后一个问题通过替换依赖解决,替代品是读取系统栏边距的 30 行 Kotlin 模块。
APK 通过 GitHub Releases 分发。作者将未上 Google Play 归因于其 AI 内容政策,原文没有提供具体审核记录。
我的判断
这个项目最有价值的部分,是把「能跑模型」推进到了「普通用户能开始用」:先检查资源、下载前确认、断点续传,再把推理等待和真实速度展示出来。对做 Node 工具或本地 AI 客户端的人,这些细节比再包一层聊天界面更有用。
但一条命令解决的是安装流程,无法降低模型的内存需求和计算成本。作者只给出一台笔记本的性能记录,没有同硬件下其他工具、其他模型的对照,也没有回答质量评测。它是否更快、更好用,目前只能视为作者的产品经验,不能据此下普遍结论。
默认移除拒答的模型也值得单独评估。拒答减少和任务完成质量是两项指标,原文没有证明前者能提升日常编程效果。既然可以替换 GGUF,选择模型时就应围绕自己的任务验证。
安全部分则是很实用的提醒,但原文列出的两项防护不等于完整安全审计。可以借鉴它们处理的具体入口,不宜把介绍文章当成全面安全保证。
能拿来做什么
- 开发 Node 本地服务时,把聊天、下载和初始化接口一起检查,明确 Content-Type、CORS 预检和
Host的处理规则。 - 实现 AI 流式界面时,用状态机处理跨 chunk 的标签,并对 Markdown 中的原始 HTML 和远程图片制定明确策略。
- 试用本地模型时,分别记录加载时间、生成速度和正文等待时间,用自己的硬件与真实任务判断是否可用。
- 把 Node 相关能力迁到 React Native 前,提前检查依赖里的内置模块和原生构建要求,避免只验证 JavaScript 部分就判断迁移完成。