跳轉到主要內容

Documentation Index

Fetch the complete documentation index at: https://docs2.openclaw.ai/llms.txt

Use this file to discover all available pages before exploring further.

本指南逐步說明如何建置 provider Plugin,將模型提供者 (LLM) 加入 OpenClaw。完成後,你會擁有一個具備模型目錄、 API key 驗證,以及動態模型解析的 provider。
如果你從未建置過任何 OpenClaw Plugin,請先閱讀 入門指南,了解基本的套件 結構與 manifest 設定。
Provider Plugin 會將模型加入 OpenClaw 的一般推論迴圈。如果模型 必須透過擁有執行緒、Compaction 或工具事件的原生 agent daemon 執行,請將 provider 搭配 agent harness, 而不是把 daemon 協定細節放進核心。

逐步說明

1

Package and manifest

步驟 1:套件與 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"
    }
  }
}
manifest 宣告 providerAuthEnvVars,讓 OpenClaw 能在不載入你的 Plugin runtime 的情況下偵測憑證。當 provider 變體應重用另一個 provider id 的驗證時,加入 providerAuthAliasesmodelSupport 是選用項目,可讓 OpenClaw 在 runtime hook 存在之前,先從像 acme-large 這類簡寫模型 id 自動載入你的 provider Plugin。如果你在 ClawHub 發布 provider,package.json 中必須包含那些 openclaw.compatopenclaw.build 欄位。
2

Register the provider

最小的文字 provider 需要 idlabelauthcatalogcatalog 是 provider 擁有的 runtime/config hook;它可以呼叫即時 供應商 API,並回傳 models.providers 項目。
index.ts
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。請將它用於文字、影像生成、 影片生成和音樂生成資料列。將供應商端點呼叫與 回應映射保留在 Plugin 中;OpenClaw 負責共用的資料列形狀、來源 標籤和說明呈現。這就是一個可運作的 provider。使用者現在可以執行 openclaw onboard --acme-ai-api-key <key>,並選擇 acme-ai/acme-large 作為他們的模型。如果上游 provider 使用的控制 token 與 OpenClaw 不同,請加入一個 小型雙向文字轉換,而不是替換串流路徑:
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 會在傳輸前重寫最終 system prompt 與文字訊息內容。 output 會在 OpenClaw 解析自身控制標記或進行頻道傳遞之前, 重寫 assistant 文字 delta 與最終文字。對於只註冊一個具備 API-key 驗證與單一目錄支援 runtime 的文字 provider 的 bundled provider,請優先使用範圍較窄的 defineSingleProviderPluginEntry(...) 輔助函式:
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 能解析真實 provider 驗證時使用的即時 目錄路徑。它可以執行 provider 專屬探索。只有在資料列可於設定驗證 之前安全顯示時,才使用 buildStaticProvider;它不得需要憑證或發出 網路請求。OpenClaw 的 models list --all 顯示目前只會對 bundled provider Plugin 執行靜態目錄,且使用空設定、空 env,沒有 agent/workspace 路徑。如果你的驗證流程也需要在 onboarding 期間修補 models.providers.*、alias,以及 agent 預設模型,請使用 openclaw/plugin-sdk/provider-onboard 中的 preset 輔助函式。範圍最窄的輔助函式是 createDefaultModelPresetAppliers(...)createDefaultModelsPresetAppliers(...)createModelCatalogPresetAppliers(...)當 provider 的原生端點在一般 openai-completions 傳輸上支援串流 usage block 時,請優先使用 openclaw/plugin-sdk/provider-catalog-shared 中的共用目錄輔助函式, 而不是硬編碼 provider-id 檢查。 supportsNativeStreamingUsageCompat(...)applyProviderNativeStreamingUsageCompat(...) 會從端點能力映射偵測支援, 因此即使 Plugin 使用自訂 provider id,原生 Moonshot/DashScope 風格 端點仍會選擇加入。
3

Add dynamic model resolution

如果你的 provider 接受任意模型 ID(例如 proxy 或 router), 請加入 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 進行非同步 warm-up - resolveDynamicModel 會在它完成後再次執行。
4

Add runtime hooks (as needed)

