这台服务器上的六个应用都在使用人工智能,而且任何地方都没有云端密钥。这是它们的实时流量数据:每一行响应状态码均为 200,耗时分别为 2.31、2.1 和 1.84 秒。它们都调用同一个端口,即 11434。OpenAI 密钥未设置,模型为 Qwen 2.5 7B,地址是 localhost:11434。Ollama 日志显示有六个聊天请求,每一个都是状态码 200,耗时在 1.47 到 3.92 秒之间。

地址与回环接口匹配,其中 .1 是 Home Assistant,而 .2 到 .6 分别是 Open Web UI、n8n、Paperless AI、Care Key 和 Mealie。这加起来意味着在过去 24 小时内服务了 1,412 个请求。在此之前,云端人工智能让我花费巨大:n8n 智能体耗费 1680,Open Web UI 耗费 1240,Paperless 耗费 890,Home Assistant 耗费 510,Care Key 耗费 4260,Mealie 耗费 120。

那相当于每月 47 美元。一年下来,这六个副项目的总费用是 564 美元。而我十月份的 API 支出为 0 美元。唯一的额外成本是电力,在 730 小时内增加了 34 瓦的功耗,共计 24.8 千瓦时。按每千瓦时 16 美分计算,这相当于 3.97 美元。

这将我的月度成本削减了 92%。整个架构可以浓缩为一行字:六个应用访问端口 11434,Ollama 服务在 RTX 3060 上运行 Qwen 2.5 7B。五个应用位于 Docker 网桥上,一个在主机网络上,它们共享同一个模型。

一个模型、一个端口、一处排查故障的地方。这台主机配备 Ryzen 7 5700G 处理器,RTX 3060(12GB 显存),64GB DDR4 内存,2TB NVMe 固态硬盘以及 Ubuntu 24.04。12GB 显存是最关键的数字。

在空闲状态下,整台主机的功耗为 28W。Ollama 只是一个 HTTP 服务器:请求进入,模型加载到 GPU,生成令牌,然后以 JSON 流形式返回。它暴露了聊天、生成和嵌入(用于向量)功能,提供列出模型的标签接口,以及一个兼容 OpenAI 的 V1 路径。

没有身份验证,没有 TLS,只有纯 JSON。官方安装脚本会创建 Ollama 系统用户,安装 Ollama 服务并检测 Nvidia 驱动。从运行脚本到收到第一次回复仅用了 3 分钟。服务显示为活动且正在运行,开机自启,并检测到 CUDA。

TCP 上的端口 11434 是默认的 Ollama 端口,这也是整个契约的核心。默认情况下,它绑定到 127.0.0.1,使用纯 HTTP,没有身份验证,你可以通过设置 Ollama host 来更改这一点。任何能访问此端口的应用都会获得相同的模型。

在接触任何应用之前,我通过 curl 访问 localhost 的 11434 端口,它回复“Ollama is running”。然后标签端点以 JSON 格式返回模型列表。回环上的往返时间仅为 3 毫秒。我在 Qwen 2.5 7B 上运行的第一个测试提示词,速度达到了每秒 58 个令牌。

我拉取了一个模型,终端从获取清单变为成功。Qwen 2.5 7B 在磁盘上占用 4.7GB,采用 Q4KM 量化,拥有 76 亿参数和原生 32,768 令牌的上下文窗口。它支持工具调用,返回干净的 JSON,并且能装入 12GB 显存中。

在原始速度方面,Mistral 7B 达到每秒 61 个令牌,Qwen 为 58,Llama 3.1 8B 为 52,Gemma 2 9B 为 39。但在有效 JSON 输出方面,Qwen 以 98% 领先,Gemma 为 94%,Llama 为 90%,而 Mistral 仅为 82%。每个模型都接受了相同的 50 个 Paperless 测试文档。

Qwen 2.5 指的是最新标签,7B 标签是精确匹配且有效。14B 从未被拉取,因此会失败,漂亮的显示名称也会失效。Ollama 返回 404:模型 Qwen 2.5 14B 未找到。请先拉取它。从 Ollama list 复制名称,永远不要手动输入。

设置其中一个变量为 Ollama host,因为在第一天,我的六个应用中有五个失败了。默认绑定是 127.0.0.1,端口 11434,仅从本机可达,因此 Docker 容器会被拒绝。在第一次测试运行时,N8N 明确提示连接被 ECONNREFUSED(连接拒绝)。

