惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
Last Week in AI
Last Week in AI
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
博客园 - 【当耐特】
博客园 - 叶小钗
量子位
博客园 - 聂微东
S
SegmentFault 最新的问题
美团技术团队
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
宝玉的分享
宝玉的分享
小众软件
小众软件
罗磊的独立博客
有赞技术团队
有赞技术团队
Stack Overflow Blog
Stack Overflow Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Stop juggling AI SDKs in PHP — meet Prisma
Aimeos · 2026-05-22 · via DEV Community

If you've ever integrated an AI provider into a PHP application, you know the drill. You pull in the OpenAI SDK. Then the client wants image generation, so you add StabilityAI — different SDK, different request format, different error handling. Then they want audio transcription — enter Deepgram, yet another integration. Before you know it, you're maintaining three separate API integrations, each with their own quirks, response formats, and retry logic.

Prisma fixes this. One package. One API. 25+ providers. Text, image, audio, and video.

composer require aimeos/prisma

Enter fullscreen mode Exit fullscreen mode

What is Prisma?

Prisma is a light-weight, MIT-licensed PHP package that provides a unified interface for working with AI providers across four media domains. No framework coupling. Just Guzzle under the hood, PHP 8.2+, and a clean fluent API.

Here's the core idea — every provider works through the same interface:

use Aimeos\Prisma\Prisma;

// Generate text with OpenAI
$text = Prisma::text()
    ->using('openai', ['api_key' => '...'])
    ->write('Summarize the benefits of renewable energy')
    ->text();

// Generate an image with StabilityAI
$image = Prisma::image()
    ->using('stabilityai', ['api_key' => '...'])
    ->imagine('a mountain landscape at sunset')
    ->binary();

// Transcribe audio with Deepgram
$transcript = Prisma::audio()
    ->using('deepgram', ['api_key' => '...'])
    ->transcribe($audioFile)
    ->text();

// Describe a video with Gemini
$description = Prisma::video()
    ->using('gemini', ['api_key' => '...'])
    ->describe($videoFile)
    ->text();

Enter fullscreen mode Exit fullscreen mode

Same pattern everywhere: Prisma::{domain}()->using(provider, config)->{method}(). Switch providers by changing a single string. Your application code stays the same.

Why this matters in practice

Imagine you're building a product listing tool. You need to:

  1. Generate product descriptions from images
  2. Extract structured data (name, price, category) from the descriptions
  3. Generate marketing images for missing

Without Prisma, that's three different SDK integrations. With Prisma:

use Aimeos\Prisma\Prisma;
use Aimeos\Prisma\Schema\Schema;

// 1. Describe a product image
$description = Prisma::image()
    ->using('openai', ['api_key' => '...'])
    ->describe($productPhoto)
    ->text();

// 2. Extract structured data
$schema = Schema::for('product', [
    'name' => Schema::string()->required(),
    'price' => Schema::number(),
    'category' => Schema::string()->enum(['electronics', 'clothing', 'food', 'other']),
]);

$product = Prisma::text()
    ->using('gemini', ['api_key' => '...'])
    ->structured("Extract product info from: {$description}", $schema)
    ->structured();
// ['name' => 'Wireless Headphones', 'price' => 79.99, 'category' => 'electronics']

// 3. Generate a product image
$image = Prisma::image()
    ->using('stabilityai', ['api_key' => '...'])
    ->imagine("Professional illustration of {$product['name']}")
    ->binary();

Enter fullscreen mode Exit fullscreen mode

Three providers, three media types, one consistent API. And if tomorrow you want to swap Gemini for Anthropic, you change one line.

You can also check provider capabilities at runtime:

$provider = Prisma::image()->using('clipdrop', ['api_key' => '...']);

if ($provider->has('upscale')) {
    $image = $provider->upscale($lowResImage)->binary();
}

// Or throw if the capability is missing
$provider->ensure('upscale'); // throws NotImplementedException if not supported

Enter fullscreen mode Exit fullscreen mode

