自定义 provider 的 ID、显示名、模型名撞在一起:命名这件小事怎么把配置搞乱

2026-08-07

**接自定义模型出问题时,你以为在调”接入方式”,其实一大半时间是在跟”名字”较劲。**一个自定义 provider 至少要起三种名字:给程序做唯一标识的 ID、给人看的显示名、真正被塞进请求体发到服务端的模型标识。这三种名字在有些产品里是三个字段,在有些产品里挤在一个 JSON 键上,而它们各自被不同的代码路径消费。填串了,请求照发不误,只是发给了错的地方,或者带着错的模型名回来一个你看不懂的错误。

先把两件常被混为一谈的事分开:接入方式说的是客户端怎么找到服务端(地址、密钥、协议形态),模型能力说的是那个模型会不会用工具、能吃多长的上下文。命名问题横跨两者——你在”接入方式”里写下的一个标识符,可能决定了客户端去哪个环境变量里找密钥;你在”模型能力”里写下的名字,则决定了服务端认不认这个请求。

站内已有几篇相邻的文章,分工是这样的:模型别名的风险 讲的是服务商侧的别名指向漂移,DeepSeek 别名失效 404 讲的是某个具体模型名失效后的排查,MCP 工具命名冲突 讲的是工具层同名带来的调用歧义。本篇只管一件事:客户端配置文件/表单里那几个名字字段各自归谁管,以及它们互相串台时你该按什么顺序查。

本篇涉及的产品事实,全部来自各家官方文档在 2026-08-07 当天的记录,URL 见文末。字段随版本会变,动手前请以官方文档最新版为准。

一、三种名字,三条不同的去路

把名字按”谁读它”分类,比按”它长什么样”分类有用得多。

第一种:provider 的唯一标识。 这是给程序用的键,通常要求在你的配置里不重复。Kilo Code 新建 provider 时有一项就叫 Provider ID,官方文档写明它是唯一标识,文档示例值是 my-provider。Continue 的 config.yamlmodels 块下要求填 name,文档同样标明它是唯一标识。Zed 的写法更直白——本篇依据的记录里没有出现单独的”ID 字段”,标识就是 JSON 里的那个键名,文档示例中 openai_compatible 下面那层 "my-provider" 就是这个 provider 的名字。

顺带说一句容易看岔的事:Kilo Code 文档里 Provider ID 的示例值是 my-provider,Zed 文档示例里那个 JSON 键也叫 my-provider。这只是两家文档各自挑了同一个占位名,不是同一样东西,别把一家的用法搬到另一家去理解。

第二种:显示名。 Kilo Code 有独立的 Display name 字段,文档说明就是界面显示名。Zed 的模型条目里有 display_name,与之并列的 name 才是模型标识。按”界面显示名”这个字段语义推,它写中文、写备注、写”公司内网网关-测试环境”都不影响你要连的那个服务——但客户端内部究竟怎么消费这一栏,各家文档并没有逐条说明,实际以官方文档为准。

第三种:模型标识。 这是真正要发出去的那个字符串。Cline 的表单里叫 Model,文档说是”选择或输入具体的模型 ID”;Continue 里叫 model(和作为唯一标识的 name 是两个字段);Zed 的 available_models 每一项里的 name 就是模型标识。按 OpenAI 兼容协议的通用行为推,这个名字得和服务端认的字符串逐字一致才可能被受理——这一步是机制推理,不是哪家产品文档写过的话,但它决定了这一栏不归你审美。

顺着这个分类看 Crush 就清楚了:README 给出的自定义 provider 命令是

provider add deepseek --type openai-compat \
  --base-url "https://api.deepseek.com/v1"

紧跟在 provider add 后面的 deepseek 是你给这个 provider 起的名字,--base-url 才是地址。这里没有”显示名”这一栏——本篇依据的这份记录里没有出现独立的显示名字段,这不等于 Crush 没有相关能力,只是本篇不据此下结论。

二、一张表:哪个名字被谁消费

下表里的字段名逐字来自各家官方文档记录。第三列凡是标了”机制推理”的,都是按 OpenAI 兼容协议的通用行为推出来的判断,不是该产品文档写过的说法。

