1. 为什么要在 OpenClaw 里做本地优先 + 云端适配
数据隐私这件事,真正落到日常开发里,往往不是一句“合规要求”就能解决的。你可能会遇到这样的场景:手里有一批内部文档、会议纪要或者客户资料,想让大模型帮忙做摘要、问答、代码解释,但又不想把这些原文直接发到外部服务上。尤其是个人开发者和小团队,既没有专门的安全团队,也没有复杂的私有化预算,最现实的做法就是——让数据先在本地跑一圈,只有确实需要更强算力时,才把脱敏后的请求送到云端。
OpenClaw 这个框架的价值就在这里。它本身是一个轻量级的大模型交互层,你可以把它理解成一个“调度台”:前面接你的业务代码,后面可以接本地 Ollama 跑的 Llama 2,也可以接云端 API。它不强制你二选一,而是允许你按任务类型、按数据敏感级别来分流。本地优先的意思是,默认请求走本地;云端适配的意思是,当本地模型搞不定时,可以切到云端,但切换过程不需要重写业务逻辑。
我试过把一套内部知识库问答流程拆成两段:日常问答走本地 Llama 2,遇到跨文档推理或者长上下文总结时,再走云端。整个过程中,最麻烦的其实不是 OpenClaw 的代码,而是“Key 怎么管、模型怎么切、配置写在哪”。如果每个模型都单独配一套 Key 和 Base URL,维护成本会很快失控。所以这篇会围绕一个核心思路:用 TaoToken 统一 Key 来打通 Ollama 本地链路和云端适配链路,让 OpenClaw 的配置保持干净。
适合读这篇的人:已经在本地跑过 Ollama,或者准备跑 Llama 2;对数据隐私敏感,不希望所有请求都出本地;同时又不排斥在必要时调用云端模型。下面从环境准备开始,一步步把配置、验证和排障都走一遍。
2. TaoToken 统一 Key 与 OpenClaw 的前置准备
在动手改 OpenClaw 配置之前,先把两件事理清楚:本地 Ollama 是否已经可用,以及 TaoToken 的 Key 和接入地址怎么拿。这两步不做,后面配置写得再漂亮也跑不起来。
先说 Ollama。它是目前本地跑 Llama 2 最省心的方式之一,安装完之后默认监听11434端口。你可以先用一条命令确认模型是否已经拉下来:
ollama pull llama2 ollama list如果ollama list里能看到llama2,说明本地模型就绪。接着启动服务:
ollama serve然后在另一个终端里直接测一下原生接口:
curl http://localhost:11434/api/generate -d '{ "model": "llama2", "prompt": "用一句话解释什么是本地优先架构", "stream": false }'能返回 JSON 结果,就说明本地推理链路是通的。这一步很关键,因为 OpenClaw 报错时,你首先要排除的就是 Ollama 本身没起来。
再说 TaoToken。它的定位是统一管理模型接入的 Key 和 Base URL,这样你在 OpenClaw 里不需要为每个模型维护一套凭证。你需要去控制台创建一个 API Key,地址是:
https://taotoken.net/api-keys创建完之后,把 Key 复制出来,后面配置里会用到。TaoToken 的 API 接入地址是:
https://taotoken.net/api注意,这个地址在配置里通常作为 Base URL 使用,不要自己拼多余的路径。模型 ID 则根据你要调用的模型来填,比如云端侧可以填对应的模型标识,本地侧仍然走 Ollama 的llama2。
这里有一个容易混淆的点:TaoToken 统一 Key 并不是要替代 Ollama,而是让云端适配那一侧有一个稳定的入口。本地请求依然直接打到http://localhost:11434,不经过外部网络。这样既保留了本地隐私链路的闭环,又让云端切换时不用再到处找 Key。
如果你后面打算用 Claude Code 或者类似的编码 Agent 来做长期开发,也可以顺手了解一下 Coding Plan 的接入方式,地址是:
https://taotoken.net/coding-plan不过这篇的重点还是 OpenClaw 的配置。前置准备清单可以归纳成下面这张表:
| 项目 | 值 | 说明 |
|---|---|---|
| 本地模型 | llama2 | 通过 Ollama 拉取 |
| Ollama 地址 | http://localhost:11434 | 本地默认端口 |
| TaoToken API 地址 | https://taotoken.net/api | 云端适配 Base URL |
| TaoToken Key | 控制台创建 | 统一凭证 |
| OpenClaw 安装 | npm install openclaw | Node 环境 |
把这些准备好之后,就可以进入 OpenClaw 的配置环节了。
3. 可复制的 OpenClaw 配置片段:Ollama 与云端双通道
OpenClaw 的配置核心在于“模型提供方”和“端点”的映射。为了让本地优先和云端适配同时存在,我建议把配置拆成两个 profile:一个local,一个cloud。这样业务代码只需要根据数据敏感级别选择 profile,不需要关心底层是 Ollama 还是 TaoToken。
下面是一份可以直接复制的 JSON 配置,文件名可以叫openclaw.config.json,放在项目根目录:
{ "defaultProfile": "local", "profiles": { "local": { "provider": "ollama", "baseUrl": "http://localhost:11434", "model": "llama2", "apiKey": "ollama-local-no-key", "options": { "temperature": 0.7, "maxTokens": 512 } }, "cloud": { "provider": "openai-compatible", "baseUrl": "https://taotoken.net/api", "model": "gpt-4-turbo", "apiKey": "sk-你的TaoTokenKey", "options": { "temperature": 0.5, "maxTokens": 1024 } } } }这份配置里,local的apiKey填一个占位符就行,因为 Ollama 本地不需要鉴权。cloud的baseUrl指向 TaoToken 的 API 地址,apiKey换成你在控制台创建的那串 Key。model字段根据你实际要调的云端模型来写,这里只是示例。
如果你更习惯用 TOML 来管理配置,也可以写成openclaw.config.toml:
default_profile = "local" [profiles.local] provider = "ollama" base_url = "http://localhost:11434" model = "llama2" api_key = "ollama-local-no-key" temperature = 0.7 max_tokens = 512 [profiles.cloud] provider = "openai-compatible" base_url = "https://taotoken.net/api" model = "gpt-4-turbo" api_key = "sk-你的TaoTokenKey" temperature = 0.5 max_tokens = 1024两种格式选一种即可,OpenClaw 在初始化时会读取项目根目录下的配置文件。接下来在代码里加载配置并创建实例:
const { OpenClaw } = require('openclaw'); const config = require('./openclaw.config.json'); const claw = new OpenClaw({ profile: config.defaultProfile, profiles: config.profiles }); async function ask(question, profile = 'local') { const response = await claw.chat({ profile, messages: [ { role: 'system', content: '你是一个技术助手,回答简洁准确' }, { role: 'user', content: question } ] }); return response.choices[0].message.content; } module.exports = { ask };这里的关键点是ask函数接受一个profile参数。默认走local,当你在业务层判断“这条请求包含敏感原文”时,就保持local;当判断“这条请求已经脱敏,且需要更强推理”时,再传cloud。这样本地优先和云端适配就在同一套代码里共存了。
如果你用的是 Cline 或者类似的 MCP 客户端,配置思路是一样的:Base URL、Key、Model ID 三件套要写全。本地侧 Base URL 是http://localhost:11434,Key 随便填,Model ID 是llama2;云端侧 Base URL 是https://taotoken.net/api,Key 是 TaoToken 的 Key,Model ID 按实际模型填。三件套缺一个,请求就会失败。
配置写完之后,不要急着跑复杂业务,先用一个最小请求验证两条通道都能通。
4. 验证请求:从本地 Llama 2 到云端适配的成功结果
验证分两步走:先确认本地通道,再确认云端通道。这样出问题时你能快速定位是哪一侧的配置有误。
先写一个本地验证脚本verify-local.js:
const { ask } = require('./claw'); (async () => { const answer = await ask('用三点说明本地大模型的隐私优势', 'local'); console.log('本地回答:', answer); })();运行:
node verify-local.js如果 Ollama 正常,你会看到类似下面的输出:
本地回答: 1. 数据不离开本地环境,减少上传过程中的暴露面; 2. 计算环境完全可控,便于满足数据驻留要求; 3. 不依赖外部服务可用性,业务连续性更有保障。这一步成功,说明 OpenClaw 到 Ollama 的链路是通的。如果卡住或者报错,先回到第 2 步用 curl 测 Ollama 原生接口,确认服务本身没问题。
接着验证云端通道,写verify-cloud.js:
const { ask } = require('./claw'); (async () => { const answer = await ask('用一句话解释云端适配的适用场景', 'cloud'); console.log('云端回答:', answer); })();运行:
node verify-cloud.js成功时会返回云端模型的回答。这里如果出现401,大概率是 TaoToken Key 没填对或者复制时带了空格;如果出现local proxy failed,说明请求没有正确走到 TaoToken 的 Base URL,检查baseUrl是否写成了https://taotoken.net/api,而不是其他路径。
两条通道都验证通过后,可以做一个混合验证:先本地总结,再云端润色。比如:
const { ask } = require('./claw'); (async () => { const localDraft = await ask('总结这段内部文档的要点:……', 'local'); const cloudPolish = await ask(`请润色以下内容,不要改变事实:${localDraft}`, 'cloud'); console.log('最终结果:', cloudPolish); })();这个流程的意义在于:原始敏感内容只经过本地模型,送到云端的已经是本地生成的摘要,隐私链路是闭环的。实测下来,这种“本地先处理、云端再加工”的方式,对个人开发者和小团队来说,是平衡隐私和效果的实用做法。
验证通过之后,你可能会遇到一些常见报错,下面单独整理一下。
5. 常见报错排查:401、local proxy failed 与 reading choices
配置和验证过程中,最容易撞上的就是下面这几类错误。每一个我都给出触发条件和处理方式,你可以对照自己的终端输出。
第一类:401 Unauthorized。这个通常出现在云端通道。原因一般是 TaoToken Key 无效、过期,或者复制时带了换行和空格。处理方式是回到控制台重新创建一个 Key,然后直接粘贴到配置里,不要手动输入。如果你用的是环境变量,确认变量名和代码里读取的一致。另外,有些客户端会把 Key 放在Authorization: Bearer头里,如果配置里已经带了Bearer前缀,就不要再重复加。
第二类:local proxy failed或者connection refused。这个一般出现在本地通道。触发条件通常是 Ollama 没有启动,或者端口不是11434。先在终端执行:
curl http://localhost:11434/api/tags如果这条命令都失败,那问题不在 OpenClaw,而在 Ollama 服务本身。确认ollama serve正在运行,并且没有被其他程序占用端口。如果本地通道配置里误填了 TaoToken 的 Base URL,也会出现类似代理失败的提示,检查local.baseUrl是否还是http://localhost:11434。
第三类:reading choices相关报错,比如Cannot read properties of undefined (reading 'choices')。这个说明请求返回的结构和代码里取值的路径不一致。常见原因是模型返回了错误对象,而不是正常的 completion 结构。你可以在ask函数里先把原始 response 打印出来:
const response = await claw.chat({ profile, messages }); console.log(JSON.stringify(response, null, 2));如果看到的是{ error: ... },那就回到前两类去排查。如果看到的是正常的choices数组,但代码里写的是response.choices.message.content,那就需要改成response.choices[0].message.content。不同版本的 OpenClaw 或者不同 provider 返回结构可能略有差异,以实际打印为准。
第四类:OAuth 或者鉴权相关的提示。如果你在配置里同时启用了多个 provider,并且某些 provider 要求 OAuth 流程,可能会出现鉴权冲突。处理方式是明确当前 profile 只使用一种鉴权方式。本地 Ollama 不需要 OAuth,云端走 TaoToken Key 即可。如果你用的是 Codex 的auth.json或者 Claude Code 的配置,注意不要把不同工具的凭证混在同一个文件里。
为了减少排查成本,建议在项目里加一个简单的健康检查脚本:
const { ask } = require('./claw'); async function healthCheck() { const results = {}; for (const profile of ['local', 'cloud']) { try { const answer = await ask('ping', profile); results[profile] = answer ? 'ok' : 'empty'; } catch (err) { results[profile] = err.message; } } console.table(results); } healthCheck();运行之后,哪条通道有问题一目了然。把这张表和上面的报错对照,基本能覆盖大部分配置问题。
6. 把统一 Key 接入流程固定下来
走到这里,OpenClaw 对接本地 Llama 2 和云端适配的链路已经能跑通了。最后想说的是,真正让这套方案稳定的,不是某一次配置成功,而是把 Key 和 Base URL 的管理固定成习惯。
我的做法是:本地通道永远只认http://localhost:11434,不填任何外部 Key;云端通道统一走 TaoToken 的 API 地址和 Key,不把其他平台的凭证散落在各个项目里。这样换机器、换项目、换模型时,只需要改一个 profile,而不是翻遍代码找 Key。
如果你还没有创建统一 Key,可以从这里开始:
https://taotoken.net/api-keys接入文档在:
https://taotoken.net/doc想先验证模型对话效果,可以直接用:
https://taotoken.net/chat长期做编码或者 Agent 开发的话,Coding Plan 的入口是:
https://taotoken.net/coding-plan把本地优先作为默认,把云端适配作为补充,数据隐私和模型能力就不需要互相妥协了。