☰
OpenClaw接入Ollama本地模型:从OpenAI兼容接口到避坑实践
2026/10/18 16:33:01 网站建设 项目流程

简介:面向需要在本地环境运行大语言模型并接入自动化代理的开发者,OpenClaw 与 Ollama 的集成代码包展示了如何利用 OpenAI 兼容接口打通两者,使支持工具调用的开源模型在离线状态下也可被稳定调用。资源共 3 个文件,由 inscode 配置片段、HTML 交互说明页与 gitignore 工程规则组成,压缩后仅 7KB,但覆盖了从安装 Ollama、拉取模型、启用集成到完成日常调用配置的完整链路。已有 182 人学习,适合具备一定 Python 基础、正在搭建个人知识库或自动化工作流的初中级开发者。包内除入门级接入示例外,还解释了隐式提供商机制如何自动发现具备工具调用能力的模型,并给出显式指定模型、切换推理模型、设置上下文窗口长度等进阶方法;同时整理了一套针对常见连接失败、模型加载异常与响应超时的排错清单,让读者可以零费用在本地复现环境,并安全地扩展到实际项目中。

1. OpenClaw 接 Ollama,卡的从来不是模型,而是应用层认不认本地接口

OpenClaw 接 Ollama 本地模型,最常见的翻车点不在模型选型,而在应用层默认不认本地接口。OpenClaw 这类工具默认把请求发给 OpenAI 兼容的云端地址,而 Ollama 自带 OpenAI 兼容层,两边只差一个 Base URL 的指向。我第一次踩进这个坑是帮某公司做内部工具改造:数据不能出内网,云 API 全被封死,本地 Qwen 模型在 Ollama 里跑得好好的,OpenClaw 却始终调不通。后来把 provider 地址改成 127.0.0.1:11434/v1,整条链路当场打通。这篇适合想把 Ollama 接进现有应用的开发者,也适合正在选型、想看清本地模型成本和边界的人。下面从接口结构、必调参数到排查顺序,把这条路完整铺开。

2. 先摸清双方接口的脾气:OpenClaw 怎么约模型,Ollama 拿什么接招

2.1 OpenClaw 的模型接入路径:OpenAI 兼容协议与自定义回调两条路

OpenClaw 这类应用框架对模型服务的抽象通常叫 provider。常见的做法是提供一个 OpenAI 兼容模式,配置文件里只需要关心三个字段:Base URL、API Key、模型名。这背后的设计直觉是:只要 OpenAI 的 chat/completions 接口格式不变,任何服务都可以“伪装”成 OpenAI 端点,客户端代码一行不用改。Ollama 在较新版本里原生暴露了 /v1/chat/completions 端点,把本地推理包装成了 OpenAI 的请求-响应结构,所以集成时优先走这条路,改动最小。

判断你的 OpenClaw 支不支持这条路,去看配置里有没有 base_url 或 api_base 这类字段。能找到,那集成就是改地址的事。找不到,也别急着放弃,OpenClaw 如果支持自定义 HTTP 回调,你可以在中间架一个极薄的服务,把 OpenClaw 发来的请求转手交给 Ollama。我一般用 FastAPI 写这个转发层,代码很短:

from fastapi import FastAPI, Request import httpx app = FastAPI() OLLAMA_URL = "http://127.0.0.1:11434/v1/chat/completions" @app.post("/v1/chat/completions") async def proxy(request: Request): # OpenClaw 发来的请求体原样转发给 Ollama body = await request.json() async with httpx.AsyncClient(timeout=180) as client: resp = await client.post(OLLAMA_URL, json=body) return resp.json()

这段代码的逻辑很简单:接收 OpenClaw 的 POST 请求,把请求体完整转发给 Ollama,再把 Ollama 的 JSON 原样返回。关键点有两个:第一,转发层必须保留 messages 结构,OpenClaw 靠这个字段传对话历史;第二,超时必须比默认值长,本地推理没有云端那么快,我给的是 180 秒。启动这个服务后,OpenClaw 的 Base URL 指向这个转发层就可以,后续模型切换完全不碰框架代码。

这里有一个值得注意的差别:走 OpenAI 兼容协议时,返回体里的 choices 数组结构不能变;走自定义回调时,框架可能只要求你返回 content 字符串。所以能用 OpenAI 兼容就别碰自定义回调,后者意味着你要自己维护一套字段映射,踩坑成本完全不划算。选型上的结论很直接:先看 OpenClaw 有没有 OpenAI 兼容选项,大概率是有的,直接用。

2.2 Ollama 侧先跑通两个命令:拉模型不是关键,验证接口才是

Ollama 侧的准备比很多人想得简单,但简单不代表不会出错。第一步是拉模型,我常用 qwen2.5:7b-instruct 作为集成验证模型,它的中文能力和工具调用能力在同尺寸里都比较稳。拉模型的命令只有一行:

