用 DeepSeek 起的实例想中途换通义或 Claude 又不想丢历史记录?这篇拆解 PUT /api/app/instances/:id/llm-config 在线热切换供应商与模型的完整流程,含切完不重启不生效、不能自填 baseUrl 等四个真实坑。
上线一个 AI Agent 实例时,多数人会先用最便宜的 DeepSeek 跑通流程(怎么起实例见《如何用 API 一键部署 AI Agent》)。但跑起来之后,真实需求往往变了:客服场景要换 Claude 应付复杂多轮、代码场景要切 deepseek-reasoner、或者纯粹想对比通义和文心的效果。重建实例意味着丢掉已有对话历史和会话配置——能不能直接在运行中的实例上把模型换掉?
怡途Claw 给的答案是 PUT /api/app/instances/:id/llm-config。这篇把这个“在线换模型”的请求拆成三步,每步带上真实字段和我踩过的坑。
一、先看实例现在挂的是哪个模型
换之前先确认现状。带上实例 id 拉当前配置:
GET /api/app/instances/ee0f78d0-83ec-4ad9-b7f6-0690e0416499/llm-config
Authorization: Bearer <token>
返回长这样:
{
"success": true,
"data": {
"provider": "deepseek",
"providerId": "8f3a6c4c-3f82-4e20-a0b6-4b1a2b5e91f2",
"baseUrl": "https://api.deepseek.com",
"modelId": "deepseek-chat",
"hasApiKey": true,
"apiKeyMasked": "sk-1****9f3a"
}
}
这里有个细节值得说:接口不会把 key 明文给你,只回 apiKeyMasked(前 4 后 4,中间打码)。APP 端的设计就是平台替你托管 key 和计费,所以你永远看不到完整 apiKey,只能确认“有没有绑、绑的是哪家的”。hasApiKey: true 说明这家供应商的 key 平台已经配好,可以直接切过去用。
记下当前的 modelId(deepseek-chat)和 providerId,待会要换掉它。
二、挑好目标供应商和模型
切换前先确认目标模型在不在 supportedModels 里,别盲切:
GET /api/app/llm/providers
Authorization: Bearer <token>
每家供应商带 supportedModels 和 modelPricing。比如你想换成通义千问的 qwen-max,先在返回里找到通义那家(业务标识 aliyun-qwen),确认 qwen-max 在 supportedModels 数组里、且 modelPricing["qwen-max"].enabled === true。
两个值都记下来:
id(供应商的数据库主键,UUID)或providerId(业务标识,如aliyun-qwen、anthropic-official)——这俩传哪个都认modelId(具体模型,如qwen-max、claude-sonnet-4-5)
另外瞄一眼 modelPricing 的 inputPrice / outputPrice。从 deepseek-chat(0.001/0.002)切到 qwen-max,单价会高一截,按 token 计费会直接体现在账单上(计费明细怎么看,见《怡途Claw 计费 API 查余额与用量明细》)。切之前心里要有数。
三、发起切换
核心请求:
PUT /api/app/instances/ee0f78d0-83ec-4ad9-b7f6-0690e0416499/llm-config
Authorization: Bearer <token>
Content-Type: application/json
{
"providerId": "aliyun-qwen",
"modelId": "qwen-max"
}
成功返回更新后的实例和新的 llmConfig:
{
"success": true,
"message": "大模型配置更新成功",
"data": {
"instance": { "id": "ee0f78d0-83ec-4ad9-b7f6-0690e0416499", "status": "running", "runtimeType": "openclaw" },
"llmConfig": {
"provider": "aliyun-qwen",
"modelId": "qwen-max",
"hasApiKey": true,
"apiKeyMasked": "sk-a****2c7e"
}
}
}
看到 apiKeyMasked 换了人,说明 key 已经跟着供应商一起切过去了——这就是平台托管的好处,你不用管通义的 key 怎么填。
坑一:什么都不传就 400
这个接口要求至少传一个供应商或媒体模型。如果你发了空 body 或只传了个空 modelId:
{
"statusCode": 400,
"message": "APP端修改大模型时至少需要选择聊天供应商或媒体供应商",
"error": "Bad Request"
}
光切 modelId 不带 providerId 也不行——APP 端的规矩是模型必须挂在系统供应商名下,不存在“模型不变只换 key”这种操作。
坑二:别想着自填 baseUrl 和 apiKey
跟创建实例时一样,APP 端切换走的是系统供应商这条路。你没法通过这个接口把实例指向自己的中转地址或自己的 key。providerId 传系统列表里有的那几家就行,baseUrl/apiKey 平台按供应商自动给你填好。
这个约束是设计上的:模型网关、key 轮换、计费扣费都在平台侧,所以 APP 接口这条线不开放自定义地址。真要用自己的 key,去网页端实例配置里改,APP 接口管不到。
坑三:切完不重启,还在用旧模型
这是最容易漏的一步。接口返回 message: "大模型配置更新成功",看着像生效了,但配置写进去了,运行中的容器还加载着旧的模型实例。你要显式调一下重启:
POST /api/app/instances/ee0f78d0-83ec-4ad9-b7f6-0690e0416499/restart
Authorization: Bearer <token>
重启要过 SubscriptionGuard 校验套餐,个人版月付以上才能调。重启完再发一条测试消息(流式对话怎么发见《怡途Claw 流式对话 API 实战》),确认返回里模型的字段变了,才算切换真正落地。我有一次切完没重启,测了半天以为通义变笨了,其实是 DeepSeek 还在答。
坑四:切到 disabled 的模型会哑火
modelPricing 里每个模型有个 enabled 字段。有些模型虽然出现在 supportedModels 里,但 enabled: false(供应商临时下线或你没开权限)。切过去不报错,但发消息会 500 或超时。所以第二步挑模型时,不光看在不在列表里,还要确认 enabled === true。
四、几个常见切换场景
- 省钱回切:高峰期用 qwen-max,下班切回 deepseek-chat。同样一个
PUT,providerId 换回deepseek、modelId 换回deepseek-chat即可,历史会话一个不丢。 - 上推理模型:处理复杂逻辑时切
deepseek-reasoner,它和deepseek-chat同属一家供应商,只换 modelId 不换 providerId 就行。 - 换家供应商:从 DeepSeek 整体迁到通义,providerId 和 modelId 一起换,key 自动跟着切。
- 上 Claude:客服类多轮复杂场景,providerId 传
anthropic-official,按需选 claude 系列模型,单价最高但效果最稳。
收尾
在线换模型这条线,本质就是 GET /llm-config 看现状 → GET /llm/providers 挑目标 → PUT /llm-config 切 → POST /:id/restart 重启生效,四个请求搞定。难的不是接口本身,而是那几个“看着成功其实没生效”的坑:不传供应商、想自填 key、切完不重启、切到 disabled 模型。
下一篇会讲实例下的文件上传与知识库——把私有文档喂给 Agent 做 RAG 的那条 /api/app/chat/instances/:id/files 线。