Laravel AI Agents: Tool-Calling &amp; Conversation Persistence | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Laravel AI SDK: Tool-Calling Agents and Conversation Persistence        On this page       1. [  Building Tool-Calling Agents in Laravel with Prism ](#building-tool-calling-agents-in-laravel-with-prism)
2. [  Defining a Tool ](#defining-a-tool)
3. [  Running a Multi-Turn Agent Loop ](#running-a-multi-turn-agent-loop)
4. [  Persisting Conversation History ](#persisting-conversation-history)
5. [  Authorising Tool Execution ](#authorising-tool-execution)
6. [  Key Takeaways ](#key-takeaways)

  ![Laravel AI SDK: Tool-Calling Agents and Conversation Persistence](https://cdn.msaied.com/260/8c84f424e42da01993c9ba4b8eb19655.png)

  #laravel   #ai   #agents   #prism   #llm  

 Laravel AI SDK: Tool-Calling Agents and Conversation Persistence 
==================================================================

     21 Jun 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Building Tool-Calling Agents in Laravel with Prism  ](#building-tool-calling-agents-in-laravel-with-prism)
2. [  02   Defining a Tool  ](#defining-a-tool)
3. [  03   Running a Multi-Turn Agent Loop  ](#running-a-multi-turn-agent-loop)
4. [  04   Persisting Conversation History  ](#persisting-conversation-history)
5. [  05   Authorising Tool Execution  ](#authorising-tool-execution)
6. [  06   Key Takeaways  ](#key-takeaways)

 Building Tool-Calling Agents in Laravel with Prism
--------------------------------------------------

Large language models become genuinely useful when they can *act* — querying a database, calling an API, or reading a file — rather than just generating text. The [Prism](https://prismphp.com) package gives Laravel developers a clean, driver-agnostic interface for exactly this. This article focuses on two hard problems: **wiring tools safely** and **persisting conversation state between HTTP requests** without leaking memory or context.

---

### Defining a Tool

Prism tools are plain PHP objects that declare their schema and a handler closure. Keep them thin — delegate real work to your existing service layer.

```php
use EchoLabs\Prism\Tool;

$orderLookup = Tool::as('get_order')
    ->for('Fetch an order by its ID')
    ->withStringParameter('order_id', 'The UUID of the order')
    ->using(function (string $order_id): string {
        $order = Order::findOrFail($order_id);
        return json_encode([
            'status'  => $order->status,
            'total'   => $order->total_cents,
            'shipped' => $order->shipped_at?->toIso8601String(),
        ]);
    });

```

The `using` closure **must return a string** — that string is injected back into the model's context as the tool result. Returning structured JSON is idiomatic.

---

### Running a Multi-Turn Agent Loop

A single `generate()` call is not enough for agents. You need an agentic loop that keeps running until the model stops requesting tools.

```php
use EchoLabs\Prism\Prism;
use EchoLabs\Prism\Enums\Provider;
use EchoLabs\Prism\ValueObjects\Messages\UserMessage;

$messages = [
    new UserMessage('What is the status of order 550e8400-e29b-41d4-a716-446655440000?'),
];

$response = Prism::text()
    ->using(Provider::OpenAI, 'gpt-4o')
    ->withMessages($messages)
    ->withTools([$orderLookup])
    ->withMaxSteps(5)   // hard cap — never let the loop run unbounded
    ->generate();

echo $response->text;

```

`withMaxSteps` is your circuit breaker. Without it, a confused model can spin indefinitely, burning tokens and time.

---

### Persisting Conversation History

HTTP is stateless; agents are not. The naive approach — storing the full message array in the session — breaks under load and leaks data across users. A better pattern: persist messages to a `conversations` table and rehydrate on each request.

```php
// Migration
Schema::create('conversation_messages', function (Blueprint $table) {
    $table->id();
    $table->ulid('conversation_id')->index();
    $table->string('role');          // user | assistant | tool
    $table->longText('content');
    $table->json('tool_calls')->nullable();
    $table->timestamps();
});

```

```php
// Rehydrating messages for Prism
use EchoLabs\Prism\ValueObjects\Messages\AssistantMessage;
use EchoLabs\Prism\ValueObjects\Messages\UserMessage;

$stored = ConversationMessage::where('conversation_id', $id)
    ->orderBy('id')
    ->get();

$messages = $stored->map(fn ($row) => match ($row->role) {
    'user'      => new UserMessage($row->content),
    'assistant' => new AssistantMessage($row->content),
    default     => null,
})->filter()->values()->all();

```

After each agent run, persist the new messages returned in `$response->messages` back to the table. This keeps your PHP process stateless while the conversation lives safely in Postgres.

---

### Authorising Tool Execution

Tools run server-side with your application's full privileges. Always scope them to the authenticated user:

```php
->using(function (string $order_id) use ($user): string {
    $order = Order::where('user_id', $user->id)
        ->findOrFail($order_id); // 404 if not owned
    // ...
})

```

Never trust the model to enforce ownership — it will not.

---

### Key Takeaways

- **Tools return strings.** Encode complex data as JSON; the model reads it as context.
- **Always set `withMaxSteps`.** Unbounded agentic loops are a production incident waiting to happen.
- **Persist messages in the database**, not the session. Rehydrate per request for true statelessness.
- **Authorise inside the tool closure**, not outside it. The model controls which tool is called; you control what it can see.
- **Keep tools thin.** Delegate to services so tools remain testable in isolation without mocking the LLM.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-ai-sdk-tool-calling-agents-and-conversation-persistence&text=Laravel+AI+SDK%3A+Tool-Calling+Agents+and+Conversation+Persistence) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-ai-sdk-tool-calling-agents-and-conversation-persistence) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Can I use providers other than OpenAI with Prism tool-calling?        Yes. Prism supports Anthropic, Gemini, Ollama, and others via its driver system. Tool-calling availability depends on the underlying model's capabilities — check the provider's documentation for function-calling support before switching drivers. 

      Q02  How do I test a tool-calling agent without hitting the real API?        Prism ships with a fake driver you can bind in tests. Use `Prism::fake()` to return pre-scripted responses, then assert that your tool closures were invoked with the expected arguments using standard Pest expectations on the side-effects they produce. 

      Q03  What is a safe value for withMaxSteps in production?        It depends on your use case, but 5–10 steps covers the vast majority of real workflows. Set it conservatively, monitor average steps per conversation in your logs, and raise it only when you have evidence a legitimate task requires more. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Laravel Livewire v3 Internals: Morph Markers, JS Hooks, and Alpine Integration](https://cdn.msaied.com/259/e8ce445f021c2b26ebe4dd5da50014f8.png) livewire laravel alpine 

### Laravel Livewire v3 Internals: Morph Markers, JS Hooks, and Alpine Integration

Go beyond the docs: understand how Livewire v3 diffs the DOM with morph markers, intercept the lifecycle with...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 21 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-livewire-v3-internals-morph-markers-js-hooks-and-alpine-integration) [ ![Laravel Package Development: Service Providers, Auto-Discovery, and Config Merging](https://cdn.msaied.com/258/673a80fa8e42ae375a4bba21bdcd92ea.png) laravel packages service-providers 

### Laravel Package Development: Service Providers, Auto-Discovery, and Config Merging

Build a production-ready Laravel package from scratch — covering service provider design, auto-discovery via c...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 21 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-package-development-service-providers-auto-discovery-and-config-merging-1) [ ![Clean Architecture Testing with Pest: Actions, Fakes, and Boundary Contracts](https://cdn.msaied.com/257/eb96b08443e07a2edd8694c0f6f8b524.png) laravel pest clean-architecture 

### Clean Architecture Testing with Pest: Actions, Fakes, and Boundary Contracts

Learn how to test Laravel actions, DTOs, and domain boundaries with Pest using fakes, contract assertions, and...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 21 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/clean-architecture-testing-with-pest-actions-fakes-and-boundary-contracts) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
