跳转到内容

构建提供商插件

本指南将详细介绍如何构建一个提供商插件,该插件用于将模型提供商 (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-"]
    },
    "providerAuthEnvVars": {
    "acme-ai": ["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 } } ```

    清单声明了 providerAuthEnvVarsOpenClaw,以便 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` 显示目前仅对打包的提供商插件执行静态目录,
    配置为空、环境变量为空,且没有
    代理/工作区路径。
    如果您的身份验证流程还需要在 期间修补 `models.providers.*`、别名
    和代理默认模型,请使用
    `openclaw/plugin-sdk/provider-onboard` 中的预设辅助函数。最窄的辅助函数是
    `createDefaultModelPresetAppliers(...)`、
    `createDefaultModelsPresetAppliers(...)` 和
    `createModelCatalogPresetAppliers(...)`。
    当提供商的原生端点在普通的 `openai-completions` 传输上支持流式使用块时,
    请优先使用 `openclaw/plugin-sdk/provider-catalog-shared` 中的共享目录辅助函数,而不是硬编码
    提供商 ID 检查。`supportsNativeStreamingUsageCompat(...)` 和
    `applyProviderNativeStreamingUsageCompat(...)` 从
    端点功能图中检测支持,因此即使插件使用自定义提供商 ID,
    原生 Moonshot/DashScope 风格的端点仍然
    会选择加入。
  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-compatible适用于 OpenAI 兼容传输的共享 OpenAI 风格重放策略,包括工具调用 ID 清理、助手优先排序修复,以及传输需要的通用 Gemini 轮次验证moonshotollamaxaizai
    anthropic-by-modelmodelId 选择的 Claude 感知重放策略,因此 Anthropic 消息传输仅在解析的模型实际上是 Claude ID 时才获得 Claude 特定的思维块清理amazon-bedrockanthropic-vertex
    google-gemini原生 Gemini 重放策略加上引导重放清理和标记推理输出模式googlegoogle-gemini-cli
    passthrough-gemini通过 OpenAI 兼容代理传输运行的 Gemini 模型的 Gemini 思维签名清理;不启用原生 Gemini 重放验证或引导重写openrouterkilocodeopencodeopencode-go
    hybrid-anthropic-openai混合策略,适用于在一个插件中混合 Anthropic 消息和 OpenAI 兼容模型表面的提供商;可选的仅 Claude 思维块删除保持限定在 Anthropic 一侧minimax

    目前可用的流式系列:

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

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

    • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamilybuildProviderReplayFamilyHooks(...) 和原始重放构建器(buildOpenAICompatibleReplayPolicybuildAnthropicReplayPolicyForModelbuildGoogleGeminiReplayPolicybuildHybridAnthropicOrOpenAIReplayPolicy)。还导出 Gemini 重放辅助函数(sanitizeGoogleGeminiReplayHistoryresolveTaggedReasoningOutputMode)和端点/模型辅助函数(resolveProviderEndpointnormalizeProviderIdnormalizeGooglePreviewModelId)。
    • openclaw/plugin-sdk/provider-stream - ProviderStreamFamilybuildProviderStreamFamilyHooks(...)composeProviderStreamWrappers(...),以及共享 OpenAI/Codex 包装器(createOpenAIAttributionHeadersWrappercreateOpenAIFastModeWrappercreateOpenAIServiceTierWrappercreateOpenAIResponsesContextManagementWrappercreateCodexNativeWebSearchWrapper)、DeepSeek V4 OpenAI 兼容包装器(createDeepSeekV4OpenAICompatibleThinkingWrapper)、Anthropic Messages 思维预填充清理(createAnthropicThinkingPrefillPayloadWrapper)和共享代理/提供商包装器(createOpenRouterWrappercreateToolStreamWrappercreateMinimaxFastModeWrapper)。
    • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamilybuildProviderToolCompatFamilyHooks("deepseek" | "gemini" | "openai") 和底层提供商模式辅助函数。

    一些流辅助函数有意保持提供商本地化。@openclaw/anthropic-providerwrapAnthropicProviderStreamresolveAnthropicBetasresolveAnthropicFastModeresolveAnthropicServiceTier 和较低级别的 Anthropic 包装器构建器保存在其自己的公共 api.ts / contract-api.ts 接缝中,因为它们编码了 Claude OAuth beta 处理和 context1m 闸。xAI 插件同样在其自己的 wrapStreamFn 中保留原生 xAI Responses 整形(/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 |contributeResolvedModelCompat| 另一个兼容传输后面的供应商模型的兼容标志 | | 14 |normalizeToolSchemas| 注册前的提供商拥有的工具模式清理 | | 15 |inspectToolSchemas| 提供商拥有的工具模式诊断 | | 16 |resolveReasoningOutputMode| 标记与原生推理输出契约 | | 17 |prepareExtraParams| 默认请求参数 | | 18 |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 环境标记解析器,尽管 Bedrock 运行时身份验证本身仍使用 AWS SDK 默认链。
    - `resolveSystemPromptContribution` 允许提供商为模型系列注入缓存感知的系统提示指导。当行为属于一个提供商/模型系列并且应保留稳定/动态缓存拆分时,优先于 `before_prompt_build` 使用它。
    有关详细说明和实际示例,请参阅 [内部:提供商运行时钩子](/zh/plugins/architecture-internals#provider-runtime-hooks)。
  5. 添加额外功能(可选)

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

    register(api) 内部注册每个功能,并与你现有的 api.registerProvider(...) 调用并列。仅选择你需要的标签页:

    import {
    assertOkOrThrowProviderError,
    postJsonRequest,
    } from "openclaw/plugin-sdk/provider-http";
    api.registerSpeechProvider({
    id: "acme-ai",
    label: "Acme Speech",
    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();
    }
    },
    });

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

  • 测试

    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最后一遍覆盖现有提供商(冲突时获胜)