Skip to content

自定义与私有化模型

把 Cetas 接到私有端点、企业网关或自建部署上。

团队很少会拿公网 API 来落地编码 agent。常见的形态是:你们已经跑着模型,前面架一个网关,key 由基础设施管而不是每个开发者自己管。Cetas 把这种用法当作一等供应商对待。

工作原理

providers 里每一个没有被内置供应商占用的 key,都会变成一个 自定义供应商。不需要注册、不需要写插件:key 本身就是供应商 id,而且它和内置供应商同等对待 —— /login、/model、目录刷新、模型缓存、编辑器入口全都认得它。端点说哪种协议,由条目里的 protocol 声明。

最小配置

{
  "providers": {
    "my-gateway": {
      "base_url": "https://llm.internal.example/v1",
      "api_key": "sk-...",
      "models": [
        { "id": "qwen3-32b", "context_window": 131072 }
      ]
    }
  }
}
  • base_url —— 必填。服务端要求 /v1 时就带上;大多数 OpenAI 形状的服务端已经把版本号写进 base URL。
  • api_key —— 实际使用中必填。也可以不写在这里,改用 /login my-gateway,凭据会落到 <CETAS_HOME>/.cetas/credentials/,密钥不进 settings 文件。
  • models —— 必填,且不能为空。每个条目要有 id,id 不能重复。

endpoint_prefix 是给”base_url 只写了裸主机”(http://10.0.0.4:8080)而 API 挂在 /v1 下的情况准备的。能把前缀写进 base_url 就写进去,这一项留空。

选择协议

自定义端点说三种协议之一:

protocol 请求 协议
chat_completions(缺省) POST {base_url}{endpoint_prefix}/chat/completions OpenAI Chat Completions
responses POST {base_url}{endpoint_prefix}/responses OpenAI Responses API
messages POST {base_url}{endpoint_prefix}/messages Anthropic Messages API
{
  "providers": {
    "claude-proxy": {
      "base_url": "https://api.anthropic.com",
      "endpoint_prefix": "/v1",
      "protocol": "messages",
      "api_key": "sk-ant-...",
      "models": [{ "id": "claude-sonnet-5", "context_window": 200000 }]
    }
  }
}
  • 不写 protocol 就是 chat_completions:协议出现之前写的条目,行为一个字节都不变。
  • 路径后缀接在 base_url + endpoint_prefix 之后。版本段二选一写:写进 base_url(https://llm.internal.example/v1),或者裸主机配 endpoint_prefix: "/v1" —— 别两边都写。
  • protocol 是供应商级的,models[] 的每一条都可以覆盖它,所以「一个端点、几个模型系列各说不同协议」仍然是一个供应商 id。
  • 写了不认识的值会明确报错并列出可选值,不会退化成 chat 协议:退化的结果是把请求发到错误形状的端点上,然后收到一个看不懂的 400。

凭据放在哪

auth 决定 key 怎么上线:

auth 效果
auto(缺省) chat_completions/responses 用 Authorization: Bearer;messages 用 x-api-key 加 anthropic-version: 2023-06-01
bearer 所有协议都用 Authorization: Bearer —— 给用 Bearer 挡在 Messages 前面的网关
x_api_key 所有协议都用 x-api-key

各协议的推理档位

档位的含义到处一样 ——「这个模型该想多深」—— 但每条协议写法不同,而且不会给一个不知道刻度的端点编数字:

  • chat_completions —— 顶层 reasoning_effort,原样发出。
  • responses —— reasoning.effort;选了档位就不再发 temperature,推理端点会拒。
  • messages —— thinking: {"type": "enabled"}。档位名字不会被换算成 budget_tokens 数字。
  • off —— 哪条协议都不发,端点用自己的默认值。

responses 还是无状态调用(store: false),不回放 reasoning items:通用端点并不声明 encrypted reasoning 契约。

输出上限

max_output_tokens(正整数,缺省 8192)是 messages 协议上的 max_tokens,该字段必填。回合自己带了上限就以回合为准,这一项只补缺口。

声明模型能力

选择器只能列出你声明过的东西。除了 id,其余全是可选项,而留空比猜一个更安全:

字段 写在 作用
context_window 模型 容量(token);不写则该模型不做自动压缩
compact_threshold 模型 触发比例,需满足 > 0 且 <= 1(默认 0.88)
image_input 模型或供应商 接受图像输入;供应商级作为其模型的默认值
reasoning_effort 模型或供应商 固定一个档位 —— 不出现选择器
reasoning_efforts 模型或供应商 选择器里要列出的档位
{
  "providers": {
    "my-gateway": {
      "base_url": "https://llm.internal.example/v1",
      "models": [
        {
          "id": "qwen3-235b",
          "context_window": 262144,
          "compact_threshold": 0.85,
          "reasoning_efforts": ["low", "medium", "high"],
          "image_input": false
        }
      ]
    }
  }
}

安全与稳定性

  • 优先用 /login my-gateway 而不是内联 api_key:凭据在 <CETAS_HOME>/.cetas/credentials/,不会跟着文件被粘进工单。
  • 拒绝 prompt_cache_key 的网关也能用:Cetas 会在本进程内记住这次拒绝,后续不再发送,而不是让整个回合失败。
  • 自定义供应商不会从任何公开模型库刷新。它的目录就是你声明的那些 —— 这也正是为什么写错的 context_window 会安静地拖低压缩质量,而不会报错。

验证

/login my-gateway
/model

然后发一条消息。如果 /model 是空的,要么这个供应商没组装起来(检查 id 是否合法、是否撞了内置 id),要么 models 数组被拒绝了 —— 写坏的段会明确报错,而不会被修补。

同一份配置编辑器入口和 runner 直接继承,不需要每个入口重配一遍。内置 id 的优先级见供应商。

Navigation

Type to search…

↑↓ navigate↵ selectEsc close