---
title: "自定义与私有化模型"
description: "把 Cetas 接到私有端点、企业网关或自建部署上。"
---

> Documentation Index
> Fetch the complete documentation index at: https://colmugx.github.io/cetas/llms.txt
> Use this file to discover all available pages before exploring further.

# 自定义与私有化模型

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

## 工作原理

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

## 最小配置

```json
{
  "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 |

```json
{
  "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` | 模型或供应商 | 选择器里要列出的档位 |

```json
{
  "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` 会安静地拖低压缩质量，而不会报错。

## 验证

```text
/login my-gateway
/model
```

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

同一份配置编辑器入口和 runner 直接继承，不需要每个入口重配一遍。内置 id 的优先级见[供应商](/cetas/configuration/providers/)。

Source: https://colmugx.github.io/cetas/configuration/custom-models/index.mdx
