symfony / ai-demo
Symfony AI Demo Application
Requires
- php: >=8.4
- ext-ctype: *
- ext-gd: *
- ext-iconv: *
- doctrine/doctrine-bundle: ^3.2
- doctrine/doctrine-migrations-bundle: ^3.4
- doctrine/orm: ^3.4
- league/commonmark: ^2.7.1
- mrmysql/youtube-transcript: ^0.0.5
- nyholm/psr7: ^1.8
- php-http/discovery: ^1.20
- symfony/ai-agent: ^1.0
- symfony/ai-bundle: ^1.0
- symfony/ai-cache-message-store: ^1.0
- symfony/ai-clock-tool: ^1.0
- symfony/ai-doctrine-store: ^1.0
- symfony/ai-hugging-face-platform: ^1.0
- symfony/ai-mcp-tool: ^1.0
- symfony/ai-mistral-platform: ^1.0
- symfony/ai-open-ai-platform: ^1.0
- symfony/ai-postgres-store: ^1.0
- symfony/ai-session-message-store: ^1.0
- symfony/ai-similarity-search-tool: ^1.0
- symfony/ai-store: ^1.0
- symfony/ai-wikipedia-tool: ^1.0
- symfony/asset: ^8.1
- symfony/asset-mapper: ^8.1
- symfony/config: ^8.1
- symfony/console: ^8.1
- symfony/doctrine-messenger: ^8.1
- symfony/dotenv: ^8.1
- symfony/flex: ^2.10
- symfony/form: ^8.1
- symfony/framework-bundle: ^8.1
- symfony/http-client: ^8.1
- symfony/mailer: ^8.1
- symfony/mcp-bundle: ^1.0
- symfony/mercure-bundle: ^0.6.1
- symfony/messenger: ^8.1
- symfony/mime: ^8.1
- symfony/monolog-bundle: ^4.0
- symfony/runtime: ^8.1
- symfony/translation: ^8.1
- symfony/twig-bundle: ^8.1
- symfony/uid: ^8.1
- symfony/ux-dropzone: ^3.0
- symfony/ux-icons: ^3.0
- symfony/ux-live-component: ^3.0
- symfony/ux-turbo: ^3.0
- symfony/yaml: ^8.1
- twig/extra-bundle: ^3.22.1
- twig/markdown-extra: ^3.22
- twig/twig: ^3.22
Requires (Dev)
- dbrekelmans/bdi: ^1.4
- doctrine/doctrine-fixtures-bundle: ^4.1
- phpstan/phpstan: ^2.1
- phpstan/phpstan-doctrine: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^12.1
- symfony/ai-mate: ^1.0
- symfony/ai-monolog-mate-extension: ^1.0
- symfony/ai-open-responses-platform: ^1.0
- symfony/ai-symfony-mate-extension: ^1.0
- symfony/browser-kit: ^8.1
- symfony/css-selector: ^8.1
- symfony/debug-bundle: ^8.1
- symfony/panther: ^2.4
- symfony/stopwatch: ^8.1
- symfony/web-profiler-bundle: ^8.1
Suggests
None
Provides
None
Conflicts
README
Symfony application demoing Symfony AI components.
Examples
Requirements
What you need to run this demo:
- Internet Connection
- Terminal & Browser
- Git & GitHub Account
- Docker with Docker Compose Plugin
- Your Favorite IDE or Editor
- An OpenAI API Key
- Node.js - only for the MCP example: one of its three servers speaks the
legacy HTTP+SSE transport and is reached through
npx mcp-remote
Technology
This small demo sits on top of following technologies:
- PHP >= 8.4
- Symfony 8.1 incl. Twig, Asset Mapper & UX
- Bootstrap 5
- OpenAI's GPT & Embeddings
- PostgreSQL with pgvector
- Symfony Messenger & Mercure
- FrankenPHP
Setup
The setup is split into three parts, the Symfony application, the OpenAI configuration, and initializing PostgreSQL.
1. Symfony App
Checkout the repository, start the docker environment and install dependencies:
git clone git@github.com:symfony/ai-demo.git
cd ai-demo
composer install
docker compose up -d
symfony serve -d
Now you should be able to open https://localhost:8000/ in your browser, and the chatbot UI should be available for you to start chatting.
Docker also starts a Mercure hub, and symfony serve starts the Messenger worker configured in
.symfony.local.yaml - the Wikipedia bot researches in that worker and pushes its progress to the
browser via the hub. Without the Symfony CLI, run bin/console messenger:consume async yourself.
The updates are public, so every subscriber of the hub receives them - fine for a local demo, but in
production, publish them as private updates.
Note
You might have to bypass the security warning of your browser with regard to self-signed certificates.
2. OpenAI Configuration
For using GPT and embedding models from OpenAI, you need to configure an OpenAI API key as environment variable.
This requires you to have an OpenAI account, create a valid API key and set it as OPENAI_API_KEY in .env.local file.
echo "OPENAI_API_KEY='sk-...'" > .env.local
Verify the success of this step by running the following command:
symfony console debug:dotenv
You should be able to see the OPENAI_API_KEY in the list of environment variables.
3. PostgreSQL Vector Store Initialization
PostgreSQL with pgvector is used to store embeddings of the chatbot's context.
To initialize the vector store, you need to run the following command:
symfony console ai:store:setup blog symfony console ai:store:index blog -vv
Now you should be able to retrieve documents from the store:
symfony console ai:store:retrieve blog "Week of Symfony"
The movie chat keeps its movies in a Doctrine entity, and its embedding in a vector column of the
same table. Create the table and load the movies from the Markdown files in fixtures/movies/.
The embedding listener of the Doctrine store embeds them when the fixtures are flushed:
symfony console doctrine:migrations:migrate
symfony console doctrine:fixtures:load
symfony console ai:store:retrieve movies "dreams within dreams"
To embed all movies again, for example after changing the embedding model, run
symfony console ai:store:index movies.
Don't forget to set up the project in your favorite IDE or editor.
Testing
vendor/bin/phpunit # unit and integration tests vendor/bin/phpunit --testsuite e2e # end-to-end tests in a real browser
End-to-End Tests
The e2e suite uses Symfony Panther to click through all eleven
use cases and assert the Symfony AI panel of the profiler for the very request the click triggered.
Every test calls an AI platform for real, which costs money and takes time - the suite is therefore
excluded from the default one, and meant to be run locally.
Next to the setup above, it needs:
- Chrome or Chromium with a matching
chromedriver, whichvendor/bin/bdi detect driversdownloads intodrivers/. If only a Snap or Flatpak Chromium is installed, point Panther at it withPANTHER_CHROME_BINARYin.env.test.local. - API keys in
.env.local, or exported in your environment - a test is skipped when the key of its use case is missing:OPENAI_API_KEYfor nine of them,HUGGINGFACE_API_KEYfor the image cropping,MISTRAL_API_KEYfor the document OCR. - ffmpeg (optional) to convert the audio fixture for the fake microphone of the speech use case.
- The Mercure hub of the Docker environment for the Wikipedia use case -
WikipediaTeststarts its own Messenger worker, since Panther's web server does not.
The blog store does not need to be indexed beforehand: StoreTest drives the indexing pipeline
through the console commands, and BlogTest sets the store up and indexes it when it is empty.
MoviesTest loads the movie fixtures when the table is empty. All of them skip themselves when the
database is not running.
Panther boots the application in the dev environment, because the profiler - and with it the
Symfony AI panel - only collects data with kernel.debug enabled. The web server therefore reads
the real API keys from .env.local itself. Chrome fakes camera and microphone, so the video and
speech use cases run without a human in front of the screen.
vendor/bin/phpunit --testsuite e2e --filter BlogTest # a single use case PANTHER_NO_HEADLESS=1 vendor/bin/phpunit --testsuite e2e # watch the browser
Screenshots of failing tests are written to var/error-screenshots/.
Functionality
- The chatbot application is a simple and small Symfony 8.1 application.
- The UI is coupled to a Twig LiveComponent, that integrates different
Chatimplementations on top of the user's session. - The answer of an agent reaches the browser in one of three ways:
- HTTP response - most chats call the agent in the live component's request and render its answer.
- Server-sent events - the Turbo Stream and the recipe bot stream the answer in a second request, as Turbo Streams.
- Mercure - the Wikipedia bot hands the question to a Messenger worker, which pushes every step of its research to the browser via a Mercure hub: the model's commentary on what it is about to look up, each tool call, and the answer as it is written.
- You can reset the chat context by hitting the
Reset chatbutton in the top right corner. - You find eleven different usage scenarios in the upper navbar.
MCP
Demo MCP server exposing a current-time tool and a Movies MCP App — an interactive HTML UI (#[AsMcpApp])
that renders the movie collection as a searchable grid in hosts supporting MCP Apps.
To add the server, add the following configuration to your MCP Client's settings, e.g. your IDE:
{
"servers": {
"symfony": {
"command": "php",
"args": [
"/your/full/path/to/bin/console",
"mcp:server"
]
}
}
}
Testing the MCP Server
You can test the MCP server by running the following command to start the MCP client:
symfony console mcp:server
With plain JSON RPC requests
Then, you can initialize the MCP session with the following JSON RPC request:
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "demo-client", "version": "dev" } } }
And, to request the list of available tools:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
With MCP Inspector
For testing, you can also use the MCP Inspector:
npx @modelcontextprotocol/inspector php bin/console mcp:server
Which opens a web UI to interactively test the MCP server.
AI Mate - Development CLI
Symfony AI Mate is a command-line assistant that gives coding
agents Symfony-specific knowledge about this application. There is no server to start: the agent
runs vendor/bin/mate like any other command.
Installation & Setup
This demo is already configured! For new projects you can set up AI Mate as follows:
# Install AI Mate composer require --dev symfony/ai-mate # Initialize configuration vendor/bin/mate init # Discover available tools vendor/bin/mate discover
mate init writes the instructions your agent reads (mate/AGENT_INSTRUCTIONS.md plus a managed
block in AGENTS.md, imported by CLAUDE.md) and installs the skills into .agents/skills/, with
a mirror in .claude/skills/. No client-specific configuration file is involved.
Running Tools
vendor/bin/mate tools:list # what is available vendor/bin/mate tools:inspect symfony-ai-features # parameters and JSON input schema vendor/bin/mate tools:call symfony-ai-features # run it vendor/bin/mate tools:call symfony-profiler-list --limit=1
Custom Capability Example
This demo includes a symfony-ai-features tool (see mate/src/SymfonyAiFeaturesTool.php) that analyzes the project's
AI configuration and reports all available platforms, agents, tools, stores, and packages.
Try it in your coding agent:
"Which Symfony AI features are available in this demo?"
"What AI agents are configured in this project?"
"Show me all the Symfony AI tools and their configuration"
"What is the current PHP version used in this project?"
"Is the php extension intl installed?"
The agent will call symfony-ai-features and the other Mate tools to answer from the project
itself rather than from reading the code.
Creating Custom Tools
Add a class with a public method carrying #[MateTool] under mate/src/, then run
composer dump-autoload and verify with vendor/bin/mate tools:list. See the
AI Mate documentation for detailed guides.
