如何为 OpenClaude 新增一个模型网关(Gateway Descriptor)?
2026/9/12 7:27:32 网站建设 项目流程

如何为 OpenClaude 新增一个模型网关(Gateway Descriptor)?

【免费下载链接】openclauderuns anywhere. uses anything项目地址: https://gitcode.com/GitHub_Trending/op/openclaude

这篇文章面向 OpenClaude 的集成系统贡献者,解决一个具体任务:把一条「以自身 endpoint 契约托管、代理或聚合模型」的路由(例如托管的 OpenAI 兼容网关、Ollama/LM Studio 这类本地路由、混合第三方品牌的聚合网关)接入 OpenClaude。完成后的结果是:新增一个位于src/integrations/gateways/下的描述符文件,运行bun run integrations:generate后,生成产物自动同步 loader、兼容映射、preset 类型和 provider UI 元数据。整个过程不需要手工编辑注册逻辑。

适用前提:

  • 你已经有 OpenClaude 仓库的本地检出,并安装好bun(文档中所有脚本均通过bun run调用);
  • 你确认要接入的路由确实符合网关形态,而不是第一方厂商直连 API 或 Anthropic 原生代理(后两者在 add-vendor.md 和 add-anthropic-proxy.md 中分别描述)。

官方操作指南在 add-gateway.md,配套参考样例在 reference-samples.md,PR 前检查清单在 common-pitfalls.md。

什么时候该用网关描述符

按文档的规则,满足以下情况之一时才添加 gateway descriptor:

  • 一条拥有自己 base URL 和鉴权契约的托管 OpenAI 兼容路由;
  • Ollama、LM Studio 一类的本地路由;
  • 混合第三方品牌/模型的聚合路由;
  • 需要发现元数据、发现缓存或 readiness 探测的路由。

如果路由是规范的厂商直连 API,应使用defineVendor而不是defineGateway;如果路由以 Anthropic 风格 env 契约接收 Anthropic 原生流量,应使用defineAnthropicProxy。描述符类型选错是 common-pitfalls.md 中列出的第一类错误。

文件布局

  1. 描述符文件放在src/integrations/gateways/<id>.ts<id>是网关的稳定标识(例如仓库中已有的ollamallmtr对应 ollama.ts、llmtr.ts)。
  2. 只有当目录(catalog)/发现规则大到值得拆分时,才新增伴生文件src/integrations/gateways/<id>.models.ts(仓库中的llmtr.models.ts就是这种两文件模式)。

编写规则(来自 how-to 文档的 Authoring rules):

  • 使用src/integrations/define.ts提供的defineGatewaydefineCatalog辅助函数;
  • 描述符文件export default导出的就是 gateway 描述符本身;伴生*.models.ts默认导出 catalog;
  • 不要在贡献者编写的描述符文件里调用registerGateway(...),注册由 loader(src/integrations/index.ts)拥有;
  • 不要使用已移除的遗留字段:targetVendorIdisOpenAICompatible、面向路由的网关classification

编写一个单文件网关描述符(最短主路径)

下面这个例子直接来自官方文档的「one-file example」,用于一条只托管自家模型的 OpenAI 兼容托管网关。文档明确说明这类样例中的 id、env 变量、URL 均为示意值,落地前必须替换成真实路由的值:

import { defineCatalog, defineGateway } from '../define.js' const catalog = defineCatalog({ source: 'static', models: [ { id: 'acme-hosted-fast', apiName: 'acme-hosted-fast', label: 'Acme Hosted Fast', modelDescriptorId: 'acme-hosted-fast', }, { id: 'acme-hosted-pro', apiName: 'acme-hosted-pro', label: 'Acme Hosted Pro', modelDescriptorId: 'acme-hosted-pro', capabilities: { supportsReasoning: true, }, notes: 'Practical input limit is lower than the full context window.', }, ], }) export default defineGateway({ id: 'acme-hosted', label: 'Acme Hosted', category: 'hosted', defaultBaseUrl: 'https://gateway.acme.example/v1', defaultModel: 'acme-hosted-fast', supportsModelRouting: true, setup: { requiresAuth: true, authMode: 'api-key', credentialEnvVars: ['ACME_HOSTED_API_KEY'], }, transportConfig: { kind: 'openai-compatible', openaiShim: { headers: { 'X-Acme-Client': 'openclaude', }, supportsApiFormatSelection: false, supportsAuthHeaders: true, ui: { showAuthHeader: false, showAuthHeaderValue: false, showCustomHeaders: true, }, // Optional: use a non-Authorization default auth header. defaultAuthHeader: { name: 'api-key', scheme: 'raw' }, // Optional: restrict Responses API mode to model ids with these prefixes. responsesApiModelPrefixes: ['gpt-'], maxTokensField: 'max_completion_tokens', }, }, preset: { id: 'acme-hosted', description: 'Acme Hosted gateway', vendorId: 'openai', apiKeyEnvVars: ['ACME_HOSTED_API_KEY'], }, catalog, usage: { supported: false, }, })

几个关键字段的用途,均以文档说明为准:

  • transportConfig.kind是路由契约,运行时靠它选择传输族,而不是categorycategory只是可选的分组/展示元数据(local/hosted/aggregating);
  • defaultModel一次性声明路由默认模型,不要在 catalog 条目里再加default/recommended标记;
  • setup声明鉴权方式,credentialEnvVars是预设流程收集 API key 时的环境变量名;
  • usage: { supported: false }表示该路由当前不支持/usage;只有路由确实具备当前运行时支持时才声明supported: true(见 common-pitfalls.md 的 Pitfall 10)。

openaiShim下的三个开关控制/provider add/provider edit暴露哪些字段:

  • supportsApiFormatSelection: false时,不暴露 API mode 选择器——适合描述符拥有固定 API 契约的托管或本地路由;为true留给允许用户自选 API 面的宽泛自定义网关;
  • supportsAuthHeaders: false时,只暴露路由常规凭据字段;为true时启用头定制(鉴权头名、值、任意自定义头),再由ui.showAuthHeader/showAuthHeaderValue/showCustomHeaders决定具体哪几个提示可见;
  • maxTokensField在路由对 max token 字段严格时必须显式声明:'max_completion_tokens'用于较新的托管 OpenAI 风格契约,'max_tokens'用于本地、legacy 形态或拒绝新字段的提供方。

startup块用于 readiness 与自动探测提示,例如autoDetectable: trueprobeReadiness: 'openai-compatible-models'。注意文档提醒:当discoveryRefreshMode: 'startup'openai-compatible-modelsreadiness 探测发起的是同一个请求时,会成倍增加启动流量,应避免两者同时配置。

选择传输族

transportConfig.kind决定路由契约,可选值在 overview.md 中列举为:

transportConfig: { kind: 'openai-compatible', openaiShim: { supportsApiFormatSelection: false, supportsAuthHeaders: false, }, }
  • 'openai-compatible':路由说 OpenAI 兼容的请求/响应契约;
  • 'local':Ollama、LM Studio 一类的本地路由,通常配maxTokensField: 'max_tokens'
  • 'anthropic-proxy':真正接收 Anthropic 原生流量的网关形态路由。文档同时指出,真实的 Anthropic 原生第三方路由更应走专门的 anthropic-proxy 指南,传输族始终来自transportConfig.kind而不是网关专属兼容标志。

不要用自定义头去替代传输族的选择——头属于openaiShim,族属于kind

选择 catalog 策略

按路由的目录形态三选一:

catalog.source适用条件
static发现不可用或不必要;目录固定的小型托管路由
dynamic完全依赖运行时发现;本地路由或频繁变化的提供方目录
hybrid聚合器,curated 默认条目要常驻,其余由发现补齐

当 catalog 需要发现时,配套声明三个字段:

  • discoveryCacheTtl:使用人类可读 TTL,30m(目录变化快)、1h(中等活跃的托管路由)、1d(稳定的托管/本地路由);
  • discoveryRefreshModemanual(易抖动/限流提供方,只按需刷新)、on-open(picker 每次打开都尝试取新列表)、background-if-stale(托管网关的常规选择,缓存模型立即可见)、startup(探测成本低的快速本地路由);
  • allowManualRefresh: true才支持/model refresh与 picker 内刷新;共享发现缓存会在刷新失败或过期时继续展示 curated 条目。

一个常见分拆:鉴权的推理路由如果暴露了公共模型列表端点,设catalog.discovery.requiresAuth: false同时保持setup.requiresAuth开启(OpenRouter 和 Gitlawb Opengateway 就是这个模式:列模型免 key,推理要 key)。

目录或发现规则很大时,按两文件模式拆分:<id>.models.tsdefineCatalog导出 catalog,<id>.tsimport catalog from './<id>.models.js'引入并传给defineGateway。文档给出的 hybrid 示例(galaxy.models.ts/galaxy.ts)完整展示了source: 'hybrid'discoveryCacheTtl: '1h'discoveryRefreshMode: 'background-if-stale'allowManualRefresh: true的组合,可参照 reference-samples.md 的 Sample 3(本地动态发现)和 Sample 4(两文件 hybrid)。

混合目录中若同一逻辑模型挂在共享模型描述符上,用该模型描述符的providerModelMap记录各路由的具体 API 名。注意边界:providerModelMap只负责元数据复用,路由可用性仍然由路由自己的 catalog 决定。

另外,涉及 reasoning 控制时,capabilities.supportsReasoning保持描述性元数据即可;/effort可控的reasoning元数据要加在每个 catalog 条目上而不是网关级别,且改动前先读 reasoning-effort.md。

让网关出现在预设流程中(可选分支)

只有当网关要在/provider等预设驱动流程中作为用户可选路由出现时,才添加preset块,并设置preset.vendorId,让兼容/profile 辅助函数知道该网关属于哪个 vendor 契约:

preset: { id: 'acme-hosted', description: 'Acme Hosted gateway', vendorId: 'openai', apiKeyEnvVars: ['ACME_HOSTED_API_KEY'], }

若预设 picker 需要展示标签,可在preset.badge中声明(overview.md 中说明这可避免在src/components/ProviderManager.tsx里硬编码 badge 逻辑)。预设排序不手工配置,由生成的 manifest 自动处理,不需要在描述符里操心顺序。

重新生成产物并验证

描述符写完后,运行:

bun run integrations:generate

该脚本(定义在 package.json 的 scripts 中,实际执行scripts/generate-integrations-artifacts.ts)让src/integrations/generated/integrationArtifacts.generated.ts同步 loader、兼容映射、preset 类型和 provider UI 元数据。正常网关接入是增量的:改描述符文件、(按需)加preset块、跑生成命令,不需要去手工编辑src/integrations/compatibility.tssrc/integrations/profileResolver.tssrc/integrations/providerUiMetadata.ts或 preset 排序表——这些都属于生成产物的范畴(common-pitfalls.md 的 Pitfall 13)。

验证方式有两条:

  1. 检查生成物是否同步package.json提供了integrations:check脚本(同一生成器加--check参数):

    bun run integrations:generate --check

    它用于核对描述符与已提交的生成产物是否一致,而不重新写文件。

  2. 按官方 Verification checklist 自查(来自 add-gateway.md 末尾):

    • 描述符位于src/integrations/gateways/下;
    • 网关只声明它实际提供的模型子集;
    • 路由默认值只通过defaultModel声明一次;
    • transportConfig.kind承担路由契约,category仅作分组/展示;
    • 需要发现的路由声明了正确的 cache TTL、refresh mode 与手动刷新行为;
    • API mode、auth/header、token 字段行为在必要时显式声明;
    • 用户可见的预设参与通过描述符preset元数据与再生成的产物表达,而不是手写后续接线。

此外,由于描述符通过define*辅助函数保持类型化,运行仓库既有的bun run typecheck(即tsc --noEmit)可以校验字段形状是否符合 descriptors.ts 当前定义的接口。

提交前避开的坑

以下错误模式在 common-pitfalls.md 中有专门条目,写描述符时逐条对照:

  • 描述符文件里调用registerGateway(...)等注册变更辅助函数;
  • 使用targetVendorIdisOpenAICompatible或路由导向的classification等已移除字段;
  • category做运行时路由决策;
  • 把大段 hybrid catalog / 发现逻辑内联在<id>.ts里而不拆<id>.models.ts
  • 假设每个网关都暴露所有共享模型——路由 catalog 拥有可用性,src/integrations/models/里的共享模型描述符只回答「模型是什么」;
  • 在严格路由上遗漏openaiShim.maxTokensField

完成上述步骤并通过integrations:generate --check与自查清单后,这条网关就按描述符时代的接入流程进入了 OpenClaude 的生成体系,后续路由变更也只需继续维护描述符文件并重新生成。

【免费下载链接】openclauderuns anywhere. uses anything项目地址: https://gitcode.com/GitHub_Trending/op/openclaude

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询