Building AI Apps with PHP
You don't need Python. You need the right library.
PHP developers build ambitious applications with Laravel and Symfony every day. But the moment AI enters the picture, the conventional wisdom says: switch to Python.
Why? The hard part of AI — training models, running inference at scale — is handled by providers like Anthropic, OpenAI, and Google behind simple HTTP APIs. What's left is application-level work: calling those APIs, managing conversations, orchestrating tool use, streaming responses. That's web development. That's what PHP does every day.
PapiAI
PapiAI is an open-source PHP library for building AI agents. Zero runtime dependencies in its core. 10 LLM providers. A proper agentic runtime with tool calling, structured output, middleware, and streaming. It works in any PHP application — standalone scripts, Laravel, Symfony, or no framework at all.
The idea is simple: write your agent logic once, and swap the underlying model by changing a single constructor argument.
What it looks like
Here's a Laravel controller that streams AI responses with tool calling — a customer support agent that can look up orders in your database:
<?php
use PapiAI\Core\Agent;
use PapiAI\Core\Tool;
use PapiAI\Core\StreamEvent;
use App\AI\Tools\OrderLookup;
$agent = Agent::build()
->provider(app('papi'))
->model('claude-sonnet-4-20250514')
->instructions('You are a support agent for Acme Corp.')
->tools(Tool::fromClass(new OrderLookup()))
->maxTurns(8)
->create();
return response()->stream(function () use ($agent, $message) {
foreach ($agent->streamEvents($message) as $event) {
match ($event->type) {
StreamEvent::TYPE_TEXT => $this->sendSSE('text', $event->text),
StreamEvent::TYPE_TOOL_CALL => $this->sendSSE('tool', $event->tool),
StreamEvent::TYPE_DONE => null,
default => null,
};
}
}, headers: ['Content-Type' => 'text/event-stream']);
The OrderLookup tool is a plain PHP class. The agent decides when to call it based on the conversation. PapiAI executes the tool, feeds the result back to the LLM, and continues — all inside a single streamEvents() call.
Tools are defined with PHP attributes:
<?php
use PapiAI\Core\Attributes\Tool;
use PapiAI\Core\Attributes\Description;
class OrderLookup
{
#[Tool('Find an order by its ID to check status and shipping')]
public function find(
#[Description('The order ID, e.g. ORD-12345')] string $orderId,
): string {
$order = Order::where('order_id', $orderId)->first();
return json_encode([
'status' => $order->status,
'shipped_at' => $order->shipped_at?->toDateString(),
]);
}
}
No Python. No microservices. No language switching. Just PHP.
What's included
PapiAI ships with providers for Anthropic, OpenAI, Google Gemini, Ollama, Mistral, Groq, Grok, DeepSeek, Cohere, and Azure OpenAI. Plus ElevenLabs for text-to-speech.
The library includes a Zod-inspired schema system for structured output, a composable middleware pipeline (retry, rate limiting, caching, logging), conversation persistence, embeddings, and official bridges for both Laravel and Symfony.
The book
I've written a practical guide that walks through building two complete AI applications from scratch:
- A customer support agent with Laravel — streaming chat, conversation persistence, tool calling, RAG-powered knowledge base
- A content generation pipeline with Symfony — structured article generation, image creation with Google Imagen, async processing with Messenger
It covers everything from architecture and prompt design to security, testing, and deployment.
Get started
composer require papi-ai/papi-core papi-ai/anthropic
That's all you need.