连接重置(Connection reset by peer)在 LangChain 调用本地 Ollama 时,常见于请求已经发出、Ollama 进程因显存耗尽被系统杀掉,或回复超时被客户端断开。显存不足会触发这种表现,但不能只盯显存。建议按“服务端是否还活着 → 模型能否加载 → 请求是否到达 → 显存/并发是否超限”的顺序排查,每一步都有可验证的命令和配置。
先确认连接重置发生在哪一层
先做三件事,把问题范围缩小:
- 服务端是否崩溃:调用后再次执行
curl http://localhost:11434/api/version,如果也连接不上,说明 Ollama 进程已退出或端口不可用。 - 是否请求超时:LangChain 抛出的如果是 timeout 类异常,先看 Ollama 日志里是否还有生成过程;如果服务端仍在计算,只是客户端等不及,属于超时设置问题。
- 是否显存耗尽:在运行 ollama serve 的终端里看是否有 CUDA error: out of memory 或 killed 字样;同时开另一个终端执行
nvidia-smi,观察显存占用是否已满。
连接重置也可能由 Linux OOM killer 杀死进程导致,此时看系统日志(如 dmesg | grep -i oom)会更直接。
用 curl 和最小 LangChain 调用定位问题
先用 curl 直接请求 Ollama,排除 LangChain 层的影响:
curl http://localhost:11434/api/generate \\
-H \"Content-Type: application/json\" \\
-d '{\"model\":\"qwen2.5:7b\",\"prompt\":\"你好\",\"stream\":false}'
如果以上命令也连接重置,问题在 Ollama 服务端或系统层;如果 curl 正常,再检查 LangChain 调用。
用一个最小化脚本复现,不要带链式调用和回调,避免其他逻辑干扰:
from langchain_ollama import ChatOllama
llm = ChatOllama(
model=\"qwen2.5:7b\",
base_url=\"http://localhost:11434\",
timeout=120,
num_ctx=4096,
)
try:
resp = llm.invoke(\"你好\")
print(resp.content)
except Exception as e:
print(type(e).__name__, str(e))
如果当前项目还在用 langchain.llms.Ollama,把导入、调用和参数换成对应写法即可。这个脚本能复现时,再逐步加入流式输出、消息记忆或外部向量库,每加一层测一次。
显存不足时的调整点
如果日志和 nvidia-smi 都指向显存不足,先做两步止血,再根据可用显存调整模型加载参数。
- 减少上下文长度:
num_ctx从 8192 降到 4096,显存占用会明显下降;但需要结合自己的提示词长度确认,不要在长文档任务里盲目调小。 - 限制并发和模型加载:设置
OLLAMA_NUM_PARALLEL=1和OLLAMA_MAX_LOADED_MODELS=1,避免多个请求或模型争抢显存。
也可以把部分层放到 CPU 上:LangChain 的 Ollama 调用中传入 num_gpu=0,或单独给 ollama 传递 num_gpu 参数。这会增加推理延迟,只作为显存不足时的降级方案。
如果确认服务端没有用 systemd 托管,直接这样启动 Ollama:
OLLAMA_NUM_PARALLEL=1 OLLAMA_MAX_LOADED_MODELS=1 ollama serve
如果用了 systemd,需要修改对应服务文件里的 Environment 行再重启服务。
验证清单
排查结束时,按下面清单核对一遍,避免漏项:
- curl /api/generate 已能正常返回文本,连接重置不再出现。
- ollama serve 日志里没有 CUDA OOM 或 killed 记录。
- nvidia-smi 看到的显存占用在模型运行期间没有持续打到 100% 边缘。
- LangChain 脚本的 timeout 设置大于实际推理耗时,而不是刚好多出几秒。
- 在不带流式、不带回调的最小脚本上复测通过后,再逐步加回业务逻辑。
如果这些都过了,连接重置仍随机出现,需要再查系统负载、磁盘 I/O 和网络代理等外部因素。Ollama 的 base_url 写错、局域网防火墙拦截请求,也会表现成连接重置。