Laravel AI SDK Agents (Hotel Booking Agent)

Since Laravel 13 has been released, a lot of developers have been building AI Agents and integrating them into their websites to build Agent-driven we...

9 min read
Table of Contents
Since Laravel 13 has been released, a lot of developers have been building AI Agents and integrating them into their websites to build Agent-driven web apps. The agents that can be built through the SDK are multimodal in nature, meaning they can process PDF's, images, audio, video, text, etc. The power of multimodality allows the Agent to get relevant and informative context for precise and accurate information processing and decision-making. The different providers supported allow us to develop Agentic tools such as text-to-speech, which can be achieved through configurations of the providers, which can be done in the file config/ai.php which was created when we were running php artisan vendor:publish --provider="Laravel\Ai\AiServiceProvider" after installation and on the .env file for environment variables.

Supported AI Providers

The list of built-in supported providers is
ANTHROPIC_API_KEY=COHERE_API_KEY=ELEVENLABS_API_KEY=GEMINI_API_KEY=MISTRAL_API_KEY=OLLAMA_API_KEY=OPENAI_API_KEY=JINA_API_KEY=VOYAGEAI_API_KEY=XAI_API_KEY=
Your selection of an AI provider should be directly dependent on the features that are needed in order to build your AI Agent, currently the following features are provided by different providers.
FeatureProviders
 Text OpenAI, Anthropic, Gemini, Azure, Groq, xAI, DeepSeek, Mistral, Ollama
 Images OpenAI, Gemini, xAI
 Text to Speech OpenAI, ElevenLabs
 Speech to text OpenAI, ElevenLabs, Mistral
 Embeddings OpenAI, Gemini, Azure, Cohere, Mistral, Jina, VoyageAI
 Reranking Cohere, Jina
 Files OpenAI, Anthropic, Gemini
Since different providers have different features supported, some Agents might need you to use more than one provider in order for you to be able to achieve a certain workflow.
What made Laravel stand out as a web application framework has been its scaffolding features, which are made possible by the artisan command. This functionality was also made available for creating AI agents. We can create an agent by executing the command. php artisan make:agent {agent-name} Through the command line interface, this will create an additional folder outside the Laravel app A directory called Agents, and inside we are going to find the {agent-name}.php file.

Example Hotel Booking Agent

To demonstrate and illustrate how AI Agents are built in Laravel through the AI SDK we are going to build a hotel booking agent which will act as a Concierge, When a user prompts, "Is there any room available next weekend?", the agent recognizes the intent, uses the CheckRoomAvailabilityTool, looks up the Property model, and returns a natural language response.
The first lines of code on the Agent file are as follows
<?phpnamespace App\Agents;use App\Models\Property;use App\Tools\CalculateBookingPriceTool;use App\Tools\CheckRoomAvailabilityTool;use App\Tools\GetBookingUrlTool;use Laravel\Ai\Contracts\Agent;use Laravel\Ai\Contracts\Conversational;use Laravel\Ai\Contracts\HasTools;use Laravel\Ai\Contracts\Tool;use Laravel\Ai\Messages\Message;use Laravel\Ai\Promptable;use Stringable;
The first line namespace App\Agents: It's just a namespace that tells Laravel where to find the file to be able to load it during the autoload bootstrap by Composer.
The App\Models\Property: Just provides the BookingAgent class access to property-related information in a way that you would normally interact with your models in your standard Laravel web application.
The App\Tools\{ToolName}: Is what provides the Agent with agentic capabilities, extending its abilities from just being a chatbot into an agent that can perform various actions such as accessing the database, creating and deleting records, and performing other tasks that a standard chat LLM wouldn't normally be able to do. This is where you are going to be spending most of your time building the capabilities of the Agent. You need to be careful about one thing: do not stack a lot of tools into a single agent because it will cause your token usage per context window to increase, leading to you building cost-inefficient AI Agents. This is created by the context-bloating problem.
The Larvel\AI\Contracts\{ContractName}: Are just a set of interfaces that define the core AI services provided by the framework.
The use Stringable : It's just a standard PHP interface that ensures an object can be treated as a string.
The Models and the Stringable Interface immediately reveal to us that we can be able to use the current features that make Laravel powerful in providing more control and capabilities to the AI Agent into building Agentic WebApps, and that is already exposed by the built-in agent tools such as the web search, web fetch, and file search.

The Agent Instructions