在 N8N 容器内部,localhost 是它自己的回环接口。那里没有任何东西监听 11434 端口,所以调用被拒绝。Home Assistant 运行在主机网络上,因此它的 localhost 就是宿主机,这就是为什么它能正常工作。五个桥接应用失败,一个主机网络应用成功。

修复方法是执行 sudo systemctl edit ollama,在 service 部分添加一行配置,然后 daemon-reload 并重启 Ollama。这一行将 ollama host 设置为 0.0.0.0,端口为 11434,通过 systemd 覆盖配置确保更新后依然有效。

一行配置修复了五个应用。为了检查,我运行 ss 并 grep 查找 11434。之前它监听在 127.0.0.1,之后显示 11434 端口有一个星号,意味着监听所有接口。重启后,100% 的应用都连接成功。

0.0.0.0 意味着任何人都可以请求,而 Ollama 要求零密码。因此我的防火墙允许 Docker 子网(172.16/12)和我的家庭局域网(192.168.1/24)。其他所有人在 11434 端口都被拒绝,路由器也不转发任何流量。Ollama 没有 API 密钥,所以防火墙就是 API 密钥。

主机网络应用拨号 localhost。桥接应用拨号 172.17.0.1。Docker 也可以使用主机网关别名,另一台机器则拨号 192.168.1.20,所有这些都使用端口 11434。这个 172 地址是 Docker0,所以永远不要在 Docker 内部使用 localhost。

三个地址涵盖了所有情况。Open Web UI 只需要一个变量,将 Ollama base URL 设置为 172.17.0.1、端口 11434,并将 OpenAI key 留空。它在首次加载时就找到了 Qwen 2.5 7B,即那一个模型。现在,浏览器聊天通过 Open Web UI 发送到端口 11434,回复随即流式返回。

在 n8n 中,Webhook 喂给 AI 智能体,现在它使用 Ollama chat model node,结果发送到 Slack。凭证是 Ollama API。基础 URL 是 172.17.0.1,端口 11434,模型是 Qwen 2.5 7B。这意味着每天 340 次工作流运行现在免费了。

Home Assistant 使用 Ollama 集成,地址为 localhost:11434,模型 Qwen 2.5 7B,并启用了 Assist API。从唤醒词到 spoken answer(语音回答)仅需 1.9 秒。云端 API 耗时 2.6 秒,所以本地实际上更快。

在 Paperless AI 中,扫描到达后,OCR 文本发送给 Qwen,然后返回标签和标题。提供商是 Ollama,API URL 为 172.17.0.1、端口 11434,模型是 Qwen 2.5 7B。1,240 份文档被标记,没有一次云端调用。

Care Key(注:原文为 Care Key,结合上下文可能是指某款应用)的基础 URL 指向 172.17.0.1,端口 11434,使用 Qwen 2.5 7B 作为文本模型。记住那个上下文长度行,因为它稍后会再次出现。860 个书签被标记和摘要总结:自动标签、摘要,且无需 OpenAI 密钥。

Mealie 只支持 Open AI。因此,它的基础 URL 指向同一主机的 V1 路径。密钥字段为单词“Ollama”,模型是 Qwen 2.5 7B。密钥字段不能为空,所以填“Ollama”即可,因为没有任何东西会检查它。212 份食谱被导入并在本地解析。

任何基于 Open AI SDK 构建的应用都可以这样做。将其基础 URL 指向 V1 路径,Ollama 就会提供 Qwen。将基础 URL 设置为端口 11434,路径为 V1。使用任何非空的 API 密钥,并将模型设置为 Qwen 2.5 7B。

聊天补全、嵌入和工具调用均有效。Journal CTL 在 Ollama 单元上实时流式传输每个请求:2.10、84 和 3.92 秒。Paperless AI 以 410 个请求领先,然后是 n8n 的 340 个,Home Assistant 290 个。

Open Web UI 205,Karabiner 120,以及 Mealie 47。这些请求的百分之百都留在这台机器上。设置二是上下文窗口,默认值为 4,096 个令牌(tokens)。我的 Paperless 提示词平均长度为 9,800 个令牌,是默认值的两倍以上。没有错误,也没有警告,它只是忘记了提示词的开头部分。9,800 个令牌进入 4,096 令牌的窗口,顶部的内容被丢弃,导致标签输出错误且没有任何报错。唯一的痕迹是 Ollama 日志中的一个警告:“截断输入提示词限制,4,096 提示词长度 9,812,保留四个”。

