跳转到内容

构建提供商插件

本指南将详细介绍如何构建一个提供商插件,该插件用于将模型提供商 (LLM) 添加到 OpenClaw。完成后,您将拥有一个包含模型目录、API 密钥身份验证和动态模型解析的提供商。

  1. Package and manifest

    {
    "name": "@myorg/openclaw-acme-ai",
    "version": "1.0.0",
    "type": "module",
    "openclaw": {
    "extensions": ["./index.ts"],
    "providers": ["acme-ai"],
    "compat": {
    "pluginApi": ">=2026.3.24-beta.2",
    "minGatewayVersion": "2026.3.24-beta.2"
    },
    "build": {
    "openclawVersion": "2026.3.24-beta.2",
    "pluginSdkVersion": "2026.3.24-beta.2"
    }
    }
    }
    {
    "id": "acme-ai",
    "name": "Acme AI",
    "description": "Acme AI model provider",
    "providers": ["acme-ai"],
    "modelSupport": {
    "modelPrefixes": ["acme-"]
    },
    "setup": {
    "providers": [
    {
    "id": "acme-ai",
    "envVars": ["ACME_AI_API_KEY"]
    }
    ]
    },
    "providerAuthAliases": {
    "acme-ai-coding": "acme-ai"
    },
    "providerAuthChoices": [
    {
    "provider": "acme-ai",
    "method": "api-key",
    "choiceId": "acme-ai-api-key",
    "choiceLabel": "Acme AI API key",
    "groupId": "acme-ai",
    "groupLabel": "Acme AI",
    "cliFlag": "--acme-ai-api-key",
    "cliOption": "--acme-ai-api-key

    ”, “cliDescription”: “Acme AI API key” } ], “configSchema”: { “type”: “object”, “additionalProperties”: false } } ```

    清单声明了 setup.providers[].envVarsOpenClaw,以便 OpenClaw 可以在 不加载插件运行时的情况下检测凭据。当提供商变体应重用 另一个提供商 ID 的身份验证时,请添加 providerAuthAliasesmodelSupportOpenClaw 是可选的,它允许 OpenClaw 在运行时挂钩存在之前 通过简写模型 ID(如 acme-largeClawHub)自动加载您的提供商插件。 如果您在 ClawHub 上发布提供商,则 package.json 中 必需包含 openclaw.compatopenclaw.build 字段。

  2. 注册提供商

    一个最简的文本提供商需要一个 idlabelauthcatalogcatalog 是提供商拥有的运行时/配置钩子;它可以调用实时的 供应商 API 并返回 models.providers 条目。

    import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
    import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth";
    export default definePluginEntry({
    id: "acme-ai",
    name: "Acme AI",
    description: "Acme AI model provider",
    register(api) {
    api.registerProvider({
    id: "acme-ai",
    label: "Acme AI",
    docsPath: "/providers/acme-ai",
    envVars: ["ACME_AI_API_KEY"],
    auth: [
    createProviderApiKeyAuthMethod({
    providerId: "acme-ai",
    methodId: "api-key",
    label: "Acme AI API key",
    hint: "API key from your Acme AI dashboard",
    optionKey: "acmeAiApiKey",
    flagName: "--acme-ai-api-key",
    envVar: "ACME_AI_API_KEY",
    promptMessage: "Enter your Acme AI API key",
    defaultModel: "acme-ai/acme-large",
    }),
    ],
    catalog: {
    order: "simple",
    run: async (ctx) => {
    const apiKey =
    ctx.resolveProviderApiKey("acme-ai").apiKey;
    if (!apiKey) return null;
    return {
    provider: {
    baseUrl: "https://api.acme-ai.com/v1",
    apiKey,
    api: "openai-completions",
    models: [
    {
    id: "acme-large",
    name: "Acme Large",
    reasoning: true,
    input: ["text", "image"],
    cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
    contextWindow: 200000,
    maxTokens: 32768,
    },
    {
    id: "acme-small",
    name: "Acme Small",
    reasoning: false,
    input: ["text"],
    cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
    contextWindow: 128000,
    maxTokens: 8192,
    },
    ],
    },
    };
    },
    },
    });
    api.registerModelCatalogProvider({
    provider: "acme-ai",
    kinds: ["text"],
    liveCatalog: async (ctx) => {
    const apiKey = ctx.resolveProviderApiKey("acme-ai").apiKey;
    if (!apiKey) return null;
    return [
    {
    kind: "text",
    provider: "acme-ai",
    model: "acme-large",
    label: "Acme Large",
    source: "live",
    },
    ];
    },
    });
    },
    });

    registerModelCatalogProvider 是用于列表/帮助/选择器 UI 的较新的控制平面目录表面。 将其用于文本、图像生成、视频生成和音乐生成行。将供应商端点调用和 响应映射保留在插件中;OpenClaw 拥有共享的行形状、源 标签和帮助渲染。

    这是一个可工作的提供商。用户现在可以 `openclaw onboard —acme-ai-api-key

    并选择 acme-ai/acme-large` 作为他们的模型。

    如果上游提供商使用的控制令牌与 OpenClaw 不同,请添加
    一个小的双向文本转换,而不是替换流路径:
    ```typescript
    api.registerTextTransforms({
    input: [
    { from: /red basket/g, to: "blue basket" },
    { from: /paper ticket/g, to: "digital ticket" },
    { from: /left shelf/g, to: "right shelf" },
    ],
    output: [
    { from: /blue basket/g, to: "red basket" },
    { from: /digital ticket/g, to: "paper ticket" },
    { from: /right shelf/g, to: "left shelf" },
    ],
    });
    ```
    `input` 在传输之前重写最终的系统提示和文本消息内容。
    `output` 在 OpenClaw 解析其自己的控制标记或渠道投递之前
    重写助手文本增量和最终文本。
    对于仅注册一个具有 API 密钥
    身份验证加上单个支持目录的运行时的打包提供商,首选更窄的
    `defineSingleProviderPluginEntry(...)` 助手:
    ```typescript
    import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
    export default defineSingleProviderPluginEntry({
    id: "acme-ai",
    name: "Acme AI",
    description: "Acme AI model provider",
    provider: {
    label: "Acme AI",
    docsPath: "/providers/acme-ai",
    auth: [
    {
    methodId: "api-key",
    label: "Acme AI API key",
    hint: "API key from your Acme AI dashboard",
    optionKey: "acmeAiApiKey",
    flagName: "--acme-ai-api-key",
    envVar: "ACME_AI_API_KEY",
    promptMessage: "Enter your Acme AI API key",
    defaultModel: "acme-ai/acme-large",
    },
    ],
    catalog: {
    buildProvider: () => ({
    api: "openai-completions",
    baseUrl: "https://api.acme-ai.com/v1",
    models: [{ id: "acme-large", name: "Acme Large" }],
    }),
    buildStaticProvider: () => ({
    api: "openai-completions",
    baseUrl: "https://api.acme-ai.com/v1",
    models: [{ id: "acme-large", name: "Acme Large" }],
    }),
    },
    },
    });
    ```
    `buildProvider` 是当 OpenClaw 可以解析真实
    提供商身份验证时使用的实时目录路径。它可能会执行特定于提供商的发现。仅对
    在配置身份验证之前显示安全的离线行使用 `buildStaticProvider`;它绝不能
    需要凭据或发出网络请求。
    OpenClaw 的 `models list --all` 显示目前仅对打包的提供商插件
    执行静态目录,配置为空、环境为空,并且没有
    代理/工作区路径。
    如果您的身份验证流程还需要在 Moonshot 期间修补 `models.providers.*`、别名
    和代理默认模型,请使用
    `openclaw/plugin-sdk/provider-onboard` 中的预设助手。最窄的助手是
    `createDefaultModelPresetAppliers(...)`、
    `createDefaultModelsPresetAppliers(...)` 和
    `createModelCatalogPresetAppliers(...)`。
    当提供商的原生端点在正常的
    `openai-completions` 传输上支持流式使用块时,首选
    `openclaw/plugin-sdk/provider-catalog-shared` 中的共享目录助手,而不是硬编码
    提供商 ID 检查。`supportsNativeStreamingUsageCompat(...)` 和
    `applyProviderNativeStreamingUsageCompat(...)` 从
    端点能力映射检测支持,因此原生 Moonshot/DashScope 风格的端点仍然
    会选择加入,即使插件使用的是自定义提供商 ID。
  3. 添加动态模型解析

    如果您的提供商接受任意模型 ID(例如代理或路由器), 请添加 resolveDynamicModel

    api.registerProvider({
    // ... id, label, auth, catalog from above
    resolveDynamicModel: (ctx) => ({
    id: ctx.modelId,
    name: ctx.modelId,
    provider: "acme-ai",
    api: "openai-completions",
    baseUrl: "https://api.acme-ai.com/v1",
    reasoning: false,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 128000,
    maxTokens: 8192,
    }),
    });

    如果解析需要进行网络调用,请使用 prepareDynamicModel 进行异步 预热 - resolveDynamicModel 将在完成后再次运行。

  4. 添加运行时钩子(根据需要)

    大多数提供商只需要 catalog + resolveDynamicModel。根据提供商的需要逐步添加钩子。

    共享辅助构建器现在涵盖了最常见的重放/工具兼容系列,因此插件通常不需要逐个手动连接每个钩子:

    import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
    import { buildProviderStreamFamilyHooks } from "openclaw/plugin-sdk/provider-stream";
    import { buildProviderToolCompatFamilyHooks } from "openclaw/plugin-sdk/provider-tools";
    const GOOGLE_FAMILY_HOOKS = {
    ...buildProviderReplayFamilyHooks({ family: "google-gemini" }),
    ...buildProviderStreamFamilyHooks("google-thinking"),
    ...buildProviderToolCompatFamilyHooks("gemini"),
    };
    api.registerProvider({
    id: "acme-gemini-compatible",
    // ...
    ...GOOGLE_FAMILY_HOOKS,
    });

    目前可用的重放系列:

    系列连接内容内置示例
    openai-compatibleOpenAIOpenAI适用于 OpenAI 兼容传输的共享 OpenAI 风格重放策略,包括工具调用 ID 清理、助手优先排序修复,以及传输需要时的通用 Gemini 轮次验证moonshotollamaxaizai
    anthropic-by-modelmodelIdAnthropic 选择的感知 Claude 的重放策略,因此仅当解析出的模型实际上是 Claude ID 时,Anthropic 消息传输才会获得 Claude 特定的思维块清理amazon-bedrockanthropic-vertex
    google-gemini原生 Gemini 重放策略加上引导重放清理。共享系列使仅文本输出的 Gemini CLI 保持标记推理;直接 google 提供商覆盖 resolveReasoningOutputModenative,因为 Gemini API 推理作为原生思维部分到达。googlegoogle-gemini-cli
    passthrough-geminiOpenAI适用于通过 OpenAI 兼容代理传输运行的 Gemini 模型的 Gemini 思维签名清理;不启用原生 Gemini 重放验证或引导重写openrouterkilocodeopencodeopencode-go
    hybrid-anthropic-openaiAnthropicOpenAI混合策略,适用于在一个插件中混合 Anthropic 消息和 OpenAI 兼容模型表面的提供商;可选的仅 Claude 思维块删除仅限于 Anthropic 端minimax

    目前可用的流系列:

    系列连接内容内置示例
    google-thinking共享流路径上的 Gemini 思维负载规范化googlegoogle-gemini-cli
    kilocode-thinking共享代理流路径上的 Kilo 推理包装器,带有 kilo/auto 和不支持的代理推理 ID 跳过注入的思维kilocode
    moonshot-thinkingMoonshot来自配置 + /think 级别的 Moonshot 二进制原生思维负载映射moonshot
    minimax-fast-modeMiniMax共享流路径上的 MiniMax 快速模式模型重写minimaxminimax-portal
    openai-responses-defaultsOpenAI共享原生 OpenAI/Codex Responses 包装器:归因标头、/fast/serviceTier、文本详细程度、原生 Codex 网络搜索、推理兼容负载塑造以及 Responses 上下文管理openai
    openrouter-thinkingOpenRouter代理路由的 OpenRouter 推理包装器,不支持的模型/auto 跳过由中央处理openrouter
    tool-stream-default-on默认启用的 tool_stream 包装器,适用于 Z.AI 等除非明确禁用否则希望工具流式传输的提供商zai
    支持系列构建器的 SDK 接口

    每个系列构建器都由同一包中导出的较低级公共辅助程序组成,当提供商需要偏离常见模式时,您可以使用它们:

    • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamilybuildProviderReplayFamilyHooks(...) 以及原始重放构建器(buildOpenAICompatibleReplayPolicybuildAnthropicReplayPolicyForModelbuildGoogleGeminiReplayPolicybuildHybridAnthropicOrOpenAIReplayPolicy)。还导出 Gemini 重放辅助程序(sanitizeGoogleGeminiReplayHistoryresolveTaggedReasoningOutputMode)和端点/模型辅助程序(resolveProviderEndpointnormalizeProviderIdnormalizeGooglePreviewModelId)。
    • openclaw/plugin-sdk/provider-stream - ProviderStreamFamilybuildProviderStreamFamilyHooks(...)composeProviderStreamWrappers(...)OpenAI,加上共享的 OpenAI/Codex 包装器(createOpenAIAttributionHeadersWrappercreateOpenAIFastModeWrappercreateOpenAIServiceTierWrappercreateOpenAIResponsesContextManagementWrappercreateCodexNativeWebSearchWrapperOpenAI)、DeepSeek V4 OpenAI 兼容包装器(createDeepSeekV4OpenAICompatibleThinkingWrapperAnthropic)、Anthropic 消息思维预填充清理(createAnthropicThinkingPrefillPayloadWrapper)、纯文本工具调用兼容(createPlainTextToolCallCompatWrapper)以及共享代理/提供商包装器(createOpenRouterWrappercreateToolStreamWrappercreateMinimaxFastModeWrapper)。
    • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamilybuildProviderToolCompatFamilyHooks("deepseek" | "gemini" | "openai") 以及底层的提供商模式辅助程序。

    对于 Gemini 系列提供商,请保持推理输出模式与传输一致。直接 Google Gemini API 提供商应使用 native 推理输出,以便 OpenClaw 消费原生思维部分而不添加 `

    /

    提示指令。解析最终 JSON/文本响应的仅文本 Gemini CLI 风格后端可以保留共享google-gemini` 标记约定。

    某些流辅助程序特意保留为提供商本地。`@openclaw/anthropic-provider` 将 `wrapAnthropicProviderStream`、`resolveAnthropicBetas`、`resolveAnthropicFastMode`、`resolveAnthropicServiceTier` 以及较低级的 Anthropic 包装器构建器保留在其自己的公共 `api.ts` / `contract-api.ts` 接口中,因为它们编码了 Claude OAuth 测试版处理和 `context1m` 门槛。xAI 插件类似地将原生 xAI Responses 塑形保留在其自己的 `wrapStreamFn` 中(`/fast` 别名、默认 `tool_stream`、不支持的严格工具清理、xAI 特定的推理负载删除)。
    相同的包根模式也支持 `@openclaw/openai-provider`(提供商构建器、默认模型辅助程序、实时提供商构建器)和 `@openclaw/openrouter-provider`(提供商构建器加上新手引导/配置辅助程序)。

    对于需要在进行每次推理调用之前进行令牌交换的提供商:

    prepareRuntimeAuth: async (ctx) => {
    const exchanged = await exchangeToken(ctx.apiKey);
    return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
    };
    },
    所有可用的提供商钩子

    OpenClaw 按此顺序调用钩子。大多数提供商仅使用 2-3 个: OpenClaw 不再调用的仅兼容性提供商字段(例如 ProviderPlugin.capabilitiessuppressBuiltInModel)未在此处列出。

    #钩子何时使用
    1catalog模型目录或基本 URL 默认值
    2applyConfigDefaults配置具体化期间的提供商拥有的全局默认值
    3normalizeModelId查找之前的旧版/预览模型 ID 别名清理
    4normalizeTransport通用模型组装之前的提供商系列 api / baseUrl 清理
    5normalizeConfig规范化 `models.providers.

    配置 | | 6 |applyNativeStreamingUsageCompat| 配置提供商的原生流式使用兼容重写 | | 7 |resolveConfigApiKey| 提供商拥有的环境标记身份验证解析 | | 8 |resolveSyntheticAuth| 本地/自托管或配置支持的综合身份验证 | | 9 |shouldDeferSyntheticProfileAuth| 将综合存储的配置文件占位符置于环境/配置身份验证之后 | | 10 |resolveDynamicModel| 接受任意上游模型 ID | | 11 |prepareDynamicModel| 解析之前的异步元数据获取 | | 12 |normalizeResolvedModel| 运行器之前的传输重写 | | 13 |normalizeToolSchemas| 注册之前的提供商拥有的工具模式清理 | | 14 |inspectToolSchemas| 提供商拥有的工具模式诊断 | | 15 |resolveReasoningOutputMode| 标记与原生推理输出约定 | | 16 |prepareExtraParams| 默认请求参数 | | 17 |createStreamFn| 完全自定义的 StreamFn 传输 | | 19 |wrapStreamFn| 常规流路径上的自定义标头/正文包装器 | | 20 |resolveTransportTurnState| 原生每轮标头/元数据 | | 21 |resolveWebSocketSessionPolicy| 原生 WS 会话标头/冷却 | | 22 |formatApiKey| 自定义运行时令牌形状 | | 23 |refreshOAuth| 自定义 OAuth 刷新 | | 24 |buildAuthDoctorHint| 身份验证修复指导 | | 25 |matchesContextOverflowError| 提供商拥有的溢出检测 | | 26 |classifyFailoverReason| 提供商拥有的速率限制/过载分类 | | 27 |isCacheTtlEligible| 提示缓存 TTL 门槛 | | 28 |buildMissingAuthMessage| 自定义缺失身份验证提示 | | 29 |augmentModelCatalog| 综合向前兼容行 | | 30 |resolveThinkingProfile| 模型特定的/think选项集 | | 31 |isBinaryThinking| 二进制思维开/关兼容性 | | 32 |supportsXHighThinking|xhigh推理支持兼容性 | | 33 |resolveDefaultThinkingLevel| 默认/think策略兼容性 | | 34 |isModernModelRef| 实时/冒烟模型匹配 | | 35 |prepareRuntimeAuth| 推理前的令牌交换 | | 36 |resolveUsageAuth| 自定义使用情况凭据解析 | | 37 |fetchUsageSnapshot| 自定义使用情况端点 | | 38 |createEmbeddingProvider| 提供商拥有的用于内存/搜索的嵌入适配器 | | 39 |buildReplayPolicy| 自定义记录重放/压缩策略 | | 40 |sanitizeReplayHistory| 通用清理后的提供商特定重放重写 | | 41 |validateReplayTurns| 嵌入式运行器之前的严格重放轮次验证 | | 42 |onModelSelected` | 选择后回调(例如遥测) |

    运行时回退说明:
    - `normalizeConfig` 首先检查匹配的提供商,然后检查其他支持钩子的提供商插件,直到有一个实际更改配置。如果没有提供商钩子重写受支持的 Google 系列配置条目,则捆绑的 Google 配置规范化器仍然适用。
    - `resolveConfigApiKey` 在公开时使用提供商钩子。Amazon Bedrock 将 AWS 环境标记解析保留在其提供商插件中;运行时身份验证本身在使用 `auth: "aws-sdk"` 配置时仍然使用 AWS SDK 默认链。
    - `resolveThinkingProfile(ctx)` 接收选定的 `provider`、`modelId`、可选合并的 `reasoning` 目录提示以及可选合并的模型 `compat` 事实。仅使用 `compat` 来选择提供商的思维 UI/配置文件。
    - `resolveSystemPromptContribution` 允许提供商为模型系列注入缓存感知的系统提示指导。当行为属于某个提供商/模型系列并且应保留稳定/动态缓存拆分时,优先选择它而不是 `before_prompt_build`。
    有关详细描述和真实示例,请参阅[内部:提供商运行时钩子](/zh/plugins/architecture-internals#provider-runtime-hooks)。
  5. 添加额外功能(可选)

    提供商插件可以注册嵌入、语音、实时转录、实时语音、媒体理解、图像生成、视频生成、Web 获取和 Web 搜索,与文本推理并存。OpenClaw 将其归类为 混合功能(hybrid-capability) 插件——这是公司插件的推荐模式 (每个供应商一个插件)。请参阅 内部原理:功能所有权

    在现有的 api.registerProvider(...) 调用旁边的 register(api) 内注册每个功能。仅选择您需要的标签页:

    import {
    assertOkOrThrowProviderError,
    postJsonRequest,
    } from "openclaw/plugin-sdk/provider-http";
    api.registerSpeechProvider({
    id: "acme-ai",
    label: "Acme Speech",
    defaultTimeoutMs: 120_000,
    isConfigured: ({ config }) => Boolean(config.messages?.tts),
    synthesize: async (req) => {
    const { response, release } = await postJsonRequest({
    url: "https://api.example.com/v1/speech",
    headers: new Headers({ "Content-Type": "application/json" }),
    body: { text: req.text },
    timeoutMs: req.timeoutMs,
    fetchFn: fetch,
    auditContext: "acme speech",
    });
    try {
    await assertOkOrThrowProviderError(response, "Acme Speech API error");
    return {
    audioBuffer: Buffer.from(await response.arrayBuffer()),
    outputFormat: "mp3",
    fileExtension: ".mp3",
    voiceCompatible: false,
    };
    } finally {
    await release();
    }
    },
    });

    使用 assertOkOrThrowProviderError(...) 处理提供商 HTTP 失败,以便 插件共享受限的错误正文读取、JSON 错误解析和 请求 ID 后缀。

  6. Test

    import { describe, it, expect } from "vitest";
    // Export your provider config object from index.ts or a dedicated file
    import { acmeProvider } from "./provider.js";
    describe("acme-ai provider", () => {
    it("resolves dynamic models", () => {
    const model = acmeProvider.resolveDynamicModel!({
    modelId: "acme-beta-v3",
    } as any);
    expect(model.id).toBe("acme-beta-v3");
    expect(model.provider).toBe("acme-ai");
    });
    it("returns catalog when key is available", async () => {
    const result = await acmeProvider.catalog!.run({
    resolveProviderApiKey: () => ({ apiKey: "test-key" }),
    } as any);
    expect(result?.provider?.models).toHaveLength(2);
    });
    it("returns null catalog when no key", async () => {
    const result = await acmeProvider.catalog!.run({
    resolveProviderApiKey: () => ({ apiKey: undefined }),
    } as any);
    expect(result).toBeNull();
    });
    });

提供商插件的发布方式与任何其他外部代码插件相同:

Terminal window
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin

在此处不要使用旧的仅技能发布别名;插件包应使用 clawhub package publish

<bundled-plugin-root>/acme-ai/
├── package.json # openclaw.providers metadata
├── openclaw.plugin.json # Manifest with provider auth metadata
├── index.ts # definePluginEntry + registerProvider
└── src/
├── provider.test.ts # Tests
└── usage.ts # Usage endpoint (optional)

catalog.order 控制目录相对于内置提供程序的合并时机:

顺序时机用例
simple第一遍纯 API 密钥提供商
profile简单之后基于认证配置文件的提供商
paired配置文件之后综合多个相关条目
late最后一遍覆盖现有提供商(冲突时获胜)