一台没有独立显卡的机器,我想在上面跑一个语言模型,并且让局域网里的其他设备也能调用它。

装的部分没什么好说的,一条命令就结束了。麻烦的地方在"跑起来"之后: 它默认只肯跟自己说话,而我看不出它到底是用什么在算、为什么第一次响应要等那么久。

这篇记的是那之后的四件事:让它对外说话、确认它在跑、看懂它在用什么算、以及把那 7 秒钟拆开。

01第一件事:让它监听所有网卡

默认情况下,服务只绑定在 127.0.0.1——也就是"只有本机能连"。 这台机器上跑得好好的,我在笔记本上 curl 它就是连不上。

后台启动并监听所有网卡
nohup env OLLAMA_HOST=0.0.0.0:11434 ollama serve >> /var/log/ollama.log 2>&1 &

这一行里有四个东西,缺一个都会出问题:

  • nohup —— 让进程脱离终端。不加它,你断开 SSH 的那一刻服务就没了。
  • env OLLAMA_HOST=0.0.0.0:11434 —— 把监听地址改成所有网卡0.0.0.0 不是某个具体地址,它的意思是"接受来自任何网卡的连接"。 这是它的默认值 127.0.0.1 的反面。
  • >> /var/log/ollama.log 2>&1 —— 标准输出和错误都追加到日志文件。 2>&1 是必须的,否则错误信息会被丢掉—— 而排查问题时,你要找的恰恰是错误信息。
  • 末尾的 & —— 放后台,让终端立刻还给你。

02第二件事:用三个动作确认它活着

确认
# 1. 进程在不在
    ps aux | grep ollama

    # 2. 日志里最后几行说了什么
    tail -n 5 /var/log/ollama.log

    # 3. 接口通不通(注意用局域网地址,不是 localhost)
    curl http://192.168.1.3:11434/api/generate \
      -d '{"model":"llama3.2","prompt":"Hi","stream":false}'

第三个动作有个容易做错的地方:测试要用局域网 IP,不能用 localhost。 在 localhost 上测通,只证明"它自己认识自己", 完全不能说明外部能不能连上。

03第三件事:它在用什么算

启动日志把硬件情况交代得很清楚:

/var/log/ollama.log
level=INFO msg="discovering available GPUs..."
    level=INFO msg="model list cache hydration complete" models=1 failures=0 elapsed=10.330729ms
    level=INFO msg="inference compute" id=cpu library=cpu name=cpu total="10.9 GiB" available="6.3 GiB"
    level=INFO msg="vram-based default context" total_vram="0 B" default_num_ctx=4096

逐行读:

  • 第一行说它在找 GPU。后面没有出现任何 GPU 的名字, 而 inference compute 那行里 id=cpulibrary=cpu—— 意思很明确:这台机器上没有它能用的加速设备,全部落到 CPU 上算
  • total="10.9 GiB" available="6.3 GiB" 是内存的账。 这是最关键的一行:模型必须装进 6.3 GiB 这个可用额度里, 而不是标称的 10.9。已经跑着别的服务时,这个数会更小。
  • total_vram="0 B" + default_num_ctx=4096 说明因为显存为零, 上下文长度被按 CPU 的默认值设成了 4096 个 token。想让它记住更长的对话,得手动调—— 代价是内存占用同步上升。

04第四件事:那 7 秒花在哪了

上面那条 curl 第一次跑完,返回的 JSON 里带着一组 duration 字段。 它们都是以纳秒为单位的整数,我把它换算成秒排了一遍:

字段纳秒占比
load_duration6 089 822 3416.09 s85.3%
prompt_eval_duration522 756 0000.52 s7.3%
eval_duration510 453 0000.51 s7.2%
total_duration7 134 792 1857.13 s100%

7.13 秒里,6.09 秒花在"把模型加载进内存"上,真正算的部分只占了 1 秒。

而且这 1 秒还能再拆:prompt_eval 是处理我那句 "Hi" 的时间(0.52 秒), eval 是生成回答的时间(0.51 秒)。生成的量是 eval_count: 8—— 八个 token。

算一下出词速度
8 token ÷ 0.51 s ≈ 15.7 token/s

15.7 token/秒,纯 CPU。这个速度用于生成短句是可以接受的—— 它大概相当于人快速阅读的速度,等一两秒出半句话,感觉不算煎熬。 但用来写长文就会很难受:一千个 token 要等一分多钟。

更重要的是那个 6.09 秒。它不代表这台机器算得慢, 它代表"模型还没进内存"。所以同一台机器上第二次问同样的问题, 只要模型还在内存里,响应会明显快得多——因为最大的一块开销被跳过了。

这也是为什么"用同一句话前后测两次"这件事很重要: 第一次的数字看着吓人,但它测的是加载,不是推理。

05停掉它

停止与确认
pkill -f "ollama serve"
    ps aux | grep "ollama serve" | grep -v grep

-f 让 pkill 匹配完整的命令行而不只是进程名, 这样能准确命中带参数启动的那个进程。 第二行的 grep -v grep 是把它自己的搜索进程过滤掉, 否则你永远会看到"似乎还有一个在跑"。

这台机器上跑着模型、Agent、还有别的服务,内存的 available 是共享的。 所以"能不能跑某个模型"这个问题,答案不取决于模型有多大, 而取决于此刻还剩多少可用内存——它每天都不一样。

06留下四个可以带走的东西

  1. 本地服务要对外,先看它绑在哪。 127.0.0.10.0.0.0 只差几个字符,一个只能自己用,一个全网可达。
  2. 测连通性要用真实 IP,不要用 localhost。 这两个测试回答的是不同的问题。
  3. available 才是能用的内存,不是 total 决定模型能不能加载的是前者,而且它随时在变。
  4. 看耗时不要只看总数,要拆开。 加载、处理输入、生成输出是三笔独立的账。 混在一起看,你会误以为"这台机器算得慢",而实际上它只是"还没醒"。
关于本文
整理自 2026 年 8 月 31 日的便签记录。日志与 JSON 返回值为当时的真实输出, 机器为无独立显卡的 aarch64 设备(可用内存 6.3 GiB)。
2026.09.20 整理
新增第 04 节。原始便签里只是把启动命令和几条验证命令罗列在一起, 没有解释那些 duration 字段——而它们才是"为什么第一次这么慢"的答案。