名词速查:OpenAI 兼容端点指服务端把接口做成和 OpenAI 那套请求/响应格式一样,于是客户端能用同一套代码去连;上下文窗口指一次对话里模型最多能吃进多少 token;**原生工具调用(native tool calling / function calling)**指模型按结构化格式直接返回”要调用哪个工具、参数是什么”,而不是靠客户端解析自然语言。

配置项它是什么(各家官方文档记录)填串了会怎样出处
Kilo Code:Provider ID该 provider 的唯一标识,文档示例 my-provider把中文备注或显示名写进来,就等于换了标识符;本篇依据的记录未说明重名时的处理方式Kilo Code 文档
Kilo Code:Display name界面显示名按字段语义推,主要影响你自己认不认得出来;客户端还拿它做什么,文档未逐条说明Kilo Code 文档
Kilo Code:Models手动添加或自动检测自动检测走 /v1/models 端点,失败时可手填模型 IDKilo Code 文档
Zed:openai_compatible 下的那层键名provider 名字,示例为 my-provider文档写明的规则:它同时决定密钥环境变量名(见第三节),改名会牵动别处Zed 文档
Zed:available_models[].name模型标识机制推理:这是发给服务端的字符串,写成显示名服务端就认不出来Zed 文档
Zed:available_models[].display_name界面显示名按字段语义推,写错主要影响可读性;具体消费方式文档未展开Zed 文档
Zed:available_models[].max_tokens上下文窗口上限由你填;数值与服务端实际上限不符时的表现属机制层面,见第五节Zed 文档
Continue:name唯一标识model 混填是最常见的一种串台Continue 文档
Continue:model具体模型名机制推理:这是发到服务端的字符串Continue 文档
Crush:provider add <名字>你给这个自定义 provider 起的名字本篇依据的记录未说明同名时的合并或覆盖规则Crush README

表里刻意没有写”会弹什么提示""什么时候被拦下来”。各家的界面与校验时机不在本篇依据的记录范围内,以你实际看到的界面为准。

三、Zed 的连锁反应:provider 的名字决定去哪找密钥

这是本篇最值得单拎出来的一条,因为它是官方文档写明的机制,不是推理。

Zed 的文档对密钥有一句原话:“Do not put API keys in settings.json.” 另一页写着:“Provider keys saved through Zed are stored in the system keychain, not in settings.json.”(keychain 指操作系统自带的凭据保管服务,密钥存在那里而不是明文躺在配置文件里。)

于是密钥有两条路:走 provider 设置界面保存,或者走环境变量。而环境变量的命名规则是 <PROVIDER_NAME>_API_KEY ——文档给的对应关系是:provider 名为 my-provider 时,环境变量就是 MY_PROVIDER_API_KEY

把这条和第一节合起来看,结论就出来了:**你在 settings.json 里给 provider 起的那个键名,不只是个标签,它参与了密钥查找。**如果哪天你觉得 my-provider 太笼统,改成别的名字,那条环境变量的名字也要跟着改。这类改动最阴的地方在于,配置文件本身看起来一切正常——名字是你精心挑的,地址、模型都没动,唯独密钥这条线断了。

Zed 文档里同时记录了 api_url(自定义 base URL)、available_models(模型数组)和 capabilities 对象(控制 tools、images、parallel_tool_calls 等能力开关),以及相关命令 agent: open settingszed: open settingszed: open settings file,还有一个 disable_ai 设置(写法 "disable_ai": true)用来关闭全部 AI 功能。要改配置文件时从这些命令进比较省事,具体以官方文档为准。

四、ID 是给机器看的:改名前先想清楚谁在引用它

Kilo Code 这边,新建 provider 的字段是一整套:Provider ID、Display name、Provider API(选 OpenAI Compatible,走 chat completions 端点)、Base URL、API key、Models、Headers(可选,自定义 HTTP 头,键值对形式)。这套字段的好处是”人看的”和”机器看的”从一开始就分开了,你不会被迫拿唯一标识去凑可读性。