ollama pull qwen2.5:7b-instruct

拉完别急着配 OpenClaw,先确认服务真的在跑、接口真的能回。很多集成失败都不是配置写错,而是 Ollama 服务压根没起来,或者模型 tag 和配置文件里差一个冒号。我用下面这组命令做验证:

# 确认 Ollama 服务在运行 ollama serve # 查看当前已拉取的模型列表,注意 name 字段要完全一致 curl -s http://127.0.0.1:11434/api/tags | head -n 20 # 直接打 OpenAI 兼容端点,确认请求能通 curl -s http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5:7b-instruct", "messages": [{"role": "user", "content": "用五个字介绍你自己"}], "max_tokens": 32 }'

第一条命令把 Ollama 服务拉起来,如果它是系统服务,这一步会提示已在运行。第二条命令最容易被忽略,/api/tags 返回的 models 数组里每个元素的 name 字段,就是你在 OpenClaw 里要填的模型名,qwen2.5:7b 和 qwen2.5:7b-instruct 是两个不同的 tag,写错一个连不上。第三条命令走的是 OpenAI 兼容端点,看返回的 choices[0].message.content 是否有内容,再看 usage.total_tokens 确认推理真正发生了。如果第三条命令报错,那问题在 Ollama 侧,跟 OpenClaw 一点关系都没有,排查范围一下子就缩小了。

注意:Ollama 的 OpenAI 兼容端点是 /v1/chat/completions,不是 /api/generate。OpenClaw 侧配置的 Base URL 要写到 /v1 这一层,写根地址会返回 404。

3. 把请求真正指到本地:OpenClaw 集成 Ollama 的配置、字段与验证

3.1 最小可跑配置:一段配置把 Base URL、模型名和 API Key 对齐

两边接口都确认可用之后,剩下的就是配置对接。OpenClaw 的配置形式因版本而异,有的是 JSON 文件,有的是环境变量,但核心字段是同一套。我通常会在配置文件里这样写:

{ "provider": { "type": "openai_compatible", "base_url": "http://127.0.0.1:11434/v1", "api_key": "ollama", "default_model": "qwen2.5:7b-instruct" }, "request": { "timeout": 180, "max_tokens": 2048, "temperature": 0.3 } }

逐字段说一遍:type 选 openai_compatible,意思是让 OpenClaw 用 OpenAI 的请求格式去访问这个地址;base_url 一定要落在 /v1 这一层,这是 Ollama 兼容层的路径前缀,写成 http://127.0.0.1:11434 不带斜杠是不行的;api_key 填任意非空字符串即可,Ollama 本地端点不校验这个字段,但 OpenAI 协议要求必须有,我用 ollama 做占位;default_model 必须和 ollama list 里显示的 tag 完全一致,大小写、冒号、后缀都不能差。

如果你的 OpenClaw 版本支持环境变量方式,映射逻辑是一样的:

OPENCLAW_API_BASE="http://127.0.0.1:11434/v1" OPENCLAW_MODEL="qwen2.5:7b-instruct" OPENCLAW_API_KEY="ollama"

环境变量方式的好处是方便切换环境,我经常在有 GPU 的机器和无 GPU 的机器之间来回切,配置文件不用动,只改环境变量就行。字段名以你手上 OpenClaw 版本的实际配置项为准,但思路一致:Base URL 指向本地端口,模型名对齐 Ollama tag,API Key 随便填。这套配置能跑通的最小前提,就是你前面已经用 curl 验证过 11434 端口真的会返回 JSON。

3.2 请求超时、上下文窗口与生成上限:三个参数决定本地模型的实际体验

配置接上了,但体验好不好,全看下面三个参数怎么调。很多人在集成阶段只关心能不能通,用起来才发现响应老超时、对话记不住、回复写到一半断掉,根源都在参数没调。

第一个是 timeout。OpenClaw 这类框架默认超时通常只有 30 秒,而本地模型的首次请求要承担模型加载时间。7B 量化模型从磁盘加载到显存大约要 5 到 15 秒,如果跑在 CPU 上,一个稍长的回答花 40 秒很正常。所以 30 秒默认值几乎必然超时,我把 timeout 调到 180 秒起步。判断标准很简单:看第二次请求是否明显快于第一次,如果是,说明首次慢是冷启动,超时调大就能解决。

第二个是上下文窗口。Ollama 侧对应 num_ctx,默认值是 2048,这个长度对单轮短问答够用,但多轮对话或者粘贴一段文档进去,模型立刻“失忆”。我把 num_ctx 调到 8192 作为起点,注意显存占用会随上下文窗口线性上涨,qwen2.5:7b 在 q4_K_M 量化下,8K 上下文大约吃 8 到 10 GB 显存。不要盲目上 32K,显存不够就降回 4096,比换模型优先级高。

