OpenClaw + 147AI 实战:用 OpenAI 风格(/v1)统一网关,搭一条多模型智能体流水线
关键词:OpenClaw,147AI,OpenAI 风格,/v1,API 网关,多模型调度,故障切换,智能体流水线
摘要:大模型更新越来越快,真正拖慢交付的往往不是 Prompt,而是接口差异、Key 管理、限流、流式和兜底这些工程细节。本文用 OpenClaw 负责流程编排与任务执行,用 147AI 的 OpenAI 风格 /v1 入口统一调用口径,给出一段可参考的 Provider 配置和一份 Python 最小示例,帮助你把“采集 → 清洗 → 调度 → 输出”做成一条能长期维护的流水线。
如果你要跑的不是一次性 Demo,而是要稳定地跑一段时间(采集、归档、生成内容、分发),先把“入口统一 + 模型可替换”这两件事做掉,后面会少很多返工。
引言:你写的不是智能体,是适配层
做 AI 应用有个现实:你以为你在写业务,最后写出来的大半却是“让模型能稳定跑起来”的适配层。
今天接 A 家,明天换 B 家试效果;SDK、鉴权、错误码、流式细节、工具调用格式都不一样。你越想多接几家,项目越容易被胶水代码包住:能跑,但每次改动都得小心翼翼。
如果你要的只是 Demo,硬怼也行;但如果你要的是能长期跑的自动化流程(比如:定时采集信息 → 归档 → 总结 → 生成报告 → 分发),你需要把“模型”从代码里解耦出来:让模型像数据库/缓存一样,是可替换的资源,而不是写死在业务里。
下面我用 OpenClaw + 147AI 这个组合,讲清楚怎么把调度权收回来:业务代码只面对一种口径,模型怎么换、怎么兜底交给配置和网关。
第一章:为什么多模型项目最容易变成一团适配代码?
问题不在“你接了几家模型”,而在于耦合点放错了位置。常见会卡在这几处:
- SDK 与请求结构:每接一家模型就多一套 client、多一份参数与返回结构的假设;一旦要迁移或做 AB 实验,改动面会从“一个调用点”扩散成“一片文件”。
- 认证与额度:Key 分散、轮换难;某个渠道限流或风控时,业务层很难优雅降级。
- 运行时行为:流式、超时、重试、并发、工具调用等细节不一致,你不得不把“兼容逻辑”塞进业务代码里。
结果就是:业务逻辑没复杂多少,适配层先膨胀了。你一换模型,改的不只是 model=,还有一串你原本不想维护的边角行为。
第二章:147AI:先把调用口径统一,再谈模型选择
把模型从业务里抽出去,最直接的办法是引入统一网关:应用只面向一种接口形态,至于背后路由到哪家模型、用哪个 Key、怎么做限流与兜底,尽量交给网关/配置层。
关于 147AI,官网首页的页面描述(meta description)写明它用于 OpenAI 接口的聚合管理,支持包括 Azure 在内的多种渠道,并提供单可执行文件与 Docker 镜像,主打“一键部署”(来源:147ai.com)。从接口路径命名也能看出它沿用 OpenAI 的 /v1/... 形态:例如对 https://147ai.com/v1/chat/completions 发起不带授权的请求会返回 401,响应里会提示“未提供令牌”。
这意味着你可以把整体链路变成这样:
业务代码 / 自动化任务
↓
OpenClaw(负责任务编排与执行)
↓
147AI(统一 OpenAI 风格入口:/v1/...)
↓
不同模型能力(文本 / 推理 / 多模态等,以你在 147AI 中实际可用的为准)
入口一旦收敛,业务侧通常只需要关心两件事:base_url 指向哪里、model 选哪个。SDK 映射、账号/Key 管理,以及一些兜底策略(比如 fallback、重试、轮换)就有机会从业务代码里抽出来。
第三章:实战:用 OpenClaw 组织流程,把 147AI 当作 Provider
OpenClaw 是一个开源 AI 助手/网关,支持用配置把“模型选择、fallback、工具与渠道”组织起来(项目地址:openclaw/openclaw;文档:OpenClaw Docs)。
这章只做一件事:让 OpenClaw 把 147AI 当成一个 OpenAI 风格 Provider(对应 OpenClaw 里的 openai-completions 协议)。之后你要换模型,很多时候只是改一个 provider/model-id 字符串。
1)先跑通 OpenClaw 的配置入口
OpenClaw 的网关配置文件默认在 ~/.openclaw/openclaw.json,格式是 JSON5(支持注释与尾逗号)。更省事的方式是先跑一遍向导(参考:Configuration):
openclaw onboard
2)把 147AI 配成一个 Provider(OpenAI 风格)
OpenClaw 的 Provider 允许你自定义 baseUrl、apiKey 以及 API 协议类型(例如 openai-completions)。下面这段写法沿用 OpenClaw 的“Model Providers”文档结构(参考:Model Providers),把 Provider 名字起成 api147:
// ~/.openclaw/openclaw.json(片段示例)
{
models: {
mode: "merge",
providers: {
api147: {
baseUrl: "https://147ai.com/v1",
apiKey: "${API147_KEY}",
api: "openai-completions",
// 模型 id 以 147AI 控制台/文档列出的为准,这里只放示例占位符
models: [
{ id: "your-model-id", name: "Primary model (from 147AI)" },
{ id: "your-fallback-model-id", name: "Fallback model (from 147AI)" },
],
},
},
},
agents: {
defaults: {
model: {
primary: "api147/your-model-id",
fallbacks: ["api147/your-fallback-model-id"],
},
models: {
"api147/your-model-id": { alias: "主力" },
"api147/your-fallback-model-id": { alias: "兜底" },
},
},
},
}
然后在运行 OpenClaw 之前,把 Key 放进环境变量里(示例):
export API147_KEY="你的 147AI Key"
到这里,你就把“模型接入”从业务代码里挪到了 OpenClaw 配置层:后面要换模型,只需要换 api147/<model-id>。
补一条很实用的坑:如果你把 agents.defaults.models 当成 allowlist(允许列表)启用了,但没把 api147/<model-id> 加进去,聊天里切模型会提示 “Model is not allowed”。这个行为在官方文档里有说明(参考:Models CLI)。
第四章:多模型落地最难的一关:稳定性
生产环境里,最难的从来不是“能不能调用”,而是“遇到抖动时能不能稳住”。
OpenClaw 的失败处理有两层:模型 fallback(agents.defaults.model.fallbacks)与同一 Provider 内的鉴权档案轮换(参考:Model Failover)。
你可以先用很朴素的策略把系统扛住:
- 先准备一主一备两档模型。主力追求效果,兜底保证可用。
- 让业务只关心“拿到结果/拿不到结果”,把重试、冷却、轮换放在网关与配置层。
- 日志里至少带上 model、耗时、错误类型。线上抖动时,这些信息能救命。
这件事看起来“很脏”,但它决定你的系统能不能持续跑。
第五章:接入 Flux / Sora 这类多模态模型时,别踩这几个坑
多模态的坑不在“调用一次接口”,而在 任务形态:图片、视频、音频通常更重、更慢、更依赖队列/存储,和普通文本请求不是一回事。
OpenClaw 里可以单独指定 agents.defaults.imageModel,用来处理主模型无法接收图片输入时的自动切换(参考:Models CLI)。
1. Flux:别把“重模型”当“轻接口”
文生图/图生图往往对输入、分辨率、并发更敏感。建议你至少做到两点:
- 把图片模型单独挂在
agents.defaults.imageModel,不要和文本模型混用同一个默认位。 - 把“上传/存储/回传图片链接”当成流程的一部分设计,而不是临时在代码里拼接。
2. Sora 类视频生成:把一次调用当成一个任务
视频生成更像“作业系统”,不是传统的“请求-响应”。
- 异步优先。即便接口支持同步返回,架构上也按异步任务来做(队列、状态机、超时与取消)。
- 让流程可重放。把输入参数与版本记下来,别让问题变成“复现不了的玄学”。
- 做分层兜底。失败时先降级分辨率/时长,再降级模型,最后再给用户明确反馈。
这些都和“选哪家模型”无关,但决定你能不能把多模态真正做成产品。
第六章:代码实战(Python 示例)
如果你不想先引入 OpenClaw,只想先做连通性验证,可以用 OpenAI Python SDK 的 base_url 方式尝试直连 https://147ai.com/v1(不带授权请求会返回 401,这一点前面已经提到)。
from openai import OpenAI
client = OpenAI(
api_key="你的 147AI Key",
base_url="https://147ai.com/v1",
)
resp = client.chat.completions.create(
# model id 以 147AI 实际提供的列表为准
model="your-model-id",
messages=[
{"role": "system", "content": "你是一个严谨的工程助手。"},
{"role": "user", "content": "用一段话说明:为什么统一网关能降低多模型接入成本?"},
],
)
print(resp.choices[0].message.content)
复制代码前,建议先看这几个点:
base_url通常以/v1结尾。model的具体 ID 以 147AI 的控制台/文档为准。- 如果返回 401 且提示“未提供令牌”,大概率是 Key/令牌没带上或无效。
- OpenAI SDK 默认用
Authorization: Bearer <api_key>方式携带令牌。 - 如果你通过 OpenClaw 切模型遇到 “Model is not allowed”,回去检查
agents.defaults.models的 allowlist 设置。
当你把 base_url 与 model 参数抽出来,切换模型就会变成“改配置”。
第七章:给架构师和开发者的建议
我更愿意把“统一网关”当成一条底线:你不一定一开始就用得很复杂,但最好从第一天就把路走对。
- 把模型当成依赖项,而不是写死的业务逻辑。业务层不关心供应商,只关心能力与返回结构。
- 把可用性当成功能的一部分。超时、重试、fallback、限流策略,最好有明确的默认值。
- 别迷信单一最强模型。真实系统里更常见的是“主力效果 + 兜底可用性”的组合。
- 先把可观测性补齐。只要不记录 model 与耗时,后面做成本控制和稳定性优化就会很痛。
结语
这篇文章从头到尾只想落实标题里的两件事:统一网关和流水线。
OpenClaw 负责把任务拆开、串起来,147AI 负责把模型调用收敛到一个 OpenAI 风格入口。入口统一之后,你就能把时间花在流程本身:数据怎么来、怎么清洗、怎么评估产出,而不是不停地改 SDK 和适配细节。
附录:主流 AI 模型与 147AI 配合表
下面这张表不假设任何“你一定能用到某个具体模型”。它只给一个工程化的对照:你要的能力是什么、在 OpenClaw 里应该放在哪个配置位、以及在 147AI 侧你需要确认哪些信息(模型 ID、是否支持流式、是否支持多模态等)。
| 你要的能力 | 常见落点(OpenClaw) | 147AI 侧你需要确认 | 备注 |
|---|---|---|---|
| 日常对话/写作 | agents.defaults.model.primary |
可用的文本模型 ID;是否支持流式输出 | 先选一个“稳定”模型做主力 |
| 复杂推理/规划 | agents.defaults.model.fallbacks(或另设 agent) |
是否有更擅长推理的模型;是否有更高延迟 | 推理模型适合做“按需调用” |
| 图片输入/图片生成 | agents.defaults.imageModel.primary |
图片模型 ID;输入输出格式;是否需要图片 URL | 把存储/回传当流程设计 |
| 视频生成(Sora 类) | 通常做成工具/任务,不建议当同步对话模型 | 是否支持异步;任务状态查询方式 | 关键在队列与状态机 |
| Embeddings / 向量化 | 取决于你是否有对应端点与工具链 | 是否提供兼容的 embeddings 端点(如 /v1/embeddings) |
没有就单独接一套也行 |