ИИ-оркестрация с LarAgent в мультиагентных системах

Современные AI-приложения редко ограничиваются одним вызовом LLM.
Реальные пользовательские сценарии требуют координации нескольких моделей, специализированных агентов, инструментов и источников данных.

Например, пользователь пишет:

«Создай 10 SEO-статей для моего блога».

На первый взгляд — простая задача.
На практике она включает:

  • анализ намерения пользователя;

  • выбор подходящего агента;

  • генерацию идей;

  • построение структуры статьи;

  • написание текста;

  • SEO-оптимизацию;

  • форматирование ответа.

В нашем продакшн-приложении на Laravel мы решили эту задачу через мультиагентную архитектуру на базе фреймворка LarAgent (maestroerror/laragent).

Эта статья показывает реальную архитектуру системы и ключевые паттерны, которые позволили построить масштабируемую AI-платформу.

Зачем нужна ИИ-оркестрация

Один вызов LLM — это просто.

Но когда система должна:

  • использовать разные агенты,

  • выполнять цепочки действий,

  • вызывать инструменты,

  • работать с пользователями и чатами,

  • поддерживать разные LLM-провайдеры,

— появляется необходимость оркестрации.

ИИ-оркестрация — это слой управления, который:

  • принимает пользовательский запрос,

  • определяет намерение пользователя,

  • выбирает подходящего агента,

  • координирует выполнение задачи.

В нашем приложении оркестратор не выполняет задачи самостоятельно — он только маршрутизирует запросы между агентами.

Архитектура: Orchestrator → Specialist Agents

Основной паттерн системы:

User Message
   ↓
AgentConversationManager
   ↓
OrchestratorAgent
   ↓
DetectUserIntentTool
   ↓
MatchIntentToAgentTool
   ↓
DelegateToAgentTool
   ↓
Specialist Agent
   ↓
FormatResponseForUserTool

Оркестратор работает как маршрутизатор задач.

В системе используется несколько специализированных агентов:

  • ArticleGeneratorAgent

  • MarketingAgent

  • SEOAgent

  • ConsultantAgent

  • DetectUserIntentAgent

Каждый агент отвечает только за свою область.

Это соответствует архитектурному принципу:

Single Responsibility for AI Agents

Пример OrchestratorAgent

class OrchestratorAgent extends AbstractAgent
    implements AgentChatAwareInterface, UserAwareInterface, AgentInterface
{
    use InteractsWithUser, InteractsWithAgentChat;

    protected $provider = 'default';
    protected $history = 'cache';

    public function registerTools(): array
    {
        return [
            new GetAvailableAgentsTool(),
            new MatchIntentToAgentTool(),
            (new DetectUserIntentTool())
                ->addProperty('provider', 'string', 'Название провайдера', [$this->provider])
                ->setRequired('provider')
                ->setMetaData(['history' => $this->chatHistory()]),
            (new DelegateToAgentTool())
                ->addProperty('chat_uuid', 'string', 'UUID чата', [$this->getChatUuid()])
                ->setRequired('chat_uuid')
                ->addProperty('provider', 'string', 'Провайдер', [$this->getProviderName()])
                ->setRequired('provider')
                ->addProperty('user_id', 'integer', 'ID пользователя', [$this->user?->id])
                ->setRequired('user_id'),
            (new FormatResponseForUserTool())
                ->addProperty('provider', 'string', 'Провайдер', [$this->getProviderName()])
                ->setRequired('provider'),
        ];
    }
}

Оркестратор использует инструменты (tools), чтобы управлять агентами.

Intent Detection — понимание намерения пользователя

Первый шаг любой AI-системы — понять, что хочет пользователь.

В нашем случае используется structured output.

LLM возвращает не текст, а типизированный объект.

class Intent extends DataModel
{
    #[Desc('Намерение пользователя')]
    public string $intent = "unknown";
}

Агент определения намерения:

class DetectUserIntentAgent extends AbstractAgent
{
    protected $responseSchema = Intent::class;

    public function registerTools(): array
    {
        return [new GetUserIntentsTool()];
    }
}

Теперь LLM возвращает, например:

intent = "article.create_detailed"

Маппинг Intent → Agent

После определения intent система выбирает нужного агента.

private function searchAgentByTools(array $requiredTools): ?Agent
{
    $agents = $this->agentRepository->getAllWithTools();

    foreach ($agents as $agent) {
        if ($this->agentHasAllTools($agent, $requiredTools)) {
            return $agent;
        }
    }

    return null;
}

Таким образом:

Intent → Required Tools → Agent

LLM определяет intent, но не выбирает агента напрямую.

Это важная архитектурная защита.

Делегирование задач между агентами

Оркестратор не вызывает агента напрямую.

Он использует DelegateToAgentTool.

private function executeAgent(
    string $agentClass,
    string $chatUuid,
    string $payload,
    int $userId
): string
{
    $agent = $agentClass::setConfiguration($chatUuid, $agentClass)
        ->addSystemMessages();

    if ($agent instanceof UserAwareInterface) {
        $user = $this->userRepository->findById($userId);
        if ($user) {
            $agent->setUser($user);
        }
    }

    if ($agent instanceof AgentChatAwareInterface) {
        $agent->setChatUuid($chatUuid);
    }

    $raw = $agent->respond($payload);

    return is_string($raw) ? $raw : (string) $raw;
}

