Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions docs/bundles/ai-bundle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ Advanced Example with Multiple Agents
agent:
rag:
platform: 'ai.platform.azure.gpt_deployment'
structured_output: false # Disables support for "output_structure" option, default is true
track_token_usage: true # Enable tracking of token usage for the agent, default is true
model: 'gpt-4o-mini'
memory: 'You have access to conversation history and user preferences' # Optional: static memory content
Expand Down Expand Up @@ -513,11 +512,6 @@ Configuration
# Fallback agent for unmatched requests (required)
fallback: 'general'

.. important::

The orchestrator agent MUST have ``structured_output: true`` (the default) to work correctly.
The multi-agent system uses structured output to reliably parse agent selection decisions.

Each multi-agent configuration automatically registers a service with the ID pattern ``ai.multi_agent.{name}``.

For the example above, the service ``ai.multi_agent.support`` is registered and can be injected::
Expand Down
76 changes: 0 additions & 76 deletions docs/components/agent.rst
Original file line number Diff line number Diff line change
Expand Up @@ -483,80 +483,6 @@ Code Examples
* `RAG with MongoDB`_
* `RAG with Pinecone`_

Structured Output
-----------------

A typical use-case of LLMs is to classify and extract data from unstructured sources, which is supported by some models
by features like Structured Output or providing a Response Format.

PHP Classes as Output
~~~~~~~~~~~~~~~~~~~~~

Symfony AI supports that use-case by abstracting the hustle of defining and providing schemas to the LLM and converting
the result back to PHP objects.

To achieve this, a specific agent processor needs to be registered::

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor;
use Symfony\AI\Agent\StructuredOutput\ResponseFormatFactory;
use Symfony\AI\Fixtures\StructuredOutput\MathReasoning;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

// Initialize Platform and LLM

$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$processor = new AgentProcessor(new ResponseFormatFactory(), $serializer);
$agent = new Agent($platform, $model, [$processor], [$processor]);

$messages = new MessageBag(
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
Message::ofUser('how can I solve 8x + 7 = -23'),
);
$result = $agent->call($messages, ['output_structure' => MathReasoning::class]);

dump($result->getContent()); // returns an instance of `MathReasoning` class

Array Structures as Output
~~~~~~~~~~~~~~~~~~~~~~~~~~

Also PHP array structures as response_format are supported, which also requires the agent processor mentioned above::

use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;

// Initialize Platform, LLM and agent with processors and Clock tool

$messages = new MessageBag(Message::ofUser('What date and time is it?'));
$result = $agent->call($messages, ['response_format' => [
'type' => 'json_schema',
'json_schema' => [
'name' => 'clock',
'strict' => true,
'schema' => [
'type' => 'object',
'properties' => [
'date' => ['type' => 'string', 'description' => 'The current date in the format YYYY-MM-DD.'],
'time' => ['type' => 'string', 'description' => 'The current time in the format HH:MM:SS.'],
],
'required' => ['date', 'time'],
'additionalProperties' => false,
],
],
]]);

dump($result->getContent()); // returns an array

Code Examples
~~~~~~~~~~~~~

* `Structured Output with PHP class`_
* `Structured Output with array`_

Input & Output Processing
-------------------------

Expand Down Expand Up @@ -825,7 +751,5 @@ Code Examples
.. _`Store Component`: https://github.com/symfony/ai-store
.. _`RAG with MongoDB`: https://github.com/symfony/ai/blob/main/examples/rag/mongodb.php
.. _`RAG with Pinecone`: https://github.com/symfony/ai/blob/main/examples/rag/pinecone.php
.. _`Structured Output with PHP class`: https://github.com/symfony/ai/blob/main/examples/openai/structured-output-math.php
.. _`Structured Output with array`: https://github.com/symfony/ai/blob/main/examples/openai/structured-output-clock.php
.. _`Chat with static memory`: https://github.com/symfony/ai/blob/main/examples/memory/static.php
.. _`Chat with embedding search memory`: https://github.com/symfony/ai/blob/main/examples/memory/mariadb.php
72 changes: 72 additions & 0 deletions docs/components/platform.rst
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,76 @@ Code Examples
* `Embeddings with Voyage`_
* `Embeddings with Mistral`_

Structured Output
-----------------

A typical use-case of LLMs is to classify and extract data from unstructured sources, which is supported by some models
by features like Structured Output or providing a Response Format.

PHP Classes as Output
~~~~~~~~~~~~~~~~~~~~~

Symfony AI supports that use-case by abstracting the hustle of defining and providing schemas to the LLM and converting
the result back to PHP objects.

To achieve this, the ``Symfony\AI\Platform\StructuredOutput\PlatformSubscriber`` needs to be registered with the platform::

use Symfony\AI\Fixtures\StructuredOutput\MathReasoning;
use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\EventDispatcher\EventDispatcher;

$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());

