# 自定义模型 · BYOK、Ollama 与 OpenAI 兼容端点

> grok 不绑死 xAI 模型——能接自带 key、Ollama、OpenAI 兼容、Anthropic。这一章看模型目录怎么分层合并、凭据怎么逐级解析、协议（api_backend）与鉴权（auth_scheme）为什么在采样器里是正交的两个字段，以及采样器为什么刻意「不认 URL」。

- 作者：David（道雾轩）
- 专栏：Grok Build 源码解读（https://daiw.org/manual/grok-build.md）
- 最后更新：2026-09-15
- 原文：https://daiw.org/manual/grok-build/custom-models
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 自定义模型 · BYOK、Ollama 与 OpenAI 兼容端点

Part 4 最后一章，回到[三种 API 流](https://daiw.org/manual/grok-build/api-streams)埋的线：grok 怎么接**任意模型**——自带 key、本地 Ollama、OpenAI 兼容端点、Anthropic。`xai-grok-config` 只管配置文件的加载与分层合并；模型目录、凭据这些逻辑在 shell 的 `agent/config.rs` 里，最后组装成采样器要的 `SamplerConfig`。

## 两个正交的字段：协议 vs 鉴权

一个清晰的设计：在采样器里，**`api_backend`(协议)和 `auth_scheme`(鉴权)是独立的**。

- `ApiBackend`:`ChatCompletions`(OpenAI 兼容，默认)/ `Responses` / `Messages`(Anthropic)——决定**请求长什么样**。
- `AuthScheme`:`Bearer`(`Authorization: Bearer`)/ `XApiKey`(`x-api-key`)——决定**怎么带凭据**。

但只有前者是你能配的：`[model.<名>]` 里有 `api_backend`，却没有 `auth_scheme`——生产路径都不设它，落到默认的 `Bearer`。所以接 Anthropic 的官方写法是 `api_backend = "messages"`，再把 key 放进 `extra_headers` 的 `x-api-key`(grok 原样发送)；接某个 OpenAI 兼容端点 = `ChatCompletions` + `Bearer`。

## 模型目录：一次分层合并

模型列表不是写死的，而是 `resolve_model_list` 组装的一个 `IndexMap`，优先级从低到高：

1. 内置默认(`default_models.json`)——若你配了自定义端点，这层**跳过**；
2. `/v1/models` **预取**的模型——注意这层是**整体替换**而不是合并：预取成功后，服务端没返回的内置模型直接丢掉，内置条目只在字段上「捐献」(比如预取条目没报上下文窗口时，从同名内置条目借 `context_window`)；
3. 你 `[model.<名>]` 的**覆盖**(最高优先级，新模型默认 200k 上下文)；
4. 全局 `[models]` 的 `extra_headers`、`temperature` 等**兜底填充**(仅当每模型没设时)。

一句话：**config `[model.*]` > 预取 `/v1/models` > 内置默认**。`[model.<名>]` 能配的很全：`base_url`、`api_key`/`env_key`、`api_backend`、`context_window`、`extra_headers`，还有 `query_params`、`env_http_headers`(从环境变量取头的值，不落盘)、`mtls_cert_dir`(按模型配 mTLS 客户端证书)……多个模型共用一个提供方时，可以写一个 `[model_providers.<id>]`，模型里用 `model_provider` 引用、继承它的地址与凭据。

## 凭据：逐级解析

`resolve_credentials` 按优先级找凭据(注释原话是 `model api_key/env_key > cached auth-provider token > session token > XAI_API_KEY`)：

1. **模型自带**(`[model.foo]` 的 `api_key` 或 `env_key` 指的环境变量)→ `ApiKey`;
2. **凭据助手**：模型声明了 `auth_provider`(引用一个 `[auth_provider.<名>]` 定义的、负责铸 token 的助手)时，用它缓存的 token；
3. **会话 token**(`grok login` 登的)→ `SessionToken`；
4. **`XAI_API_KEY` 环境变量** → `ApiKey`；
5. 都没有(若配了 `env_key` 却没设，会警告)。

还有个企业 kill-switch `enforce_disable_api_key_auth`：把第一方 xAI 的 API key 强制换成会话鉴权，但**BYOK / 非 xAI 端点不受影响**。

## 采样器刻意「不认 URL」

一个漂亮的解耦：[采样器](https://daiw.org/manual/grok-build/sampler-actor)本身是 **URL-agnostic** 的——它不知道自己在连 xAI 代理还是 Ollama。所有和具体端点相关的头(代理鉴权头等)由 **shell 在边界上**用 `inject_url_derived_headers` 注入，且**从不覆盖你已设的头**(你的 `extra_headers` 赢)；它还会给所有请求补一个标明交互或 headless 的客户端模式头，BYOK、Ollama 也不例外。**让核心组件不认具体端点、把端点差异挤到边界**，是这类「要支持多后端」的系统里反复出现的架构原则。

<Callout type="info">
  用法侧对应仓库内 user-guide `11-custom-models`，别把两种配方混在一起：接 Ollama 只要一个 `[model.*]`，把 `base_url` 指向 `http://localhost:11434/v1`；而 `GROK_MODELS_BASE_URL`(或 `[endpoints] models_base_url`)是另一种「自定义模型端点」模式——从 `{base_url}/models` 拉整张模型表、跳过全部内置模型、改走 API key 鉴权(免 `grok login`)。BYOK 记得设 `context_window`：自己配的新模型默认给 200k，从端点拉来却没报窗口的默认 256k，都可能和实际不符。
</Callout>

## 和《从 LLM 到 Coding Agent》对照

对照 [raw-llm-api](https://daiw.org/manual/llm-to-agent/raw-llm-api)：最小实现里模型端点常是写死的一个。grok 的增量是一整套**模型目录 + 凭据解析 + 协议/鉴权正交 + URL-agnostic 采样器**，让「换任意模型」成为配置而非改码。这也是 [api-streams](https://daiw.org/manual/grok-build/api-streams) 那三种后端存在的最终理由。Part 4 扩展机制完——下一部分钻进[终端 UI](https://daiw.org/manual/grok-build/tui-architecture)。

---

上一篇：[Subagents 与 personas](https://daiw.org/manual/grok-build/subagents)