它的 Base URL 还接受两种形态:标准形态 https://api.provider.com/v1,或者完整端点 https://api.provider.com/v1/chat/completions;文档说明第二种是给”端点结构非标准”的服务商和自建网关准备的。凭据有效时,Kilo 会从 /v1/models 端点自动拉取模型列表,自动检测失败可以手填模型 ID。这条对命名的意义是:自动拉回来的那份列表来自服务端本身,用它当拼写基准,比你凭记忆敲一遍靠谱

Kilo Code 文档里还有一条与命名相邻的提醒值得记住:接 Azure GPT-5 时不要用通用的 OpenAI 兼容 provider,要用 Kilo 原生的 azure provider,因为 Azure 会拒绝 max_tokens 参数。这说明”选哪个 provider 类型”和”给它起什么名字”是两件事,名字起得再规范也救不了选错类型。

Crush 那边是另一种形态。它的配置文件是 crushrc(bash 风格加 Crush 内建命令,不是 JSON),README 列出的位置顺序是 ./.crushrc(项目级)在前、~/.config/crush/crushrc(全局,Unix 类系统)在后。自定义 provider 必须是 OpenAI 兼容或 Anthropic 兼容 API。如果你在项目级和全局两个文件里用了同一个 provider 名字,会按什么规则合并——本篇依据的这份 README 记录里没有写明,别猜,去查官方 README。

Continue 则把名字和职责绑在了一起:models 块下每一项有 name(唯一标识)、providermodel,另有 roles 决定这个条目干什么活,取值是 chatautocompleteembedrerankeditapplysummarize,默认为 [chat, edit, apply, summarize]。(嵌入 embed 是把文本转成向量便于检索,重排 rerank 是对检索回来的结果重新打分排序,两者都不是聊天。)文档给的示例可以照抄结构:

models:
  - name: GPT-4o
    provider: openai
    model: gpt-4o
    roles:
      - chat
      - edit
    defaultCompletionOptions:
      temperature: 0.7
      maxTokens: 1500

注意这个示例里 name 写的是 GPT-4o(带大写和连字符,一望即知是给人看的),model 写的是 gpt-4o。两者长得像但角色不同,这恰恰是最容易埋雷的一种排版——看一眼觉得”这不重复了吗”,随手删掉一个,配置就废了。

顺带说,各家 base URL 的字段名根本不是同一个东西:Cline / Roo Code / Kilo Code 表单里叫 Base URL,Continue 叫 apiBase,Zed 叫 api_url,goose 用 OPENAI_HOST(另有 OPENAI_BASE_PATH),Crush 用命令行参数 --base-url。命名冲突的表亲就是字段名串台,把 A 家的键名写进 B 家的配置,按配置解析的一般行为推,更可能是那一项被忽略、客户端继续用默认值,而不是当场报一个指名道姓的错——各家实际怎么处理未知键,本篇依据的记录没有说明,以官方文档和你看到的实际表现为准。想系统过一遍接入方式,可以先看 编辑器接入自定义 API 的通用路径

五、边界与代价:命名规范不管什么

把名字理顺,是一件成本很低、收益也很有限的事。说清楚它管不到哪里,比夸大它的价值有用。

它不管模型能力。 名字起得再好,模型不支持工具调用还是用不了。Roo Code 官方文档的原话是:“Roo Code uses native tool calling exclusively. This is the only supported tool protocol — there is no XML-based fallback.” 这是官方文档的说法,不是本文的断言——意思是所选模型必须支持 OpenAI 兼容的 function calling,文档建议先查服务商文档确认该模型是否支持工具调用。Continue 那边有 capabilities.tool_use,Zed 的 capabilities 含 tools、parallel_tool_calls。这些都是能力开关,跟你怎么起名毫无关系。

它不管数值填得对不对。 上下文窗口要手填的场景不少:Cline 的 Context Window size、Roo Code 的 Context Window、Zed 的 max_tokens、aider 用 .aider.model.metadata.json 注册的 max_input_tokens / max_output_tokens。这些字段在各家文档里主要是被”列出来”的——客户端内部拿它做什么,本篇依据的记录没有逐条说明,实际行为以官方文档为准。至于”窗口填得比服务端上限大会怎样""最大输出设太小会不会被截断”,属于 OpenAI 兼容协议的通用机制推理,不是哪家文档的记载,真要确认得看服务端返回。

