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 responsePoint d'entrée global
Le panneau de l'assistant IA est inclus sans condition dans templates/base.html.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__ :
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 :
<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 :
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 :
App\Service\AI\Context\ViewEditorAiContext:
tags:
- { name: 'app.ai_context' }Ajouter un contexte de page
- Créez une classe implémentant
AiContextProviderInterface - Ajoutez
tags: [{ name: 'app.ai_context' }]dansservices.yaml - 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 :
$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:- Ajoute les ToolCall au MessageBag
- Exécute ToolCall → ToolResult et le réécrit dans le MessageBag
- Appelle récursivement jusqu'à ce qu'un
TextResultsoit retourné
Système d'outils
Basé sur l'attribut #[AsTool] de symfony/ai-agent pour marquer les méthodes d'outil :
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
| Tool | Fonction |
|---|---|
view.getInfo | Récupère les informations de la vue (entité, champs, disposition) |
view.updateSectionConfig | Met à jour la configuration de disposition |
view.updateFieldConfig | Met à jour la configuration des champs |
view.listEntityFields | Liste 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
{
"context": "view_editor",
"message": "帮我改成三列布局"
}Réponse en cas de succès :
{
"code": 200,
"message": "success",
"data": { "reply": "已修改为三列布局。" }
}Fichiers associés
| Fichier | Rôle |
|---|---|
AiChatController.php | Reçoit {context, message}, délègue au fournisseur correspondant |
AiContextRegistry.php | Collecte les services taggés app.ai_context, indexés par name |
AiAssistant.php | Fabrique d'agents générique |
LlmRouterPlatform.php | Pont PlatformInterface (MessageBag ↔ tableau) |
ChatResultConverter.php | Convertit les données de réponse → TextResult/ToolCallResult |
ViewEditorToolProvider.php | Méthodes Tool de l'éditeur de vue |
ChromeDevToolsToolProvider.php | Outils de débogage navigateur CDP |
ViewFileToolProvider.php | Outils de lecture/écriture de fichiers de vue |