$platform = PlatformFactory::create($apiKey, eventDispatcher: $dispatcher);
$messages = new MessageBag(
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
Message::ofUser('how can I solve 8x + 7 = -23'),
);
$result = $platform->invoke('mistral-small-latest', $messages, ['output_structure' => MathReasoning::class]);

dump($result->asObject()); // returns an instance of `MathReasoning` class

Array Structures as Output
~~~~~~~~~~~~~~~~~~~~~~~~~~

Also PHP array structures as response_format are supported, which also requires the event subscriber mentioned above. On
top this example uses the feature through the agent to leverage tool calling::

use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;

// Initialize Platform, LLM and agent with processors and Clock tool

$messages = new MessageBag(Message::ofUser('What date and time is it?'));
$result = $agent->call($messages, ['response_format' => [
'type' => 'json_schema',
'json_schema' => [
'name' => 'clock',
'strict' => true,
'schema' => [
'type' => 'object',
'properties' => [
'date' => ['type' => 'string', 'description' => 'The current date in the format YYYY-MM-DD.'],
'time' => ['type' => 'string', 'description' => 'The current time in the format HH:MM:SS.'],
],
'required' => ['date', 'time'],
'additionalProperties' => false,
],
],
]]);

dump($result->getContent()); // returns an array

Code Examples
~~~~~~~~~~~~~

* `Structured Output with PHP class`_
* `Structured Output with array`_

Server Tools
------------

Expand Down Expand Up @@ -426,6 +496,8 @@ Code Examples
.. _`Embeddings with OpenAI`: https://github.com/symfony/ai/blob/main/examples/openai/embeddings.php
.. _`Embeddings with Voyage`: https://github.com/symfony/ai/blob/main/examples/voyage/embeddings.php
.. _`Embeddings with Mistral`: https://github.com/symfony/ai/blob/main/examples/mistral/embeddings.php
.. _`Structured Output with PHP class`: https://github.com/symfony/ai/blob/main/examples/openai/structured-output-math.php
.. _`Structured Output with array`: https://github.com/symfony/ai/blob/main/examples/openai/structured-output-clock.php
.. _`Parallel GPT Calls`: https://github.com/symfony/ai/blob/main/examples/misc/parallel-chat-gpt.php
.. _`Parallel Embeddings Calls`: https://github.com/symfony/ai/blob/main/examples/misc/parallel-embeddings.php
.. _`LM Studio`: https://lmstudio.ai/
Expand Down
17 changes: 10 additions & 7 deletions examples/deepseek/structured-output-clock.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,27 @@
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor as StructuredOutputProcessor;
use Symfony\AI\Agent\Toolbox\AgentProcessor as ToolProcessor;
use Symfony\AI\Agent\Toolbox\AgentProcessor;
use Symfony\AI\Agent\Toolbox\Tool\Clock;
use Symfony\AI\Agent\Toolbox\Toolbox;
use Symfony\AI\Platform\Bridge\DeepSeek\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\Clock\Clock as SymfonyClock;
use Symfony\Component\EventDispatcher\EventDispatcher;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('DEEPSEEK_API_KEY'), http_client());
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());

$platform = PlatformFactory::create(env('DEEPSEEK_API_KEY'), http_client(), eventDispatcher: $dispatcher);

$clock = new Clock(new SymfonyClock());
$toolbox = new Toolbox([$clock]);
$toolProcessor = new ToolProcessor($toolbox);
$structuredOutputProcessor = new StructuredOutputProcessor();
$agent = new Agent($platform, 'deepseek-chat', [$toolProcessor, $structuredOutputProcessor], [$toolProcessor, $structuredOutputProcessor]);
$toolbox = new Toolbox([$clock], logger: logger());
$toolProcessor = new AgentProcessor($toolbox);
$agent = new Agent($platform, 'deepseek-chat', [$toolProcessor], [$toolProcessor]);

$messages = new MessageBag(
// for DeepSeek it is *mandatory* to mention JSON anywhere in the prompt when using structured output
Expand Down
15 changes: 9 additions & 6 deletions examples/gemini/structured-output-clock.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,27 @@
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor as StructuredOutputProcessor;
use Symfony\AI\Agent\Toolbox\AgentProcessor as ToolProcessor;
use Symfony\AI\Agent\Toolbox\AgentProcessor;
use Symfony\AI\Agent\Toolbox\Tool\Clock;
use Symfony\AI\Agent\Toolbox\Toolbox;
use Symfony\AI\Platform\Bridge\Gemini\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\Clock\Clock as SymfonyClock;
use Symfony\Component\EventDispatcher\EventDispatcher;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('GEMINI_API_KEY'), http_client());
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());

$platform = PlatformFactory::create(env('GEMINI_API_KEY'), http_client(), eventDispatcher: $dispatcher);

