KI-Kennzeichnung in TYPO3-Extensions: AI Label in die eigene Erweiterung einbauen

KI-Kennzeichnung in TYPO3-Extensions: AI Label in die eigene Erweiterung einbauen

Ihre Extension erzeugt einen Text, schreibt ihn nach tt_content, und damit endet die Spur. Monate später soll jemand sagen, welche Absätze aus einem Modell stammen und welche von einem Menschen, und die ehrliche Antwort lautet: das weiß niemand mehr. Dieses Problem hat jede KI-Funktion in TYPO3, und ein weiteres Häkchen in einem weiteren Backend-Formular löst es nicht.

AI Label in AI Foundation löst es einmal, für alle Erweiterungen einer Installation. AI Foundation ist quelloffen unter GPL-2.0-or-later, Ihre Extension kann die Schnittstelle also heute nutzen. So funktioniert KI-Kennzeichnung in TYPO3-Extensions von Anfang bis Ende: ein Event-Listener, ein Aufruf beim Speichern, ein ViewHelper im Template. Das Beispiel arbeitet mit EXT:news, weil die bei den meisten von uns produktiv läuft.

Die Pflicht dahinter ist Artikel 50 der EU KI-Verordnung, gültig seit dem 2. August 2026. Den Rahmen behandeln wir im Beitrag zur EU KI-Verordnung für TYPO3, den Redaktionsalltag im Beitrag zur KI-Kennzeichnungspflicht in TYPO3. Dieser Beitrag richtet sich an die Person, die die Extension schreibt.

Drei Dinge, und keines davon bauen Sie selbst. Ihre Extension bekommt einen Herkunftsnachweis am gerade gespeicherten Datensatz, einen Prüf- und Bestätigungsschritt für die Redaktion im AI-Label-Modul, und einen Besucherhinweis im Frontend, der aus dem bestätigten Zustand entsteht und die offiziellen Symbole der Europäischen Kommission verwendet. In einem Projekt mit Fluid Styled Content erscheint dieser Hinweis ganz ohne Template-Anpassung.

Sie schreiben das Mittelstück: die Zeile, die sagt "dieser Datensatz, jene Generierung". Alles links und rechts davon ist bereits da.

AufgabeWer sie trägtIhr Aufwand
Die Generierung speichernAI Foundation, automatischKeiner, das passiert in der Service-Schicht
Generierung und Datensatz verknüpfenIhre ExtensionEin Aufruf dort, wo die UID feststeht
Datenbankspalten auf der eigenen TabelleAI FoundationEin Event-Listener und eine Datenbankanalyse
Redaktionelle Prüfung, Bestätigung, RegelnAI FoundationKeiner
Besucherhinweis samt SymbolenAI FoundationEine Site-Set-Abhängigkeit oder ein ViewHelper
Nachweisexport für eine PrüfungAI FoundationKeiner
  • AI Foundation installiert. composer require nitsan/ns-t3af, danach aktivieren. Läuft auf TYPO3 v12 bis v14 mit PHP 8.2 oder neuer. Kostenlos und quelloffen, ohne Lizenzschlüssel, ohne Registrierung und ohne Domain-Limit, ausführlich im Beitrag zur kostenlosen KI-Erweiterung für TYPO3.
  • Eine Stelle, an der Ihre Extension KI-Ausgaben speichert. pages, tt_content und sys_file_metadata sind ab Werk vorgesehen. Für eine eigene Tabelle kommt ein Schritt dazu, siehe Schritt 1.
  • KI-Aufrufe über AI Foundation. Ruft Ihre Extension AiServiceInterface auf, wird die Generierung für Sie erfasst und trägt eine Korrelations-ID. Ruft sie einen Anbieter direkt auf, funktioniert trotzdem alles, Sie nehmen dann Schritt 3 statt Schritt 2.

Hinweis: Für AI Label brauchen Sie keinen konfigurierten KI-Anbieter. Die Kennzeichnung läuft ohne, eine Installation kann also damit anfangen, bevor sie mit allem anderen anfängt.

Erfassen passiert automatisch. Jede Generierung, die durch AI Foundation läuft, liegt in tx_nst3af_ailabel_generation, bevor Ihr Code das Ergebnis überhaupt sieht. Das ist Absicht und es ist die Entscheidung, die den Rest günstig macht: Die Erfassung sitzt in der Service-Schicht, in der die Generierung tatsächlich stattfindet, Datensatz und Generierung teilen sich eine Transaktion, und keine Extension muss daran denken, etwas zu melden.

