Key Takeaways

  • Most businesses need to add an AI feature to an existing app, not build a new AI product — and that distinction matters for scope and cost
  • Laravel's built-in HTTP client handles calls to OpenAI, Claude, and any other AI API cleanly, without a separate Python service or new codebase
  • The real work in an AI integration is prompt design, context formatting, and result storage — the API call itself is the straightforward part
  • For structured, testable AI features, laravel-ai-action gives every AI capability a consistent, discoverable home — the same way laravel/actions does for business logic
  • Wrapping AI calls in action classes, storing results, and dispatching non-interactive tasks to queues keeps integrations maintainable long-term

Most businesses do not need to build an AI product. They need to add an AI feature to the product they already have. That distinction matters more than it might seem — the second is far more achievable, far less expensive, and often delivers better results because it augments a workflow people already understand rather than introducing a new one.

Laravel's HTTP client makes this clean. You add a service class, call the API, and wire the result into your existing application. No new codebase. No Python microservice. No separate deployment pipeline.

What does "AI integration" actually mean in a Laravel app?

When clients ask about adding AI to their application, the request usually falls into one of a few categories. Generate a first draft of something — a proposal, a summary, a job posting. Classify or label incoming data, like support tickets or form submissions. Answer questions about their own content through a chat interface over their documentation or knowledge base. Extract structured data from unstructured text, like parsing an email into form fields.

All of these are HTTP calls to an AI API. The model does the work. Your Laravel application handles the before and after: retrieving context, formatting the request, storing the result, presenting it to the user.

The complexity is not in the API call. It is in making the integration fit cleanly into your existing data model, keeping the results useful and auditable, and building the UI that makes the output actionable.

How does Laravel's HTTP client handle AI API calls?

Laravel's built-in HTTP client wraps Guzzle with a fluent, readable API that works the same way for AI endpoints as it does for any other external service. Here is what a call to OpenAI looks like inside a service class:

class AiDraftService
{
    public function generateProposal(Project $project): string
    {
        $response = Http::withToken(config('services.openai.key'))
            ->timeout(30)
            ->post('https://api.openai.com/v1/chat/completions', [
                'model'    => 'gpt-4o',
                'messages' => [
                    ['role' => 'system', 'content' => 'You are a professional copywriter.'],
                    ['role' => 'user',   'content' => $this->buildPrompt($project)],
                ],
                'max_tokens' => 800,
            ]);

        return $response->json('choices.0.message.content');
    }

    private function buildPrompt(Project $project): string
    {
        return "Write a project proposal for the following: {$project->description}. 
                Client industry: {$project->client->industry}. 
                Budget range: {$project->budget_label}.";
    }
}

You send a POST request with your API key and a structured message array. You get back text. The buildPrompt() method pulls in project data to give the model relevant context. The result is a string you can store, display, or pass to the next step in your application.

The same pattern works for Anthropic's Claude API, Google Gemini, or any provider that exposes an HTTP endpoint. You are swapping a base URL and a model name, not rearchitecting anything.

How should you structure AI integrations to stay maintainable?

The short answer: the same way you structure everything else in a Laravel application. Single-responsibility classes, queues, proper error handling. A few specifics worth calling out.

Give each AI capability its own class. Do not call the AI API directly from a controller, and avoid bundling multiple AI tasks into one service class. As integrations grow, a single AiService with a dozen methods becomes hard to test, hard to reason about, and hard to hand off to another developer. Each AI task — summarise a post, classify a ticket, draft a proposal — deserves its own class with a single job.

We use and maintain an open source package called laravel-ai-action that formalises this pattern on top of laravel/ai. It provides an AgentAction interface, an AgentContext DTO for passing records and instructions, and a typed AgentResult that includes the output text and token usage. Scaffold a new action with:

composer require pixelworxio/laravel-ai-action
php artisan make:ai-action SummarizePost

The generated class makes the structure explicit:

final class SummarizePost implements AgentAction
{
    use InteractsWithAgent;

    public function instructions(AgentContext $context): string
    {
        return 'You are a concise technical writer. Summarize in three sentences.';
    }

    public function prompt(AgentContext $context): string
    {
        return sprintf("Summarize:\n\n%s", $context->record->body);
    }

    public function handle(AgentContext $context): AgentResult
    {
        return app(RunAgentAction::class)->execute($this, $context);
    }
}

Calling it from a controller or job is one line:

$result = $this->runner->execute(new SummarizePost(), AgentContext::fromRecord($post));

echo $result->text;        // "This post covers..."
echo $result->inputTokens; // 320

The instructions() and prompt() methods are separate by design — instructions set the model's behaviour, the prompt provides the content. Keeping them distinct makes both easier to iterate on and test independently. The package also ships with FakeAgentAction for testing without hitting the API.

Store the results. AI calls are slow and cost money. If a user generates a proposal, save it to the database. Let them regenerate on demand, but do not call the API on every page load. Storing results gives you an audit trail — useful for debugging, useful for showing users what the model produced before they edited it, and useful for understanding how each integration is actually being used.

Handle failures gracefully. AI APIs time out, hit rate limits, and occasionally return malformed responses. Set a reasonable timeout, wrap calls appropriately, and have a fallback — even if that fallback is just a clear error message rather than a blank field.

Use queues for anything non-interactive. If the AI task does not need to complete before the user sees a response — batch summarization, background classification, overnight processing — dispatch it as a queue job. laravel-ai-action includes RunAgentActionJob for exactly this. Laravel Queues handle the execution, and Laravel Horizon gives you visibility into what is running, what failed, and how long jobs are taking.

What about streaming responses?

Some AI use cases benefit from streaming — showing the response as it generates rather than waiting for the full output. Laravel's HTTP client does not handle streaming natively, but you can use Guzzle's streaming option directly or reach for a dedicated package. For most business integrations, streaming adds UI complexity without a proportional benefit. Start with a standard request/response pattern and add streaming only if users are visibly waiting and noticing.

How long does a typical AI integration take to build?

A focused integration — one that generates or summarizes content using the application's own data — usually takes a few days of development time, not weeks. The API call itself takes an afternoon. The work is in designing the prompt so results are consistently useful, formatting the context the model needs, storing results cleanly in the data model, and building the UI that presents the output in a way that fits the existing workflow.

The applications that get the most value from AI augmentation are the ones with a clear, repetitive task that currently lives in someone's head. Drafting the same kind of document dozens of times a month. Categorizing the same types of inputs. Answering the same questions from different customers. AI does not replace the judgment required for edge cases and novel situations. It removes the repetition from the cases that follow a pattern.

If you are already using Laravel's scheduler to run tasks on a cadence, AI-powered batch processing fits naturally into that same pattern — generate summaries overnight, classify new records as they arrive, or pre-draft documents before a user opens them.

Where does this fit in a broader AI strategy?

A single AI integration is not an AI strategy — but it is a reasonable place to start. Pick the one task in your application that is repetitive, pattern-driven, and currently requires a person every time. Build the integration. Measure whether it saves meaningful time or improves output quality. Use that as the basis for deciding what to tackle next.

This is the opposite of rebuilding your product around AI. It is identifying where AI earns its place within the product you already have, and adding it there first.

If there is a task in your application that follows a pattern but still requires a person every time, get in touch. It is probably a stronger candidate for AI augmentation than you expect.