正确的标签准确率从上下文为 4K 时的 61% 提升到了 16K 时的 94%。回到伪系统 CTL 编辑 Ollama,我在服务部分下添加第二行并重启服务。上下文长度变量设置为 16,384,位于 Ollama 主机地址 0.0.0.0:11434。这适用于每个应用和每次调用。但有一个例外,单次请求的 num_ctx 设置优先级更高,所以也要检查应用设置,或者通过模型文件将其固化。从 Qwen 2.57B 开始,参数 num_ctx 设为 16,384,然后使用 Ollama create Qwen 16K。

Qwen 16K 在磁盘上增加的空间为 0 GB,因为它与具有 16,384 个令牌上下文的模型共享相同的权重。名称体现了设置,且能抵御应用更新的影响。上下文并非免费午餐:4K 使用 5.2 GB,8K 为 5.7 GB,16K 为 6.6 GB,32K 则为 8.4 GB。在 16K 下,这占用了我的 12 GB VRAM 的 55%。剩下的 5.4 GB 空间用于并行请求。

为了证明这一点,我展示了 Ollama 的 Qwen 2.57B 在上下文为 16,384 时占用 GPU 的 6.6 GB。GPU 使用率为 100%,没有溢出到 CPU。在不到 7 GB 的占用下,CPU 未分担任何负载。额外提示:默认情况下,Ollama 会在空闲 5 分钟后卸载模型。冷启动需要 6.8 秒,而热模型只需 0.4 秒即可响应。因此我将 keep_alive(保持活跃时间)设置为 24 小时,它占用 6.6 GB VRAM。对于语音处理来说,这是值得的。

当六个应用同时调用时,它们的请求进入队列,分配到单个 GPU 上的两个并行槽位。每个槽位使用 16,384 个令牌,共占用 7.5 GB(总计 12 GB)。最多可有 512 个请求在队列中等待。在实际负载下,一个请求的处理速度为每秒 58 个令牌,两个同时运行则各得每秒 47 个。这意味着在两个槽位上总共达到每秒 94 个令牌的速度。峰值时,GPU 利用率高达 91%。

该机器空闲功耗为 28 W,加载模型时为 39 W,生成内容时高达 165 W。24 小时平均额外功耗为 34 W,即每月约 24.8 kWh,电费约为 4 美元。三个错误让我浪费了一个晚上。首先,我输入了 llama 3 而不是正确的标签,导致 N8N 抛出 404 错误,花了 20 分钟才找到原因。

然后我直接编辑了 unit 文件,更新后覆盖了它,导致五个应用再次出错。我还误信了默认上下文设置,致使 Paperless 的标签错误持续了一周。这三者加起来耗费了我 3 小时。“连接被拒绝”意味着将 Ollama host 设置为 0.0.0.0。“模型未找到”意味着拉取确切的标签,“忽略长输入”则意味着提高 num_ctx。

首次回复慢需要设置 keep_alive 为 24 小时,负载下速度慢则需要两个并行槽位。无论哪里出错,先用 journalctl 查看 Ollama unit 的日志。在 12 个月内,云 API 的费用将是 564 美元,而本地方案是一台二手 RTX 3060(24 W)加上电费 48 美元,第一年总计 288 美元。第二年本地成本仅为 48 美元,远低于云服务的 564 美元。GPU 在六个月内就收回了成本。

本地方案在处理长步数多步骤推理时仍显不足,例如在大型代码重构中 7B 模型容易偏离方向,此时我仍会手动使用云模型。此外,超过 16K 令牌的文档也处理不了。本地方案能处理好那枯燥的、昂贵的 95% 的工作量,即我 95% 的 AI 调用都能在本地正常运行。作为额外好处,我的数据没有一字节发送给外部 AI 提供商。

扫描的税务表格通过 Ollama(端口 11434)进入 Paperless AI,并保留在本地磁盘。银行 PDF、语音命令和私人笔记也是如此。五个步骤:安装 Ollama 并检查端口 11434,拉取 Qwen 2.5 7B(原文误拼为 quent),将 Ollama host 设置为 0.0.0.0,将上下文提升至 16,384,并将端口防火墙限制在局域网和 Docker。从 Docker 内部访问时,拨打 172.17.0.1:11434。

如果你今天开始设置,整个过程只需 20 分钟。我这个月的云 AI 账单是 0 美元。端口 11434,Qwen 2.5 7B(原文误拼为 quent),Ollama host 设为 0.0.0.0,以及 num_ctx 为 16,384。如果这个端点、端口和这两个关键设置帮你避免了头痛,请点赞并订阅。你会首先将哪个应用指向你的本地 Ollama 模型?请在评论区告诉我。如果你更愿意跳过设置过程,我可以在你自己的服务器上为你完成所有操作,详情见描述。