Это позволяет:

  • передавать контекст пользователя

  • передавать чат

  • управлять историей сообщений

Контракт оркестрируемых агентов

Чтобы агент мог быть вызван оркестратором, он должен реализовать интерфейс:

interface OrchestratableAgentInterface extends AgentInterface {}

Пример:

class ArticleGeneratorAgent extends AbstractAgent
    implements OrchestratableAgentInterface,
               UserAwareInterface,
               AgentChatAwareInterface
{
}

Таким образом система контролирует доступ агентов.

Expert Chain — мультишаговая генерация статей

Некоторые задачи слишком сложны для одного LLM-запроса.

Например, генерация экспертной статьи.

Мы используем Expert Chain.

Цепочка из 5 шагов:

  1. Генерация идей

  2. Выбор лучшей идеи

  3. План статьи

  4. Написание секций

  5. Финальное ревью

public function generate(string $topic, ?array $plan = null)
{
    $selectedIdea = $topic;

    $plan = $plan ?? $this->generateArticlePlan($topic);

    $sections = $this->writeSections($plan);

    $content = $this->reviewArticle($sections);

    return new ArticleGeneratedContent(
        $topic,
        $content,
        $selectedIdea,
        $plan
    );
}

Каждый шаг вызывает LLM отдельно.

Это даёт:

  • лучшее качество текста

  • более стабильный результат

  • контроль над процессом генерации

Мульти-провайдерность LLM

Система может работать с разными LLM.

Поддерживаются:

  • OpenAI

  • Claude

  • Gemini

  • YandexGPT

  • Groq

  • Ollama

  • OpenRouter

Конфигурация:

'providers' => [

    'default' => [
        'driver' => ChatGPTDriver::class,
        'model' => 'gpt-5-mini',
    ],

    'gemini' => [
        'driver' => GeminiDriver::class,
        'model' => 'gemini-2.0-flash-latest',
    ],

    'claude' => [
        'driver' => ClaudeDriver::class,
        'model' => 'claude-3-7-sonnet-latest',
    ],

    'yandexgpt' => [
        'driver' => YandexDriver::class,
        'model' => 'gpt://folder_id/yandexgpt-lite',
    ],
]

Переключение происходит динамически:

$instance->changeProvider($provider);
$instance->withModel($model);

Это позволяет:

  • менять LLM без изменения бизнес-логики

  • тестировать разные модели

  • использовать разные модели для разных задач

Фоновая обработка через Laravel Queues

Массовая генерация контента требует фоновой обработки.

Например:

«Создай 10 статей»

Каждая статья — отдельная очередь.

class CreateArticleJob implements ShouldQueue
{
    public function handle(): void
    {
        $agent = $this->buildAgent();

        $payload = $this->getCreateArticlePayload();

        $agent->respond($payload);
    }
}

Преимущества:

  • система не блокирует пользователя

  • задачи масштабируются горизонтально

  • можно генерировать тысячи статей

Управление контекстом

Большая проблема LLM-систем — рост контекста.

Для решения используется Truncation Strategy.

Оркестратор хранит историю:

return new SimpleTruncationStrategy([
    'keep_messages' => 25,
    'preserve_system' => true,
]);

Специализированные агенты — только 1 сообщение.

return new SimpleTruncationStrategy([
    'keep_messages' => 1,
    'preserve_system' => true,
]);

Это резко уменьшает стоимость запросов.

Защита от зацикливания

В мультиагентных системах может возникнуть бесконечный цикл:

Agent → Tool → Agent → Tool

Поэтому используется Loop Detection Service, который ограничивает число вызовов инструментов.

Точка входа системы

Все начинается с AgentConversationManager.

private function callOrchestratorAgent(
    AgentChat $chat,
    string $payload
): string
{
    $agent = OrchestratorAgent::setConfiguration(
        $chat->uuid,
        OrchestratorAgent::class
    )
        ->setChatUuid($chat->uuid)
        ->setUser($this->getUser());

    $raw = $agent->respond($payload);

    return is_string($raw) ? $raw : (string) $raw;
}

Поток работы:

HTTP Request
   ↓
Controller
   ↓
AgentConversationManager
   ↓
OrchestratorAgent
   ↓
Specialist Agent
   ↓
Response

Итоги

Мультиагентные системы становятся стандартом для AI-приложений.

Основные архитектурные выводы:

1. Используйте Orchestrator + Specialists

Оркестратор должен только маршрутизировать задачи.

2. Используйте Intent-based routing

LLM определяет intent, а система выбирает агента.

3. Используйте интерфейсы

Контракты вроде:

OrchestratableAgentInterface
UserAwareInterface
AgentChatAwareInterface

дают архитектурный контроль.

4. Разбивайте сложные задачи на цепочки

Expert Chain даёт намного более стабильные результаты.

5. Делайте мульти-LLM архитектуру

Модели быстро меняются — архитектура должна это учитывать.

6. Используйте очереди

LLM-задачи должны выполняться в фоне.

Заключение

Мультиагентная архитектура позволяет превратить LLM из простого генератора текста в полноценную AI-платформу.

Используя:

  • orchestrator pattern

  • intent detection

  • tool-based delegation

  • expert chains

  • multi-provider LLM

мы смогли построить систему, которая масштабируется от одного запроса до массовой генерации контента.

И это только начало развития AI-архитектур.