AIService 核心文档
适用项目:XIUNOX(XIUNO BBS X重构版) 源文件:
xiunobbs-master/lib/AIService.php最后更新:2026-07-03
一、概述
AIService 是 XIUNOX 的 AI 调用中台,统一管理所有 AI 功能的调用入口。核心职责:
多 provider 调用:支持 failover/round_robin/random/concurrent 四种模式
健康检查:kv 持久化 provider 在线/离线状态,自动故障转移
功能注册:插件通过
registerFeature()注册新 AI 功能内容后处理:插件通过
registerPostFilter()注册回调过滤 AI 返回内容配置解析:按 mode(global/user_key/both)合并全局与用户配置
二、配置结构
2.1 全局配置 conf.ai(conf/conf.php)
'ai' => array (
// 全局提供商库(管理员维护,含 api_key)
'providers' => array (
array(
'name' => 'openai', // 唯一标识
'type' => 'text', // text/image/video/audio/transcription
'url' => 'https://api.openai.com',
'api_key' => 'sk-xxx',
'models' => array( // 模型列表
array('name' => 'gpt-4o', 'enabled' => 1),
array('name' => 'gpt-4o-mini', 'enabled' => 1),
),
),
),
// 功能配置(每个 AI 功能一项)
'features' => array (
'editor' => array (
'name' => 'AIeditor',
'type' => 'text',
'mode' => 'user_key', // global/user_key/both
'call_method' => 'frontend', // frontend/proxy
'default_provider' => '',
'default_model' => '',
'allowed_providers' => array('openai', 'deepseek'),
),
),
// 编辑器专属配置(可选)
'promptContinue' => '请根据上下文续写内容',
'promptImprove' => '请优化以下文本的表达',
),
2.2 用户配置 user.ai_config
// 存储在 user 表 ai_config 字段(JSON)
// 新版结构:{featureKey: {apiKey, model, url, provider_name}}
array(
'editor' => array(
'apiKey' => 'sk-xxx',
'model' => 'gpt-4o-mini',
'url' => 'https://api.openai.com',
'provider_name' => 'openai',
),
)
2.3 健康状态(kv 持久化)
kv 键:
ai_provider_health结构:
{provider_name: {online: bool, last_check: int}}写入时机:仅状态变化时写 kv(减少写开销)
读取:请求内 static 缓存,避免重复读 kv
2.4 轮询状态(kv 持久化)
kv 键:
ai_roundrobin_last_{feature}作用:round_robin 模式记录上次使用的 provider,下次从下一个开始
三、API 参考
3.1 静态方法(功能注册)
registerFeature($key, $config)
注册新 AI 功能。插件应在 model_inc_start.php 钩子中调用,先注册者胜(已注册不覆盖)。
AIService::registerFeature('xnx_ai_reply', array(
'name' => 'AI 自动回复',
'type' => 'text',
'mode' => 'global',
'call_method' => 'proxy',
'default_provider' => '',
'default_model' => '',
'allowed_providers' => array(),
));
字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| string | 是 | 功能名称(显示用) |
| string | 是 | provider 类型:text/image/video/audio/transcription |
| string | 是 | global(用全局配置)/ user_key(用用户配置)/ both(优先用户,回退全局) |
| string | 是 | frontend(前端直连)/ proxy(服务端代理) |
| string | 否 | 默认 provider 名 |
| string | 否 | 默认模型名 |
| array | 否 | 允许的 provider 名数组 |
registerPostFilter($key, $callback)
注册内容后处理过滤器。call() 和 callWithFailover() 成功后会自动调用。
AIService::registerPostFilter('xnx_ai_reply', function($content, $context) {
// $context = ['key', 'messages', 'provider_name', 'options']
return trim($content);
});
getRegisteredFeatures()
返回所有已注册功能(核心 editor + 插件注册的)。
3.2 实例方法(配置解析)
getFeatureConfig($key)
返回功能配置(合并注册默认值 + conf.ai.features.$key,conf 覆盖注册默认值)。
getEffectiveConfig($key, $uid = null)
按 mode 合并全局/用户配置,返回最终生效配置。配置不完整时返回空数组。
$ai = new AIService($db, $conf);
$config = $ai->getEffectiveConfig('editor', $uid);
// 返回:['apiKey', 'model', 'url', 'provider_name', 'promptContinue'(可选), 'promptImprove'(可选)]
3.3 实例方法(AI 调用)
call($key, $messages, $options = [])
单 provider 调用(按功能 key 解析配置后调用)。
$result = $ai->call('editor', $messages, array(
'uid' => $uid,
'temperature' => 0.7,
'max_tokens' => 1024,
'timeout' => 30,
'source' => 'core',
));
返回结构:
array(
'code' => 0, // 0成功 / 1失败
'message' => '', // 错误信息
'data' => array(
'content' => 'AI 回复文本',
'usage' => array('prompt_tokens', 'completion_tokens', 'total_tokens'),
'provider_name' => 'openai',
'model' => 'gpt-4o-mini',
'time_ms' => 1234,
),
)
callWithFailover($key, $messages, $options = []) ★
多 provider 调用,支持四种模式。插件复用此方法实现轮询、故障转移、并发竞速。
$result = $ai->callWithFailover('xnx_ai_reply', $messages, array(
'mode' => 'failover', // failover/round_robin/random/concurrent
'retry' => 2, // 每个 provider 重试次数
'providers' => array('openai', 'deepseek'), // 可选,覆盖 feature.allowed_providers
'uid' => $uid,
'temperature' => 0.7,
'max_tokens' => 1024,
'timeout' => 30,
'source' => 'xnx_ai_reply',
'recover_threshold' => 600, // 离线恢复阈值秒数
));
provider 来源优先级:
options.providers显式指定feature.allowed_providersfeature.default_provider
四种模式:
模式 | 行为 | 适用场景 |
|---|---|---|
| 顺序故障转移,每个 provider retry 次后切下一个 | 默认,高可用 |
| 轮询,从上次使用的下一个开始(kv 持久化) | 负载均衡 |
| shuffle 后顺序 fallback | 随机分散 |
| curl_multi 前 3 个并发竞速,取最快返回 | 低延迟 |
健康检查逻辑:
调用前过滤掉已离线未过
recover_threshold的 provider调用成功后标记 provider online
调用失败后标记 provider offline
未知 provider(kv 无记录)视为健康
3.4 实例方法(健康状态)
markProviderOnline($name) / markProviderOffline($name)
标记 provider 在线/离线(仅状态变化时写 kv)。
isProviderHealthy($name, $recoverThreshold = 600)
判断 provider 是否健康。未知 provider 视为健康,离线超过阈值视为可恢复。
getProviderHealth($name = null)
返回单个或全部 provider 健康状态。
$all = $ai->getProviderHealth();
// 返回:['openai' => ['online' => true, 'last_check' => 1234567890], ...]
$one = $ai->getProviderHealth('openai');
// 返回:['online' => true, 'last_check' => 1234567890]
3.5 实例方法(测试)
testProvider($name)
测试 provider 连接(发送 ping 请求)。成功/失败后自动标记健康状态。
$result = $ai->testProvider('openai');
// 返回:['code' => 0/1, 'message' => ..., 'data' => ['time_ms' => ...]]
四、调用流程
4.1 单 provider 调用流程(call())
call($key, $messages, $options)
├─ getEffectiveConfig($key, $uid) // 按 mode 解析配置
├─ callByConfig($config, $messages, $options, $logBase) // 底层 curl 调用
│ ├─ 构造请求体(model/messages/temperature/max_tokens)
│ ├─ curl POST 到 {url}/chat/completions
│ ├─ 解析响应(choices[0].message.content + usage)
│ └─ writeLog() // 写入 xnx_ai_call_log
└─ applyPostFilters($key, $content, $context) // 应用已注册的后处理过滤器
4.2 多 provider 调用流程(callWithFailover())
callWithFailover($key, $messages, $options)
├─ 解析 providerNames(options.providers > feature.allowed_providers > feature.default_provider)
├─ 构建 configs 列表(过滤掉配置不完整和已离线未恢复的)
├─ 按模式调用:
│ ├─ concurrent: callConcurrent() // curl_multi 前 3 个并发竞速
│ ├─ random: callRandom() // shuffle 后顺序 fallback
│ ├─ round_robin: callRoundRobin() // 从上次下一个开始,kv 持久化
│ └─ failover: callFailover() // 顺序故障转移 + retry
│ 每种模式内部都调用 callByConfig() 执行单次 curl
└─ applyPostFilters($key, $content, $context)
五、插件接入指南
5.1 接入步骤
注册功能:在
hook/model_inc_start.php调用AIService::registerFeature()配置功能:在
install.php写入conf.ai.features.{key}调用 AI:在插件业务代码中调用
$ai->call()或$ai->callWithFailover()(可选)注册后处理:通过
registerPostFilter()注册内容过滤器
5.2 接入示例(xnx_ai_reply 插件)
步骤 1:注册功能(hook/model_inc_start.php)
if (class_exists('AIService') && method_exists('AIService', 'registerFeature')) {
AIService::registerFeature('xnx_ai_reply', array(
'name' => 'AI 自动回复',
'type' => 'text',
'mode' => 'global',
'call_method' => 'proxy',
'allowed_providers' => array(),
));
}
步骤 2:调用 AI(插件 Service 类)
$ai = new AIService($db, $conf);
$result = $ai->callWithFailover('xnx_ai_reply', $messages, array(
'mode' => 'failover',
'retry' => 2,
'temperature' => 0.7,
'recover_threshold' => 600,
'source' => 'xnx_ai_reply',
));
if ($result['code'] === 0) {
$content = $result['data']['content'];
$provider_name = $result['data']['provider_name'];
$usage = $result['data']['usage']; // prompt_tokens/completion_tokens/total_tokens
}
5.3 接入注意事项
类加载守卫:生产环境(DEBUG=0)走
tmp/model.min.php合并加载,类加载顺序不可预测。调用 AIService 前必须:if (!class_exists('AIService')) { include_once APP_PATH . 'lib/AIService.php'; }provider 来源:插件不应自建 provider 表,统一用核心
conf.ai.providers。用户在后台「AI - 全局提供商」页面配置。健康状态:核心用 kv 持久化(
ai_provider_health),插件不要自建健康检查逻辑,直接调用isProviderHealthy()或getProviderHealth()。日志写入:
call()和callWithFailover()内部已自动写入核心日志表xnx_ai_call_log,插件如需自有日志表可双写(参考 xnx_ai_reply 的 AiLogService)。流式调用:
call()和callWithFailover()是非流式调用。流式调用(SSE)由route/ai.php的/ai-chat端点处理,插件如需流式需自行实现。
六、相关文件
文件 | 职责 |
|---|---|
| 核心 AI 调用中台(本文档) |
| 统一 AI 调用日志接口(写入 |
| 前台 AI 代理路由( |
| 后台 AI 配置路由(providers/features) |
| 后台全局提供商配置页 |
| 后台功能配置页 |
| 后台 AI 调用日志页 |
| 前台「我的 AI」配置页 |
| 默认配置(含预置 5 个 AI 厂商) |
七、数据库表
7.1 xnx_ai_call_log(核心统一日志表)
字段 | 类型 | 说明 |
|---|---|---|
id | int unsigned | 主键 |
uid | int unsigned | 用户ID |
feature | varchar(32) | 功能标识(editor/xnx_ai_reply/…) |
source | varchar(32) | 来源标识(core/xnx_ai_reply/…) |
provider_name | varchar(64) | provider 名 |
model | varchar(64) | 模型名 |
mode | varchar(16) | 模式(global/user_key/both) |
prompt_tokens | int | 输入 token 数 |
completion_tokens | int | 输出 token 数 |
total_tokens | int | 总 token 数 |
response_time | int | 响应时间(ms) |
status | tinyint | 1成功 / 0失败 |
error_msg | varchar(500) | 错误信息 |
request_summary | varchar(500) | 请求摘要 |
response_summary | varchar(500) | 响应摘要 |
create_time | int unsigned | 创建时间 |
7.2 kv 表
键 | 说明 |
|---|---|
| provider 健康状态(name => {online, last_check}) |
| round_robin 模式上次使用的 provider 名 |
八、错误码
code | 含义 | 说明 |
|---|---|---|
0 | 成功 | data 含 content/usage/provider_name/model/time_ms |
1 | 失败 | message 含错误信息 |
常见错误信息:
AI 配置不完整:apiKey/url/model 为空无可用 provider:allowed_providers 为空且无 default_provider无可用 provider 配置(可能全部离线或配置不完整):所有 provider 都离线或配置缺失curl error: ...:curl 调用失败HTTP 4xx/5xx: ...:provider 返回错误状态码empty content:provider 返回空内容