Verknüpfen ist Ihre Aufgabe. Eine erfasste Generierung hängt noch an nichts, was ein Besucher sehen könnte. Nur Ihre Extension weiß, in welcher Datenbankzeile die Ausgabe gelandet ist, also kann auch nur sie diese Verbindung herstellen. Ein Aufruf, beim Speichern.

Die Ausgabe liest den bestätigten Zustand. Das Frontend fragt Ihre Extension nichts. Es liest die Spalten am Datensatz und die Einstellungen im Modul und entscheidet selbst, ob ein Hinweis fällig ist.

Warum das vor dem Code steht: Wenn Sie anfangen, an einem Dutzend Stellen Herkunft zu melden, sind Sie falsch abgebogen. Es gibt eine Stelle, und das ist die, an der Sie speichern.

pages, tt_content und sys_file_metadata tragen die AI-Label-Spalten bereits. Ihre eigene Tabelle melden Sie über CollectApplicableTablesEvent an.

use NITSAN\NsT3AF\AiLabel\Event\CollectApplicableTablesEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;

#[AsEventListener]
final class RegisterNewsTableForAiLabel
{
    public function __invoke(CollectApplicableTablesEvent $event): void
    {
        $event->addTable('tx_news_domain_model_news');
    }
}

Dasselbe geht ohne Code in AI Label, Einstellungen, anwendbare Tabellen oder über $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['ns_t3af']['ailabelApplicableTables']. Das Event nehmen Sie, wenn die Tabelle zu Ihrer Extension gehört und überall dort registriert sein soll, wo die Extension installiert ist.

AI Foundation steuert daraufhin die Spaltendefinitionen für diese Tabelle bei. Ihr Datensatz bekommt eigene Herkunftsfelder, darunter tx_nst3af_ailabel_involvement, tx_nst3af_ailabel_recording_source, tx_nst3af_ailabel_confirmed_by und tx_nst3af_ailabel_confirmed_at. Sie sind der Nachweis, und sie liegen am Datensatz statt in einer Nebentabelle. Genau deshalb bleiben sie beim Inhalt, auch durch eine Kopie, einen Workspace oder einen Export hindurch.

Hinweis: Nach dem Hinzufügen einer Tabelle führen Sie Wartung, Datenbankstruktur analysieren aus. Die Spalten kommen als Schema-Fragmente dazu, vorher existieren sie nicht, und jeder Aufruf aus Schritt 2 sieht aus, als hätte er stillschweigend nichts getan.

Rufen Sie AiLabelBindHelper an der Stelle auf, an der die endgültige UID feststeht, also nachdem der DataHandler oder Ihr Repository gespeichert hat.

use NITSAN\NsT3AF\AiLabel\Service\AiLabelBindHelper;

// nach DataHandler oder Repository
AiLabelBindHelper::bindContentRecord($uid, 'my_extension');
AiLabelBindHelper::bindPageRecord($uid, 'my_extension');
AiLabelBindHelper::bindFileMetadata($metaUid, 'my_extension');
AiLabelBindHelper::bindRecord('tx_news_domain_model_news', $uid, 'my_extension');

Übergeben Sie Ihren eigenen Extension-Key als Quelle. Er wird als Erfassungsquelle gespeichert, er steht im Nachweisexport, den eine Prüfung zu sehen bekommt, und die Regeln zur automatischen Bestätigung im Modul greifen darauf zu. Ein beliebiger Wert kostet Sie heute nichts und den Betreiber später eine Erklärung.

Beide Fälle erledigt der Helper selbst. Liegt im aktuellen Request eine Korrelations-ID vor, verknüpft er die gespeicherte Generierung mit Ihrer Zeile. Liegt keine vor, etwa weil das Speichern in einem Folge-Request nach asynchroner Dateiverarbeitung passiert, schreibt er die Herkunft direkt. Sie brauchen dafür keine Fallunterscheidung.

Soll die Anbindung optional bleiben, sichern Sie sie ab. Eine Klassenprüfung genügt, damit Ihre Extension auch ohne AI Foundation weiterläuft.

if ($uid <= 0 || !class_exists(AiLabelBindHelper::class)) {
    return;
}

AiLabelBindHelper::bindContentRecord($uid, 'my_extension');

Genau diese Prüfung verwendet unsere eigene Referenz-Extension. EXT:ns_t3af_extended auf GitHub ist ein öffentliches Repository, das jeden Integrationspunkt vorführt, und sein T3afExtendedAiLabelBinder ist diese Anleitung in zwanzig Zeilen, mit ns_t3af_extended als Erfassungsquelle. Sein MCP-Tool t3af_extended_summarize_content schreibt eine Zusammenfassung nach tt_content und verknüpft sie im selben Request. Schneller können Sie eine Verknüpfung im Modul nicht ankommen sehen, ohne selbst etwas zu schreiben.

