Skip to content

建構供應器外掛程式

本指南將引導您建構一個提供者外掛,用於將模型提供者 (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 } } ```

    Manifest 會宣告 setup.providers[].envVars,以便 OpenClaw 可以在不載入外掛程式執行時間的情況下偵測認證。當供應器變體應該重複使用另一個供應器 ID 的認證時,請新增 providerAuthAliasesmodelSupport 是選用的,它允許 OpenClaw 在執行時間掛鉤存在之前,從簡寫模型 ID(例如 acme-large)自動載入您的供應器外掛程式。如果您在 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
    解析其自己的控制標記或通道傳遞之前,重寫助手文字增量(deltas)和最終文字。
    對於僅註冊一個使用 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(...)` 會從端點功能映射中偵測支援,
    因此原生 Moonshot/DashScope 風格的端點即使插件使用自訂提供者 ID 仍會
    選擇加入。
  3. Add dynamic model resolution

    如果您的供應商接受任意模型 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. 新增執行時 hooks(視需要)

    大多數供應商僅需 catalog + resolveDynamicModel。根據供應商需求逐步新增 hooks。

    共用輔助構建器現在涵蓋了最常見的 replay/tool-compat 系列,因此外掛通常無需手動逐一連接每個 hook:

    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,
    });

    目前可用的 replay 系列:

    系列連接內容內建範例
    openai-compatible適用於 OpenAI 相容傳輸的共用 OpenAI 風格 replay 策略,包括 tool-call-id 清理、assistant-first 排序修正,以及傳輸需要的通用 Gemini-turn 驗證moonshot, ollama, xai, zai
    anthropic-by-modelmodelId 選擇的 Claude 感知 replay 策略,因此 Anthropic-message 傳輸僅在解析出的模型實際為 Claude ID 時才會獲得 Claude 特定的思考區塊清理amazon-bedrock, anthropic-vertex
    google-gemini原生 Gemini replay 策略加上啟動 replay 清理。共用系列使文字輸出的 Gemini CLI 保持標籤化推論;直接的 google 供應商將 resolveReasoningOutputMode 覆寫為 native,因為 Gemini API 推論以原生思考部分的形式到達。google, google-gemini-cli
    passthrough-gemini透過 OpenAI 相容代理傳輸執行的 Gemini 模型的 Gemini 推論簽章清理;不啟用原生 Gemini replay 驗證或啟動重寫openrouter, kilocode, opencode, opencode-go
    hybrid-anthropic-openai混合策略,適用於在一個外掛中混合 Anthropic-message 和 OpenAI 相容模型介面的供應商;可選的僅 Claude 思考區塊刪除保持在 Anthropic 端的範圍內minimax

    目前可用的 stream 系列:

    系列連接內容內建範例
    google-thinking共用串流路徑上的 Gemini 推論 payload 正規化google, google-gemini-cli
    kilocode-thinking共用代理串流路徑上的 Kilo 推論包裝器,具有 kilo/auto 和不支援的代理推論 ID 會跳過注入的推論kilocode
    moonshot-thinking來自配置 + /think 層級的 Moonshot 二進位原生推論 payload 對應moonshot
    minimax-fast-mode共用串流路徑上的 MiniMax 快速模式模型重寫minimax, minimax-portal
    openai-responses-defaults共用原生 OpenAI/Codex Responses 包裝器:歸因標頭、/fast/serviceTier、文字詳細程度、原生 Codex 網路搜尋、推論相容 payload 塑形以及 Responses 內容管理openai
    openrouter-thinking代理路由的 OpenRouter 推論包裝器,不支援的模型/auto 跳過由中央處理openrouter
    tool-stream-default-on預設開啟的 tool_stream 包裝器,適用於像 Z.AI 這樣除非明確停用否則想要工具串流的供應商zai
    支援系列構建器的 SDK 接縫

    每個系列構建器都是由同一個套件匯出的較低層級公開輔助函式所組成,當供應商需要偏離常見模式時,您可以使用這些函式:

    • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamilybuildProviderReplayFamilyHooks(...) 和原始 replay 構建器(buildOpenAICompatibleReplayPolicybuildAnthropicReplayPolicyForModelbuildGoogleGeminiReplayPolicybuildHybridAnthropicOrOpenAIReplayPolicy)。也匯出 Gemini replay 輔助函式(sanitizeGoogleGeminiReplayHistoryresolveTaggedReasoningOutputMode)和端點/模型輔助函式(resolveProviderEndpointnormalizeProviderIdnormalizeGooglePreviewModelId)。
    • openclaw/plugin-sdk/provider-stream - ProviderStreamFamilybuildProviderStreamFamilyHooks(...)composeProviderStreamWrappers(...),加上共用 OpenAI/Codex 包裝器(createOpenAIAttributionHeadersWrappercreateOpenAIFastModeWrappercreateOpenAIServiceTierWrappercreateOpenAIResponsesContextManagementWrappercreateCodexNativeWebSearchWrapper)、DeepSeek V4 OpenAI 相容包裝器(createDeepSeekV4OpenAICompatibleThinkingWrapper)、Anthropic Messages 思考預填清理(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 beta 處理和 `context1m` 閘控。xAI 外掛類似地將原生 xAI Responses 塑形保留在其自己的 `wrapStreamFn` 中(`/fast` 別名、預設 `tool_stream`、不支援的嚴格工具清理、xAI 特定推論 payload 移除)。
    相同的套件根模式也支援 `@openclaw/openai-provider`(供應商構建器、預設模型輔助函式、即時供應商構建器)和 `@openclaw/openrouter-provider`(供應商構建器加上上架/配置輔助函式)。

    對於在每次推論呼叫前需要 token 交換的供應商:

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

    OpenClaw 會依此順序呼叫 hooks。大多數供應商僅使用 2-3 個: OpenClaw 不再呼叫的僅相容性供應商欄位(例如 ProviderPlugin.capabilitiessuppressBuiltInModel)未列在此處。

    #Hook使用時機
    1catalog模型目錄或基礎 URL 預設值
    2applyConfigDefaults配置具體化期間的供應商擁有的全域預設值
    3normalizeModelId查閱前的舊版/預覽 model-id 別名清理
    4normalizeTransport通用模型組裝前的供應商系列 api / baseUrl 清理
    5normalizeConfig正規化 `models.providers.

    配置 | | 6 |applyNativeStreamingUsageCompat| 配置供應商的原生串流使用量相容性重寫 | | 7 |resolveConfigApiKey| 供應商擁有的 env-marker 驗證解析 | | 8 |resolveSyntheticAuth| 本地/自我託管或配置支援的合成驗證 | | 9 |shouldDeferSyntheticProfileAuth| 將合成儲存的設定檔預留位置置於 env/config 驗證之後 | | 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| 自訂執行時 token 形狀 | | 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| 推論前的 token 交換 | | 36 |resolveUsageAuth| 自訂使用量憑證解析 | | 37 |fetchUsageSnapshot| 自訂使用量端點 | | 38 |createEmbeddingProvider| 供應商擁有的記憶體/搜尋嵌入介面卡 | | 39 |buildReplayPolicy| 自訂逐字稿 replay/壓縮策略 | | 40 |sanitizeReplayHistory| 通用清理後的供應商特定 replay 重寫 | | 41 |validateReplayTurns| 內嵌執行器之前的嚴格 replay 回合驗證 | | 42 |onModelSelected` | 選擇後回呼(例如遙測) |

    執行時後援說明:
    - `normalizeConfig` 會先檢查相符的供應商,然後檢查其他具備 hook 能力的供應商外掛,直到其中一個實際變更了配置。如果沒有供應商 hook 重寫支援的 Google 系列配置項目,內建的 Google 配置正規化器仍會套用。
    - `resolveConfigApiKey` 在公開時使用供應商 hook。Amazon Bedrock 將 AWS env-marker 解析保留在其供應商外掛中;當配置為 `auth: "aws-sdk"` 時,執行時驗證本身仍使用 AWS SDK 預設鏈。
    - `resolveThinkingProfile(ctx)` 會接收已選取的 `provider`、`modelId`、選擇性的合併 `reasoning` 目錄提示,以及選擇性的合併模型 `compat` 事實。僅使用 `compat` 來選取供應商的思考 UI/設定檔。
    - `resolveSystemPromptContribution` 讓供應商為模型系列注入具備快取感知能力的系統提示指引。當行為屬於單一供應商/模型系列且應保留穩定/動態快取分割時,請優先使用它而不是 `before_prompt_build`。
    如需詳細描述和真實範例,請參閱 [Internals: Provider Runtime Hooks](/zh-Hant/plugins/architecture-internals#provider-runtime-hooks)。
  5. 新增額外功能(選用)

    提供者外掛可以註冊嵌入、語音、即時轉錄、即時語音、媒體理解、影像生成、影片生成、 Web 擷取和 Web 搜尋,以及文字推論。OpenClaw 將此歸類為 混合功能 外掛 —— 這是公司外掛的建議模式 (每個供應商一個外掛)。請參閱 Internals: Capability Ownership

    請在 register(api) 中註冊每項功能,與您現有的 api.registerProvider(...) 呼叫並列。僅選取您需要的分頁:

    ```typescript
    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 錯誤解析和

    request-id 後綴。

  6. 測試

    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最後一輪覆寫現有供應商(衝突時優先採用)