第三个是单次生成上限,OpenClaw 侧一般是 max_tokens。中文在这个值上的消耗大约是一到两个 token 一个字,2048 的 max_tokens 大概能支撑一千多字的中文回答。设太小,长文章写到一半就被硬截断;设太大,首 token 响应变慢,交互卡顿。我给的建议起点是 2048,遇到长文任务再临时调大。三者之间有个联动关系:上下文窗口决定模型能“看到”多少,max_tokens 决定能“写出”多少,timeout 决定你愿意等多少。

参数常见默认值建议起点调整理由
timeout30 秒180 秒本地模型首次请求要加载权重,冷启动经常超过 30 秒
num_ctx20488192多轮对话和长文档需要更大上下文,但显存占用线性上涨
max_tokens视框架而定2048覆盖常见问答长度,避免长回复被截断

3.3 验证集成成功的三个信号:日志、返回体与模型名

配置完成不等于集成成功,我习惯用三个信号判断这一步到底通没通。第一个信号是 OpenClaw 日志里出现本机 11434 端口的访问记录,或者 HTTP 状态码 200。大多数框架在 debug 模式下会打印每次模型请求的地址和耗时,看到 127.0.0.1:11434 出现在日志里,说明请求已经发到了本地。第二个信号是返回体结构正确,OpenClaw 能解析出内容。你可以用一段独立脚本先验证 Ollama 侧返回,再回到 OpenClaw 里做同样的事,这样能精确切分故障边界:

import requests url = "http://127.0.0.1:11434/v1/chat/completions" payload = { "model": "qwen2.5:7b-instruct", "messages": [{"role": "user", "content": "把这句话翻译成英文:本地模型接入应用工具链"}], "max_tokens": 200 } r = requests.post(url, json=payload, timeout=180) print(r.status_code) print(r.json()["choices"][0]["message"]["content"]) print("tokens:", r.json()["usage"]["total_tokens"])

这段脚本做的事情和 OpenClaw 内部完全一致,如果脚本跑通了而 OpenClaw 没通,问题一定在 OpenClaw 的配置或协议解析上;如果脚本本身就报错,问题在 Ollama 服务或者模型 tag 上。第三个信号是界面上的模型名正确显示为 qwen2.5:7b-instruct,而不是 fallback 到默认模型。很多人配置完没注意模型下拉框里还选着旧模型,导致请求根本没走新配置。这三个信号全过了,集成才算真正完成。

4. 集成避坑清单:OpenClaw 接 Ollama 常见的 5 个故障现场

本地链路比云端多一个环节,就多一堆毛病。以下按我实际遇到过的频率排序,每一条都给出现象、原因和解决路径,照着排查能省下大量时间。

4.1 现象一:HTTP 415 Unsupported Media Type

现象:OpenClaw 请求发出去,Ollama 直接返回 415,界面没有任何可用输出,日志里能看到 HTTP 状态码。原因多数不是内容格式问题,而是地址拼错了。我遇到过两次:一次是 OpenClaw 配置里把 provider 类型选成了自定义回调,导致请求体结构不符合 Ollama 兼容层的预期;另一次是 base_url 写了 http://127.0.0.1:11434 而漏掉了 /v1。解决方法是先确认 base_url 以 /v1 结尾,再用 curl 手测一次确认 Ollama 侧能正常返回 JSON。curl 能过而 OpenClaw 不能过,就去查 provider 类型和请求头里的 Content-Type 是否明确为 application/json。

4.2 现象二:响应慢到像卡死,模型加载一次要 40 秒

现象:第一次发起对话,OpenClaw 转圈转很久,最后报超时;第二次再问明显变快。原因就是模型冷启动,Ollama 需要把权重文件从磁盘加载到显存,7B 模型要用掉 5 到 15 秒,CPU 环境更久。这个不是故障,但默认超时会把正常慢请求误杀。解决有两个方向:把 timeout 调到 180 秒以上不误杀冷启动,或者让模型常驻。Ollama 的请求体支持 keep_alive 字段,我习惯设为 30 分钟,模型在显存里驻留更久,冷启动频率大幅降低。另一个土办法是集成前先在终端跑一次 ollama run qwen2.5:7b-instruct,把加载过程提前走完。

4.3 现象三:connection refused,OpenClaw 连不上 Ollama

现象:OpenClaw 报 connection refused,curl 127.0.0.1:11434 也不通。这个最好查:先确认 Ollama 服务真的在运行,ollama serve 会告诉你端口监听状态。再确认监听地址,Ollama 默认只绑 127.0.0.1,如果 OpenClaw 跑在容器里或者另一台机器上,127.0.0.1 指向的是它自己,自然连不上。跨容器访问时,启动 Ollama 要加 OLLAMA_HOST=0.0.0.0,然后 OpenClaw 侧填宿主机 IP。这类问题有个排查技巧:先在 OpenClaw 所在的网络环境里 curl 一次 11434 端口,通则继续查配置,不通则问题在网络层,怎么改 OpenClaw 都没用。

