StackTraces
Ollama从零跑通

从零跑通 Ollama + Qwen3 本地对话:5 步,外加 4 个容易卡住的地方

@debug_master2026-09-28

跟着这篇走完,你会在本机把 Qwen3 跑起来:先用命令行聊一轮,再用 HTTP 接口发起一次带上下文的多轮会话。整个过程 5 步,每步都有一条命令能验证自己做对了没有。文中出现的 localhost:11434 是 Ollama 的默认监听地址,模型固定用 qwen3:8b;如果你换了端口或换了 tag,把示例值替换掉即可。

前置条件

项 要求 说明
Ollama 0.34.4 或更高 本文按 0.34.4 写,它是 2026-09 的最新稳定版;0.40.0 仍是预发布版,不要用
磁盘 6 GB 以上空闲 qwen3:8b 的权重文件 5.2 GB,另需一点空间放运行时文件
内存 8 GB 以上 8B 模型按默认 Q4_K_M 量化后约 5 GB 常驻,统一内存或显存都能兜住
网络 能访问 ollama.com 只在首次拉模型时需要下载 5.2 GB,之后可以完全离线运行

装完或升级后先跑这条确认版本。

ollama --version

看到 ollama version is 0.34.4 就是对的。Windows 上有些版本只回显一行版本号字符串,内容一致即可;命令直接报 command not found 说明没装成功,回到第一步。版本低于 0.34 时 ollama ps 和 thinking 相关参数的行为会和本文不一致,建议先升级再往下走。

第一步:安装并启动 Ollama

macOS 和 Linux 用同一条安装脚本,Windows 用 PowerShell 的对应版本。不想跑脚本的话,官方下载页 上有各平台的图形安装包,装出来是同一个东西。

# macOS / Linux
curl -fsSL https://ollama.com/install.sh | sh
# Windows(PowerShell)
irm https://ollama.com/install.ps1 | iex

装完之后 macOS 和 Windows 上 Ollama 会常驻菜单栏并自动拉起服务,Linux 上安装脚本会注册 systemd 服务并立即启动。这一步不需要手动执行 ollama serve,只有 Docker 或纯命令行环境才需要自己起进程。

验证服务是否已经在监听默认端口。

curl http://localhost:11434/api/version

返回 {"version":"0.34.4"} 说明服务在跑,可以直接进入下一步。返回 curl: (7) Failed to connect to localhost port 11434 是服务没起或没绑在这个地址上,先看 Ollama 进程在不在,再看是不是被 OLLAMA_HOST 改到了别的地址。

第二步:拉取 qwen3:8b

Ollama 的模型不会随安装包一起下发,要单独 pull 到本地。qwen3 是仓库名,8b 是规格 tag,写全了才能避开歧义。

ollama pull qwen3:8b

下载 5.2 GB,速度取决于网络。qwen3 仓库里还有更小和更大的规格,按机器内存挑一档(完整 tag 列表见 qwen3 模型库页):

tag 下载体积 上下文 适合
qwen3:1.7b 1.4 GB 40K 只验证链路,不追求效果
qwen3:4b 2.5 GB 256K 8 GB 内存以下的机器
qwen3:8b 5.2 GB 40K 本文用的档位,16 GB 内存机器跑得舒服
qwen3:14b 9.3 GB 40K 32 GB 内存以上

验证模型是否真的落到本地。

ollama list

输出里出现一行 qwen3:8b、SIZE 列显示 5.2 GB,就算拉好了。列表里没有它,说明前面的 pull 中途失败,重跑一次 ollama pull qwen3:8b 会断点续传。

第三步:用命令行完成一次会话

ollama run 会拉起模型并进入交互提示符,这是最快确认「模型到底能不能答」的方式。

ollama run qwen3:8b

首次执行需要把权重加载进内存,会等几秒到几十秒。加载完出现 >>> 提示符,直接敲问题回车即可。Qwen3 默认开启 thinking,你会先看到一段推理过程,再看到正式回答。聊完输入 /bye 退出。

会话变长以后如果发现模型开始忘掉前面的内容,是默认上下文只有 4096 token 被塞满了。可以在会话里临时抬高。

>>> /set parameter num_ctx 8192

这个设置只对当前会话生效。想改所有会话的默认值,用环境变量起服务:OLLAMA_CONTEXT_LENGTH=8192 ollama serve。

验证。

在 >>> 下输入 用一句话解释什么是栈溢出,能看到先出一段 thinking 再给出答案;输入 /bye 能干净退出回到 shell,这一步就算成了。如果一直停在 pulling manifest,那是网络没通,不是模型问题。

第四步:用 REST API 发一次请求

Ollama 服务同时暴露了一套 HTTP 接口,端口就是刚才验证过的 11434。先发一条单轮请求确认接口通不通。

curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [
    { "role": "user", "content": "用一句话说明 /api/chat 和 /api/generate 的区别" }
  ],
  "stream": false
}'

stream 默认是 true,会把响应切成一行一个 JSON 分片推回来。这里显式写成 false,一次拿到完整 JSON,便于确认链路。想看流式效果就把它打开,同时给 curl 加上 -N 关掉输出缓冲。

curl -N http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [{ "role": "user", "content": "从 1 数到 5" }],
  "stream": true
}'

验证。

拿第一个请求的返回体,同时满足三条就算通了:"done": true、message.content 非空、eval_count 大于 0。eval_count 是这次实际生成的 token 数,它是 0 就说明模型没产出内容,通常是模型名写错或显存不够导致加载失败。total_duration 和 eval_duration 单位都是纳秒,顺手除一下能得到每秒 token 数。

第五步:把会话接下去

/api/chat 是无状态的,它不记得你上一次请求过什么。所谓多轮会话,就是每轮都把历史消息按顺序拼进 messages 再发一遍。下面这条把第一轮的问和答都带了进去。

curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [
    { "role": "user", "content": "我叫阿禾,在做支付网关的限流。" },
    { "role": "assistant", "content": "<上一轮真实的回答原文>" },
    { "role": "user", "content": "我刚才说我在做什么?" }
  ],
  "stream": false
}'

第二条 assistant 消息要填上一轮返回的 message.content 原文,不能自己编一句。这一段就是你以后写客户端时要维护的会话状态:一个按 role 和 content 累积的数组,越聊越长,直到撞上 num_ctx 上限再考虑截断或摘要。

验证。

返回的 message.content 里出现「支付网关」或「限流」,说明上下文真的被带进去了。如果答非所问,先检查 messages 数组里有没有漏掉 assistant 那一条——只塞 user 消息等于把上一轮的答案抹掉,模型自然接不上话。

核心概念

概念 是什么 类比
Ollama 把权重文件、运行参数和推理引擎(llama.cpp / MLX)打包成本地常驻服务的运行时 像本地的数据库服务,装好就有一个进程守在 11434 端口
模型 tag 仓库名:规格 形式的模型标识,如 qwen3:8b、qwen3:4b 像镜像 tag,同一个仓库下不同规格
量化 把权重压到 4 bit 左右再存,默认 Q4_K_M,体积能小到三分之一上下 像给图片降码率,体积大降、质量损失有限
num_ctx 一次请求能看到的 token 上限,默认 4096,超出的历史会被截掉 相当于工作台面积,放不下的材料只能推到地上
/api/chat 无状态的对话接口,历史会话完全由调用方自己拼 和 HTTP 一样天然无状态,服务端不替你记 session

常见问题

curl: (7) Failed to connect to localhost port 11434

现象:命令行 curl 或客户端都连不上 11434,报 Connection refused,不是超时。

原因:Ollama 服务没起来,或者只绑在别的地址上(容器里最常见,容器内的 localhost 不是宿主机)。

相关文章:Spring AI 接 Ollama 报 Connection refused

model "qwen3:9b" not found, try pulling it first

现象:请求发出去了,Ollama 回一句 model not found 并让你先 pull。

原因:服务是通的,只是本地库里没有这个名字——tag 写错、规格不存在,或者压根没拉过。

相关文章:Spring AI 接 Ollama 报 model not found

多轮对话到后面报 400,或者模型开始忘掉开头的内容

现象:前几轮正常,聊长了以后要么被服务端拒绝,要么回答里丢掉早先的设定。

原因:历史消息越堆越长,撞上了 num_ctx;默认 4096,条数没超但 token 早就爆了。

相关文章:Spring AI 报 400 context_length_exceeded

Java 客户端里模型名写错,抛的是 NullPointerException

现象:服务端明明只是「没这个模型」,客户端栈里却是 NPE,连模型名都不提。

原因:Ollama 对不存在的模型返回 404、响应体为空,客户端解析空响应体时炸在 HTTP 层。

相关文章:LangChain4j Ollama 模型名写错抛 NullPointerException

下一步

把本地模型接进 Spring Boot

qwen3:8b 拉好之后,服务端只要把 Ollama starter 的 base-url 指到 11434 就能用,装配不上多半是 starter 没引或模型名拼错。

Spring AI 报 No qualifying bean of type ChatModel

改成流式输出

把 stream 打开只是第一步,接进 Web 层还要处理 SSE 的连接生命周期和超时。

Spring AI 流式输出:stream 与 SseEmitter

管好长会话的上下文

会话越长越要主动截断或摘要,别等报 400 才回头加。

Spring AI 报 400 context_length_exceeded

卡在哪一步了?

从零跑通的过程中撞到报错?把命令和输出记下来,帮助下一个刚起步的人。

贡献一条解法