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