OpenClaw + 147AI:把多模型调用从业务代码里抽离(简书笔记版)
这是一篇纯技术笔记:不做价格对比、不做平台推荐。只记录一件事——当你需要“能长期跑”的多模型流程时,怎么把接入复杂度从业务层搬走。
1)我遇到的真实问题:多模型项目最先烂掉的不是 Prompt
做 AI 功能时,大家最早关注的是 Prompt、效果、幻觉。
但如果项目要上线,最先把工程拖垮的往往是这些“水管活”:
- SDK/协议差异:每家模型一套参数、返回结构、流式细节;AB 实验很快就变成“全局改接口”。
- Key/鉴权散落:Key 分在多个服务、多个环境变量里,轮换和排错都费劲。
- 运行时行为不一致:超时、错误码、重试、fallback、并发限制,每家都不一样,最后业务层塞满 if-else。
你以为在做“智能体”,结果写出来是一堆适配层。
2)一个更省心的思路:统一入口 + 可配置调度
我现在更倾向于把模型当成“可替换的基础设施”,像数据库连接一样对待:
- 业务层只知道一个入口(例如 OpenAI 风格的
/v1)和一个model字符串 - 模型选择、fallback、allowlist、失败策略放在配置/网关层
这篇文章用两个组件来落地这件事:
- OpenClaw:负责流程编排与运行时治理(模型选择、fallback、工具等都更适合放配置里)
- 147AI:提供 OpenAI 风格
/v1入口作为示例网关
为了避免写成宣传,我只写两条能确认的技术事实:147AI 对外暴露的是 OpenAI 风格 /v1 路径(例如 /v1/chat/completions),并且未携带令牌时会返回 401 提示“未提供令牌”。除此之外(比如支持哪些模型、具体参数),请以你登录控制台后看到的列表为准。
3)把 147AI 接进 OpenClaw:自定义一个 Provider
OpenClaw 的配置文件默认在:
~/.openclaw/openclaw.json(JSON5,支持注释与尾逗号)
你可以先跑一遍向导把环境搭起来:
openclaw onboard
接下来把 147AI 当作一个 OpenAI 风格 Provider(OpenClaw 的 openai-completions 协议)。下文里我用“网关域名”占位,避免正文出现过多外链文本:
// ~/.openclaw/openclaw.json(片段)
{
models: {
mode: "merge",
providers: {
api147: {
baseUrl: "https://<你的网关域名>/v1",
apiKey: "${API147_KEY}",
api: "openai-completions",
// 具体模型 id 以你在 147AI 控制台/文档里看到的为准
models: [{ id: "your-model-id", name: "Primary" }],
},
},
},
agents: {
defaults: {
model: { primary: "api147/your-model-id" },
},
},
}
Key 用环境变量注入(示例):
export API147_KEY="你的令牌"
到这一步,你已经把“模型接入”从业务代码挪到了配置层:业务侧不需要知道你背后换了哪家模型,只需要 provider/model-id。
4)最小验证:先确认鉴权和 /v1 入口通不通
最常见的“看似配好了但跑不通”,本质都是鉴权没带上。
你可以用 curl 先测一下(不带令牌会 401)。把 <你的网关域名> 替换成你实际使用的网关域名:
curl -i -X POST 'https://<你的网关域名>/v1/chat/completions' \
-H 'Content-Type: application/json' \
-d '{"model":"your-model-id","messages":[{"role":"user","content":"ping"}]}'
如果你用 OpenAI Python SDK 做连通性验证,一般是这样:
from openai import OpenAI
client = OpenAI(
api_key="你的令牌",
base_url="https://<你的网关域名>/v1",
)
resp = client.chat.completions.create(
model="your-model-id",
messages=[{"role": "user", "content": "ping"}],
)
print(resp.choices[0].message.content)
排错时我通常先盯四件事:
base_url是否以/v1结尾model是否是你控制台里真实存在的 ID- 401 是否是“未提供令牌/令牌无效”(多数情况下就是这个)
- 如果在 OpenClaw 里切模型没反应,先看 allowlist
5)一个容易踩的坑:allowlist 把你自己拦住了
OpenClaw 里如果设置了 agents.defaults.models,它会变成允许列表(allowlist)。
你在会话里用 /model 选择的模型不在列表里,就会出现 “Model is not allowed” 之类的提示。
处理方式也简单:
- 不需要限制就去掉 allowlist
- 需要限制就把
api147/your-model-id明确加进去
这个问题在多模型场景非常常见:不是接口坏了,是配置把你挡住了。
6)多模态/视频这类请求,别按“文本请求”写
最后补一句经验:图片、音频、视频这些请求,工程形态更像“任务系统”,不是一次 HTTP 就完事的聊天接口。
如果你后面要接视频生成,建议直接按异步任务设计:
- 任务创建返回 task_id
- 轮询/回调查询状态
- 失败可重试、可取消、可降级
把它当成“作业系统”会更稳。
7)收尾
这篇笔记想证明的只有一件事:多模型不是“多写几份 SDK 适配”,而是“统一入口 + 配置化调度”。
当你把入口收敛到 /v1,把策略搬到 OpenClaw 配置层,业务代码会干净很多,后续做成本控制、稳定性兜底也更顺手。