#379·inkos

[Bug] 自定义(custom) LLM 提供方未实现 /models 接口时,Studio 后台拒绝保存

Author: CCkerberCreated Aug 18, 2026Updated Aug 28, 2026
Labelsbug

What happened?

在 Studio 后台配置 custom 类型 (OpenAI 兼容) 的 LLM 提供方时,即便已正确填写 baseUrl、apiKey 和默认模型 ID,点击「验证/保存」仍被拒绝,无法保存。 测试使用火山方舟 Agent Plan (volcengine agent plan) 火山方舟提供的兼容 OpenAI 接口协议工具(已支持Responses API)为 https://ark.cn-beijing.volces.com/api/plan/v3

Image 火山方舟AgentPlan提供的API符合OpenAI接口规范,但inkos不应当限制API必须有/models端点,这在逻辑上是错误的

根因:Studio 在保存前会无条件向 baseUrl + "/models" 发起探测 (inkos-core/dist/llm/providers/probe.jsprobeModelsFromUpstream),而许多自建/聚合 API 并不实现该可选端点。探测失败后,inkos-studio/dist/api/server.js:3076 直接 return 400 拒绝保存。矛盾点在于:custom 提供方在 inkos-core/dist/llm/providers/endpoints/custom.js 中定义为 models: []checkModel: undefined(即设计上本就不掌握模型清单),验证环节却强制要求 /models 探测通过。同一份配置在 CLI 下不调 verifyService、不探测,可直接推理,仅在 Studio 后台卡死。

Steps to reproduce

  1. 启动 Studio (inkos studio),打开 Web 后台 → 设置 → LLM 提供方 → 新增 custom 类型
  2. 填写:
    • baseUrl:一个 OpenAI 兼容但不提供 /models 端点的上游地址(例如火山方舟AgentPlan仅暴露 /v3/chat/completions,可以正常调用)
    • apiKey:有效密钥
    • 默认模型 ID:例如 deepseek-v4-pro(该 ID 在 chat/completions 中实际可用,为火山方舟AgentPlan提供的标准模型ID)
  3. 打开浏览器开发者工具 → Network 面板,准备观察验证请求
  4. 点击「测试连接」或「保存」
  5. 随即页面显示红色字样「无法自动确定模型,请先填写可用模型或提供支持 /models 的服务端点。」

Expected behavior

只要 chat/completions 可正常调用、且用户已手动指定可用模型 ID,服务就应当保存成功。/models 是 OpenAI 兼容协议的可选端点,缺失不应阻断保存。/models 仅可用于自动获取API提供的模型列表,不应当用于校验API上游的chat/completions 对话端点是否可用。运营商的models端点请求后返回的列表不一定准确,因为模型提供商可能滞后更新该列表,应当以用户指定的模型ID为高优先级。

InkOS version

1.8.0

Operating system

Windows (native)

LLM provider / model

deepseek-v4-pro

Relevant logs

bash
安装方式:
- npm 全局 `@actalk/inkos`
- 操作系统:Windows
- 提供方类型:custom(上游未实现 `/models` 接口)
**根据源码推断的返回结构(server.js:3076 拦截分支):**

HTTP/1.1 400 Bad Request
{
  "ok": false,
  "error": "<probe.error 或 connectionFailed 文案>",
  "probe": { "ok": false, "error": "..." }
}


**关键源码(v1.8.0):**
- `inkos-studio/dist/api/server.js:3076` — 硬性拦截:
  
  if (!probe.ok) {
      return c.json({ ok: false, error: probe.error ?? connectionFailed, ... }, 400);
  }
  
- `inkos-core/dist/llm/providers/probe.js` — `probeModelsFromUpstream()` 无条件请求 `baseUrl + "/models"`
- `inkos-core/dist/llm/providers/endpoints/custom.js`:
  
  export const CUSTOM = {
      id: "custom",
      api: "openai-completions",
      baseUrl: "",
      models: [],              // 空,不预置模型清单
      checkModel: undefined,   // 无模型校验
  };
  

---

## 补充:建议修复与临时绕过方案
**建议修复**(对 custom 放宽门槛,不影响其他 provider):
- 方案 A(最小改动):在 `server.js:3076`,对 `custom` 类型,若已填模型 ID 且 `chat/completions` 可达,则 `/models` 探测失败也放行保存。同时全面排查类似校验方式,彻底改正该验证步骤。
- 方案 B(更彻底):在 `probe.js` 中,对 `custom` 缺失 `/models` 时直接返回 `ok: true`,依赖核心库已有的 `UNKNOWN_MODEL_FALLBACK_MAX_TOKENS` 兜底。

**临时绕过方式(目前可用,但不修复该bug仍有可能导致其他功能出现错误):**
1. 反代/中转层补一个 `/models` 端点返回 `{"data":[{"id":"你的模型ID"}]}`;
2. 或改用 CLI 直连:`inkos config set-global --provider openai --base-url <URL> --api-key <KEY> --model <模型ID>`。