Eine Falle, die einen Namen verdient. bindFileMetadata() kennt den Schalter altTextOnly. Setzen Sie ihn, wenn sich nur Metadatentexte geändert haben, also Alternativtext, Titel oder Beschreibung, und lassen Sie ihn weg, wenn die Datei selbst generiert wurde.

// Der Alternativtext wurde generiert. Das Foto nicht.
AiLabelBindHelper::bindFileMetadata($metaUid, 'my_extension', altTextOnly: true);

Ein Foto, dessen Alternativtext ein Modell geschrieben hat, ist kein KI-generiertes Bild. Wer es trotzdem so stempelt, trifft eine Aussage über die eigene Redaktion, die nicht stimmt. Zu viel zu kennzeichnen ist ebenso eine Aussage wie zu wenig.

Spricht Ihre Extension direkt mit einem Anbieter, gibt es keine Erfassung zum Verknüpfen. Dann melden Sie die Herkunft selbst über die öffentliche Schnittstelle.

use NITSAN\NsT3AF\AiLabel\Domain\Involvement;
use NITSAN\NsT3AF\Api\AiLabelRecorderInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;

$recorder = GeneralUtility::makeInstance(AiLabelRecorderInterface::class);
$recorder->recordOrigin(
    'tt_content',
    $uid,
    Involvement::AiGenerated,
    'my_extension',
    aiSystem: 'gpt-4',
    aiVendor: 'openai',
);

AiLabelRecorderInterface bringt außerdem drei Kurzwege mit, markGenerated(), markModified() und clearInvolvement(). Jeder von ihnen setzt die Bestätigung zurück, weil sich der Inhalt geändert hat. Alle drei werfen \InvalidArgumentException, wenn die Tabelle nicht registriert ist, und das ist der Fehler, den Sie sich wünschen: Eine nicht registrierte Tabelle ist ein Konfigurationsfehler und nichts, was man verschlucken sollte.

WertWann er gilt
not_reviewedStandard. Noch hat niemand aus der Redaktion entschieden
no_aiDie Redaktion stellt fest, dass keine KI beteiligt war
ai_generatedDer Inhalt ist im Wesentlichen von einer KI erstellt
ai_modifiedEine KI hat vorhandenen Inhalt verändert
origin_unknownDie Rolle der KI lässt sich nicht mehr feststellen
suggestionDas System hat erkannt oder vorgeschlagen, ein Mensch hat noch nicht geprüft

Eine Verknüpfung aus einer Kind-Extension speichert immer ai_generated. Die Redaktion kann das später im Modul ändern, und das ist die richtige Richtung: Ihr Code meldet, was passiert ist, ein Mensch entscheidet, was es bedeutet.

In einem Projekt mit Fluid Styled Content sind der Hinweis am Inhaltselement und die Bild-Überlagerung bereits vorhanden, sobald das TypoScript geladen ist. Zu den ViewHelpern greifen Sie erst, wenn Sie Datensätze selbst ausgeben.

Das Site Set, ab TYPO3 v13.4

Nehmen Sie das Site Set in Ihr Sitepackage auf und importieren Sie sein Setup.

dependencies:
  - nitsan/ns-t3af-label
@import 'EXT:ns_t3af/Configuration/TypoScript/setup.typoscript'

Der zweite Block ist nicht optional, und er ist der, der übersehen wird. Ein Site Set als Abhängigkeit zu führen lädt sein TypoScript nicht mit. Bei klassischen Templates binden Sie stattdessen das statische Template "AI Foundation labels" ein oder importieren dieselbe Datei.

Den Hinweis in Fluid ausgeben

Den Namensraum ail registriert AI Foundation, Ihr Template kann ihn also direkt verwenden.

<html xmlns:ail="http://typo3.org/ns/NITSAN/NsT3AF/AiLabel/ViewHelpers"
      data-namespace-typo3-fluid="true">
    <ail:label record="{data}" table="tt_content" />
    <ail:label file="{file}" />
</html>

Den Zustand lesen, statt ihn auszugeben

Wenn Sie den Zustand ohne fertiges Markup brauchen, weil Ihr Design den Hinweis an einer eigenen Stelle platziert, weisen Sie ihn zu und lesen ihn aus.

<ail:recordState record="{data}" table="tt_content" as="labelState" />
<f:if condition="{labelState.showLabel}">
    <p class="ai-notice">{labelState.involvementKey}</p>
</f:if>

<ail:fileState file="{image}" as="labelState" />

