构建提供商插件
构建提供商插件
Section titled “构建提供商插件”本指南介绍了如何构建一个提供商插件,用于向 LLM 添加模型提供商 (OpenClaw)。完成本指南后,你将拥有一个包含模型目录、API 密钥身份验证和动态模型解析的提供商。
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.compat和openclaw.build字段 是必填的。Register the 提供商
最小的提供商需要一个
id、label、auth和catalog: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(...)` 辅助函数:```typescriptimport { 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(...)`。添加动态模型解析
如果您的提供商接受任意的模型 ID(例如代理或路由器), 请添加
resolveDynamicModel:api.registerProvider({// ... id, label, auth, catalog from aboveresolveDynamicModel: (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将在完成后再次运行。添加运行时钩子(根据需要)
大多数提供商只需要
catalog+resolveDynamicModel。根据提供商的需要逐步添加钩子。对于需要在每次推理调用之前进行令牌交换的提供商:
prepareRuntimeAuth: async (ctx) => {const exchanged = await exchangeToken(ctx.apiKey);return {apiKey: exchanged.token,baseUrl: exchanged.baseUrl,expiresAt: exchanged.expiresAt,};},对于需要自定义请求标头或正文修改的提供商:
// wrapStreamFn returns a StreamFn derived from ctx.streamFnwrapStreamFn: (ctx) => {if (!ctx.streamFn) return undefined;const inner = ctx.streamFn;return async (params) => {params.headers = {...params.headers,"X-Acme-Version": "2",};return inner(params);};},对于公开使用/计费数据的提供商:
resolveUsageAuth: async (ctx) => {const auth = await ctx.resolveOAuthToken();return auth ? { token: auth.token } : null;},fetchUsageSnapshot: async (ctx) => {return await fetchAcmeUsage(ctx.token, ctx.timeoutMs);},所有可用的提供商钩子
OpenClaw 按此顺序调用钩子。大多数提供商仅使用 2-3 个:
# Hook 何时使用 1 catalog模型目录或基础 URL 默认值 2 resolveDynamicModel接受任意上游模型 ID 3 prepareDynamicModel解析前的异步元数据获取 4 normalizeResolvedModel运行器之前的传输重写 5 capabilities副本/工具元数据(数据,不可调用) 6 prepareExtraParams默认请求参数 7 wrapStreamFn自定义标头/正文包装器 8 formatApiKey自定义运行时令牌形状 9 refreshOAuth自定义 OAuth 刷新 10 buildAuthDoctorHint认证修复指导 11 isCacheTtlEligible提示缓存 TTL 门控 12 buildMissingAuthMessage自定义缺失认证提示 13 suppressBuiltInModel隐藏陈旧的上游行 14 augmentModelCatalog合成向前兼容行 15 isBinaryThinking二元思维开/关 16 supportsXHighThinkingxhigh推理支持17 resolveDefaultThinkingLevel默认 /think策略18 isModernModelRef实时/冒烟模型匹配 19 prepareRuntimeAuth推理前的令牌交换 20 resolveUsageAuth自定义使用凭证解析 21 fetchUsageSnapshot自定义使用端点 22 onModelSelected选择后回调(例如遥测) 有关详细描述和实际示例,请参阅 Internals: Provider Runtime Hooks。
添加额外功能(可选)
提供商插件可以在文本推理之外注册语音、媒体理解、图像 生成和网络搜索功能:
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。
测试
import { describe, it, expect } from "vitest";// Export your provider config object from index.ts or a dedicated fileimport { 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
Section titled “发布到 ClawHub”提供商插件的发布方式与任何其他外部代码插件相同:
clawhub package publish your-org/your-plugin --dry-runclawhub 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) — 钩子详细信息和捆绑示例