pv-source / aivory
PHP библиотека для работы с AI LLM-провайдерами (OpenAI-совместимое API). Единый интерфейс с поддержкой типизированных ответов, JSON Schema и fluent API, вдохновленным Eloquent
Requires
- php: ^8.3
- guzzlehttp/guzzle: ^7.10
README
Aivory — PHP библиотека для работы с AI LLM-провайдерами (OpenAI-совместимое API, пример: DeepSeek, ChatGPT). Предоставляет единый интерфейс для отправки запросов к различным AI API с поддержкой типизированных ответов, JSON Schema и удобного fluent API. Реализация библиотеки вдохновлена Eloquent и стремится использовать подход API AS DB по отношению к нейросетям, а также функциональность стремящуюся к схожести c Eloquent.
🚀 Основные возможности
- ✅ Множественные провайдеры — поддержка DeepSeek, OpenAI и легко расширяемая архитектура
- ✅ Типизированные ответы — автоматическое преобразование JSON ответов в PHP объекты через
JsonSchemaInterface - ✅ Fluent API — удобный builder pattern для построения запросов
- ✅ JSON Schema — использование классов вместо ручного написания схем
- ✅ Thinking Mode — поддержка режима размышления (DeepSeek)
- ✅ Scope методы — создание переиспользуемых конфигураций (как в Laravel Eloquent)
- ✅ PSR-7 совместимость — работа с стандартными HTTP интерфейсами
- ✅ Type-safe — строгая типизация и валидация на всех уровнях
📦 Установка
composer require pv-source/aivory
Требования
- PHP 8.3+
- Guzzle HTTP Client 7.10+
🎯 Быстрый старт
Простой пример
<?php use PvSource\Aivory\Client; use PvSource\Aivory\LLM\Turn\Turn; // Создаем клиент $client = new Client( providerName: 'deepseek', auth: ['apiKey' => 'sk-your-api-key'] ); $provider = $client->getProvider(); // Отправляем запрос $turn = Turn::query() ->withProvider($provider) ->setUserPrompt('Привет! Расскажи о PHP') ->setModel('deepseek-chat') ->setTemperature(0.7) ->send(); // Получаем ответ $assistantMessage = $turn->getResponse()->getAssistant(); echo $assistantMessage->content;
Использование с JSON Schema
<?php use PvSource\Aivory\LLM\Turn\Request\ResponseFormat; // Создаем ResponseFormat с использованием класса $responseFormat = ResponseFormat::jsonSchema( schema: ['type' => MathSolution::class], name: 'math_solution', strict: true ); $turn = Turn::query() ->withProvider($provider) ->setUserPrompt('Реши: 2 + 2 * 3') ->setModel('deepseek-chat') ->setResponseFormat($responseFormat) ->send(); // Автоматическое преобразование в типизированный объект $mathSolution = $turn->getResponse()->getSchemaObjects(); echo $mathSolution->answer; // "8"
📚 Документация
Основные концепции
1. Client — точка входа
Client создает и координирует работу всех компонентов библиотеки:
$client = new Client( providerName: 'deepseek', // или 'openai' auth: ['apiKey' => 'sk-...'], httpClient: $customHttpClient // опционально );
2. Turn — базовый класс для запросов
Turn предоставляет fluent API для построения и отправки запросов:
$turn = Turn::query() ->withProvider($provider) ->setSystemPrompt('Ты помощник') ->setUserPrompt('Вопрос') ->setModel('deepseek-chat') ->setTemperature(0.7) ->setMaxTokens(1000) ->send();
3. Кастомные Turn классы
Создавайте свои классы, наследующие Turn, для переиспользования конфигураций:
class MathTurn extends Turn { // Значения по умолчанию (как в Eloquent) protected static ?string $defaultSystemPrompt = 'Ты математик'; protected static ?string $defaultModel = 'deepseek-chat'; protected static ?float $defaultTemperature = 0.3; // Scope методы для разных режимов public static function scopeAdvancedSolver(TurnBuilder $builder): void { $builder->setIsThinking(true); $builder->setMaxTokens(2000); } } // Использование $turn = MathTurn::query() ->withProvider($provider) ->advancedSolver() // вызывает scopeAdvancedSolver() ->setUserPrompt('Реши задачу') ->send();
4. JsonSchemaInterface — типизированные ответы
Создавайте классы, реализующие JsonSchemaInterface, для автоматического преобразования ответов:
class MathSolution implements JsonSchemaInterface { public function __construct( public string $answer, public array $steps = [] ) {} public static function getJsonSchema(?array $rootSchema = null): array { $schema = [ 'type' => 'object', 'properties' => [ 'answer' => ['type' => 'string'], ] ]; // Адаптивная схема в зависимости от контекста if ($rootSchema['name'] === 'advanced_math_solution') { $schema['properties']['steps'] = [ 'type' => 'array', 'items' => ['type' => MathStep::class] ]; } return $schema; } public static function fromResponse(array $data): static { return new self( answer: $data['answer'], steps: array_map( fn($step) => MathStep::fromResponse($step), $data['steps'] ?? [] ) ); } }
Поддерживаемые провайдеры
DeepSeek
$client = new Client('deepseek', ['apiKey' => 'sk-...']);
Особенности:
- ✅ Поддержка thinking mode (
isThinking) - ✅ Reasoning content в ответах
- ✅ JSON Schema через системное сообщение
OpenAI
$client = new Client('openai', ['apiKey' => 'sk-...']);
Особенности:
- ✅ JSON Schema через отдельное поле
json_schema - ❌ Не поддерживает thinking mode
Параметры запроса
Все параметры доступны через fluent API:
$turn = Turn::query() ->setModel('deepseek-chat') ->setTemperature(0.7) // 0.0-2.0 ->setMaxTokens(2000) // Максимум токенов ->setFrequencyPenalty(0.5) // -2.0 до 2.0 ->setPresencePenalty(0.3) // -2.0 до 2.0 ->setTopP(0.9) // 0.0-1.0 ->setIsThinking(true) // DeepSeek only ->setStop(['\n\n', 'END']) // Стоп-последовательности ->setStream(false) // Streaming ->setResponseFormat($format) // JSON Schema или text ->send();
Работа с ответами
$response = $turn->getResponse(); // Получить сообщение от ассистента $assistantMessage = $response->getAssistant(); echo $assistantMessage->content; // Получить reasoning content (если включен thinking mode) if ($assistantMessage->reasoningContent !== null) { echo $assistantMessage->reasoningContent; } // Получить типизированный объект (если использовался JSON Schema) $mathSolution = $response->getSchemaObjects(); // Получить usage информацию $rawBody = $response->getRawBody(); $usage = $rawBody['usage']; echo "Токенов использовано: {$usage['total_tokens']}";
📖 Примеры
Простой пример
Продвинутый пример
См. examples/advanced/index.php
Демонстрирует:
- Использование
JsonSchemaInterface - Создание кастомных
Turnклассов - Scope методы
- Адаптивные схемы
- Thinking mode и reasoning content
Пример с разными моделями
См. examples/models_example.php
🏗️ Архитектура
Библиотека следует принципам Domain-Driven Design (DDD):
src/
├── LLM/ # Доменный слой
│ ├── Turn/ # Основные доменные модели
│ │ ├── Turn.php # Базовый класс Turn
│ │ ├── Request/ # DTO запроса
│ │ ├── Response/ # Интерфейс ответа
│ │ └── Options/ # Настройки запроса
│ └── ProviderInterface.php
├── Providers/ # Инфраструктурный слой
│ ├── DeepSeek/ # Реализация для DeepSeek
│ └── OpenAI/ # Реализация для OpenAI
└── Transport/ # HTTP транспорт
└── HttpClientInterface.php
Паттерны проектирования
- Builder Pattern — для построения запросов
- Adapter Pattern — для преобразования доменных моделей в API формат
- Factory Pattern — для создания провайдеров
- Strategy Pattern — для различных провайдеров
🔧 Расширение библиотеки
Добавление нового провайдера
- Создайте класс провайдера, реализующий
ProviderInterface - Создайте
RequestAdapterдля преобразования запросов - Создайте
ChatTurnResponseдля обработки ответов - Зарегистрируйте в
ProviderFactory
Кастомный HTTP клиент
class CustomHttpClient implements HttpClientInterface { public function sendRequest(RequestInterface $request): ResponseInterface { // Ваша реализация } } $client = new Client( 'deepseek', ['apiKey' => 'sk-...'], new CustomHttpClient() );
📝 Конфигурация
Для того, чтобы запускать примеры из examples, необходимо создать файл .env в корне библиотеки:
PROVIDER=deepseek API_KEY=sk-your-api-key-here
🗺️ Планы развития
Библиотека активно развивается. Вот что планируется добавить и улучшить:
- Добавление Conversation - сущности, содержащей в себе переписку
- Join/with - добавление join-подобного интерфейса для группы последовательных и/или параллельных запросов, в том числе с использованием разных провайдеров, концепция "отношений" между Turn классами
- Доменные исключения - иерархия специализированных исключений для лучшей обработки ошибок
- Валидация на уровне Request - расширенная валидация запросов перед отправкой
- Middleware/Interceptors - система middleware для логирования, кэширования, retry и т.д.
- Событийная модель - добавление возможности подписываться на события жизненного цикла обьектов библиотеки
- Расширение числа провайдеров - увеличение числа возможных провайдеров, доступных "из коробки"
- Типизация и унификация работы с системными полямя ответов - работа с usage и прочими полями ответа
- Асинхронные запросы, ReactPHP - поддержка Promise-based API для параллельных запросов
- Поддержка streaming - полноценная обработка потоковых ответов
- Rate limiting - встроенная защита от превышения лимитов API
- Тесты - покрытие тестами всех компонентов библиотеки
Если у вас есть идеи или предложения, пожалуйста, создавайте issue или пишите в Telegram!
🤝 Вклад в проект
Приветствуются любые улучшения! Пожалуйста, создавайте issue или pull request. А также пишите в telegram: @blueberryMgn
Сделано с ❤️ для PHP разработчиков