Das Objekt trägt die Art der KI-Beteiligung, ob ein Mensch bestätigt hat, ob überhaupt ein Hinweis fällig ist, und den Grund für diese Entscheidung.

Derselbe Zustand aus TypoScript

Wer aus TypoScript statt aus einem Template heraus ausgibt, bekommt denselben Zustand über den DataProcessor-Alias nst3af-label.

tt_content {
    dataProcessing {
        1550 = nst3af-label
        1550 {
            as = labelState
        }
    }
}

Achten Sie darauf, was in keinem der vier Schritte passiert ist: Keiner hat einem Besucher einen Hinweis angezeigt. Eine Verknüpfung hält Herkunft fest. Der Hinweis erscheint erst, wenn ein Mensch bestätigt, oder wenn eine Regel bestätigt, die der Betreiber dafür eingerichtet hat.

Diese Grenze ist keine Hürde, um die herum man entwickelt. Ein Hinweis auf einer veröffentlichten Seite ist eine Aussage über die Redaktion, die dahintersteht, und eine Extension ist nicht in der Lage, sie zu treffen. Wer die Website betreibt, ist im Sinne der Verordnung der Betreiber, und im Bestätigungsschritt sitzt genau diese Verantwortung. Ihre Aufgabe ist es, dafür zu sorgen, dass die bestätigende Person etwas Wahres vor sich hat.

AI Foundation stellt die technischen Voraussetzungen für Compliance bereit, ersetzt jedoch keine rechtliche Prüfung. Ob ein bestimmter Inhalt auf einer bestimmten Website eine Pflicht auslöst, gehen wir gern gemeinsam mit Ihnen durch, und es ist keine Frage, die ein ViewHelper beantwortet.

AI Foundation steht unter GPL-2.0-or-later, im TYPO3 Extension Repository und auf GitHub, gepflegt vom NITSAN-Team hinter T3Planet. Für die Anbindung oben heißt das ganz praktisch: Sie können die Klasse lesen, die Sie aufrufen, bevor Sie sie aufrufen. AiLabelBindHelper hat achtzig Zeilen. AiLabelRecorderInterface ist die gesamte öffentliche Oberfläche, in einer Datei. Die Unit-Tests zu AI Label liegen in Tests/Unit/AiLabel/, und sie sind der schnellste Weg herauszufinden, was eine Regel wirklich tut.

Es heißt außerdem, dass diese Schnittstelle keine private Abmachung zwischen unseren eigenen Erweiterungen ist. Jede TYPO3-Extension, die Inhalte erzeugt, kann Herkunft darüber melden, und eine Website mit drei solchen Erweiterungen bekommt eine Prüfansicht statt drei. Genau das würden wir am liebsten entstehen sehen. Es ist auch der Grund, warum die Schnittstelle ein veröffentlichter Vertrag ist und kein interner Service.

Wenn bei Ihrer Anbindung etwas fehlt, ist der Issue-Tracker von AI Foundation auf GitHub die richtige Adresse, und Pull Requests sind willkommen. Wer lieber vorher spricht: Die Erweiterung hat einen eigenen Kanal im TYPO3 Slack.

AI Foundation entdecken

Zum Verknüpfen ja, Ihr Code ruft deren Klassen auf. Schritt 2 zeigt die eine Zeile, die sie optional macht.

Es funktioniert trotzdem. Ihnen fehlt die automatische Erfassung, also nehmen Sie recordOrigin() aus Schritt 3 und übergeben System und Anbieter selbst.

pages, tt_content und sys_file_metadata ab Werk, dazu jede Tabelle, die Sie über CollectApplicableTablesEvent, den Einstellungen-Tab oder das EXTCONF-Array registrieren. Danach die Datenbankstruktur analysieren.

Nein. Die Verknüpfung hält die Herkunft fest. Für den Hinweis braucht es eine Bestätigung, aus der Redaktion oder aus einer Regel, die der Betreiber aktiviert hat.

Nein. Die Kennzeichnung läuft ohne.

TYPO3 v12 bis v14 mit PHP 8.2 oder neuer. Das Site Set aus Schritt 4 setzt v13.4 voraus, auf älteren Installationen binden Sie stattdessen das statische Template ein.

Möchten Sie Ihr AI Universe Produkt individuell anpassen?

Entdecken Sie KI-gestützte TYPO3-Lösungen im T3Planet Shop und passen Sie diese an die Anforderungen Ihres Projekts an.

  • 5+ KI-Extensions
  • 4500+ Downloads insgesamt
  • 200+ individuell entwickelte Funktionen
  • 15+ Jahre Erfahrung
AI Universe entdecken
TYPO3 AI

Post a Comment

×