它不管配置分层带来的覆盖问题。 Gemini CLI 的 settings.json 有四处位置(/etc/gemini-cli/system-defaults.json~/.gemini/settings.json、项目根的 .gemini/settings.json/etc/gemini-cli/settings.json),优先级从低到高是:硬编码默认 → system defaults 文件 → user settings → project settings → system settings → 环境变量 → 命令行参数。名字相同的设置项在不同层级同时存在,赢的是优先级更高的那一层,跟名字好不好看无关。

它对”名字失效”也无能为力。 你写的模型标识本身可能在服务商侧被下线或改指向,这是另一个话题,见 模型别名的风险

代价是啥? 主要是改名的迁移成本。像 Zed 这种 provider 名字参与环境变量命名的设计,一旦你在团队里铺开了配置模板,再想统一改名就得连着环境变量、部署脚本一起动。所以命名规范值得在第一天定,不值得在第三十天推翻重来。

六、避坑清单

1)把显示名填进了模型标识那一栏。 为什么会踩:两个字段在很多产品里挨着,都叫”名字”,而且 Continue 示例里 name: GPT-4omodel: gpt-4o 长得极像。 怎么避:填之前先问自己一句”这个值会不会被发到服务端”。会发的那一栏,一律从服务商文档或 /v1/models 的返回里复制粘贴,不手敲。Kilo Code 的自动检测能拉列表,就别自己拼。

2)在 Zed 里改了 provider 键名,忘了改环境变量。 为什么会踩:settings.json 改完看着完全正常,密钥那条线是隐式的。 怎么避:记住 <PROVIDER_NAME>_API_KEY 这条规则,改名当成”两处改动”来做。Zed 文档明确写了不要把 API key 放进 settings.json,凭据要么走 provider 设置界面(保存在系统 keychain),要么走环境变量。

3)拿 A 家的字段名去填 B 家。 为什么会踩:都是”填地址”,脑子里就归成一类了。 怎么避:apiBase(Continue)、api_url(Zed)、OPENAI_HOST(goose)、--base-url(Crush)、界面上的 Base URL(Cline / Roo Code / Kilo Code)互不通用。写之前对着对应产品的文档确认拼写,别靠印象。

4)base URL 结尾该不该带 /v1 靠猜。 为什么会踩:各家示例形态确实不一样——Cline 文档的 v0 示例是 https://api.v0.dev/v1(含 /v1),Zed 示例是 https://example.com/v1,Kilo Code 明确接受 /v1/v1/chat/completions 两种,Groq 官方 base URL 是 https://api.groq.com/openai/v1,goose 则把它拆成 OPENAI_HOST 加可选的 OPENAI_BASE_PATH 两段。 怎么避:以你要接的那家服务商文档给的地址为准,再对照客户端文档看它期望的是哪一段,不要拿别家示例做类比。相关排查思路见 OpenAI 兼容端点怎么接

5)项目级和全局配置里用了同一个 provider 名字。 为什么会踩:一开始在项目里试通了,后来又往全局配置抄了一份,两边慢慢分叉。 怎么避:Crush 的 README 列出了 ./.crushrc~/.config/crush/crushrc 两处位置,Gemini CLI 有四处、优先级明确。给不同层级的 provider 起可区分的名字(比如带上环境后缀),比事后猜谁覆盖了谁省事得多。

6)把密钥写进要进版本库的配置文件。 为什么会踩:图省事,反正”先跑通再说”。 怎么避:Gemini CLI 的 settings.json 支持环境变量插值(写成 $VAR_NAME${VAR_NAME},加载时自动解析),这样配置能进版本库而密钥留在环境里;它的 .env 查找顺序是当前工作目录 → 逐级父目录(到项目根或 home 为止)→ 用户 home 的 ~/.env。Zed 那句 “Do not put API keys in settings.json.” 也是同一个意思。

