Skip to content

Assistant IA

Doggy fournit un assistant IA global, présent sur toutes les pages sous forme de bouton flottant + panneau coulissant, profondément intégré aux pages via un mécanisme d'enregistrement de contexte, avec prise en charge de la boucle de raisonnement ReAct et de l'appel d'outils.

Aperçu

L'assistant IA est construit sur la pile technologique symfony/ai-agent + symfony/ai-platform, connecté à la passerelle LlmRouter propre à la plateforme :

Client POST /api/admin/ai/chat  { context, message }
  → AiChatController
    → AiContextRegistry::get(context)
      → AiContextProviderInterface (e.g. ViewEditorAiContext)
        → AiAssistant::chat(roleCode, systemPrompt, toolProviders, message)
          → Agent::call(MessageBag, options)
            → AgentProcessor::processInput (注入 Tool)
            → LlmRouterPlatform::invoke → LlmRouter → LlmGatewayFactory
            → AgentProcessor::processOutput (ReAct 循环)
            ← string response

Point d'entrée global

Le panneau de l'assistant IA est inclus sans condition dans templates/base.html.twig :

twig
<body>
    {% block body %}{% endblock %}
    {% include 'admin/ai_chat.html.twig' %}
</body>
  • Ouvrir/fermer : bouton flottant en bas à droite toggle-ai-chat / ai-chat-close
  • Saisie : Entrée pour envoyer, Maj+Entrée pour passer à la ligne
  • État de chargement : la saisie est désactivée pendant la requête, « Réflexion en cours... » s'affiche
  • Style : public/sunui/admin/ai_chat.css

Enregistrement du contexte de page

Chaque page enregistre son contexte auprès de l'assistant via window.__AI_CONTEXT__ :

js
window.__AI_CONTEXT__ = {
    name: 'view_editor',                  // backend AiContextProviderInterface::getName()
    buildPrompt: function(msg) {          // facultatif, construit le message envoyé au backend
        return '[当前视图ID: xxx]\n\n' + msg;
    },
};

Exemple d'enregistrement de l'éditeur de vue :

twig
<script>
  window.__VIEW_ID__ = {{ id|json_encode|raw }};
  window.__AI_CONTEXT__ = {
      name: 'view_editor',
      buildPrompt: function(msg) {
          var vid = window.__VIEW_ID__;
          return vid ? '[当前视图ID: ' + vid + ']\n\n' + msg : msg;
      },
  };
</script>

Système de fournisseurs de contexte

AiContextProviderInterface définit les fournisseurs de contexte :

php
namespace App\Service\AI\Runtime;

interface AiContextProviderInterface
{
    public function getName(): string;                    // identifiant du contexte
    public function getRoleCode(): string;                // code de rôle LlmRouter
    public function getSystemPrompt(): string;            // prompt système de l'agent
    public function getToolProviders(): array;            // tableau d'objets Tool
}

Enregistrement via le tag app.ai_context :

yaml
App\Service\AI\Context\ViewEditorAiContext:
    tags:
        - { name: 'app.ai_context' }

Ajouter un contexte de page

  1. Créez une classe implémentant AiContextProviderInterface
  2. Ajoutez tags: [{ name: 'app.ai_context' }] dans services.yaml
  3. Définissez window.__AI_CONTEXT__ = { name: 'your_name' } dans le template de la page

Runtime d'agents

AiAssistant est une fabrique d'agents générique ; chaque appel chat() crée une instance d'agent indépendante, garantissant l'absence de pollution d'état :

php
$platform = new LlmRouterPlatform($this->router, $this->converter);
$toolbox = new Toolbox($toolProviders);

$agent = new Agent(
    platform: $platform,
    model: $roleCode,
    inputProcessors: [
        new SystemPromptInputProcessor($systemPrompt),
        new AgentProcessor($toolbox),
    ],
    outputProcessors: [
        new AgentProcessor($toolbox),
    ],
    name: 'ai-assistant',
);

Boucle ReAct

AgentProcessor agit à la fois comme processeur d'entrée et de sortie, implémentant la boucle d'appel d'outils :

  • processInput : injecte les métadonnées Tool de la Toolbox
  • processOutput : lorsqu'il détecte un résultat de type ToolCallResult :
    1. Ajoute les ToolCall au MessageBag
    2. Exécute ToolCall → ToolResult et le réécrit dans le MessageBag
    3. Appelle récursivement jusqu'à ce qu'un TextResult soit retourné

Système d'outils

Basé sur l'attribut #[AsTool] de symfony/ai-agent pour marquer les méthodes d'outil :

php
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;

class ViewEditorToolProvider
{
    #[AsTool(name: 'view.getInfo', description: '获取视图的完整信息')]
    public function getViewInfo(string $viewId): array { ... }

    #[AsTool(name: 'view.updateSectionConfig', description: '更新视图的布局配置')]
    public function updateSectionConfig(string $viewId, string $contentWidth, ...): array { ... }
}

Outils actuels de l'éditeur de vue

ToolFonction
view.getInfoRécupère les informations de la vue (entité, champs, disposition)
view.updateSectionConfigMet à jour la configuration de disposition
view.updateFieldConfigMet à jour la configuration des champs
view.listEntityFieldsListe les champs de l'entité

Principes de conception

  • Chaque outil est une méthode à responsabilité unique
  • Les noms de paramètres correspondent aux noms de paramètres du schéma JSON de #[AsTool] (mapping automatique)
  • Retourne un array (converti en texte de résultat d'outil)

Points de terminaison API

POST /api/admin/ai/chat

json
{
    "context": "view_editor",
    "message": "帮我改成三列布局"
}

Réponse en cas de succès :

json
{
    "code": 200,
    "message": "success",
    "data": { "reply": "已修改为三列布局。" }
}

Fichiers associés

FichierRôle
AiChatController.phpReçoit {context, message}, délègue au fournisseur correspondant
AiContextRegistry.phpCollecte les services taggés app.ai_context, indexés par name
AiAssistant.phpFabrique d'agents générique
LlmRouterPlatform.phpPont PlatformInterface (MessageBag ↔ tableau)
ChatResultConverter.phpConvertit les données de réponse → TextResult/ToolCallResult
ViewEditorToolProvider.phpMéthodes Tool de l'éditeur de vue
ChromeDevToolsToolProvider.phpOutils de débogage navigateur CDP
ViewFileToolProvider.phpOutils de lecture/écriture de fichiers de vue

Open source sous licence MIT | Copyright © 2026 Doggy