使用 laradock 运行,本地运行正常,线上部署异常
线上环境
php8.2
+laravel11
相关代码
配置相关
<?php
namespace App\Services\AI;
use App\Contracts\AI\ProviderInterface;
use Illuminate\Support\Manager;
/**
* AI 管理器类
*/
class AIManager extends Manager
{
/**
* 获取默认驱动
*
* @return string 默认驱动名称
*/
public function getDefaultDriver(): string
{
return $this->config->get('ai.default', 'openai');
}
/**
* 创建驱动
*
* @param string $driver 驱动名称
* @return ProviderInterface
*/ protected function createDriver( $driver): ProviderInterface
{
$driverClass = match ($driver) {
'doubao' => DouBao\DoubaoAIProvider::class,
'openai' => OpenAI\OpenAIProvider::class,
'aliyun' => ALiYun\ALiYunAIProvider::class,
'deepSeek' => DeepSeek\DeepSeekProvider::class,
default => throw new \InvalidArgumentException("未知的驱动类型: $driver"),
};
return $this->container->make($driverClass, [
'config' => $this->config->get("ai.providers.$driver", []),
]);
}
}
<?php
namespace App\Services\AI;
use App\Contracts\AI\ServiceInterface;
use Exception;
use Illuminate\Support\Facades\Validator;
/**
* 抽象服务类
*/
abstract class AbstractService implements ServiceInterface
{
protected readonly array $config; // 配置信息
protected readonly string $version; // 服务版本
/**
* 构造函数
*
* @param array $config 服务配置
* @param string $version 服务版本
*/
public function __construct(array $config, string $version)
{
$this->config = $config;
$this->version = $version;
}
/**
* 定义参数的验证规则
*
* @return array 验证规则数组
*/
abstract protected function rules(): array;
/**
* 验证输入参数
*
* @param array $params 参数数组
* @return bool 验证是否通过
* @throws Exception 如果验证失败
*/
public function validate(array $params): bool
{
$validator = Validator::make($params, $this->rules());
if ($validator->fails()) {
throw new \InvalidArgumentException('错误的数据格式: ' . implode(', ', $validator->errors()->all()));
}
return true;
}
/**
* 获取配置信息,带默认值
*
* @param string $key 配置键
* @param mixed $default 默认值
* @return mixed 配置值
*/
protected function getConfig(string $key, mixed $default = null): mixed
{
return data_get($this->config, $key, $default);
}
}
服务相关
<?php
namespace App\Services\AI\DouBao;
use App\Contracts\AI\ProviderInterface;
use App\Contracts\AI\ServiceInterface;
use Illuminate\Contracts\Container\Container;
use InvalidArgumentException;
/**
* DouBao AI 提供者
*/
readonly class DouBaoAIProvider implements ProviderInterface
{
private Container $container; // 服务容器
private array $config; // 配置信息
/**
* 构造函数
*
* @param Container $container 服务容器
* @param array $config 提供者配置信息
*/
public function __construct(Container $container, array $config)
{
$this->container = $container;
$this->config = $config;
}
/**
* 检查支持的服务类型和版本
*
* @param string $type 服务类型
* @param string $version 服务版本
* @return bool 是否支持该服务
*/
public function supports(string $type, string $version): bool
{
return isset($this->config['versions'][$type]) &&
in_array($version, $this->config['versions'][$type], true);
}
/**
* 获取指定服务
*
* @param string $type 服务类型
* @param string $version 服务版本
* @return ServiceInterface 指定服务实例
* @throws InvalidArgumentException|\Illuminate\Contracts\Container\BindingResolutionException 如果不支持指定类型或版本
*/
public function getService(string $type, string $version = ''): ServiceInterface
{
$serviceClass = "App\\Services\\AI\\DouBao\\" . ucfirst($type) . "Service";
if (!class_exists($serviceClass)) {
throw new InvalidArgumentException("服务类 '$serviceClass' 未找到。");
}
return $this->container->make($serviceClass, [
'config' => $this->config,
'version' => $version,
]);
}
}
<?php
namespace App\Services\AI\DouBao;
use App\Services\AI\AbstractService;
use Exception;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Client\Response;
/**
* 文本服务
*/
class TextService extends AbstractService
{
/**
* 定义参数的验证规则
*
* @return array 验证规则数组
*/
protected function rules(): array
{
return [
'prompt' => 'required|array',
'prompt.*.role' => 'required|string',
'prompt.*.content' => 'required|string',
'max_tokens' => ['sometimes', 'integer', 'min:1', 'max:4000'],
'temperature' => ['sometimes', 'numeric', 'between:0,2'],
];
}
/**
* 执行服务
*
* @param array $params 参数数组
* @return array 执行结果
*@throws Exception 如果参数验证失败或请求失败
*/
public function execute(array $params): array
{
$this->validate($params);
$apiKey = $this->getConfig('access_key');
$url = $this->getConfig('api_url') . $this->getConfig('text.url');
$body = [
'model' => $this->getConfig('text.model'),
'messages' => $params['prompt'],
'max_tokens' => $params['max_tokens'] ?? 150,
'temperature' => $params['temperature'] ?? 0.7,
];
try {
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $apiKey,
'Content-Type' => 'application/json',
])->post($url, $body);
return $this->handleResponse($response);
} catch (\Throwable $e) {
Log::error('DouBao 文本服务错误', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw new Exception('调用 DouBao 文本服务失败: ' . $e->getMessage());
}
}
/**
* 处理 API 响应
*
* @param Response $response API 响应
* @return array 处理后的结果
* @throws Exception 如果响应格式无效
*/
protected function handleResponse(Response $response): array
{
$responseBody = json_decode($response->getBody()->getContents(), true);
if (isset($responseBody['choices'][0]['message']['content'])) {
return [
'role' => 'assistant',
'content' => $responseBody['choices'][0]['message']['content'],
];
} else {
Log::error('DouBao API 响应格式错误', ['response' => $responseBody]);
throw new Exception('无效的响应格式。');
}
}
}
报错
try {
$result = Ai::driver(driver:'doubao')
->getService(type:'text')
->execute([
'prompt' => $data
]);
return response()->json($result);
} catch (\Exception $e) {
return response()->json(['error' => '请求失败,错误信息:' . $e->getMessage()], 500);
}
本地
线上
这是爪子问题嘛,这文件怎么可能不存在
本作品采用《CC 协议》,转载必须注明作者和本文链接
大小写
估计是大小写问题 DouBaoAIProvider 对 DoubaoAIProvider 错
class找不到的,一律默认文件名有问题~