4.4 现象四:中文答得稀碎,要么乱码要么无限重复

现象:模型能出内容,但中文夹杂英文、重复词语、或者只回几个字就停。原因通常不是模型不行,而是采样参数不合适。温度偏高时,小尺寸模型很容易陷入重复循环;上下文窗口太短,长回答写到一半被截断,看起来也像乱码。解决方法是把 temperature 降到 0.2 到 0.4 之间,给请求体加 repeat_penalty 字段,值在 1.1 到 1.2 之间,同时确认用的模型本身对中文友好。我用 qwen 系列基本没踩过中文坑,但换成某些英文为主的模型后,同样参数下中文输出质量明显下降。本地推理有时候就是玄学,换一个量化等级、换一个模型家族,问题可能就消失了。

4.5 现象五:并发一高就 500,日志里全是 out of memory

现象:多个会话同时调用,OpenClaw 连续报 500,Ollama 服务端日志里出现 out of memory 或 context deadline exceeded。原因是显存或内存不够了,多个请求同时持有各自的上下文,KV cache 叠加后超出显存上限。解决要看硬件条件:显存足够就把 OLLAMA_NUM_PARALLEL 调大,比如设为 2 或 4,让 Ollama 主动并行处理请求;显存不够就把上下文窗口调回 4096 或换更小的模型。这里一定要养成看日志的习惯,Ollama 的日志在 ~/.ollama/logs/server.log,里面会明确写出是显存不足还是上下文分配失败,比对着错误码猜要高效得多。

5. 打通之后还能玩的进阶方向:多模型路由、流式响应与本地 RAG

5.1 多模型路由:让 3B 做杂活,让 14B 出长文

集成打通后,很多人就停在“一个模型用到底”。实际上 OpenClaw 这类框架大多支持配置多个模型实例,按任务类型切换。我的常见做法是:短文本任务用 qwen2.5:3b-instruct,比如命名实体抽取、意图分类、标题改写,这类任务对推理深度要求不高,小模型延迟低、显存占用小;代码生成、长文写作这类任务用 14B 模型,质量明显更高。路由规则写在业务侧,比如按 prompt 长度或任务标识选择不同模型 id。这样做的收益是显存利用率更高,响应延迟更稳定,而不是所有请求都去挤一个大模型。

5.2 流式输出:把 Ollama 的 SSE 接到 OpenClaw 的 stream 开关

Ollama 的 OpenAI 兼容端点支持 stream 参数,开启后返回 SSE 格式的数据流。OpenClaw 侧如果有流式输出开关,把 stream 打开就能看到 token 逐字出现,交互感受完全不同。如果框架不支持流式,可以自己拉流,把逐 token 的结果处理后拼进你的业务界面:

import requests import json resp = requests.post( "http://127.0.0.1:11434/v1/chat/completions", json={ "model": "qwen2.5:7b-instruct", "stream": True, "messages": [{"role": "user", "content": "写两句产品更新公告"}] }, stream=True, timeout=180 ) for line in resp.iter_lines(): if not line: continue line = line.decode("utf-8") if line.startswith("data:"): data = line[5:].strip() if data == "[DONE]": break chunk = json.loads(data) content = chunk["choices"][0]["delta"].get("content", "") print(content, end="", flush=True)

这段代码把 SSE 流逐行读出来,遇到 [DONE] 结束标记就退出。注意一点:流式响应的返回体和普通模式不一样,choices[0] 里是 delta 字段而不是 message 字段,解析时要区分。这个逻辑在集成自定义界面时非常有用,值得保留成一份常用脚本。

5.3 把 embedding 也本地化:一条完整的离线 RAG 链路

最后这个方向是把 embedding 模型也接到本地,比如 bge-m3 或 nomic-embed-text 这类开源 embedding 模型。这样文档切块、向量化、相似度检索、最终生成全部在本地完成,数据不出内网的承诺才算真正闭环。OpenClaw 如果支持 embedding 配置,单独配一个本地 embedding provider 就行;如果不支持,就自己写检索脚本,把 top-k 结果拼进 prompt 交给 Ollama。这一步做完,本地模型的应用范围就不再是单轮问答,而是可以挂企业内部文档做知识库问答了。

说到这,我养成了一个习惯想分享给你:每换一个新环境,第一件事不是改配置,而是先 curl 一次 11434 端口的 /v1/chat/completions 确认服务可用,再动 OpenClaw 的配置。这个顺序帮我少踩了至少一半的 415 和 connection refused 坑,也希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询