Asistente IA
Doggy ofrece un asistente IA global, presente en todas las páginas en forma de botón flotante + panel deslizante, con integración profunda con las páginas mediante un mecanismo de registro de contexto, y soporte para el bucle de razonamiento ReAct y la llamada a herramientas.
Descripción general
El Asistente IA está construido sobre la pila tecnológica symfony/ai-agent + symfony/ai-platform y se conecta con el sistema de puerta de enlace LlmRouter propio de la plataforma:
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 (bucle ReAct)
← string responseEntrada global
El panel del Asistente IA se incluye de forma incondicional en templates/base.html.twig:
<body>
{% block body %}{% endblock %}
{% include 'admin/ai_chat.html.twig' %}
</body>- Abrir/Cerrar: botón flotante en la esquina inferior derecha
toggle-ai-chat/ai-chat-close - Entrada: Enter envía, Shift+Enter salto de línea
- Estado de carga: durante la petición se deshabilita la entrada y se muestra "Pensando..."
- Estilos:
public/sunui/admin/ai_chat.css
Registro de contexto de página
Cada página registra su contexto en el asistente a través de window.__AI_CONTEXT__:
window.__AI_CONTEXT__ = {
name: 'view_editor', // AiContextProviderInterface::getName() del backend
buildPrompt: function(msg) { // opcional, construye el mensaje enviado al backend
return '[ID de vista actual: xxx]\n\n' + msg;
},
};Ejemplo de registro del editor de vistas:
<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 de vista actual: ' + vid + ']\n\n' + msg : msg;
},
};
</script>Sistema de proveedores de contexto
AiContextProviderInterface define los proveedores de contexto:
namespace App\Service\AI\Runtime;
interface AiContextProviderInterface
{
public function getName(): string; // Identificador de contexto
public function getRoleCode(): string; // Código de rol de LlmRouter
public function getSystemPrompt(): string; // Prompt del sistema del Agente
public function getToolProviders(): array; // Matriz de objetos Tool
}Se registra mediante la etiqueta app.ai_context:
App\Service\AI\Context\ViewEditorAiContext:
tags:
- { name: 'app.ai_context' }Añadir un contexto de página nuevo
- Crea una clase que implemente
AiContextProviderInterface - Añade
tags: [{ name: 'app.ai_context' }]enservices.yaml - Define
window.__AI_CONTEXT__ = { name: 'your_name' }en la plantilla de la página
Runtime de Agente
AiAssistant es una fábrica de Agentes genérica: cada llamada a chat() crea una instancia de Agente independiente para garantizar que no haya contaminación de estado:
$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',
);Bucle ReAct
AgentProcessor actúa a la vez como procesador de entrada y de salida, implementando el bucle de llamada a herramientas:
- processInput: inyecta los metadatos de las Tool del Toolbox
- processOutput: cuando el resultado es
ToolCallResult:- Añade la matriz de ToolCall al MessageBag
- Ejecuta ToolCall → escribe el ToolResult de vuelta en el MessageBag
- Llama de forma recursiva hasta devolver un
TextResult
Sistema de herramientas
Las herramientas se marcan con el atributo #[AsTool] de symfony/ai-agent:
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
class ViewEditorToolProvider
{
#[AsTool(name: 'view.getInfo', description: 'Obtiene la información completa de la vista')]
public function getViewInfo(string $viewId): array { ... }
#[AsTool(name: 'view.updateSectionConfig', description: 'Actualiza la configuración de diseño de la vista')]
public function updateSectionConfig(string $viewId, string $contentWidth, ...): array { ... }
}Herramientas actuales del editor de vistas
| Tool | Función |
|---|---|
view.getInfo | Obtener información de la vista (entidad, campos, diseño) |
view.updateSectionConfig | Actualizar la configuración del diseño |
view.updateFieldConfig | Actualizar la configuración de campos |
view.listEntityFields | Listar los campos de la entidad |
Principios de diseño
- Cada herramienta es un método con una única responsabilidad
- Los nombres de parámetros coinciden con los del JSON Schema de
#[AsTool](mapeo automático) - Devuelven
array(convertido en texto de resultado de la herramienta)
Endpoints de API
POST /api/admin/ai/chat
{
"context": "view_editor",
"message": "Cámbialo a un diseño de tres columnas"
}Respuesta de éxito:
{
"code": 200,
"message": "success",
"data": { "reply": "Modificado a un diseño de tres columnas." }
}Archivos relacionados
| Archivo | Responsabilidad |
|---|---|
AiChatController.php | Recibe {context, message} y delega en el Provider correspondiente |
AiContextRegistry.php | Recopila los servicios etiquetados con app.ai_context, indexados por nombre |
AiAssistant.php | Fábrica de Agentes genérica |
LlmRouterPlatform.php | Puente de PlatformInterface (MessageBag ↔ array) |
ChatResultConverter.php | Convierte los datos de respuesta en TextResult/ToolCallResult |
ViewEditorToolProvider.php | Métodos Tool del editor de vistas |
ChromeDevToolsToolProvider.php | Herramientas de depuración del navegador CDP |
ViewFileToolProvider.php | Herramientas de lectura/escritura de archivos de vista |