Skip to content

AI-Assistent

Doggy stellt einen globalen AI-Assistenten bereit, der als schwebender Button + seitliches Panel auf allen Seiten verfügbar ist, über einen Kontext-Registrierungsmechanismus tief in die Seiten integriert wird und eine ReAct-Inferenzschleife sowie Tool-Aufrufe unterstützt.

Übersicht

Der AI-Assistent basiert auf dem Technologie-Stack symfony/ai-agent + symfony/ai-platform und bindet an das eigene LlmRouter-Gateway-System der Plattform an:

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

Globaler Einstiegspunkt

Das Panel des AI-Assistenten wird in templates/base.html.twig bedingungslos eingebunden:

twig
<body>
    {% block body %}{% endblock %}
    {% include 'admin/ai_chat.html.twig' %}
</body>
  • Öffnen/Schließen: Schwebender Button unten rechts toggle-ai-chat / ai-chat-close
  • Eingabe: Enter sendet, Shift+Enter erzeugt einen Zeilenumbruch
  • Ladezustand: Die Eingabe wird während der Anfrage deaktiviert, Anzeige "Denke nach..."
  • Stil: public/sunui/admin/ai_chat.css

Kontext-Registrierung der Seiten

Jede Seite registriert über window.__AI_CONTEXT__ einen Kontext beim Assistenten:

js
window.__AI_CONTEXT__ = {
    name: 'view_editor',                  // 后端 AiContextProviderInterface::getName()
    buildPrompt: function(msg) {          // 可选,构造发送给后端的消息
        return '[当前视图ID: xxx]\n\n' + msg;
    },
};

Registrierungsbeispiel des View-Editors:

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>

System der Kontext-Anbieter

AiContextProviderInterface definiert die Kontext-Anbieter:

php
namespace App\Service\AI\Runtime;

interface AiContextProviderInterface
{
    public function getName(): string;                    // 上下文标识
    public function getRoleCode(): string;                // LlmRouter 角色代码
    public function getSystemPrompt(): string;            // Agent 系统提示词
    public function getToolProviders(): array;            // Tool 对象数组
}

Registrierung über das app.ai_context-Tag:

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

Seitenkontext hinzufügen

  1. Klasse erstellen, die AiContextProviderInterface implementiert
  2. In services.yaml tags: [{ name: 'app.ai_context' }] hinzufügen
  3. Im Seiten-Template window.__AI_CONTEXT__ = { name: 'your_name' } setzen

Agent-Laufzeit

AiAssistant ist eine generalisierte Agent-Factory, die bei jedem chat() eine unabhängige Agent-Instanz erstellt, um Zustandsverschmutzung zu vermeiden:

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',
);

ReAct-Schleife

AgentProcessor fungiert gleichzeitig als Ein- und Ausgabeprozessor und realisiert die Tool-Aufruf-Schleife:

  • processInput: Injiziert die Tool-Metadaten des Toolbox
  • processOutput: Wenn das Ergebnis ToolCallResult ist:
    1. ToolCall-Array in die MessageBag aufnehmen
    2. ToolCall ausführen → ToolResult in die MessageBag zurückschreiben
    3. Rekursiv aufrufen, bis ein TextResult zurückgegeben wird

Tool-System

Tool-Methoden werden über das Attribut #[AsTool] von symfony/ai-agent markiert:

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 { ... }
}

Aktuelle View-Editor-Tools

ToolFunktion
view.getInfoAnsichtsinformationen abrufen (Entität, Felder, Layout)
view.updateSectionConfigLayout-Konfiguration aktualisieren
view.updateFieldConfigFeldkonfiguration aktualisieren
view.listEntityFieldsEntitätsfelder auflisten

Design-Prinzipien

  • Jedes Tool ist eine Methode mit einer einzigen Verantwortung
  • Parameternamen stimmen mit den JSON-Schema-Parameternamen von #[AsTool] überein (automatische Zuordnung)
  • Gibt array zurück (wird in Tool-Ergebnistext umgewandelt)

API-Endpunkte

POST /api/admin/ai/chat

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

Erfolgreiche Antwort:

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

Zugehörige Dateien

DateiVerantwortung
AiChatController.phpEmpfängt {context, message} und delegiert an den passenden Provider
AiContextRegistry.phpSammelt app.ai_context-Tag-Dienste, indexiert nach Name
AiAssistant.phpGeneralisierte Agent-Factory
LlmRouterPlatform.phpPlatformInterface-Brücke (MessageBag ↔ Array)
ChatResultConverter.phpAntwortdaten → TextResult/ToolCallResult
ViewEditorToolProvider.phpTool-Methoden des View-Editors
ChromeDevToolsToolProvider.phpCDP-Browser-Debugging-Tools
ViewFileToolProvider.phpLese-/Schreibtools für Ansichtsdateien

Open Source unter MIT | Copyright © 2026 Doggy