上周折腾 OpenClaw 本地 Agent 平台,被它的 Provider 抽象层搞得头大。文档写得像论文摘要,GitHub Issue 里一堆人问同样的问题,官方回复永远是「请参考文档」。花了两天把这套配置摸清了,踩的坑全记下来,今天一次性讲明白。
OpenClaw 的 Provider 抽象层核心作用是:用统一的配置格式对接不同的大模型 API(OpenAI 协议、Anthropic 协议、Gemini 协议等),不用为每个模型写不同的调用逻辑。配好之后,Agent 可以在 GPT-5、Claude Opus 4.6、DeepSeek V3、Qwen 3 之间自由切换,代码一行不改。
先说结论
| 配置方式 | 适用场景 | 上手难度 | 灵活度 |
|---|---|---|---|
| YAML 静态配置 | 模型固定、不常切换 | ⭐ 最简单 | 一般 |
| 环境变量 + YAML 混合 | 多环境部署(dev/staging/prod) | ⭐⭐ | 较高 |
| 动态 Provider API | 运行时切换模型、A/B 测试 | ⭐⭐⭐ | 最高 |
我最终选了方案二,兼顾简单和灵活。下面逐个讲。
环境准备
OpenClaw 要求 Python 3.11+,我用的 3.12。先把基础环境搞好:
# 安装 OpenClaw(2026 年 6 月最新版)
pip install openclaw>=0.9.0
# 初始化项目
openclaw init my-agent
cd my-agent
初始化完目录结构长这样:
my-agent/
├── openclaw.yaml # 核心配置文件
├── providers/ # Provider 配置目录
│ └── default.yaml
├── agents/
│ └── main.py
└── .env
方案一:YAML 静态配置(最简单)
打开 providers/default.yaml,OpenClaw 的 Provider 抽象层用的是分层配置结构:
# providers/default.yaml
providers:
# Provider 名称,随便起,后面 Agent 里引用这个名字
my-gpt5:
protocol: openai # 协议类型:openai / anthropic / gemini
base_url: "https://api.openai.com/v1"
api_key: "sk-xxx"
model: "gpt-5"
timeout: 30
max_retries: 3
parameters:
temperature: 0.7
max_tokens: 4096
my-claude:
protocol: anthropic
base_url: "https://api.anthropic.com"
api_key: "sk-ant-xxx"
model: "claude-opus-4.6"
timeout: 60
parameters:
temperature: 0.5
max_tokens: 8192
my-deepseek:
protocol: openai # DeepSeek 兼容 OpenAI 协议
base_url: "https://api.deepseek.com/v1"
api_key: "sk-ds-xxx"
model: "deepseek-v3"
timeout: 30
parameters:
temperature: 0.3
max_tokens: 4096
然后在 Agent 里引用:
# agents/main.py
from openclaw import Agent, ProviderManager
# 加载 Provider 配置
pm = ProviderManager.from_yaml("providers/default.yaml")
# 创建 Agent,指定用哪个 Provider
agent = Agent(
name="my-assistant",
provider=pm.get("my-gpt5"), # 切换模型改这一行就行
system_prompt="你是一个技术助手。"
)
response = agent.chat("解释一下 Python 的 GIL")
print(response.content)
这种方式最直白,但问题也明显——API Key 硬编码在 YAML 里,不适合团队协作和版本管理。
方案二:环境变量 + YAML 混合(推荐)
YAML 里用变量占位,敏感信息走 .env:
# providers/default.yaml
providers:
primary:
protocol: openai
base_url: "${PRIMARY_BASE_URL}"
api_key: "${PRIMARY_API_KEY}"
model: "${PRIMARY_MODEL}"
timeout: 30
max_retries: 3
parameters:
temperature: 0.7
max_tokens: 4096
fallback:
protocol: openai
base_url: "${FALLBACK_BASE_URL}"
api_key: "${FALLBACK_API_KEY}"
model: "${FALLBACK_MODEL}"
timeout: 45
parameters:
temperature: 0.7
max_tokens: 4096
.env 文件:
# .env
PRIMARY_BASE_URL=https://api.ofox.ai/v1
PRIMARY_API_KEY=your-ofox-key
PRIMARY_MODEL=gpt-5
FALLBACK_BASE_URL=https://api.ofox.ai/v1
FALLBACK_API_KEY=your-ofox-key
FALLBACK_MODEL=claude-opus-4.6
这里我用了 ofox.ai 的聚合接口作为 base_url。ofox.ai 是一个 AI 模型聚合平台,一个 API Key 可以调用 GPT-5、Claude Opus 4.6、Gemini 3、DeepSeek V3 等 50+ 模型,兼容 OpenAI 协议,所以 primary 和 fallback 可以用同一个 Key,只换 model 名就行,省得管理一堆不同平台的密钥。
Agent 代码加上 fallback 逻辑:
# agents/main.py
from openclaw import Agent, ProviderManager, ProviderChain
pm = ProviderManager.from_yaml("providers/default.yaml", env_file=".env")
# ProviderChain:主 Provider 挂了自动切到 fallback
chain = ProviderChain([
pm.get("primary"),
pm.get("fallback"),
])
agent = Agent(
name="my-assistant",
provider=chain,
system_prompt="你是一个技术助手。"
)
response = agent.chat("用 Python 写一个快排")
print(response.content)
print(f"实际使用模型: {response.meta.model}")
print(f"延迟: {response.meta.latency_ms}ms")
整个调用链路长这样:
graph LR
A[Agent 发起请求] --> B[ProviderChain]
B --> C{Primary Provider}
C -->|成功| D[返回响应]
C -->|超时/报错| E{Fallback Provider}
E -->|成功| D
E -->|失败| F[抛出异常]
style B fill:#f9f,stroke:#333
style C fill:#bbf,stroke:#333
style E fill:#bfb,stroke:#333
方案三:动态 Provider API(高级玩法)
需要运行时动态切换模型的场景——比如根据任务复杂度选模型,简单问题用便宜的,复杂推理用贵的——可以用 OpenClaw 的动态 Provider API:
from openclaw import Agent, DynamicProvider
def model_selector(message: str, context: dict) -> dict:
"""根据消息内容动态选择模型"""
# 简单判断:包含"代码"或"debug"用强模型
if any(kw in message for kw in ["代码", "debug", "架构", "重构"]):
return {
"protocol": "openai",
"base_url": "https://api.ofox.ai/v1",
"api_key": context["api_key"],
"model": "claude-opus-4.6",
"parameters": {"temperature": 0.3, "max_tokens": 8192}
}
else:
return {
"protocol": "openai",
"base_url": "https://api.ofox.ai/v1",
"api_key": context["api_key"],
"model": "deepseek-v3",
"parameters": {"temperature": 0.7, "max_tokens": 4096}
}
provider = DynamicProvider(
selector=model_selector,
context={"api_key": "your-ofox-key"}
)
agent = Agent(name="smart-router", provider=provider)
# 这条会路由到 Claude Opus 4.6
r1 = agent.chat("帮我重构这段代码的架构")
print(f"模型: {r1.meta.model}") # claude-opus-4.6
# 这条会路由到 DeepSeek V3
r2 = agent.chat("今天天气怎么样")
print(f"模型: {r2.meta.model}") # deepseek-v3
说实话这个方案我在生产环境没大规模用过,目前只在本地测试阶段跑通了。动态路由逻辑写复杂了容易出幺蛾子,建议先用方案二稳定跑起来再考虑。
踩坑记录
坑 1:protocol 写错不报错,默默用默认值
我一开始把 protocol: anthropic 拼成了 protocol: anthrpic(少了个 o),OpenClaw 没报错,直接 fallback 到 openai 协议去调 Anthropic 的接口,返回的错误信息是 401 Unauthorized,排查了半小时才发现是拼写问题。
配置写完跑一下验证命令:
openclaw provider verify --config providers/default.yaml
坑 2:环境变量没加载,YAML 里的 ${} 被当成字符串
ProviderManager.from_yaml() 不传 env_file 参数的话,不会自动读 .env。我以为它会像 Docker Compose 那样自动识别,结果 base_url 直接变成了字符串 "${PRIMARY_BASE_URL}",报了一个很迷惑的 DNS 解析错误。
要么显式传 env_file=".env",要么在 shell 里先 source .env 再跑脚本。
坑 3:timeout 设太短,Streaming 响应被截断
给 Claude Opus 4.6 设了 timeout: 15,结果长文本生成到一半就断了。OpenClaw 的 timeout 是整个请求的超时,不是首字节超时。Streaming 模式下模型可能持续输出 30 秒以上。
Streaming 场景 timeout 至少设 60,或者用 stream_timeout 单独配置:
my-claude:
protocol: openai
base_url: "https://api.ofox.ai/v1"
api_key: "${API_KEY}"
model: "claude-opus-4.6"
timeout: 30 # 普通请求超时
stream_timeout: 120 # Streaming 超时,单独设
坑 4:ProviderChain 的 fallback 触发条件
ProviderChain 默认只在网络超时和 5xx 错误时触发 fallback。4xx 错误(比如 429 限频、401 鉴权失败)不会触发 fallback,它认为这是你自己的配置问题。想让 429 也触发 fallback,需要手动指定:
chain = ProviderChain(
providers=[pm.get("primary"), pm.get("fallback")],
fallback_on=[429, 500, 502, 503, 504], # 加上 429
)
小结
OpenClaw 的 Provider 抽象层设计思路是对的——把模型调用这层脏活封装掉,Agent 逻辑不用关心底层用的是哪家 API。但 2026 年这个版本的文档确实还差点意思,很多配置项得翻源码才能搞明白。
三种方案怎么选:
- 个人项目、快速验证:方案一,YAML 写死,五分钟跑起来
- 正经项目、多环境部署:方案二,环境变量隔离,配合 CI/CD 很舒服
- 需要智能路由:方案三,但建议等 OpenClaw 1.0 稳定版再上生产
我现在的做法是方案二 + ProviderChain,主备都指向同一个聚合接口但用不同模型,一个 Key 管所有模型,省心。配置文件提交 Git,.env 加进 .gitignore,团队协作也没问题。
有问题评论区聊,踩到新坑我会更新。