symfony/ai-agent
Experimental Symfony AI Agent component for building AI agents on top of the Platform and Store components. Create agents that interact with users, perform tasks, and orchestrate workflows, with optional tool bridges (search, scraping, maps, weather, files).
## Getting Started
### Minimal Setup
1. **Install Core Packages**:
```bash
composer require symfony/ai-agent symfony/ai-platform
Create a Basic Agent:
use Symfony\Component\Ai\Agent\Agent;
use Symfony\Component\Ai\Agent\Input;
use Symfony\Component\Ai\Agent\Output;
$agent = new Agent(
new Input('What is Laravel?'),
new \Symfony\Component\Ai\Platform\OpenAiPlatform('your-api-key')
);
$output = $agent->run();
echo $output->getContent();
First Use Case: Chatbot with Wikipedia Tool
composer require symfony/ai-wikipedia-tool
use Symfony\Component\Ai\Tool\WikipediaTool;
$agent = new Agent(
new Input('Explain Symfony AI in simple terms'),
new \Symfony\Component\Ai\Platform\OpenAiPlatform('api-key'),
new \Symfony\Component\Ai\Toolbox\Toolbox([new WikipediaTool()])
);
src/Agent.php: Entry point for agent creation.src/Toolbox/: Tool integration patterns.tests/: Real-world usage examples (e.g., AgentTest.php, MultiAgentTest.php).$agent->addInputProcessor(new \Symfony\Component\Ai\Agent\InputProcessor\SystemPromptInputProcessor('You are a helpful assistant.'));
$toolbox = new \Symfony\Component\Ai\Toolbox\Toolbox([
new \Symfony\Component\Ai\Tool\BraveSearchTool('your-api-key'),
new \Symfony\Component\Ai\Tool\FilesystemTool('/tmp'),
]);
$agent->setToolbox($toolbox);
$memory = new \Symfony\Component\Ai\Memory\StaticMemoryProvider();
$agent->setMemory($memory);
$output = $agent->run();
$output->getContent(); // Final response
$output->getToolCalls(); // Logged tool invocations
Service Provider Integration:
// app/Providers/AiServiceProvider.php
public function register()
{
$this->app->singleton(Agent::class, function ($app) {
return new Agent(
new Input(''),
new \Symfony\Component\Ai\Platform\OpenAiPlatform(config('services.openai.key')),
new \Symfony\Component\Ai\Toolbox\Toolbox([
new \Symfony\Component\Ai\Tool\SerpApiTool(config('services.serpapi.key')),
])
);
});
}
Tool Bridge Registration:
// app/Providers/AiServiceProvider.php
public function boot()
{
$this->app->bind(
\Symfony\Component\Ai\Tool\ClockTool::class,
fn() => new \Symfony\Component\Ai\Tool\ClockTool()
);
}
Event-Driven Tool Calls (Laravel Events):
// Listen to tool call events
event(new \Symfony\Component\Ai\Event\ToolCallRequested(
$toolCall,
$agent
));
Async Processing with Queues:
// Dispatch agent job
dispatch(new RunAgentJob($input, $agent));
use Symfony\Component\Ai\MultiAgent\MultiAgent;
$researchAgent = new Agent(/* ... */);
$responseAgent = new Agent(/* ... */);
$multiAgent = new MultiAgent([$researchAgent, $responseAgent]);
$output = $multiAgent->run(new Input('Research and summarize Symfony AI'));
$memory = new \Symfony\Component\Ai\Memory\StaticMemoryProvider();
$agent->setMemory($memory);
$store = new \Symfony\Component\Ai\Store\PostgresStore(
new \Doctrine\DBAL\Connection($connectionParams)
);
$memory = new \Symfony\Component\Ai\Memory\EmbeddingProvider($store);
$agent->setMemory($memory);
Tool Call Validation Failures:
symfony/validator for argument validation:
use Symfony\Component\Validator\Constraints as Assert;
#[Tool]
public function search(string #[Assert\NotBlank] $query): string { ... }
Memory Leaks:
EmbeddingProvider with TTL or clear memory manually:
$memory->clear();
Tool Dispatch Conflicts:
$toolbox->addTool(new \App\Tool\CustomBraveSearchTool(), 'custom_brave');
Streaming Quirks:
DeltaInterface for chunked responses:
$output->stream(function (DeltaInterface $delta) {
echo $delta->getContent();
});
Symfony Dependency Conflicts:
symfony/clock or symfony/http-client may conflict with Laravel.$this->app->bind(\Symfony\Component\Clock\ClockInterface::class, function () {
return \Illuminate\Support\Facades\Clock::getFacadeRoot();
});
Enable Verbose Logging:
$agent->setLogger(new \Monolog\Logger('ai_agent', [
new \Monolog\Handler\StreamHandler('storage/logs/ai.log', Monolog\Logger::DEBUG),
]));
Inspect Tool Calls:
$output = $agent->run();
foreach ($output->getToolCalls() as $call) {
dump($call->getName(), $call->getArguments());
}
Test with Mock Platform:
use Symfony\Component\Ai\Platform\MockPlatform;
$agent = new Agent(
new Input('Test'),
new MockPlatform()
);
Custom Input/Output Processors:
class UppercaseOutputProcessor implements OutputProcessorInterface {
public function __invoke(Output $output): Output {
$output->setContent(strtoupper($output->getContent()));
return $output;
}
}
$agent->addOutputProcessor(new UppercaseOutputProcessor());
Dynamic Tool Registration:
$toolbox->addToolsFromDirectory(__DIR__.'/Tools');
Override JSON Schema Generation:
use Symfony\Component\Ai\Tool\Attribute\Tool;
#[Tool(
schema: [
'properties' => [
'query' => ['type' => 'string', 'description' => 'Custom search query']
]
]
)]
public function customSearch(string $query) { ... }
Cache Tool Responses:
$toolbox->addTool(new \App\Tool\CachedSerpApiTool(
new \Symfony\Component\Ai\Tool\SerpApiTool('key'),
new \Illuminate\Cache\Repository
));
Batch Tool Calls:
$agent->setToolbox(new \Symfony\Component\Ai\Toolbox\Toolbox([
new \App\Tool\BatchWebScraperTool(),
]));
Async Tool Execution:
$toolbox->addTool(new \App\Tool\AsyncClockTool(
new \Symfony\Component\Ai\Tool\ClockTool()
));
Blade Integration:
OutputProcessor to render responses:
$agent->addOutputProcessor(function (Output $output) {
return new Output(view('ai.response', ['content' => $output->getContent()])->render());
});
Nova Tool Integration:
public function tools(Nova $nova)
{
Nova::
How can I help you explore Laravel packages today?