跳转到内容

构建提供商插件

本指南介绍了如何构建一个提供商插件,用于向 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"],
    "providerAuthEnvVars": {
    "acme-ai": ["ACME_AI_API_KEY"]
    },
    "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 } } ```

    清单声明了 providerAuthEnvVars,以便 OpenClaw 能够在 不加载插件运行时的情况下检测凭据。如果您在 ClawHub 上 发布该提供商,则 package.json 中的 openclaw.compatopenclaw.build 字段 是必填的。

  2. Register the 提供商

    最小的提供商需要一个 idlabelauthcatalog

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

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

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

    对于仅注册一个使用 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" }],
    }),
    },
    },
    });
    ```
    如果您的身份验证流程还需要在引导过程中修补 `models.providers.*`、别名
    和代理默认模型,请使用 `openclaw/plugin-sdk/provider-onboard` 中的预设辅助函数。
    范围最窄的辅助函数是
    `createDefaultModelPresetAppliers(...)`、
    `createDefaultModelsPresetAppliers(...)` 和
    `createModelCatalogPresetAppliers(...)`。
  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。根据提供商的需要逐步添加钩子。

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

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

    OpenClaw 按此顺序调用钩子。大多数提供商仅使用 2-3 个:

    #Hook何时使用
    1catalog模型目录或基础 URL 默认值
    2resolveDynamicModel接受任意上游模型 ID
    3prepareDynamicModel解析前的异步元数据获取
    4normalizeResolvedModel运行器之前的传输重写
    5capabilities副本/工具元数据(数据,不可调用)
    6prepareExtraParams默认请求参数
    7wrapStreamFn自定义标头/正文包装器
    8formatApiKey自定义运行时令牌形状
    9refreshOAuth自定义 OAuth 刷新
    10buildAuthDoctorHint认证修复指导
    11isCacheTtlEligible提示缓存 TTL 门控
    12buildMissingAuthMessage自定义缺失认证提示
    13suppressBuiltInModel隐藏陈旧的上游行
    14augmentModelCatalog合成向前兼容行
    15isBinaryThinking二元思维开/关
    16supportsXHighThinkingxhigh 推理支持
    17resolveDefaultThinkingLevel默认 /think 策略
    18isModernModelRef实时/冒烟模型匹配
    19prepareRuntimeAuth推理前的令牌交换
    20resolveUsageAuth自定义使用凭证解析
    21fetchUsageSnapshot自定义使用端点
    22onModelSelected选择后回调(例如遥测)

    有关详细描述和实际示例,请参阅 Internals: Provider Runtime Hooks

  5. 添加额外功能(可选)

    提供商插件可以在文本推理之外注册语音、媒体理解、图像 生成和网络搜索功能:

    register(api) {
    api.registerProvider({ id: "acme-ai", /* ... */ });
    api.registerSpeechProvider({
    id: "acme-ai",
    label: "Acme Speech",
    isConfigured: ({ config }) => Boolean(config.messages?.tts),
    synthesize: async (req) => ({
    audioBuffer: Buffer.from(/* PCM data */),
    outputFormat: "mp3",
    fileExtension: ".mp3",
    voiceCompatible: false,
    }),
    });
    api.registerMediaUnderstandingProvider({
    id: "acme-ai",
    capabilities: ["image", "audio"],
    describeImage: async (req) => ({ text: "A photo of..." }),
    transcribeAudio: async (req) => ({ text: "Transcript..." }),
    });
    api.registerImageGenerationProvider({
    id: "acme-ai",
    label: "Acme Images",
    generate: async (req) => ({ /* image result */ }),
    });
    }

    OpenClaw 将此归类为混合功能(hybrid-capability)插件。这是 公司插件的推荐模式(每个供应商一个插件)。请参阅 Internals: Capability Ownership

  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

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

## 目录合并顺序参考
`catalog.order` 控制您的目录相对于内置
提供商的合并时机:
| 顺序 | 时机 | 用例 |
| --------- | -------------- | ---------------------------- |
| `simple` | 首轮 | 纯 API 密钥提供商 |
| `profile` | 在简单类型之后 | 基于认证配置文件的提供商 |
| `paired` | 在配置文件之后 | 合成多个相关条目 |
| `late` | 末轮 | 覆盖现有提供商(冲突时胜出) |
## 后续步骤
- [渠道插件](/en/plugins/sdk-channel-plugins) — 如果您的插件还提供渠道
- [SDK Runtime](/en/plugins/sdk-runtime) — `api.runtime` 辅助工具(TTS、搜索、子代理)
- [SDK 概述](/en/plugins/sdk-overview) — 完整的子路径导入参考
- [插件内部机制](/en/plugins/architecture#provider-runtime-hooks) — 钩子详细信息和捆绑示例