前言
WordPress 6.9 引入了 PHP AI Client SDK,为 WordPress 生态提供了统一的 AI 服务接入标准。本文分析我最近实现的 AI Provider for DeepSeek 插件,它是该 SDK 的 DeepSeek 适配实现,同时支持作为 Composer 包和 WordPress 插件两种使用方式。
插件架构概览
插件的目录结构遵循 PSR-4 规范:
wp-ai-provider-for-deepseek/
├── plugin.php # WordPress 插件入口
├── readme.txt # WordPress 插件描述
├── assets/images/deepseek.svg # 供应商 Logo
└── src/
├── autoload.php # PSR-4 自动加载器
├── Provider/
│ ├── DeepSeekProvider.php # 主 Provider 类
│ └── DeepSeekProviderAvailability.php # API Key 可用性检查器
├── Models/
│ └── DeepSeekTextGenerationModel.php # 文本生成模型实现
└── Metadata/
└── DeepSeekModelMetadataDirectory.php # 模型元数据目录
核心实现分析
1. 插件入口与 Hook 注册(plugin.php)
插件通过三个关键 Hook 完成初始化:
// 注册 AI Provider(优先级 5,确保在 AI Client 之后加载)
add_action('init', __NAMESPACE__ . '\\register_provider', 5);
// 输出 Provider 数据到前端(确保 admin 页面可用)
add_action('admin_enqueue_scripts', __NAMESPACE__ . '\\ensure_provider_data_output', 5);
// 注册 Connector(WordPress 连接器系统)
add_action('wp_connectors_init', __NAMESPACE__ . '\\register_connector', 10);
// 自动审批 Connector 使用权限(优先级 20,确保 Approvals_Store 可用)
add_action('init', __NAMESPACE__ . '\\auto_approve_connector', 20);
设计亮点:
register_provider()先检查AiClient类是否存在,避免依赖未安装时 fatal error- 使用
$registry->hasProvider()防止重复注册 ensure_provider_data_output()处理边缘情况:当 AI Client 的脚本未加载时,手动输出window.aiProviderData
2. Provider 主类(DeepSeekProvider.php)
核心类继承自 AbstractApiProvider,实现四个工厂方法:
class DeepSeekProvider extends AbstractApiProvider
{
// API 基础 URL
protected static function baseUrl(): string
{
return 'https://api.deepseek.com';
}
// 创建模型实例(根据能力分发到具体模型类)
protected static function createModel(...): ModelInterface
{
foreach ($capabilities as $capability) {
if ($capability->isTextGeneration()) {
return new DeepSeekTextGenerationModel(...);
}
}
throw new \RuntimeException('Unsupported model capabilities');
}
// 创建 Provider 元数据(支持版本化特性)
protected static function createProviderMetadata(): ProviderMetadata
{
$args = [
'deepseek',
'DeepSeek',
ProviderTypeEnum::cloud(),
'https://platform.deepseek.com/api_keys',
RequestAuthenticationMethod::apiKey()
];
// 1.2.0+ 支持描述
if (version_compare(AiClient::VERSION, '1.2.0', '>=')) {
$args[] = __('Text generation with DeepSeek models.', 'ai-provider-for-deepseek');
}
// 1.3.0+ 支持 Logo
if (version_compare(AiClient::VERSION, '1.3.0', '>=')) {
$args[] = dirname(__DIR__, 2) . '/assets/images/deepseek.svg';
}
return new ProviderMetadata(...$args);
}
// 自定义可用性检查器(用真实 API 请求验证 Key)
protected static function createProviderAvailability(): ProviderAvailabilityInterface
{
return new DeepSeekProviderAvailability(static::class);
}
// 模型元数据目录(动态从 API 发现可用模型)
protected static function createModelMetadataDirectory(): ModelMetadataDirectoryInterface
{
return new DeepSeekModelMetadataDirectory();
}
}
版本兼容处理是这段代码的精华:通过 version_compare 逐步添加新特性支持,确保插件在旧版 PHP AI Client 上也能正常运行。
3. API Key 验证与缓存(DeepSeekProviderAvailability.php)
DeepSeek 不支持标准的”列出模型”端点,因此插件采用真实请求验证法:发送一个 max_tokens=1 的最小化请求,根据 HTTP 状态码判断 Key 是否有效。
public function isConfigured(): bool
{
// 1. 检查缓存(5 分钟过期)
$cached = get_transient(self::CACHE_KEY);
if ($cached !== false) {
return (bool) $cached;
}
// 2. 获取 API Key(优先 WordPress 选项,fallback 到环境变量)
$apiKey = $this->getApiKey();
if (empty($apiKey)) {
$this->cacheResult(false);
return false;
}
// 3. 发送最小化请求
$response = wp_remote_post($url, [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $apiKey,
],
'body' => json_encode([
'model' => 'deepseek-v4-flash',
'messages' => [['role' => 'user', 'content' => 'test']],
'max_tokens' => 1,
]),
'timeout' => 30,
]);
// 4. 根据状态码判断(200/400 = Key 有效,401/403 = Key 无效)
$responseCode = wp_remote_retrieve_response_code($response);
$isConfigured = !in_array($responseCode, [401, 403], true);
// 5. 缓存结果
$this->cacheResult($isConfigured);
return $isConfigured;
}
缓存策略有效减少了重复验证请求:使用 WordPress Transient API,5 分钟过期。注意错误时不缓存,允许下次重试。
4. 模型元数据动态发现(DeepSeekModelMetadataDirectory.php)
插件通过调用 DeepSeek 的 /models 端点动态获取可用模型列表,而非硬编码:
protected function parseResponseToModelMetadataList(Response $response): array
{
$responseData = $response->getData();
// 定义 DeepSeek 模型支持的能力和选项
$textGenerationCapabilities = [
CapabilityEnum::textGeneration(),
CapabilityEnum::chatHistory(),
];
$textGenerationOptions = [
new SupportedOption(OptionEnum::systemInstruction()),
new SupportedOption(OptionEnum::candidateCount()),
new SupportedOption(OptionEnum::maxTokens()),
new SupportedOption(OptionEnum::temperature()),
new SupportedOption(OptionEnum::topP()),
new SupportedOption(OptionEnum::customOptions()),
new SupportedOption(OptionEnum::inputModalities()), // 修复:添加必需的能力声明
new SupportedOption(OptionEnum::outputModalities()),
];
// 将 API 响应映射为 ModelMetadata 对象
$models = array_map(function ($modelData) use ($textGenerationCapabilities, $textGenerationOptions) {
return new ModelMetadata(
$modelData['id'], // model ID(如 deepseek-v4-flash)
$modelData['id'], // model name
$textGenerationCapabilities,
$textGenerationOptions
);
}, $responseData['data']);
// 排序:deepseek-v4-flash 优先,其次是 deepseek-v4-pro,然后字母序
usort($models, [$this, 'modelSortCallback']);
return $models;
}
注意inputModalities 和 outputModalities 的添加——这是修复 ModelRequirements::fromPromptData() 和 generate_text() 调用的关键,缺少这两个选项会导致运行时错误。
5. 文本生成模型实现(DeepSeekTextGenerationModel.php)
DeepSeek API 兼容 OpenAI 的 Chat Completions 格式,因此直接继承 AbstractOpenAiCompatibleTextGenerationModel:
class DeepSeekTextGenerationModel extends AbstractOpenAiCompatibleTextGenerationModel
{
protected function createRequest(
HttpMethodEnum $method,
string $path,
array $headers = [],
$data = null
): Request {
// 覆盖父类:使用 DeepSeek Provider 的 URL 而非 OpenAI 的
return new Request(
$method,
DeepSeekProvider::url($path), // => https://api.deepseek.com/chat/completions
$headers,
$data,
$this->getRequestOptions()
);
}
}
这个实现非常简洁,因为大部分工作(请求格式化、响应解析、流式输出等)都由父类 AbstractOpenAiCompatibleTextGenerationModel 完成。只需要覆盖 createRequest() 将请求路由到 DeepSeek 的 API 地址即可。
Connector 审批系统
WordPress 的 AI Client 引入了 Connector 审批机制:每个插件使用 Connector(如 DeepSeek)前必须获得审批。本插件在 init hook(优先级 20)自动审批自己:
function auto_approve_connector(): void
{
if (!class_exists('\WordPress\AI\Connector_Approval\Approvals_Store')) {
return; // 旧版 AI Client 不支持审批系统
}
$store = new \WordPress\AI\Connector_Approval\Approvals_Store();
$plugin_basename = plugin_basename(__FILE__);
$connector_id = 'deepseek';
if ($store->is_approved($plugin_basename, $connector_id)) {
return; // 已审批,跳过
}
$store->set_approval($plugin_basename, $connector_id, true);
}
这避免了用户手动在设置页面审批插件,提升了用户体验。
使用方式
作为 WordPress 插件
// 1. 安装并激活插件(依赖 PHP AI Client 插件)
// 2. 配置 API Key
putenv('DEEPSEEK_API_KEY=your-api-key');
// 3. 使用
$result = AiClient::prompt('解释量子计算')
->usingProvider('deepseek')
->generateTextResult();
echo $result->toText();
作为 Composer 包
composer require wordpress/ai-provider-for-deepseek
<?php
use WordPress\AiClient\AiClient;
use WordPress\DeepSeekAiProvider\Provider\DeepSeekProvider;
// 注册 Provider
$registry = AiClient::defaultRegistry();
$registry->registerProvider(DeepSeekProvider::class);
// 设置 API Key
putenv('DEEPSEEK_API_KEY=your-api-key');
// 生成文本
$result = AiClient::prompt('Explain quantum computing')
->usingProvider('deepseek')
->generateTextResult();
echo $result->toText();
技术亮点总结
| 特性 | 实现方式 | 价值 |
|---|---|---|
| 版本兼容 | version_compare 渐进式添加特性 |
支持旧版 AI Client,无 breaking change |
| API Key 验证 | 最小化真实请求 + Transient 缓存 | 准确验证 + 减少重复请求 |
| 动态模型发现 | 调用 /models API + 元数据映射 |
自动支持新模型,无需更新代码 |
| Connector 审批 | init hook 自动审批 |
零配置用户体验 |
| OpenAI 兼容 | 继承 AbstractOpenAiCompatible* |
复用大量现有逻辑,代码量极小 |
| 双模式运行 | Composer 包 + WordPress 插件 | 最大灵活性,可在任何 PHP 项目中使用 |
结论
这个插件的实现展示了如何为一个新的 AI 服务商编写符合 WordPress PHP AI Client 标准的 Provider。核心要点:
- 继承正确的抽象类:文本生成继承
AbstractOpenAiCompatibleTextGenerationModel - 实现四个工厂方法:
baseUrl()、createModel()、createProviderMetadata()、createModelMetadataDirectory() - 自定义可用性检查:当标准方法(列出模型)不可用时,用真实请求验证
- 版本兼容处理:使用
version_compare渐进式添加新特性支持 - WordPress 集成:正确注册 Hook、Connector、审批
完整代码已开源在 GitHub,欢迎试用和贡献。