7)名字对了,但选错了 provider 类型。 为什么会踩:满脑子都在调地址和模型名,忘了还有”用哪个接入类型”这一层。 怎么避:Kilo Code 文档写明接 Azure GPT-5 要用原生的 azure provider 而不是通用 OpenAI 兼容 provider,因为 Azure 会拒绝 max_tokens 参数。遇到”地址密钥都对却报参数错误”,先回头看类型选得对不对。

七、排查顺序:从名字这条线往下走

真出问题时,按下面这个顺序走一遍,比乱改配置快。每一步都写明了看哪里、做什么、看到什么算过。

第一步:把地址这条线单独验一次,绕开客户端。 打开终端,用通用 HTTP 工具直接打你填的那个 base URL 的模型列表端点,例如 curl -H "Authorization: Bearer $KEY" <你的 base URL>/models/v1/models 这个路径在 Kilo Code 文档里出现过,Kilo 正是从它自动拉列表的)。算过的标准:拿到一段 JSON 且里面有模型条目。如果这一步就失败,问题不在名字,在地址或密钥——回去核对该产品的 base URL 字段名有没有串台(Continue 是 apiBase、Zed 是 api_url、goose 是 OPENAI_HOST、Crush 是 --base-url、Cline / Roo Code / Kilo Code 是界面上的 Base URL),以及末尾该不该带 /v1

第二步:验密钥是不是被客户端按它自己的规则找到了。 这一步按产品分:Zed 的规则文档写得最明确,provider 名为 my-provider 时对应 MY_PROVIDER_API_KEY,在终端跑 echo $MY_PROVIDER_API_KEY(Windows PowerShell 用 $env:MY_PROVIDER_API_KEY),算过的标准是回显出非空字符串,且它跟你 settings.json 里那个键名严格对得上(键名改过就必须同步改变量名);Zed 文档另给了一条路是走 provider 设置界面保存到系统 keychain。goose 走环境变量或 config.yaml,Gemini CLI 可以在 settings 里用 $VAR_NAME 插值引用环境变量。

第三步:把模型标识逐字比对。 打开第一步拿回的那段 JSON,用它里面的字符串跟你配置里填的那一栏做字符级比对(复制粘贴,别肉眼扫)。算过的标准:两串完全一致,包括大小写、连字符、斜杠和厂商前缀。特别检查有没有把显示名填到了模型标识那一栏——Continue 示例里 name: GPT-4omodel: gpt-4o 就是最容易看串的一对。

第四步:再看能力。 前三步全过还是不工作,就不是名字问题了。这时才去查所选模型支不支持工具调用(Roo Code 文档明确说它只认原生 tool calling、没有 XML 回退)、上下文窗口那一栏填的数有没有依据。很多人会因为前三步没查干净,误把能力问题当成名字问题继续折腾。

数据来源与核对日期

以下 URL 全部来自本篇写作时依据的官方文档记录,核对日期均为 2026-08-07。文档随版本更新,请以官方最新版为准。

本篇没有写什么,以及为什么:

  • 不写价格、免费额度、限速数字、订阅档位。这几类数字变动频繁,本次也未核实,写进来只会误导。请以各产品与各服务商官方页面为准。
  • 不写完整模型清单。上面提到的模型标识只是各家文档里出现过的示例,不代表当前可用的全部型号;能自动拉取模型列表的客户端,以拉回来的结果为准。
  • 不写界面长什么样、什么时候会弹提示、错误文案是什么。本篇依据的是配置层的文档记录,不含任何一家的界面细节与校验时机,以你实际看到的界面为准。
  • 不写版本号、发布日期与产品之间的归属关系
  • 不给各家文档或产品排座次。上文所有对比只陈述设计取向上的差异,差异本身都能在文末各 URL 里复核。
  • 凡文中标注”机制推理”的判断,都是按 OpenAI 兼容协议的通用行为推出来的,不是对应产品文档的记载;凡写”本篇依据的记录里没有出现”的地方,也只说明本篇没查到,不等于该产品没有这项能力。

延伸阅读:同一组里的 上下文窗口要你手填的那几家编辑器与终端 Agent 接自定义模型;接完之后照 接完自定义模型别急着干活 逐项过一遍,才算真接通。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。