$clock = new Clock(new SymfonyClock());
$toolbox = new Toolbox([$clock], logger: logger());
$toolProcessor = new ToolProcessor($toolbox);
$structuredOutputProcessor = new StructuredOutputProcessor();
$agent = new Agent($platform, 'gemini-2.5-flash', [$toolProcessor, $structuredOutputProcessor], [$toolProcessor, $structuredOutputProcessor]);
$toolProcessor = new AgentProcessor($toolbox);
$agent = new Agent($platform, 'gemini-2.5-flash', [$toolProcessor], [$toolProcessor]);

$messages = new MessageBag(Message::ofUser('What date and time is it?'));
$result = $agent->call($messages, ['response_format' => [
Expand Down
15 changes: 8 additions & 7 deletions examples/gemini/structured-output-math.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,24 @@
* file that was distributed with this source code.
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor;
use Symfony\AI\Fixtures\StructuredOutput\MathReasoning;
use Symfony\AI\Platform\Bridge\Gemini\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\EventDispatcher\EventDispatcher;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('GEMINI_API_KEY'), http_client());
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());

$processor = new AgentProcessor();
$agent = new Agent($platform, 'gemini-2.5-flash', [$processor], [$processor]);
$platform = PlatformFactory::create(env('GEMINI_API_KEY'), http_client(), eventDispatcher: $dispatcher);
$messages = new MessageBag(
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
Message::ofUser('how can I solve 8x + 7 = -23'),
);
$result = $agent->call($messages, ['output_structure' => MathReasoning::class]);

dump($result->getContent());
$result = $platform->invoke('gemini-2.5-flash', $messages, ['output_structure' => MathReasoning::class]);

dump($result->asObject());
20 changes: 7 additions & 13 deletions examples/mistral/structured-output-math.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,23 @@
* file that was distributed with this source code.
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor;
use Symfony\AI\Agent\StructuredOutput\ResponseFormatFactory;
use Symfony\AI\Fixtures\StructuredOutput\MathReasoning;
use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\EventDispatcher\EventDispatcher;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('MISTRAL_API_KEY'), http_client());
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());

$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);

$processor = new AgentProcessor(new ResponseFormatFactory(), $serializer);
$agent = new Agent($platform, 'mistral-small-latest', [$processor], [$processor]);
$platform = PlatformFactory::create(env('MISTRAL_API_KEY'), http_client(), eventDispatcher: $dispatcher);
$messages = new MessageBag(
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
Message::ofUser('how can I solve 8x + 7 = -23'),
);
$result = $agent->call($messages, ['output_structure' => MathReasoning::class]);
$result = $platform->invoke('mistral-small-latest', $messages, ['output_structure' => MathReasoning::class]);

dump($result->getContent());
dump($result->asObject());
13 changes: 6 additions & 7 deletions examples/multi-agent/orchestrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,23 @@
use Symfony\AI\Agent\InputProcessor\SystemPromptInputProcessor;
use Symfony\AI\Agent\MultiAgent\Handoff;
use Symfony\AI\Agent\MultiAgent\MultiAgent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor;
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\EventDispatcher\EventDispatcher;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client());

// Create structured output processor for the orchestrator
$structuredOutputProcessor = new AgentProcessor();
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());
$platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client(), eventDispatcher: $dispatcher);

// Create orchestrator agent for routing decisions
$orchestrator = new Agent(
$platform,
'gpt-4o-mini',
[new SystemPromptInputProcessor('You are an intelligent agent orchestrator that routes user questions to specialized agents.'), $structuredOutputProcessor],
[$structuredOutputProcessor],
[new SystemPromptInputProcessor('You are an intelligent agent orchestrator that routes user questions to specialized agents.')],
);

// Create technical agent for handling technical issues
Expand Down
14 changes: 7 additions & 7 deletions examples/ollama/structured-output-math.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@
* file that was distributed with this source code.
*/

use Symfony\AI\Agent\Agent;
use Symfony\AI\Agent\StructuredOutput\AgentProcessor;
use Symfony\AI\Fixtures\StructuredOutput\MathReasoning;
use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory;
use Symfony\AI\Platform\Message\Message;
use Symfony\AI\Platform\Message\MessageBag;
use Symfony\AI\Platform\StructuredOutput\PlatformSubscriber;
use Symfony\Component\EventDispatcher\EventDispatcher;

require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), http_client());
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new PlatformSubscriber());

$processor = new AgentProcessor();
$agent = new Agent($platform, env('OLLAMA_LLM'), [$processor], [$processor]);
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), http_client(), eventDispatcher: $dispatcher);
$messages = new MessageBag(
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
Message::ofUser('how can I solve 8x + 7 = -23'),
);
$result = $agent->call($messages, ['output_structure' => MathReasoning::class]);
$result = $platform->invoke(env('OLLAMA_LLM'), $messages, ['output_structure' => MathReasoning::class]);

dump($result->getContent());
dump($result->asObject());
Loading