They act as constraints to the Agent with a definition of restrictions and rules that it needs to implement when loading tools and making decisions, which looks as follows
 public function instructions(): Stringable|string    {        $checkIn  =$this->property->check_in_time  ?? '14:00';        $checkOut =$this->property->check_out_time ?? '11:00';        $currency =$this->property->currency       ?? 'ZAR';        return <<<EOTYou are a booking assistant for {$this->property->name}. Your sole purpose is to help guests make a reservation.## Your WorkflowFollow these steps in order to complete a booking enquiry:1. **Collect check-in date** — Ask the guest when they plan to arrive (YYYY-MM-DD).2. **Collect check-out date** — Ask when they plan to depart.3. **Collect number of guests** — Ask how many adults (and children if any).4. **Check availability** — Use the `CheckRoomAvailabilityTool` with those dates.5. **Present options** — List only the available room types with nightly rates and capacity.6. **Confirm room choice** — Ask which room type the guest prefers.7. **Calculate price** — Use the `CalculateBookingPriceTool` to show a full price breakdown.8. **Provide booking link** — Use `GetBookingUrlTool` to generate the direct booking URL. Present it clearly so the guest can click it to complete the reservation.## Rules- Only show rooms that are available for the requested dates.- Always present the full price breakdown before sending the booking link (nights × price, tax, total).- If dates are unclear or in the past, politely ask the guest to clarify.- Confirm once: "Great — here is your booking link: [URL]. It will take you directly to the payment step."- Currency: {$currency}- Check-in time: {$checkIn} | Check-out time: {$checkOut}- This property: {$this->property->name} only — never reference other properties.- Never invent pricing — always use the tool to calculate.EOT;   }
The rules and instructions are straightforward regarding the capabilities of the AI Agent.

Tool Loading

public function tools(): iterable    {        return [            new CheckRoomAvailabilityTool($this->property),            new CalculateBookingPriceTool($this->property),            new GetBookingUrlTool($this->property),        ];    }

To make the LLM have the ability to detect tools, tools that are associated with an agent must be registered through the following the above tools method method. I think you can pick up the familiar method of dependency injection, in which we are injecting the property model into the tools. What I didn't mention before was that the Model was injected in the Agent class using the constructor method, so that's how you can be able to pass your model capabilities into your agent tools.

Calculate the booking price tool

Tools will be located in the app folder as well; however, they are in the Tools folder. Our tool to calculate the room price is as follows.
<?phpnamespace App\Tools;use App\Models\Property;use App\Models\RoomType;use Illuminate\Contracts\JsonSchema\JsonSchema;use Laravel\Ai\Contracts\Tool;use Laravel\Ai\Tools\Request;use Stringable;class CalculateBookingPriceTool implements Tool{    public function __construct(        private readonly Property $property    ) {}    public function description(): Stringable|string    {        return 'Calculate a full price breakdown for a stay at this property. Given a room type name, check-in date, check-out date, and number of rooms, returns nights, price per night, subtotal, tax, and total cost.';    }    public function handle(Request$request): Stringable|string    {        $roomTypeName =$request->string('room_type_name')->toString();        $checkIn      =$request->string('check_in_date')->toString();        $checkOut     =$request->string('check_out_date')->toString();        $rooms        = max(1,$request->integer('number_of_rooms', 1));        $roomType = RoomType::where('property_id',$this->property->id)            ->where('is_active', true)            ->where(function ($q) use ($roomTypeName) {                $q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($roomTypeName) . '%'])                  ->orWhereRaw('LOWER(slug) LIKE ?', ['%' . strtolower($roomTypeName) . '%']);            })            ->first();        if (!$roomType) {            return json_encode(['error' => "Room type '{$roomTypeName}' not found at this property."]);        }        try {$checkInDate  = new \DateTimeImmutable($checkIn);$checkOutDate = new \DateTimeImmutable($checkOut);        } catch (\Throwable) {            return json_encode(['error' => 'Invalid date format. Please use YYYY-MM-DD.']);        }        if ($checkOutDate <= $checkInDate) {            return json_encode(['error' => 'Check-out date must be after check-in date.']);        }$nights      = (int) $checkInDate->diff($checkOutDate)->days;        $pricePerNight = (float)$roomType->price_per_night;        $taxRate      = (float) ($roomType->tax_rate ?? 0);        $subtotal     =$pricePerNight * $nights *$rooms;        $taxAmount    = round($subtotal * ($taxRate / 100), 2);$total        = round($subtotal +$taxAmount, 2);
return json_encode([ 'property' => $this->property->name, 'room_type' =>$roomType->name, 'room_type_slug' => $roomType->slug, 'check_in_date' =>$checkIn, 'check_out_date' => $checkOut, 'nights' =>$nights, 'rooms' => $rooms, 'price_per_night'=>$pricePerNight, 'tax_rate_pct' => $taxRate, 'subtotal' =>$subtotal, 'tax_amount' => $taxAmount, 'total' =>$total, 'currency' => $this->property->currency ?? 'ZAR', ]); }
public function schema(JsonSchema$schema): array { return [ 'room_type_name' => $schema->string() ->description('The name or partial name of the room type to price') ->required(), 'check_in_date' =>$schema->string() ->description('Check-in date in YYYY-MM-DD format') ->required(), 'check_out_date' => $schema->string() ->description('Check-out date in YYYY-MM-DD format') ->required(), 'number_of_rooms' =>$schema->integer() ->description('Number of rooms to book (defaults to 1)'), ]; }}
The above code is just filled with most of Laravel's built-in functionalities, which reveals to you the idea of tooling, that it is not strictly defined, you can make anything an AI Agent tool, such as scripts, command prompts, etc., your imagination and your expertise are the limit when building Agent tools.

Conclusion

We think the current trend of building Agentic Web Applications is going to persist, and those who understand the foundational power of Laravel are going to thrive in building more powerful functional Agentic Web Apps that enhance users' experience. We are still exploring the idea of integrating custom UI packages for Laravel into building generative User interfaces, which would be more beneficial for the system's users and will enhance users' experience.

Share This Article

Get new tutorials in your inbox

No spam. Unsubscribe any time.

Also follow us on Google Search

Add as a Preferred Source on Google

Comments

0

Please log in or register to post a comment.

No comments yet — be the first to comment.

Keep Learning

More Articles
Await You

Browse the full collection of tutorials, guides and deep-dives — all free, all practical.