LarAgent: An Open-source package to Build & Manage AI Agents in Laravel
Photo by Sumaid pal Singh Bakshi on Unsplash
Laravel has all the right ingredients to become a strong candidate for AI development. With its elegant architecture and built-in components, it has huge potential to become a go-to framework for AI-driven applications.
There are existing PHP packages like LLPhant and Prism that already simplify interactions with large language models (LLMs). However, Laravel still lacks a tool for building and managing AI agents. That’s where LarAgent comes in. Inspired by LangChain - a widely used framework for building AI agents in Python - I’m Revaz Ghambarashvili, Lead Developer at Redberry. I created a Laravel-native solution that brings the same flexibility and ease of use to PHP developers. LarAgent is designed to simplify the process of creating, managing, and extending AI agents while staying true to Laravel’s fluent API design.
Under the hood, LarAgent uses the OpenAI PHP package by Nuno Maduro and Sandro Gehri, which simplifies communication between your application and LLM’s API.
In this article, I’ll walk you through all of LarAgent’s key features and how they make AI agent development in Laravel more intuitive than ever.
Standout Features of LarAgent
Eloquent-like syntax for creating and managing AI agents
The first standout feature of LarAgent is that the process of creating AI agents is just like creating any other Eloquent model.
php artisan make:agent MyAgent
LarAgent brings the same smooth syntax and class structure that Laravel developers are familiar with. Its low learning curve and user-friendly design make it easy to get started. The process of creating and managing AI agents feels natural, just like working with Laravel’s artisan commands. You’ll feel right at home with LarAgent’s familiar structure; in fact, that’s what makes AI agent development extremely intuitive with this package.
// app/AiAgents/MyAgent.php
class MyAgent extends Agent
{
protected $model = 'gpt-4';
protected $history = 'in_memory';
protected $provider = 'default';
protected $tools = [];
public function instructions()
{
return "Define your agent's instructions here.";
}
public function prompt($message)
{
return $message;
}
}
Structured Output Handling
Structured output allows you to define the exact format of the agent's response using JSON Schema. Schema has to be defined in the OpenAPI standard.
The main purpose is to get a predictable, structured response from LLM with the pre-defined schema that can be used in your application logic.
In the case of LarAgent, you just need to add the protected $responseSchema
property, and your agent will automatically handle returned JSON from LLM, so that the responses from the respond
method will be array adhering to your specified schema instead of strings.
protected $responseSchema = [
'name' => 'weather_info',
'schema' => [
'type' => 'object',
'properties' => [
'temperature' => [
'type' => 'number',
'description' => 'Temperature in degrees'
],
],
'required' => ['temperature'],
'additionalProperties' => false,
],
'strict' => true,
];
For defining more complex schemas you can add the public function structuredOutput()
method to your agent class, build it up with custom logic, and return an array of the schema.
Multiple built-in chat history storage options
Chat history is essential for maintaining context in AI conversations. It accumulates every interaction the user has with the agent, so each new message needs to be sent along with the entire conversation history to preserve context.
LarAgent simplifies this process by offering several built-in chat history storage options, while also allowing you to implement your own custom storage solutions. Whether you prefer cache storage or a different method, LarAgent gives you flexibility in how chat history is managed, ensuring your AI agents maintain context across sessions.
- in_memory
- Session
- Cache
- File
- JSON
The “in_memory” and “JSON” chat histories will work even if you use LarAgent outside of Laravel framework.
Easily extendable, including chat histories and LLM drivers
The structure of this package allows you to add a new element (for example, a new chat history) quickly and easily. Each element has its abstraction, which can be extended by adding a couple of methods. For example, to make a new type of chat history, you will need to extend the LarAgent\Core\Abstractions\ChatHistory
class and implement these methods:
- readFromMemory
- writeToMemory
- saveKeyToMemory:
- loadKeysFromMemory
- removeChatFromMemory
- removeChatKey
As an example, you can check the ”LarAgent\History\InMemoryChatHistory” which is a minimalistic implementation of this feature and makes it easy to understand each needed method.
Custom tool creation with attribute-based configuration
Tools are essential for extending the capabilities of AI agents. They help the agent decide the best way to respond based on user input. For instance, if you ask an agent about the current weather, it might use several tools in parallel: one to identify your location, another to fetch the weather data for that location, and a third to let you choose the unit for the temperature (Celsius or Fahrenheit). This process, called parallel tool execution, allows the agent to run multiple tools at the same time while responding to a single user query, providing a more accurate and efficient response. LarAgent makes it easy to create custom tools with attribute-based configuration, giving you full control over how your agent uses and manages these tools. Users have different versions of creating the tools - Standalone classes, Tool facade, and Tool attributes. Creating tool classes is a recommended way of using tools since they give the highest level of control and reusability.
class WeatherTool extends LarAgent\Tool
{
protected string $name = 'get_current_weather';
protected string $description = 'Get the current weather in a given location';
protected array $properties = [
'location' => [
'type' => 'string',
'description' => 'The city and state, e.g. San Francisco, CA',
],
'unit' => [
'type' => 'string',
'description' => 'The unit of temperature',
'enum' => ['celsius', 'fahrenheit'],
],
];
protected array $required = ['location'];
public function execute(array $input): mixed
{
// Call the weather API
return 'The weather in '.$input['location'].' is '.rand(10, 60).' degrees '.$input['unit'];
}
}
Can be registered via your agent's property:
protected $tools = [
WeatherTool::class,
LocationTool::class
];
Another way is to add the registerTools
method and return an array of tools created via the LarAgent\Tool
class. This is the simplest way of adding new tools. While setCallback
allows any callable type in PHP, according to experience this is ideal for the creation of small, simple tools:
use LarAgent\Tool;
// ...
public function registerTools()
{
$user = auth()->user();
return [
Tool::create("user_location", "Returns user's current location")
->setCallback(function () use ($user) {
return $user->location()->city;
}),
];
}
And yet another, but my favorite way of adding tools is a Tool attribute, which automatically builds names, property types and enums, you only need to specify the descriptions and any method of your agent class will become a tool:
Use LarAgent\Attributes\Tool;
class WeatherAgent extends LarAgent\Agent {
// …
// Example of a tool defined as a method with optional and required parameters
#[Tool('Get the current weather in a given location')]
public function weatherTool($location, $unit = 'celsius') {
return WeatherService::get($location)->withUnit($unit);
}
}
The best part is that you can use all three ways of adding tools in one agent simultaneously.
Extensive Event system
Often, packages doing the heavy lifting for you are struggling when a project needs to implement a really custom solution and tweak some deeply nested processes. LarAgent provides a comprehensive event system to address this issue that allows you to hook into almost any stage of the agent's lifecycle and conversation flow.
You can add hook methods to your agent’s class, which provide some inner context and are called at appropriate places. Here are several methods you can use:
onInitialize()
onConversationStart()
onConversationEnd($message)
onToolChange($tool, $added = true)
beforeSaveHistory($history)
beforeResponse($history, $message)
afterResponse($message)
afterToolExecution($tool, &$result)
For more events and examples, please refer to the documentation’s Events section.
Hope this article gave you a clear look at the LarAgent package and how it can simplify AI agent development in Laravel. Can’t wait to see it in action in your projects.
driesvints liked this article
Other articles you might like
Covariance and Contravariance in PHP
Introduction "Covariance" and "contravariance" are two terms I didn't know exist...
Human-Readable File Sizes in Laravel (KB, MB, GB)
Introduction There may be times when you want to display file sizes to your users in a human-readabl...
Formatting and Spelling Ordinal Numbers in PHP and Laravel
Introduction There may be times when you want to convert numbers to ordinal numbers in your PHP and...
The Laravel portal for problem solving, knowledge sharing and community building.
The community