大多數 provider 只需要 catalog + resolveDynamicModel。請依照 provider 的需求逐步加入 hook。共用輔助建置器現在涵蓋最常見的 replay/tool-compat 家族,因此 Plugin 通常不需要逐一手動接線每個 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 風格重播政策,包括 tool-call-id 清理、assistant 優先排序修正,以及傳輸需要時的通用 Gemini 回合驗證moonshot, ollama, xai, zai
anthropic-by-modelmodelId 選擇的 Claude 感知重播政策,因此 Anthropic-message 傳輸只有在解析後模型實際上是 Claude id 時,才會取得 Claude 專屬 thinking-block 清理amazon-bedrock, anthropic-vertex
google-gemini原生 Gemini 重播政策,加上啟動重播清理和帶標籤的 reasoning-output 模式google, google-gemini-cli
passthrough-gemini針對透過 OpenAI 相容代理傳輸執行的 Gemini 模型進行 Gemini thought-signature 清理;不啟用原生 Gemini 重播驗證或啟動改寫openrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openai適用於在單一 Plugin 中混合 Anthropic-message 與 OpenAI 相容模型介面的提供者的混合政策;選用的僅限 Claude thinking-block 丟棄仍限定在 Anthropic 端minimax
目前可用的串流系列:
系列接入內容內建範例
google-thinking共用串流路徑上的 Gemini thinking 承載資料正規化google, google-gemini-cli
kilocode-thinking共用代理串流路徑上的 Kilo reasoning 包裝器,並讓 kilo/auto 和不支援的代理 reasoning id 跳過注入的 thinkingkilocode
moonshot-thinking從設定 + /think 層級對應 Moonshot 二進位原生 thinking 承載資料moonshot
minimax-fast-mode共用串流路徑上的 MiniMax fast-mode 模型改寫minimax, minimax-portal
openai-responses-defaults共用原生 OpenAI/Codex Responses 包裝器:歸因標頭、/fast/serviceTier、文字詳細程度、原生 Codex 網頁搜尋、reasoning 相容承載資料塑形,以及 Responses 脈絡管理openai, openai-codex
openrouter-thinking適用於代理路由的 OpenRouter reasoning 包裝器,集中處理不支援模型/auto 跳過openrouter
tool-stream-default-on適用於 Z.AI 這類想要工具串流預設開啟,除非明確停用的提供者的預設開啟 tool_stream 包裝器zai
每個系列建構器都由同一套套件匯出的較低階公開輔助工具組成;當提供者需要偏離常見模式時,你可以使用這些工具:
  • 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 thinking 預填清理(createAnthropicThinkingPrefillPayloadWrapper),以及共用代理/提供者包裝器(createOpenRouterWrappercreateToolStreamWrappercreateMinimaxFastModeWrapper)。
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamilybuildProviderToolCompatFamilyHooks("gemini"),以及底層 Gemini 結構描述輔助工具(normalizeGeminiToolSchemasinspectGeminiToolSchemas)。
有些串流輔助工具刻意維持在提供者本地。@openclaw/anthropic-providerwrapAnthropicProviderStreamresolveAnthropicBetasresolveAnthropicFastModeresolveAnthropicServiceTier,以及較低階的 Anthropic 包裝器建構器保留在它自己的公開 api.ts / contract-api.ts 接縫中,因為它們編碼了 Claude OAuth beta 處理與 context1m 閘控。xAI Plugin 同樣將原生 xAI Responses 塑形保留在它自己的 wrapStreamFn 中(/fast 別名、預設 tool_stream、不支援 strict-tool 清理、xAI 專屬 reasoning-payload 移除)。同樣的套件根模式也支援 @openclaw/openai-provider(提供者建構器、預設模型輔助工具、即時提供者建構器)和 @openclaw/openrouter-provider(提供者建構器加上 onboarding/設定輔助工具)。
對於每次推論呼叫前需要權杖交換的提供者:
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.<id> 設定
6applyNativeStreamingUsageCompat設定提供者的原生 streaming-usage 相容改寫
7resolveConfigApiKey由提供者擁有的 env-marker 驗證解析
8resolveSyntheticAuth本地/自託管或設定支援的合成驗證
9shouldDeferSyntheticProfileAuth將合成儲存設定檔預留位置降到 env/設定驗證之後
10resolveDynamicModel接受任意上游模型 ID
11prepareDynamicModel解析前的非同步中繼資料擷取
12normalizeResolvedModelrunner 前的傳輸改寫
13contributeResolvedModelCompat在另一個相容傳輸後方的供應商模型相容旗標
14normalizeToolSchemas註冊前由提供者擁有的工具結構描述清理
15inspectToolSchemas由提供者擁有的工具結構描述診斷
16resolveReasoningOutputMode帶標籤與原生 reasoning-output 合約
17prepareExtraParams預設請求參數
18createStreamFn完全自訂的 StreamFn 傳輸
19wrapStreamFn正常串流路徑上的自訂標頭/主體包裝器
20resolveTransportTurnState原生每回合標頭/中繼資料
21resolveWebSocketSessionPolicy原生 WS 工作階段標頭/cool-down
22formatApiKey自訂執行期權杖形狀
23refreshOAuth自訂 OAuth 重新整理
24buildAuthDoctorHint驗證修復指引
25matchesContextOverflowError由提供者擁有的溢位偵測
26classifyFailoverReason由提供者擁有的速率限制/過載分類
27isCacheTtlEligiblePrompt cache TTL 閘控
28buildMissingAuthMessage自訂缺少驗證提示
29augmentModelCatalog合成 forward-compat 列
30resolveThinkingProfile模型專屬 /think 選項集
31isBinaryThinking二進位 thinking 開/關相容性
32supportsXHighThinkingxhigh reasoning 支援相容性
33resolveDefaultThinkingLevel預設 /think 政策相容性
34isModernModelRef即時/煙霧測試模型比對
35prepareRuntimeAuth推論前的權杖交換
36resolveUsageAuth自訂用量憑證剖析
37fetchUsageSnapshot自訂用量端點
38createEmbeddingProvider由提供者擁有、用於記憶/搜尋的 embedding 配接器
39buildReplayPolicy自訂 transcript 重播/Compaction 政策
40sanitizeReplayHistory通用清理後的提供者專屬重播改寫
41validateReplayTurns內嵌 runner 前的嚴格重播回合驗證
42onModelSelected選擇後回呼(例如 telemetry)
執行期後援備註:
  • normalizeConfig 會先檢查相符的提供者,接著檢查其他具備鉤子能力的提供者 Plugin,直到其中一個實際變更設定為止。如果沒有提供者鉤子改寫支援的 Google 系列設定項目,仍會套用內建 Google 設定正規化器。
  • resolveConfigApiKey 會在公開時使用提供者鉤子。內建 amazon-bedrock 路徑此處也有內建 AWS env-marker 解析器,即使 Bedrock 執行期驗證本身仍使用 AWS SDK 預設鏈。
  • resolveSystemPromptContribution 讓提供者為模型系列注入快取感知的 system-prompt 指引。當行為屬於單一提供者/模型系列,且應保留穩定/動態快取分割時,請優先使用它,而不是 before_prompt_build
如需詳細描述和實際範例,請參閱 內部機制:提供者執行期鉤子
5

Add extra capabilities (optional)

步驟 5:新增額外能力

提供者 Plugin 可以在文字推論之外,同時註冊語音、即時轉錄、即時 語音、媒體理解、圖片生成、影片生成、網頁擷取, 以及網頁搜尋。OpenClaw 會將其分類為 混合能力 Plugin - 這是公司 Plugin (每個供應商一個 Plugin)的建議模式。請參閱 內部機制:能力擁有權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(...),讓 Plugin 共享受上限控管的錯誤本文讀取、JSON 錯誤解析,以及 request-id 後綴。
6

Test

步驟 6:測試

src/provider.test.ts
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();
  });
});

發布至 ClawHub

提供者 Plugin 的發布方式與任何其他外部程式碼 Plugin 相同:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
請勿在此使用舊版僅限 Skill 的發布別名;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 順序參考

catalog.order 控制你的 catalog 相對於內建 提供者合併的時機:
順序時機使用情境
simple第一輪一般 API-key 提供者
profilesimple 之後受 auth profiles 限制的提供者
pairedprofile 之後合成多個相關項目
late最後一輪覆寫既有提供者(衝突時勝出)

後續步驟

相關