1tomany/llm-sdk
Laravel-friendly PHP SDK for working with LLM providers. Provides a clean client API, request/response handling, and configurable drivers so you can send prompts, manage completions, and integrate AI features into your app with minimal boilerplate.
Installation:
composer require 1tomany/llm-sdk
For Laravel, consider using the Symfony bundle for autowiring and configuration.
First Use Case: Generate a simple LLM response using OpenAI:
use OneToMany\LlmSdk\Clients\OpenAI\Client;
use OneToMany\LlmSdk\Requests\GenerateOutputRequest;
$client = new Client('your-api-key');
$request = new GenerateOutputRequest(
model: 'gpt-3.5-turbo',
prompt: 'Explain Laravel dependency injection in simple terms.'
);
$response = $client->generateOutput($request);
echo $response->getResponse();
Key Files to Review:
examples/outputs/generate.php (for basic usage).src/Clients (for client-specific details).src/Requests (for request structures).use OneToMany\LlmSdk\Clients\OpenAI\Client;
use OneToMany\LlmSdk\Requests\FileRequest;
$client = new Client(config('services.openai.key'));
$fileRequest = FileRequest::fromPath('/path/to/file.pdf', 'application/pdf');
$response = $client->uploadFile($fileRequest);
ClientFactory and inject actions:
// Register clients
$factory = new \OneToMany\LlmSdk\Factory\ClientFactory();
$factory->register('openai', new \OneToMany\LlmSdk\Clients\OpenAI\Client(config('services.openai.key')));
// Define an action (e.g., in a service)
$action = new \OneToMany\LlmSdk\Actions\GenerateOutputAction($factory, 'openai');
$response = $action->execute(new GenerateOutputRequest(...));
use OneToMany\LlmSdk\Requests\ProcessQueryRequest;
$query = new ProcessQueryRequest(
model: 'gpt-4',
prompt: 'Summarize this document:',
files: [$fileRequest],
schema: ['title' => 'Summary', 'type' => 'object', 'properties' => [...]]
);
$compiled = $client->compileQuery($query);
$hash = $compiled->getHash(); // For caching or deduplication
$response = $client->processQuery($compiled);
// Create a search store (Gemini example)
$store = $client->createSearchStore('my_store', 'gemini-1.5-flash');
$client->importFileToSearchStore($store->getId(), $fileRequest);
// Search the store
$results = $client->searchStore($store->getId(), 'What is the main topic?');
Configuration Management:
.env and use the bundle’s configuration or a service provider to initialize clients:
// config/llm-sdk.php
return [
'clients' => [
'openai' => [
'key' => env('OPENAI_KEY'),
'base_uri' => env('OPENAI_BASE_URI', 'https://api.openai.com/v1'),
],
],
];
Dependency Injection:
ClientFactory in Laravel’s service container:
$this->app->singleton(\OneToMany\LlmSdk\Factory\ClientFactory::class, function ($app) {
$factory = new \OneToMany\LlmSdk\Factory\ClientFactory();
foreach (config('llm-sdk.clients') as $name => $config) {
$factory->register($name, new \OneToMany\LlmSdk\Clients\OpenAI\Client($config['key'], $config['base_uri']));
}
return $factory;
});
Mocking for Testing:
Mock client for unit tests:
$mockClient = new \OneToMany\LlmSdk\Clients\Mock\Client();
$mockClient->setResponse(new GenerateOutputResponse('Mocked response'));
Batching:
$batch = $client->createBatch();
$batch->addQuery($query1);
$batch->addQuery($query2);
$responses = $client->readBatch($batch->getId());
Error Handling:
BaseException class:
try {
$response = $client->generateOutput($request);
} catch (\OneToMany\LlmSdk\Exceptions\BaseException $e) {
Log::error('LLM Error: ' . $e->getMessage());
// Handle specific errors (e.g., rate limits, invalid requests)
}
Platform-Specific Limitations:
gpt-3.5-turbo vs. gpt-4).File Handling Quirks:
FileRequest are not automatically listed or downloaded by any provider. Track file IDs manually if needed.gpt-4-vision) exclude files from embeddings by default. Explicitly opt in if required.Query Compilation:
sha256 hash (getHash()), but hash collisions are possible for identical payloads with different metadata (e.g., timestamps). Use cautiously for deduplication.CompileQueryResponse is invokable, meaning you can call it directly to execute the query:
$compiled = $client->compileQuery($query);
$response = $compiled(); // Executes the query
Schema Requirements:
title property. The SDK attempts to extract the schema name from this title, but invalid titles may cause silent failures. Validate schemas before compilation:
if (empty($schema['title'])) {
throw new \InvalidArgumentException('Schema must have a title.');
}
Deprecated Methods:
ExecuteQuery was renamed to ProcessQuery in v0.7.0. Update any existing code:
// Old (deprecated)
$response = $client->executeQuery($query);
// New
$response = $client->processQuery($query);
Logging Requests:
getPayload() method on requests to log raw API payloads:
Log::debug('LLM Request Payload:', ['payload' => $request->getPayload()]);
Response Inspection:
getResponse() for raw data and getModel() for metadata:
$response = $client->generateOutput($request);
Log::info('Model used:', [$response->getModel()]);
Log::info('Raw response:', [$response->getResponse()]);
Mock Debugging:
Mock client logs all interactions. Enable debug mode to inspect:
$mockClient = new \OneToMany\LlmSdk\Clients\Mock\Client();
$mockClient->setDebug(true);
Rate Limiting:
throttle to manage API calls:
Route::middleware(['throttle:100,1'])->group(function () {
// LLM routes
});
How can I help you explore Laravel packages today?