1. 本地部署 AI 模型到底在解决什么问题:从 Ollama 到 OpenClaw 的完整链路
本地部署 AI 模型这件事,很多人第一次尝试时容易走两个极端:要么只装了个 Ollama 跑一句ollama run就以为完事,要么一上来就上 Kubernetes,结果卡在镜像拉取和端口映射上三天没跑通。我试过把这两条路都走一遍,最后发现真正能落地的路径其实在中间:用 Ollama 管模型、用 Docker 管运行环境、用 OpenClaw 做代理层,再留一个统一出口接 TaoToken 做兜底和增强。这套组合的好处是每一层职责清晰,出问题能快速定位是哪一层挂了。
先说清楚这三个东西分别是什么。Ollama 是一个本地模型运行时,负责把 GGUF 量化模型拉下来、加载进显存、暴露一个兼容 OpenAI 风格的 HTTP 接口,默认监听11434。Docker 负责把 Ollama 和 OpenClaw 装进容器,解决"我这能跑你那不能跑"的环境差异。OpenClaw 是一个开源的 AI 代理框架,它本身不产模型,而是把模型能力包装成可执行任务的代理,对外暴露 Web 界面和 API,默认端口18789。三者串起来的数据流是:OpenClaw 收到请求 → 转发给 Ollama 的/v1/chat/completions→ Ollama 加载本地模型推理 → 结果回传。
那为什么还要接 TaoToken?因为本地模型有两个绕不过去的短板:一是小参数模型在复杂推理、长上下文、代码生成上确实打不过云端大模型;二是本地机器不可能 7×24 小时开着,一旦关机服务就断。TaoToken 在这里扮演的是"统一模型网关"的角色——它提供 OpenAI 兼容的 API 端点,你可以在 OpenClaw 里配置多个 provider,简单任务走本地 Ollama,复杂任务或本地离线时自动切到 TaoToken 的云端模型,Key 和 Base URL 统一管理,不用在代码里到处改地址。这样既保住了数据主权(敏感数据走本地),又保住了能力上限(难题走云端)。
这套方案适合谁?我梳理了一下:个人开发者想在自己的笔记本上跑一个能对话、能读文档的助手;小团队想在内网搭一个共享的推理服务,避免每个人都去申请云端 Key;以及对数据敏感、要求推理过程不出内网、但又希望保留云端增强能力的场景。不适合的是追求极致吞吐的生产集群——那种场景你应该直接上 vLLM 加负载均衡,本文不展开。
下面这张表是我实测下来各层的职责和默认端口,先建立整体印象,后面每一步都会对应到这张表:
| 组件 | 职责 | 默认端口 | 部署方式 |
|---|---|---|---|
| Ollama | 模型拉取、加载、推理 API | 11434 | 原生安装或 Docker |
| OpenClaw | 代理框架、Web UI、任务编排 | 18789 | npm 或 Docker |
| TaoToken | 云端模型统一网关(兜底/增强) | 443 (HTTPS) | SaaS,无需部署 |
| Docker Compose | 编排上述容器、网络、卷 | - | 宿主机安装 |
需要提前说明一个容易踩的坑:Ollama 在容器内和宿主机上的监听地址不一样。容器里必须监听0.0.0.0:11434,否则宿主机和其他容器访问不到;而原生安装默认只监听127.0.0.1。这个差异会导致后面 OpenClaw 报connection refused,我在第 5 节会专门讲怎么排查。另外,模型文件体积很大,7B 的 q4 量化大约 4-5GB,14B 大约 9GB,务必把 Docker 的 volume 挂到磁盘空间充足的分区,别默认丢在系统盘。
2. 前置准备:Ollama 模型拉取与 TaoToken Key 获取的完整步骤
这一节做两件事:把本地模型跑起来,把 TaoToken 的接入凭证拿到手。两件事互不依赖,可以并行做。
2.1 环境检查与 Ollama 安装
先确认基础环境。Node.js 建议 18 以上(OpenClaw 依赖),Docker 建议 24 以上(compose v2 语法),显卡驱动用nvidia-smi确认 CUDA 可用。Windows 下用 PowerShell 管理员权限执行:
node --version docker --version docker compose version nvidia-sminvidia-smi能打出显卡型号和显存占用就说明驱动正常。如果提示命令不存在,先装显卡驱动,别急着往下走——CPU 推理虽然能跑,但 7B 模型在纯 CPU 上大概每秒 3-5 个 token,体验会很差。
安装 Ollama 最省事的方式是直接跑官方脚本(Linux/macOS):
curl -fsSL https://ollama.com/install.sh | sh ollama --versionWindows 用户去官网下载安装包双击即可,装完会自动注册为系统服务。装好后拉模型,这里选通义千问系列,中文支持好、量化版本全:
# 7B 模型,显存 6GB 以上推荐 ollama pull qwen2.5:7b # 4B 轻量版,显存 4GB 或纯 CPU 可跑 ollama pull qwen2.5:4b # 需要更强代码能力时 ollama pull qwen2.5-coder:7b拉完后用ollama list确认,再用一条 curl 验证推理是否正常:
curl http://localhost:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5:7b", "messages": [{"role": "user", "content": "用一句话解释什么是容器"}] }'能返回choices[0].message.content就说明本地模型这层通了。注意这里用的是/v1/chat/completions而不是 Ollama 原生的/api/generate,因为 OpenClaw 和 TaoToken 都走 OpenAI 兼容协议,统一用/v1路径后面配置能少改很多。
2.2 获取 TaoToken 的 Base URL 与 API Key
TaoToken 这边需要三样东西:Base URL、API Key、Model ID。Base URL 固定是https://taotoken.net/api,注意不要带任何查询参数。API Key 的获取路径是登录后进入控制台的 API Keys 页面创建,创建时建议按用途命名(比如openclaw-local),方便后面轮换和审计。
创建完 Key 后,先别急着往 OpenClaw 里填,用一条 curl 单独验证 Key 是否有效、模型是否可调:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer 你的Key" \ -H "Content-Type: application/json" \ -d '{ "model": "你的ModelID", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 16 }'返回 200 且有choices字段就说明 Key 和 Model ID 都对。如果返回 401,先检查 Key 有没有复制全(前后空格、换行都会导致失败);如果返回 404 或模型不存在,去控制台确认 Model ID 拼写,别自己猜。
注意:API Key 属于敏感凭证,不要写进会提交到 Git 的配置文件。本文后面的配置片段统一用环境变量
${TAOTOKEN_API_KEY}引用,实际部署时通过.env文件或容器环境变量注入,.env记得加进.gitignore。
到这里前置准备就完成了:本地有qwen2.5:7b可调,云端有 TaoToken 的 Key 和 Model ID 可用。接下来进入容器化编排。
3. 可复制配置:docker-compose 编排 Ollama 与 OpenClaw 并接入 TaoToken
这一节给出完整的docker-compose.yml和 OpenClaw 的 provider 配置片段,路径和字段名都按实际可用的写,复制后改三个值(Key、Model ID、模型名)就能起。
3.1 目录结构与 .env
先在宿主机建一个工作目录,结构如下:
mkdir -p ~/ai-stack/{models,workspace,config} cd ~/ai-stack同目录下建.env文件,存放敏感值和可变参数:
# .env TAOTOKEN_API_KEY=sk-你的Key TAOTOKEN_MODEL_ID=你的ModelID LOCAL_MODEL=qwen2.5:7b3.2 docker-compose.yml 完整片段
services: ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ./models:/root/.ollama environment: - OLLAMA_HOST=0.0.0.0:11434 - OLLAMA_KEEP_ALIVE=24h deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] openclaw: image: openclaw/server:latest container_name: openclaw restart: unless-stopped ports: - "18789:18789" volumes: - ./workspace:/app/workspace - ./config:/app/config environment: - MODEL_PROVIDER=ollama - OLLAMA_BASE_URL=http://ollama:11434 - TAOTOKEN_BASE_URL=https://taotoken.net/api - TAOTOKEN_API_KEY=${TAOTOKEN_API_KEY} - TAOTOKEN_MODEL_ID=${TAOTOKEN_MODEL_ID} - LOCAL_MODEL=${LOCAL_MODEL} depends_on: - ollama几个关键点解释一下。OLLAMA_HOST=0.0.0.0:11434是必须的,否则容器内只监听回环地址,OpenClaw 容器通过服务名ollama访问会失败。OLLAMA_KEEP_ALIVE=24h让模型常驻显存,避免每次请求重新加载导致首 token 延迟飙到十几秒。deploy.resources.reservations.devices那段是 GPU 透传,没有 NVIDIA 显卡的话整段删掉,Ollama 会自动走 CPU。depends_on只保证启动顺序,不保证 Ollama 已经 ready,所以 OpenClaw 首次启动可能报一次连接失败,重启一次即可,或者用 healthcheck 解决(见第 5 节)。
3.3 OpenClaw 的 provider 配置片段
OpenClaw 的模型配置放在./config/openclaw.json,这个文件会被挂载进容器。核心是把本地 Ollama 和 TaoToken 配成两个 provider,并设置路由策略:
{ "models": { "providers": { "local-ollama": { "baseUrl": "http://ollama:11434/v1", "apiKey": "ollama", "api": "openai-completions", "models": [ { "id": "qwen2.5:7b", "name": "Qwen2.5 7B (Local)", "contextWindow": 32768 } ] }, "taotoken-cloud": { "baseUrl": "https://taotoken.net/api/v1", "apiKey": "${TAOTOKEN_API_KEY}", "api": "openai-completions", "models": [ { "id": "${TAOTOKEN_MODEL_ID}", "name": "TaoToken Cloud", "contextWindow": 128000 } ] } }, "routing": { "default": "local-ollama", "fallback": "taotoken-cloud", "rules": [ { "match": { "task": "code" }, "target": "taotoken-cloud" }, { "match": { "contextTokens": ">32000" }, "target": "taotoken-cloud" } ] } } }这里local-ollama的apiKey填ollama是占位,Ollama 本身不校验 Key,但 OpenAI 兼容客户端要求这个字段非空。routing段是这套方案的价值所在:默认走本地,代码类任务和超长上下文自动切云端,本地服务挂了走 fallback。contextWindow要和模型实际能力对齐,qwen2.5:7b 标称 32K,填大了会被截断。
3.4 启动与模型预拉取
配置就位后启动:
docker compose up -d docker compose ps两个容器都是running后,进 Ollama 容器把模型拉下来(模型存在挂载的./models里,重建容器不丢):
docker exec -it ollama ollama pull qwen2.5:7b docker exec -it ollama ollama list如果你在宿主机已经用原生 Ollama 拉过模型,也可以直接把~/.ollama/models的内容拷到./models下,省一次下载。启动完成后 OpenClaw 的 Web 界面在http://localhost:18789,先别急着开界面,下一节先做逐项连通性验证,把问题在命令行阶段解决掉。
4. 验证请求与成功结果:逐层检查服务连通与推理响应
部署类文章最容易糊弄的地方就是"启动成功"四个字带过,实际上一堆人卡在容器起来了但请求不通。这一节按数据流方向逐层验证,每一层给出命令和预期结果,哪层断了就停在哪层排查。
4.1 第一层:Ollama 容器自身健康
docker exec -it ollama ollama list curl http://localhost:11434/api/tags预期:第一条列出已拉取的模型,第二条返回 JSON 里models数组包含qwen2.5:7b。如果ollama list为空,说明模型没拉成功,回第 3.4 步;如果 curl 拒绝连接,检查docker compose ps里 ollama 是否 running,以及端口映射是否为0.0.0.0:11434->11434/tcp。
4.2 第二层:容器间网络连通
OpenClaw 容器访问 Ollama 用的是服务名ollama而不是localhost,这一步最容易出错。进 OpenClaw 容器里测:
docker exec -it openclaw sh -c "curl -s http://ollama:11434/api/tags | head -c 200"预期返回模型列表的 JSON 片段。如果报Could not resolve host: ollama,说明两个容器不在同一网络,检查 compose 文件里有没有手动指定 network 导致隔离;如果报Connection refused,回到 3.2 节确认OLLAMA_HOST=0.0.0.0:11434这行在不在。
4.3 第三层:本地模型推理响应
绕过 OpenClaw,直接对 Ollama 发一条完整对话请求,确认推理链路和显存加载正常:
curl http://localhost:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5:7b", "messages": [ {"role": "system", "content": "你是一个简洁的助手"}, {"role": "user", "content": "列出 Docker 的三个核心概念,每个一句话"} ], "temperature": 0.7, "max_tokens": 256 }'预期:返回 JSON 中choices[0].message.content是一段中文,包含镜像、容器、仓库之类的概念;usage字段有 prompt 和 completion 的 token 数。首次请求会慢(模型加载进显存),第二次开始应该在 1-3 秒内返回。如果返回model not found,模型名拼写和ollama list输出对不上;如果卡住超过 60 秒,大概率是显存不足在往 CPU 换页,用nvidia-smi看显存占用。
4.4 第四层:TaoToken 云端通道
在宿主机验证云端 provider 可用(命令同 2.2 节那条 curl),确认返回 200。这一步单独做的好处是:后面 OpenClaw 里如果云端路由失败,你能立刻判断是 Key 问题还是 OpenClaw 配置问题。
4.5 第五层:OpenClaw 端到端
打开http://localhost:18789,在对话界面输入一条测试指令,比如"帮我生成一份今日工作计划,包含三个优先级任务"。预期返回结构化列表。然后做一次路由验证:发一条明确要求写代码的消息(比如"写一个 Python 快速排序函数"),观察 OpenClaw 日志:
docker compose logs -f openclaw日志里应该能看到请求被路由到taotoken-cloud。再发一条普通闲聊,日志显示走local-ollama。两条都通,说明本地加云端的双通道和路由规则都生效了。
4.6 成功状态汇总
全部通过后,你的服务状态应该是:docker compose ps两个容器 healthy;curl localhost:11434/api/tags有模型;Web 界面能对话;日志能看到路由切换。把这几个检查点记下来,以后出问题按顺序过一遍,五分钟能定位。
5. 本篇常见错排查:401、local proxy failed、reading choices 与 OAuth 报错对照
这一节按真实报错信息组织,每条给出触发场景、根因和修复动作。报错文本我尽量保留原始英文,方便你直接搜索对照。
5.1 401 Unauthorized
最常见于 TaoToken 通道。原始报错形如:
{"error":{"message":"Invalid API key","type":"authentication_error"}}根因有三类:Key 复制时带了空格或换行;.env文件里 Key 没被 compose 正确注入(变量名拼错、文件不在 compose 同目录);Key 被撤销或过期。排查顺序:先在宿主机用 2.2 节的 curl 直连验证 Key 本身有效,有效则说明是注入问题,执行docker exec -it openclaw env | grep TAOTOKEN看容器内变量是否为空。修复后docker compose up -d重建容器让环境变量生效,注意restart不会重新读.env。
5.2 local proxy failed
OpenClaw 日志里出现local proxy failed: dial tcp ... connection refused,指向本地 Ollama 通道。根因基本是容器网络或监听地址问题。检查三件事:OLLAMA_HOST是否为0.0.0.0:11434;OpenClaw 配置里的baseUrl是否用了http://ollama:11434/v1而不是localhost;两个容器是否在同一 compose 网络(默认会,除非你手动指定了network_mode: host混用)。还有一种隐蔽情况:Ollama 容器刚启动还没 ready,OpenClaw 抢先请求失败后缓存了失败状态,重启 OpenClaw 容器即可。长期方案是给 ollama 加 healthcheck:
healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 10s timeout: 5s retries: 5并把 openclaw 的depends_on改成带条件的写法。
5.3 reading choices 相关报错
报错形如cannot read properties of undefined (reading 'choices')或reading '0'。这是客户端拿到了非预期响应体却按 OpenAI 格式解析导致的。根因通常是:请求打到了错误的路径(比如把/v1/chat/completions写成了/api/chat,返回结构不同);或者上游返回了错误 JSON(如 401 的错误体)但客户端没先判断状态码。排查:用docker compose logs openclaw找到实际请求的 URL,用 curl 手动打同一个 URL 看返回体结构。修复:确认 provider 的baseUrl以/v1结尾且api字段为openai-completions;TaoToken 的 Base URL 是https://taotoken.net/api/v1,少写/v1会 404 并触发这个解析错误。
5.4 OAuth 与鉴权类报错
如果你在 OpenClaw 里启用了需要 OAuth 的插件或外部工具,可能遇到OAuth token expired或invalid_grant。这类报错和模型通道无关,属于插件鉴权层。处理方式:在 OpenClaw 配置里重新走一次授权流程,或临时禁用该插件确认模型通道本身正常。注意不要把 OAuth 的 client secret 和 TaoToken 的 API Key 混在同一个环境变量里,排查时会互相干扰。
5.5 模型加载失败与显存不足
报错CUDA out of memory或模型加载后立刻退出。根因是显存不够。7B 的 q4 量化约需 5-6GB 显存,加上上下文缓存会更高。修复:换qwen2.5:4b,或拉q4_0量化版本,或在 Ollama 启动参数里限制 GPU 层数(OLLAMA_NUM_GPU)。用nvidia-smi -l 1实时看占用,别凭感觉判断。
5.6 端口冲突
bind: address already in use,说明宿主机 11434 或 18789 被占用。用lsof -i :11434(Linux/macOS)或netstat -ano | findstr 11434(Windows)找到占用进程,要么停掉,要么改 compose 里的宿主机端口映射(如"11435:11434"),改完记得同步改 OpenClaw 配置里的 baseUrl 端口。
6. 把本地服务用起来:TaoToken 接入文档与 Coding Plan 的下一步
服务跑通只是起点,真正决定这套东西好不好用的是后面怎么用。我自己的用法是把它当成一个"分层推理入口":日常问答、文档摘要、内网敏感数据走本地qwen2.5:7b,代码生成、长文档分析、复杂多步推理走 TaoToken 云端通道,路由规则在第 3.3 节的routing里已经配好,用起来不需要手动切。
如果你要长期跑编码类任务或者搭 Agent 工作流,建议把 TaoToken 的 Coding Plan 用起来,它针对代码场景做了模型和配额的优化,配合 OpenClaw 的task: code路由规则正好对上。配置方式不复杂:在 OpenClaw 的 provider 里把taotoken-cloud的 Model ID 换成 Coding Plan 对应的模型,路由规则不用动。需要确认当前可用的模型列表和配额,去模型对话页面实际发几条请求看返回的usage字段最直接。
接入过程中如果遇到本文没覆盖的报错,两个地方最有用:一是 TaoToken 的接入文档,里面按协议和错误码分类整理了常见问题,比到处搜帖子快;二是 API Keys 页面,Key 的权限范围、调用统计、轮换记录都在那,排查 401 和配额问题先看这里。文档和 Key 管理这两个入口建议收藏,后面换机器、加同事、做轮换都会反复用到。
最后给一个实用技巧:把这套 compose 目录整个打包备份,换机器时只需要改.env里的 Key 和 Model ID,docker compose up -d就能复现,模型文件如果太大可以只备份配置、重新拉取。另外定期执行docker exec -it ollama ollama pull qwen2.5:7b更新模型版本,OpenClaw 镜像用docker compose pull更新,更新前先docker compose down保留 volume,避免模型缓存丢失。这套流程我反复用过几次,从裸机到服务可用大概二十分钟,前提是镜像和模型提前下好。