Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Orchestrace skupinového chatu modeluje konverzaci mezi několika agenty, která koordinuje orchestrátor, který určuje výběr mluvčího a tok konverzace. Tento model je ideální pro scénáře vyžadující iterativní upřesnění, řešení problémů ve spolupráci nebo analýzu s více perspektivami.
Orchestrace skupinového chatu interně sestavuje agenty do hvězdicové topologie s orchestrátorem uprostřed. Orchestrátor může implementovat různé strategie pro výběr toho, který agent mluví dál, jako je kruhové dotazování, výběr na základě výzvy nebo vlastní logika založená na kontextu konverzace, což z něj dělá flexibilní a výkonný vzor pro spolupráci s více agenty.
Rozdíly mezi skupinovými chaty a jinými vzory
Orchestrace skupinového chatu má odlišné charakteristiky v porovnání s jinými vzory více agentů:
- Centralizovaná koordinace: Na rozdíl od vzorů předávání, kdy agenti přímo přenesou řízení, používá skupinový chat orchestrátor ke koordinaci toho, kdo bude mluvit dál.
- Iterativní upřesnění: Agenti mohou přezkoumávat a zlepšovat odpovědi ostatních v několika kolech.
- Flexibilní výběr mluvčího: Orchestrátor může použít různé strategie (kruhové dotazování, založené na příkazovém řádku, vlastní logika) k výběru mluvčích.
- Sdílený kontext: Všichni agenti vidí celou historii konverzací a umožňují upřesnění spolupráce.
Co se naučíte
- Vytvoření specializovaných agentů pro spolupráci skupin
- Konfigurace strategií výběru mluvčího
- Jak vytvářet pracovní postupy se zdokonalováním agenta iterativním způsobem
- Přizpůsobení toku konverzace pomocí vlastních orchestrátorů
Nastavení klienta Azure OpenAI
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;
using Microsoft.Agents.AI;
// Set up the Azure OpenAI client
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ??
throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
var client = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.GetProjectOpenAIClient()
.GetProjectResponsesClient()
.AsIChatClient(deploymentName);
Warning
DefaultAzureCredential je vhodný pro vývoj, ale vyžaduje pečlivé zvážení v produkčním prostředí. V produkčním prostředí zvažte použití konkrétních přihlašovacích údajů (např ManagedIdentityCredential. ) k zabránění problémům s latencí, neúmyslnému testování přihlašovacích údajů a potenciálním bezpečnostním rizikům z náhradních mechanismů.
Definování agentů
Vytvořte specializované agenty pro různé role v konverzaci skupiny:
// Create a copywriter agent
ChatClientAgent writer = new(client,
"You are a creative copywriter. Generate catchy slogans and marketing copy. Be concise and impactful.",
"CopyWriter",
"A creative copywriter agent");
// Create a reviewer agent
ChatClientAgent reviewer = new(client,
"You are a marketing reviewer. Evaluate slogans for clarity, impact, and brand alignment. " +
"Provide constructive feedback or approval.",
"Reviewer",
"A marketing review agent");
Konfigurace skupinového chatu pomocí nástroje Round-Robin Orchestrator
Vytvoření pracovního postupu skupinového chatu pomocí AgentWorkflowBuilder:
// Build group chat with round-robin speaker selection
// The manager factory receives the list of agents and returns a configured manager
var workflow = AgentWorkflowBuilder
.CreateGroupChatBuilderWith(agents =>
new RoundRobinGroupChatManager(agents)
{
MaximumIterationCount = 5 // Maximum number of turns
})
.AddParticipants(writer, reviewer)
.Build();
Spuštění workflowu skupinového chatu
Spusťte pracovní postup a sledujte iterativní konverzaci:
// Start the group chat
var messages = new List<ChatMessage> {
new(ChatRole.User, "Create a slogan for an eco-friendly electric vehicle.")
};
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
if (evt is AgentResponseUpdateEvent update)
{
// Process streaming agent responses
AgentResponse response = update.AsResponse();
foreach (ChatMessage message in response.Messages)
{
Console.WriteLine($"[{update.ExecutorId}]: {message.Text}");
}
}
else if (evt is WorkflowOutputEvent output)
{
// Workflow completed
var conversationHistory = output.As<List<ChatMessage>>();
Console.WriteLine("\n=== Final Conversation ===");
foreach (var message in conversationHistory)
{
Console.WriteLine($"{message.AuthorName}: {message.Text}");
}
break;
}
}
Ukázková interakce
[CopyWriter]: "Green Dreams, Zero Emissions" - Drive the future with style and sustainability.
[Reviewer]: The slogan is good, but "Green Dreams" might be a bit abstract. Consider something
more direct like "Pure Power, Zero Impact" to emphasize both performance and environmental benefit.
[CopyWriter]: "Pure Power, Zero Impact" - Experience electric excellence without compromise.
[Reviewer]: Excellent! This slogan is clear, impactful, and directly communicates the key benefits.
The tagline reinforces the message perfectly. Approved for use.
[CopyWriter]: Thank you! The final slogan is: "Pure Power, Zero Impact" - Experience electric
excellence without compromise.
Nastavení chatovacího klienta
import os
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
# Initialize the Azure OpenAI client
client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
)
Definování agentů
Vytváření specializovaných agentů s odlišnými rolemi:
from agent_framework import Agent
# Create a researcher agent
researcher = Agent(
client=client,
name="Researcher",
description="Collects relevant background information.",
instructions="Gather concise facts that help answer the question. Be brief and factual.",
)
# Create a writer agent
writer = Agent(
client=client,
name="Writer",
description="Synthesizes polished answers using gathered information.",
instructions="Compose clear, structured answers using any notes provided. Be comprehensive.",
)
Konfigurace skupinového chatu pomocí jednoduchého selektoru
Vytvoření skupinového chatu s vlastní logikou výběru mluvčího:
from agent_framework.orchestrations import GroupChatBuilder, GroupChatState
def round_robin_selector(state: GroupChatState) -> str:
"""A round-robin selector function that picks the next speaker based on the current round index."""
participant_names = list(state.participants.keys())
return participant_names[state.current_round % len(participant_names)]
# Build the group chat workflow
workflow = GroupChatBuilder(
participants=[researcher, writer],
termination_condition=lambda conversation: len(conversation) >= 4,
intermediate_output_from=[researcher, writer],
selection_func=round_robin_selector,
).build()
Konfigurace skupinového chatu pomocí nástroje Agent-Based Orchestrator
Případně můžete použít orchestrátor založený na agentech pro inteligentní výběr mluvčího. Orchestrátor má plný Agent přístup k nástrojům, kontextu a sledování:
# Create orchestrator agent for speaker selection
orchestrator_agent = Agent(
name="Orchestrator",
description="Coordinates multi-agent collaboration by selecting speakers",
instructions="""
You coordinate a team conversation to solve the user's task.
Guidelines:
- Start with Researcher to gather information
- Then have Writer synthesize the final answer
- Only finish after both have contributed meaningfully
""",
client=client,
)
# Build group chat with agent-based orchestrator
workflow = GroupChatBuilder(
participants=[researcher, writer],
# Set a hard termination condition: stop after 4 assistant messages
# The agent orchestrator will intelligently decide when to end before this limit but just in case
termination_condition=lambda messages: sum(1 for msg in messages if msg.role == "assistant") >= 4,
orchestrator_agent=orchestrator_agent,
intermediate_output_from=[researcher, writer],
).build()
Spuštění workflowu skupinového chatu
Spusťte pracovní postup a zpracujte aktualizace účastníků streamování. Nestreamovaný výstup terminálu je AgentResponse; streamovaný výstup terminálu je odesílán jako bloky AgentResponseUpdate.
from agent_framework import AgentResponseUpdate, Message
task = "What are the key benefits of async/await in Python?"
print(f"Task: {task}\n")
print("=" * 80)
last_author: str | None = None
# Run the workflow with streaming enabled
stream = workflow.run(task, stream=True)
async for event in stream:
if event.type in ("intermediate", "output") and isinstance(event.data, AgentResponseUpdate):
# Print streaming agent updates
author = event.data.author_name
if author != last_author:
if last_author is not None:
print()
print(f"[{author}]:", end=" ", flush=True)
last_author = author
print(event.data.text, end="", flush=True)
result = await stream.get_final_response()
if outputs := result.get_outputs():
print("\n\n" + "=" * 80)
print("Final Response:")
print(outputs[-1])
print("\nWorkflow completed.")
Ukázková interakce
Task: What are the key benefits of async/await in Python?
================================================================================
[Researcher]: Async/await in Python provides non-blocking I/O operations, enabling
concurrent execution without threading overhead. Key benefits include improved
performance for I/O-bound tasks, better resource utilization, and simplified
concurrent code structure using native coroutines.
[Writer]: The key benefits of async/await in Python are:
1. **Non-blocking Operations**: Allows I/O operations to run concurrently without
blocking the main thread, significantly improving performance for network
requests, file I/O, and database queries.
2. **Resource Efficiency**: Avoids the overhead of thread creation and context
switching, making it more memory-efficient than traditional threading.
3. **Simplified Concurrency**: Provides a clean, synchronous-looking syntax for
asynchronous code, making concurrent programs easier to write and maintain.
4. **Scalability**: Enables handling thousands of concurrent connections with
minimal resource consumption, ideal for high-performance web servers and APIs.
--------------------------------------------------------------------------------
Workflow completed.
Nastavení konfigurace Foundry
endpoint := os.Getenv("FOUNDRY_PROJECT_ENDPOINT")
model := cmp.Or(os.Getenv("FOUNDRY_MODEL"), "gpt-4o-mini")
token, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
return err
}
Warning
azidentity.NewDefaultAzureCredential je vhodný pro vývoj, ale vyžaduje pečlivé zvážení v produkčním prostředí. V produkčním prostředí zvažte použití konkrétních přihlašovacích údajů, například azidentity.NewManagedIdentityCredential, abyste se vyhnuli problémům s latencí, neúmyslnému testování přihlašovacích údajů a potenciálním bezpečnostním rizikům z náhradních mechanismů.
Definování agentů
Vytvořte specializované agenty s odlišnými rolemi v konverzaci:
copywriter := foundryprovider.NewAgent(
endpoint,
token,
foundryprovider.ModelDeployment(model),
foundryprovider.AgentConfig{
Instructions: "You are a creative copywriter. Generate catchy slogans and marketing copy. Be concise and impactful.",
Config: agent.Config{Name: "CopyWriter"},
},
)
reviewer := foundryprovider.NewAgent(
endpoint,
token,
foundryprovider.ModelDeployment(model),
foundryprovider.AgentConfig{
Instructions: "You are a marketing reviewer. Evaluate slogans for clarity, impact, and brand alignment. Provide constructive feedback or approval.",
Config: agent.Config{Name: "Reviewer"},
},
)
Konfigurace skupinového chatu pomocí Round-Robin Manageru
Vytvořte postup skupinového chatu pomocí agentworkflow.NewGroupChatWorkflowBuilder. Tvůrce vezme vedoucí továrnu a zúčastněné agenty.
NewRoundRobinGroupChatManager postupně vybere každého agenta a zastaví se po dosažení nakonfigurovaného maximálního počtu tahů účastníků.
managerFactory := func(agents []*agent.Agent) *agentworkflow.GroupChatManager {
return agentworkflow.NewRoundRobinGroupChatManager(
agents,
agentworkflow.RoundRobinGroupChatOptions{MaximumIterationCount: 5},
)
}
wf, err := agentworkflow.NewGroupChatWorkflowBuilder(managerFactory, copywriter, reviewer).
WithName("Marketing Review Group Chat").
WithDescription("A copywriter and reviewer collaborate on marketing copy.").
Build()
if err != nil {
return err
}
Spuštění workflowu skupinového chatu
Spusťte pracovní postup se zprávou uživatele a tokenem turn. Když je povolená emise událostí, aktualizace účastníků dorazí jako přechodné výstupní události a konečný přepis přijde jako výstupní událost terminálu.
run, err := inproc.Default.RunStreaming(ctx, wf, []*message.Message{
message.NewText("Create a slogan for an eco-friendly electric vehicle."),
})
if err != nil {
return err
}
defer run.Close(ctx)
emitEvents := true
if err := run.SendMessage(ctx, workflow.TurnToken{EmitEvents: &emitEvents}); err != nil {
return err
}
lastExecutorID := ""
for evt, err := range run.WatchStream(ctx) {
if err != nil {
return err
}
switch e := evt.(type) {
case workflow.OutputEvent:
switch value := e.Output.(type) {
case *agent.ResponseUpdate:
if e.ExecutorID != lastExecutorID {
lastExecutorID = e.ExecutorID
fmt.Printf("\n[%s]: ", e.ExecutorID)
}
fmt.Print(value.String())
case []*message.Message:
fmt.Println("\n\n=== Final Conversation ===")
for _, msg := range value {
author := msg.AuthorName
if author == "" {
author = string(msg.Role)
}
fmt.Printf("%s: %s\n", author, msg.String())
}
}
case workflow.ErrorEvent:
return e.Error
case workflow.ExecutorFailedEvent:
return fmt.Errorf("executor %q failed: %w", e.ExecutorID, e.Error)
}
}
Ukázková interakce
[CopyWriter]: "Pure Power, Zero Impact" - Experience electric performance without compromise.
[Reviewer]: This is clear and memorable. It communicates performance and sustainability directly.
Approved.
[CopyWriter]: The final slogan is: "Pure Power, Zero Impact" - Experience electric performance
without compromise.
=== Final Conversation ===
user: Create a slogan for an eco-friendly electric vehicle.
CopyWriter: "Pure Power, Zero Impact" - Experience electric performance without compromise.
Reviewer: This is clear and memorable. It communicates performance and sustainability directly. Approved.
CopyWriter: The final slogan is: "Pure Power, Zero Impact" - Experience electric performance without compromise.
Klíčové koncepty
- Centralizovaný manažer: Skupinový chat používá manažera ke koordinaci výběru a toku mluvčího.
- AgentWorkflowBuilder.CreateGroupChatBuilderWith(): Vytvoří pracovní postupy pomocí funkce továrny správců.
- RoundRobinGroupChatManager: Předdefinovaný manažer, který střídá mluvčí v kruhovém pořadí.
- MaximumIterationCount: Určuje maximální počet iterací agenta před ukončením.
-
Vlastní manažeři: Rozšíření
RoundRobinGroupChatManagernebo implementace vlastní logiky - Iterativní upřesnění: Agenti kontrolují a vylepšují příspěvky ostatních
- Sdílený kontext: Všichni účastníci uvidí celou historii konverzací.
-
Flexibilní strategie orchestratoru: Volba mezi jednoduchými selektory, orchestrátory založenými na agentech nebo vlastní logikou prostřednictvím parametrů konstruktoru (
selection_func,orchestrator_agentneboorchestrator). - GroupChatBuilder: Vytvoří pracovní postupy s konfigurovatelným výběrem mluvčího.
- GroupChatState: Poskytuje stav konverzace pro rozhodnutí o výběru
- Iterativní spolupráce: Agenti staví na příspěvcích ostatních
-
AgentResponse Output: Výstup terminálu je
AgentResponseobsahující zprávu o dokončení orchestrátoru. -
Streamování událostí: Zpracování
AgentResponseUpdateudálostí v reálném čase prostřednictvímworkflow.run(task, stream=True) -
Průběžné výstupy: Předejte
intermediate_output_from=[participant, ...], aby se výstup každého z uvedených účastníků zobrazil jako události"intermediate", vedle koncové události"output"orchestrace
- GroupChatWorkflowBuilder: Vytvoří pracovní postup hvězdicové topologie s hostitelem skupinového chatu v centru a hostovanými agenty jako účastníky.
- GroupChatManager: Vybere dalšího účastníka, může aktualizovat historii vysílání a může ukončit konverzaci.
- NewRoundRobinGroupChatManager: Integrovaný správce, který střídá účastníky v kruhovém pořadí
- RoundRobinGroupChatOptions: Nakonfiguruje maximální počet účastníků a volitelnou funkci ukončení.
- Výstupní události: Výstupy účastníků jsou ve výchozím nastavení přechodné události a hostitel skupinového chatu poskytuje přepis terminálu.
-
Vlastní správci: Implementujte
SelectNextAgenta volitelné callbacky životního cyklu pro vlastní výběr mluvčího nebo stav uložený do kontrolního bodu
Pokročilé: Výběr vlastního mluvčího
Logiku vlastního správce můžete implementovat vytvořením vlastního správce chatu skupiny:
public class ApprovalBasedManager : RoundRobinGroupChatManager
{
private readonly string _approverName;
public ApprovalBasedManager(IReadOnlyList<AIAgent> agents, string approverName)
: base(agents)
{
_approverName = approverName;
}
// Override to add custom termination logic
protected override ValueTask<bool> ShouldTerminateAsync(
IReadOnlyList<ChatMessage> history,
CancellationToken cancellationToken = default)
{
var last = history.LastOrDefault();
bool shouldTerminate = last?.AuthorName == _approverName &&
last.Text?.Contains("approve", StringComparison.OrdinalIgnoreCase) == true;
return ValueTask.FromResult(shouldTerminate);
}
}
// Use custom manager in workflow
var workflow = AgentWorkflowBuilder
.CreateGroupChatBuilderWith(agents =>
new ApprovalBasedManager(agents, "Reviewer")
{
MaximumIterationCount = 10
})
.AddParticipants(writer, reviewer)
.Build();
Na základě stavu konverzace můžete implementovat sofistikovanou logiku výběru:
def smart_selector(state: GroupChatState) -> str:
"""Select speakers based on conversation content and context."""
conversation = state.conversation
last_message = conversation[-1] if conversation else None
# If no messages yet, start with Researcher
if not last_message:
return "Researcher"
# Check last message content
last_text = last_message.text.lower()
# If researcher finished gathering info, switch to writer
if "i have finished" in last_text and last_message.author_name == "Researcher":
return "Writer"
# Else continue with researcher until it indicates completion
return "Researcher"
workflow = GroupChatBuilder(
participants=[researcher, writer],
selection_func=smart_selector,
).build()
Důležité
Při použití vlastní implementace BaseGroupChatOrchestrator pro pokročilé scénáře musí být nastaveny všechny vlastnosti, včetně participant_registry, max_roundsa termination_condition.
max_rounds a termination_condition nastavení v builderu bude ignorováno.
Zprostředkující výstupy
Ve výchozím nastavení se jako událost pracovního postupu "output" (terminálu) zobrazí pouze konečný výstup orchestrátoru. Předejte intermediate_output_from účastníkům, které chcete určit jako přechodné zdroje, aby se také zobrazovaly jejich jednotlivé výstupy jako "intermediate" události:
workflow = GroupChatBuilder(
participants=[researcher, writer],
termination_condition=lambda conversation: len(conversation) >= 4,
selection_func=round_robin_selector,
intermediate_output_from=[researcher, writer],
).build()
Implementujte vlastní výběr mluvčího vrácením hodnoty GroupChatManager z továrny správce builderu:
type approvalManager struct {
agents []*agent.Agent
}
func newApprovalManager(agents []*agent.Agent) *agentworkflow.GroupChatManager {
manager := &approvalManager{agents: agents}
return &agentworkflow.GroupChatManager{
SelectNextAgent: manager.selectNextAgent,
ShouldTerminate: manager.shouldTerminate,
}
}
func (m *approvalManager) selectNextAgent(_ context.Context, history []*message.Message) (*agent.Agent, error) {
last := lastAssistantMessage(history)
if last == nil || last.AuthorName == "Reviewer" {
return m.agentByName("CopyWriter")
}
return m.agentByName("Reviewer")
}
func (m *approvalManager) shouldTerminate(_ context.Context, history []*message.Message, iterationCount int) (bool, error) {
if iterationCount >= 10 {
return true, nil
}
last := lastAssistantMessage(history)
return last != nil &&
last.AuthorName == "Reviewer" &&
strings.Contains(strings.ToLower(last.String()), "approve"), nil
}
func (m *approvalManager) agentByName(name string) (*agent.Agent, error) {
for _, currentAgent := range m.agents {
if currentAgent.Name() == name {
return currentAgent, nil
}
}
return nil, fmt.Errorf("agent %q is not part of the group chat", name)
}
func lastAssistantMessage(history []*message.Message) *message.Message {
for i := len(history) - 1; i >= 0; i-- {
if history[i].Role == message.RoleAssistant {
return history[i]
}
}
return nil
}
wf, err := agentworkflow.NewGroupChatWorkflowBuilder(newApprovalManager, copywriter, reviewer).
WithName("Approval Group Chat").
Build()
GroupChatManager také podporuje UpdateHistory, Reset, OnCheckpoint a OnCheckpointRestored zpětná volání pro pokročilé správce, kteří filtrují vysílané zprávy nebo uchovávají stav vlastněný správcem.
Zprostředkující výstupy
Ve výchozím nastavení GroupChatWorkflowBuilder generuje výstupy účastníků jako výstupy zprostředkujícího pracovního postupu a generuje přepis kumulované konverzace jako výstup terminálu. Použijte OutputEvent.IsIntermediate() k odlišení aktualizací účastníků od konečného přepisu:
if output, ok := evt.(workflow.OutputEvent); ok {
if output.IsIntermediate() {
fmt.Printf("intermediate from %s: %v\n", output.ExecutorID, output.Output)
return nil
}
fmt.Printf("terminal output: %v\n", output.Output)
}
Volání WithOutputFrom nebo WithIntermediateOutputFrom v nástroji pro vytváření skupinového chatu přepne na explicitní určení výstupu. Použijte tyto metody, pokud chcete vybrané výstupy účastníků místo výchozího konečného přepisu a všech průběžných výstupů účastníků.
Synchronizace kontextu
Jak je uvedeno na začátku tohoto průvodce, všichni agenti ve skupinovém chatu uvidí celou historii konverzací.
Agenti v rozhraní Agent Framework spoléhají na relace agenta (AgentSession) ke správě kontextu. V orchestraci skupinového chatu agenti nesdílí stejnou instanci relace, ale orchestrátor zajistí synchronizaci relace jednotlivých agentů s úplnou historií konverzací před každým turnem. Aby toho bylo dosaženo, orchestrátor po tahu každého agenta vysílá odpověď všem ostatním agentům a zajistí, aby všichni účastníci měli nejnovější kontext pro jejich další tah.
Tip
Agenti nesdílejí stejnou instanci relace, protože různé typy agentů mohou mít různé implementace AgentSession abstrakce. Sdílení stejné instance relace může vést ke nekonzistencím v tom, jak každý agent zpracovává a udržuje kontext.
Po vysílání odpovědi orchestrátor rozhodne dalšího mluvčího a odešle žádost vybranému agentovi, který teď má úplnou historii konverzací, aby vygeneroval odpověď.
Kdy použít skupinovou chat
Orchestrace skupinového chatu je ideální pro:
- Iterativní upřesnění: Více kol kontroly a vylepšení
- Spolupráce při řešení problémů: Specialisté s doplňkovými odbornými znalostmi, kteří spolupracují
- Vytváření obsahu: Pracovní postupy pro autory revidujících pro vytváření dokumentů
- Analýza s více perspektivami: Získání různých hledisek na stejném vstupu
- Kontrola kvality: Automatizované procesy kontroly a schvalování
Zvažte alternativy v případech:
- Potřebujete striktní sekvenční zpracování (použijte sekvenční orchestraci).
- Agenti by měli pracovat zcela nezávisle (používat souběžnou orchestraci).
- Jsou potřeba přímé předání agenta agentovi (použijte orchestraci předání).
- Vyžaduje se komplexní dynamické plánování (použití magentické orchestrace)