Představuji knihovnu AI Access: jednotné rozhraní pro různé LLM v PHP
- David Grudl
- Nette Core | 8268
Ahoj,
poslední dobou hodně pracuju s různými AI modely (OpenAI, Claude, Gemini, Grok…), takže mě frustrovalo, že má každý z nich jiný API styl, jiné SDK, některé naopak žádného klienta v PHP nemají, některé knihovny jsou větší než celé Nette, mají různé pojmenování parametrů, odlišné výstupy atd.
Tak jsem napsal vlastní knihovnu. Malou, jednoduchou, čistě v PHP, s jednotným rozhraním pro všechny hlavní poskytovatele. Výměna modelu nebo výměna poskytovatele je tak otázkou pár znaků.
Vydal jsem první verzi 0.1 – co umí?
- 📤 Chatování – jednotné metody
createChat()
,sendMessage()
atd., stejné pro OpenAI, Claude, Gemini, DeepSeek i Grok (xAI) - 🧠 Embeddings – podpora pro OpenAI a Gemini, snadno použitelné v RAG projektech
- 📚 Batch API – chatování ale za poloviční cenu
- ⚙️ Nastavení parametrů (
temperature
,topP
,tools
, …) - 📜 Historie konverzace,
systemInstruction
, funkce, tokenové limity…
Podporuje 90% toho, co s LLM dělám, ale postupně chci přidávat další funkcionalitu.
Instalace (funguje s PHP 8.1+)
composer require ai-access/ai-access
Základní použití:
use AIAccess\Provider\OpenAI\Client;
$client = new Client(apiKey: 'sk-...'); // nahraď svým klíčem
$chat = $client->createChat('gpt-4o-mini');
$response = $chat->sendMessage('Napiš krátké haiku o PHP.');
echo $response->getText(); // např. "Elegantní kód / proudí mezi tagy / server tiše zpívá"
Metoda $response->getFinishReason()
vrací enum
AIAccess\Chat\FinishReason
,
který říká, proč model ukončil odpověď (např. TokenLimit
,
ContentFiltered
, Complete
…).
To se hodí pro ošetření případů, kdy třeba model odpověď nestihl dokončit a tak:
use AIAccess\Chat\FinishReason;
$reason = $response->getFinishReason();
if ($reason === FinishReason::Complete) {
echo "✅ Model odpověď dokončil.\n";
} elseif ($reason === FinishReason::TokenLimit) {
echo "⚠️ Odpověď byla přerušena tokenovým limitem. Dopsání…\n";
$response = $chat->sendMessage(); // pokračuje tam, kde skončil
echo $response->getText();
}
Knihovna má vlastní výjimkovou hierarchii:
AIAccess\ServiceException ← základ pro všechny chyby služby
├── ApiException ← API odpovědělo validně, ale s chybou (např. 401,
429, bad input…)
├── CommunicationException ← Nelze se spojit / odpověď je nečitelná
(timeout, DNS, invalid JSON…)
└── UnexpectedResponseException ← API odpovědělo zvláštně (změna
struktury, chybějící pole…)
Můžeš tedy zpracovat všechny chyby jednotně:
use AIAccess\ServiceException;
try {
$response = $chat->sendMessage('Napiš článek o PHP.');
echo $response->getText();
} catch (ServiceException $e) {
echo "Chyba při komunikaci s AI: " . $e->getMessage();
}
A nebo rozlišit konkrétní typy podle potřeby (např. při rate-limitu zkusit znovu atd.).
💸 Batch API = za poloviční cenu
U OpenAI a Claude lze posílat dávky dotazů (batch), které se zpracují
na pozadí.
Výhoda? Mnohem nižší cena, např. OpenAI GPT-4o batch = 50 %
běžné ceny.
Konverzací lze do dávky poslat víc, každou si pojmenuješ
(customId
), abys později poznal, co je co:
use AIAccess\Provider\Claude\Client;
use AIAccess\Chat\Role;
$client = new Client($apiKey);
$batch = $client->createBatch();
$chat1 = $batch->addChat('claude-3-haiku-20240307', customId: 'pozdrav');
$chat1->addMessage('Ahoj!', Role::User);
$chat2 = $batch->addChat('claude-3-haiku-20240307', customId: 'tip-na-clanek');
$chat2->addMessage('O čem psát v PHP?', Role::User);
$response = $batch->submit();
echo "Batch ID: " . $response->getId(); // uložit pro kontrolu později
Zpracování je asynchronní (trvá minuty až hodiny), výsledek zjistíš třeba v CRONu:
$batch = $client->retrieveBatch($batchId);
if ($batch->getStatus()->isCompleted()) {
foreach ($batch->getMessages() as $customId => $msg) {
echo "[$customId] " . $msg->getText() . "\n";
}
}
🧬 Embeddings – najdi podobné články
Embeddings jsou vektory, které reprezentují význam textu. Využívám je třeba na phpFashion.com pro doporučování podobných článků.
$texts = [
'Nette a komponentový přístup',
'Novinky v PHP 8.3',
'Jak psát bezpečné šablony',
];
$embeddings = $client->calculateEmbeddings(
model: 'text-embedding-3-small',
input: $texts
);
foreach ($embeddings as $index => $vector) {
echo "Text: " . $texts[$index] . "\n";
echo "Rozměr vektoru: " . count($vector->getVector()) . "\n";
}
Knihovna obsahuje počítání vzdálenosti vektorů
Budu rád za zpětnou vazbu, testování, bugreporty nebo nápady na vylepšení.
🧙 Jeden klient vládne všem…