What's new in 0.4

Version 0.4 is a major release that adds text generation, structured output, tool calling, and a lot more. Here's what landed.

Text generation across 14 providers

The write() method brings text generation to Prisma with support for OpenAI, Anthropic, Gemini, Bedrock, Mistral, Groq, Cohere, Deepseek, Alibaba, xAI, Perplexity, OpenRouter, Ollama, and Deepseek. All multimodal — pass images, audio, or documents alongside your prompt:

use Aimeos\Prisma\Base\File;

$response = Prisma::text()
    ->using('anthropic', ['api_key' => '...'])
    ->withSystemPrompt('You are a helpful assistant')
    ->write('Describe this image', [File::from('photo.jpg')]);

echo $response->text();

Enter fullscreen mode Exit fullscreen mode

Structured output

Get typed JSON responses from LLMs using a fluent Schema builder. Prisma uses each provider's native structured output API — no prompt engineering hacks:

use Aimeos\Prisma\Schema\Schema;

$schema = Schema::for('event', [
    'title' => Schema::string()->required(),
    'date' => Schema::string()->format('date')->required(),
    'attendees' => Schema::array()->items(Schema::string()),
    'location' => Schema::object([
        'city' => Schema::string()->required(),
        'country' => Schema::string(),
    ]),
]);

$response = Prisma::text()
    ->using('openai', ['api_key' => '...'])
    ->structured('Parse: Team meetup on June 15 in Berlin with Alice and Bob', $schema);

$event = $response->structured();
// [
//     'title' => 'Team meetup',
//     'date' => '2026-06-15',
//     'attendees' => ['Alice', 'Bob'],
//     'location' => ['city' => 'Berlin', 'country' => 'Germany'],
// ]

Enter fullscreen mode Exit fullscreen mode

The Schema builder supports strings, integers, numbers, booleans, arrays, objects, enums (including PHP BackedEnum), nested objects, required(), nullable(), min()/max(), regex pattern(), and more. You can also pass raw JSON Schema arrays via Schema::fromArray().

Tool calling with auto-execution

This is where things get interesting. Prisma supports full agentic tool calling with an automatic execution loop. You define tools, the model calls them, Prisma executes the handlers and feeds results back — all automatically:

use Aimeos\Prisma\Tools;
use Aimeos\Prisma\Schema\Schema;

$searchTool = Tools::make(
    'search_products',
    'Search the product database',
    Schema::for('search', [
        'query' => Schema::string()->description('Search query')->required(),
        'limit' => Schema::integer()->description('Max results')->min(1)->max(50),
    ]),
    function(array $args): string {
        $results = ProductSearch::query($args['query'], $args['limit'] ?? 10);
        return json_encode($results);
    }
);

$response = Prisma::text()
    ->using('openai', ['api_key' => '...'])
    ->withTools([$searchTool])
    ->withMaxSteps(5)
    ->write('Find me the top 3 wireless headphones under $100');

echo $response->text();
// The model searched, got results, and wrote a summary

Enter fullscreen mode Exit fullscreen mode

You can inspect what happened during the tool loop:

foreach ($response->steps() as $step) {
    echo $step->name();      // 'search_products'
    echo $step->arguments(); // ['query' => 'wireless headphones', 'limit' => 3]
    echo $step->result();    // '[ ... search results ... ]'
}

Enter fullscreen mode Exit fullscreen mode

Tools also support:

  • Per-tool call limits: Tools::make(...)->max(3) — the tool can only be called 3 times
  • Custom error handlers: ->failed(fn($e, $args) => 'Fallback message') — catch exceptions gracefully
  • Concurrent execution: ->concurrent() — tools run in parallel via pcntl_fork
  • Decorators: wrap tools with logging, caching, or any custom behavior
  • Tool choice: ->withToolChoice(Provider::REQ) to force tool use

Provider tools

Some providers offer built-in server-side tools like web search and code execution. Prisma normalizes these too:

use Aimeos\Prisma\Tools;

$response = Prisma::text()
    ->using('anthropic', ['api_key' => '...'])
    ->withTools([
        Tools::provider('web_search'),
        Tools::provider('code_execution'),
    ])
    ->write('Search for the latest PHP version and verify it');

Enter fullscreen mode Exit fullscreen mode

Available provider tools include web_search, code_execution, file_search, web_fetch, image_generation, and document_library — each mapped to the providers that support them. You can mix custom and provider tools in the same request.

Framework tool adapters

Already have tools built for Laravel AI or Symfony? Reuse them directly:

// Laravel AI / Prism tools
$tool = Tools::laravel(new MyLaravelTool());

// Symfony #[AsTool] classes
$tool = Tools::symfony(MySymfonyTool::class);

Enter fullscreen mode Exit fullscreen mode

Thinking budgets

Enable extended reasoning for models that support it. Prisma automatically maps token counts to each provider's native format:

$response = Prisma::text()
    ->using('anthropic', ['api_key' => '...'])
    ->withThinkingBudget(5000)
    ->withMaxTokens(4096)
    ->write('Solve this step by step: ...');

// Access the model's reasoning
$thinking = $response->meta()['thinking'] ?? null;

Enter fullscreen mode Exit fullscreen mode

Citations

Normalized citation objects across providers that support them (Anthropic, OpenAI, Gemini, Perplexity, xAI):

foreach ($response->citations() as $citation) {
    $citation->title();  // source title
    $citation->url();    // source URL
    $citation->text();   // output text that cites this source
    $citation->source(); // verbatim quote from the source
}

Enter fullscreen mode Exit fullscreen mode

Rate limits and retry handling

// Automatic retry with exponential backoff
$response = Prisma::text()
    ->using('openai', ['api_key' => '...'])
    ->withClientRetry(3, fn($attempt, $resp) => 100 * pow(2, $attempt))
    ->write('...');

// Inspect rate limit headers
$limit = $response->rateLimit();
$limit->remaining();  // requests left
$limit->retryAfter(); // seconds until reset

Enter fullscreen mode Exit fullscreen mode

Provider coverage

Here's what's supported for text providers in 0.4:

Provider structured translate write citations custom tools provider tools thinking budget
Alibaba yes yes - yes yes -
Anthropic yes yes yes yes yes yes
Bedrock yes yes - yes yes
Cohere yes yes - yes -
Deepseek yes yes - yes -
DeepL yes
Gemini yes yes yes yes yes yes
Google yes
Groq yes yes - yes -
Mistral yes yes - yes yes -
Ollama beta beta - yes -
OpenAI yes yes yes yes yes yes
Openrouter yes yes - yes yes -
Perplexity beta beta yes yes -
xAI beta beta yes yes yes yes

And that's just text. Prisma also covers 9 audio providers (speak, transcribe, demix, denoise, revoice, describe), 14 image providers (imagine, inpaint, upscale, vectorize, background, erase, and more), and video description via Gemini.

Getting started

composer require aimeos/prisma

Enter fullscreen mode Exit fullscreen mode

Minimal example:

<?php

use Aimeos\Prisma\Prisma;

// Text
echo Prisma::text()
    ->using('openai', ['api_key' => getenv('OPENAI_API_KEY')])
    ->write('What makes PHP great?')
    ->text();

// Image
$binary = Prisma::image()
    ->using('openai', ['api_key' => getenv('OPENAI_API_KEY')])
    ->imagine('a PHP elephant wearing sunglasses')
    ->binary();

file_put_contents('elephant.png', $binary);

Enter fullscreen mode Exit fullscreen mode

No service providers, no config files, no framework dependencies. Just require and use.


Prisma is MIT-licensed and open source. Check it out:

If you've been looking for a unified way to work with AI providers in PHP — especially beyond just text — give it a try. Feedback, issues, and stars are all welcome.

In case you like Prisma, leave a star in the Github repo :-)