Artikel

19. Kommentarlogik

Allgemein

Die Kommentarlogik entscheidet, ob eine Reaktion überhaupt sinnvoll ist und welche Art von Kommentar erzeugt werden darf.

Kommentare sind riskanter als eigene Beiträge, weil sie in fremden Kontexten stehen. Deshalb gilt:

Lieber kein Kommentar als ein generischer Kommentar.

Das System soll keine Präsenz simulieren. Es soll nur dann einen Vorschlag erzeugen, wenn ein fachlicher Zusatz möglich ist.

19.1 Wann kommentieren

Ein Kommentar ist sinnvoll, wenn mindestens einer dieser Punkte zutrifft:

Der Beitrag behandelt Bücher, Verlage, E-Books, KI, Automatisierung oder digitale Kultur.
Der Beitrag berührt ein Thema, zu dem der Verlag eine fachliche Perspektive hat.
Der Kommentar kann einen konkreten Zusatz liefern.
Der Kommentar kann eine sachliche Beobachtung ergänzen.
Der Kommentar wirkt auch ohne Link oder Eigenwerbung sinnvoll.

Geeignete Themen:

Buchmarkt
digitale Verlagsarbeit
E-Book-Produktion
Metadaten
Public Domain
KI in der Produktion
Automatisierung
Auffindbarkeit kleiner Anbieter
Plattformabhängigkeit
Selfpublishing vs. Verlag
digitale Distribution

Beispiel:

Beitrag:
Kleine Anbieter haben oft gute Produkte, aber zu wenig Sichtbarkeit.

Kommentar:
Der Punkt ist im Buchmarkt ähnlich. Technisch kann ein Angebot sehr gut sein, aber Auffindbarkeit entscheidet oft früher als Qualität.

Der Kommentar enthält einen eigenen Gedanken. Er verkauft nichts.

19.2 Wann nicht kommentieren

Nicht kommentieren bei:

politischen Debatten
persönlichen Konflikten
Shitstorms
Empörungsthemen
reinen Selbstdarstellungen
privaten Lebensereignissen
medizinischen Themen
juristischen Einzelfällen
reinen Verkaufsbeiträgen anderer Anbieter
unklarem Kontext
zu wenig fachlichem Bezug

Technische Regel:

Wenn kein konkreter fachlicher Zusatz möglich ist, Ergebnis NO_COMMENT.

Prompt-Regel:

Wenn der Kommentar nur Zustimmung, Lob oder eine Floskel wäre, gib exakt NO_COMMENT zurück.

Beispiele für Ablehnung:

Toller Beitrag!
Danke fürs Teilen.
Spannender Gedanke.
Sehe ich genauso.
Sehr wichtiges Thema.

Diese Kommentare sind formal harmlos, aber wertlos.

19.3 Kommentararten

Das System unterscheidet mehrere Kommentararten.

fachlicher Zusatz
präzisierende Ergänzung
kurzer Erfahrungsbezug
vorsichtiger Widerspruch
Rückfrage
Antwort auf Kommentar unter eigenem Beitrag

Fachlicher Zusatz

Der Punkt zur Sichtbarkeit kleiner Anbieter ist im Buchmarkt ähnlich. Gute digitale Ausgaben scheitern selten an der Technik, häufiger an Auffindbarkeit und Metadaten.

Präzisierende Ergänzung

Bei E-Books kommt noch ein technischer Punkt hinzu: Die eigentliche Qualität liegt oft nicht im sichtbaren Text, sondern in Struktur, Metadaten und sauberem EPUB.

Kurzer Erfahrungsbezug

Aus Verlagssicht ist genau diese Wiederholbarkeit entscheidend. Einzelne gute Inhalte helfen wenig, wenn der Produktions- und Veröffentlichungsprozess nicht stabil ist.

Vorsichtiger Widerspruch

Ich würde den Punkt etwas anders gewichten: Nicht nur die Erstellung ist das Problem, sondern die dauerhafte Pflege der Daten und Formate.

Rückfrage

Interessant wäre, ob hier eher die technische Umsetzung oder die interne Zuständigkeit der Engpass ist.

Antwort auf eigenen Kommentarbereich

Ja, genau. Bei gemeinfreien Texten ist der Rohtext nur der Anfang. Die eigentliche Arbeit liegt oft in Korrektur, Struktur und Metadaten.

19.4 Fachlicher Zusatz

Ein Kommentar braucht einen Mehrwert.

Er sollte mindestens eines leisten:

einen fachlichen Zusammenhang herstellen
eine praktische Erfahrung ergänzen
einen Begriff präzisieren
eine Folge benennen
einen blinden Fleck sichtbar machen
eine sachliche Rückfrage stellen

Nicht ausreichend:

Zustimmung
Lob
Dank
allgemeines Interesse
Wiederholung des Beitrags

Prüflogik:

class CommentValuePolicy:
    def has_minimum_value(self, comment_text: str) -> bool:
        lowered_text = comment_text.lower()

        weak_fragments = [
            "toller beitrag",
            "spannender beitrag",
            "danke fürs teilen",
            "sehe ich genauso",
            "sehr interessant",
            "wichtiges thema",
        ]

        for fragment in weak_fragments:
            if fragment in lowered_text:
                return False

        if len(comment_text.strip()) < 80:
            return False

        return True

19.5 Keine generischen Komplimente

Generische Komplimente sind ein typisches Bot-Signal.

Blockierte Muster:

Toller Beitrag
Sehr spannend
Danke fürs Teilen
Wichtiger Punkt
Super erklärt
Sehe ich genauso
Interessanter Gedanke

Validator:

class GenericComplimentValidator:
    def __init__(self) -> None:
        self.blocked_fragments = [
            "toller beitrag",
            "sehr spannender beitrag",
            "spannender beitrag",
            "danke fürs teilen",
            "wichtiger punkt",
            "super erklärt",
            "sehe ich genauso",
            "interessanter gedanke",
            "sehr interessant",
        ]

    def validate(self, text: str) -> None:
        lowered_text = text.lower()

        for fragment in self.blocked_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Generic compliment found: " + fragment)

Regel für den Prompt:

Kein Kommentar darf nur Lob oder Zustimmung ausdrücken. Wenn kein konkreter Zusatz möglich ist: NO_COMMENT.

19.6 Keine Verkaufslinks

Kommentare enthalten keine Verkaufslinks.

Nicht erlaubt:

Shoplink
Buchlink
Bloglink
Newsletterlink
Profilaufforderung
DM-Aufforderung

Auch indirekte Verkaufsformen werden blockiert:

finden Sie in meinem Shop
bei mir erhältlich
mehr dazu auf meiner Seite
Link im Profil
schreiben Sie mir

Validator:

class CommentLinkValidator:
    def validate(self, text: str) -> None:
        lowered_text = text.lower()

        blocked_fragments = [
            "https://",
            "http://",
            "www.",
            "mein shop",
            "meine seite",
            "link im profil",
            "bei mir erhältlich",
            "schreiben sie mir",
            "dm",
            "pn",
        ]

        for fragment in blocked_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Comment contains blocked link or CTA fragment: " + fragment)

Zulässig ist ein fachlicher Bezug ohne Link:

Bei gemeinfreien Klassikern ist der Text frei, aber die digitale Ausgabe bleibt Arbeit: Korrektur, Struktur, Metadaten und Formatqualität entscheiden stark über die Nutzbarkeit.

19.7 Keine politischen Debatten

Politische Debatten werden ausgeschlossen, auch wenn ein Kommentar fachlich möglich wäre.

Grund:

hohes Eskalationsrisiko
geringer Nutzen für den Verlag
schlechter Kontext für Buchmarketing
unklare Anschlusskommunikation

Blockierte Themen:

Parteien
Wahlen
Krieg
Migration
Nahost
Ukraine/Russland
Pandemie
Verschwörungsthemen
Extremismus
Tagesaufreger

Validator:

class PoliticalTopicValidator:
    def __init__(self) -> None:
        self.blocked_fragments = [
            "afd",
            "cdu",
            "spd",
            "grüne",
            "fdp",
            "bsw",
            "wahl",
            "bundestag",
            "regierung",
            "krieg",
            "ukraine",
            "russland",
            "israel",
            "palästina",
            "gaza",
            "migration",
            "flüchtlinge",
            "corona",
            "impfung",
            "verschwörung",
            "nazi",
            "hitler",
        ]

    def validate_source(self, source_text: str) -> None:
        lowered_text = source_text.lower()

        for fragment in self.blocked_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Political or high-risk topic found: " + fragment)

Bei politischem Kontext:

NO_COMMENT

Keine Begründung notwendig.

19.8 Ähnlichkeitsprüfung

Das System darf nicht immer denselben Kommentarstil erzeugen.

Zu prüfen:

identischer Kommentar
ähnliche Formulierung
gleicher Einstieg
gleicher fachlicher Punkt
zu häufige Wiederholung derselben Begriffe

Einfache Jaccard-Prüfung:

class CommentSimilarityValidator:
    def validate(
        self,
        new_comment: str,
        previous_comments: list[str],
        max_similarity: float,
    ) -> None:
        new_words = self._words(new_comment)

        for previous_comment in previous_comments:
            previous_words = self._words(previous_comment)
            similarity = self._jaccard(new_words, previous_words)

            if similarity >= max_similarity:
                raise CommentGeneratorError("Comment is too similar to previous comment.")

    def _words(self, text: str) -> set[str]:
        lowered_text = text.lower()
        cleaned_text = ""

        for character in lowered_text:
            if character.isalnum() is True or character == " ":
                cleaned_text = cleaned_text + character
            else:
                cleaned_text = cleaned_text + " "

        return set(cleaned_text.split())

    def _jaccard(self, left_words: set[str], right_words: set[str]) -> float:
        if len(left_words) == 0 and len(right_words) == 0:
            return 1.0

        intersection = left_words.intersection(right_words)
        union = left_words.union(right_words)

        return len(intersection) / len(union)

Empfohlener Schwellenwert:

0.55

Zusätzlich können typische Einstiege begrenzt werden:

class CommentOpeningValidator:
    def __init__(self) -> None:
        self.blocked_openings = [
            "der punkt",
            "genau dieser punkt",
            "aus verlagssicht",
            "bei e-books",
        ]

    def validate(self, new_comment: str, previous_comments: list[str]) -> None:
        normalized_new_comment = new_comment.lower().strip()

        for opening in self.blocked_openings:
            if normalized_new_comment.startswith(opening) is False:
                continue

            count = 0

            for previous_comment in previous_comments:
                normalized_previous_comment = previous_comment.lower().strip()

                if normalized_previous_comment.startswith(opening):
                    count += 1

            if count >= 2:
                raise CommentGeneratorError("Comment opening used too often: " + opening)

19.9 Beispiel: comment_generator.py

Datei:

src/comment_generator.py

from dataclasses import dataclass


class CommentGeneratorError(Exception):
    pass


@dataclass(frozen=True)
class CommentGenerationRequest:
    source_text: str
    publisher_context: str
    previous_comments: list[str]


@dataclass(frozen=True)
class CommentGenerationResult:
    status: str
    comment_text: str | None
    reason: str | None


class PoliticalTopicValidator:
    def __init__(self) -> None:
        self.blocked_fragments = [
            "afd",
            "cdu",
            "spd",
            "grüne",
            "fdp",
            "bsw",
            "wahl",
            "bundestag",
            "regierung",
            "krieg",
            "ukraine",
            "russland",
            "israel",
            "palästina",
            "gaza",
            "migration",
            "flüchtlinge",
            "corona",
            "impfung",
            "verschwörung",
            "nazi",
            "hitler",
        ]

    def validate_source(self, source_text: str) -> None:
        lowered_text = source_text.lower()

        for fragment in self.blocked_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Political or high-risk topic found: " + fragment)


class GenericComplimentValidator:
    def __init__(self) -> None:
        self.blocked_fragments = [
            "toller beitrag",
            "sehr spannender beitrag",
            "spannender beitrag",
            "danke fürs teilen",
            "wichtiger punkt",
            "super erklärt",
            "sehe ich genauso",
            "interessanter gedanke",
            "sehr interessant",
        ]

    def validate(self, text: str) -> None:
        lowered_text = text.lower()

        for fragment in self.blocked_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Generic compliment found: " + fragment)


class CommentLinkValidator:
    def validate(self, text: str) -> None:
        lowered_text = text.lower()

        blocked_fragments = [
            "https://",
            "http://",
            "www.",
            "mein shop",
            "meine seite",
            "link im profil",
            "bei mir erhältlich",
            "schreiben sie mir",
            "dm",
            "pn",
        ]

        for fragment in blocked_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Comment contains blocked link or CTA fragment: " + fragment)


class CommentValuePolicy:
    def validate(self, comment_text: str) -> None:
        cleaned_text = comment_text.strip()

        if cleaned_text == "":
            raise CommentGeneratorError("Comment text must not be empty.")

        if len(cleaned_text) < 80:
            raise CommentGeneratorError("Comment text is too short.")

        if len(cleaned_text) > 500:
            raise CommentGeneratorError("Comment text is too long.")

        weak_fragments = [
            "toller beitrag",
            "spannender beitrag",
            "danke fürs teilen",
            "sehe ich genauso",
            "sehr interessant",
            "wichtiges thema",
        ]

        lowered_text = cleaned_text.lower()

        for fragment in weak_fragments:
            if fragment in lowered_text:
                raise CommentGeneratorError("Comment has no sufficient fachlicher Zusatz: " + fragment)


class CommentSimilarityValidator:
    def validate(
        self,
        new_comment: str,
        previous_comments: list[str],
        max_similarity: float,
    ) -> None:
        new_words = self._words(new_comment)

        for previous_comment in previous_comments:
            previous_words = self._words(previous_comment)
            similarity = self._jaccard(new_words, previous_words)

            if similarity >= max_similarity:
                raise CommentGeneratorError("Comment is too similar to previous comment.")

    def _words(self, text: str) -> set[str]:
        lowered_text = text.lower()
        cleaned_text = ""

        for character in lowered_text:
            if character.isalnum() is True or character == " ":
                cleaned_text = cleaned_text + character
            else:
                cleaned_text = cleaned_text + " "

        return set(cleaned_text.split())

    def _jaccard(self, left_words: set[str], right_words: set[str]) -> float:
        if len(left_words) == 0 and len(right_words) == 0:
            return 1.0

        intersection = left_words.intersection(right_words)
        union = left_words.union(right_words)

        return len(intersection) / len(union)


class CommentOpeningValidator:
    def __init__(self) -> None:
        self.blocked_openings = [
            "der punkt",
            "genau dieser punkt",
            "aus verlagssicht",
            "bei e-books",
        ]

    def validate(self, new_comment: str, previous_comments: list[str]) -> None:
        normalized_new_comment = new_comment.lower().strip()

        for opening in self.blocked_openings:
            if normalized_new_comment.startswith(opening) is False:
                continue

            count = 0

            for previous_comment in previous_comments:
                normalized_previous_comment = previous_comment.lower().strip()

                if normalized_previous_comment.startswith(opening):
                    count += 1

            if count >= 2:
                raise CommentGeneratorError("Comment opening used too often: " + opening)


class RuleBasedCommentDraftGenerator:
    def generate(self, source_text: str) -> str:
        lowered_text = source_text.lower()

        if "sichtbarkeit" in lowered_text:
            return (
                "Im Buchmarkt ist Sichtbarkeit oft der eigentliche Engpass. "
                "Eine digitale Ausgabe kann technisch sauber sein, aber ohne Metadaten, "
                "Auffindbarkeit und Wiederholung bleibt sie praktisch unsichtbar."
            )

        if "ki" in lowered_text or "automatisierung" in lowered_text:
            return (
                "Aus Verlagssicht ist Automatisierung vor allem dort sinnvoll, "
                "wo sie wiederkehrende Arbeit stabilisiert. Die Auswahl und Bewertung "
                "der Inhalte bleibt trotzdem der entscheidende menschliche Teil."
            )

        if "ebook" in lowered_text or "e-book" in lowered_text:
            return (
                "Bei E-Books liegt ein Teil der Qualität unter der Oberfläche: "
                "Struktur, saubere Metadaten und robuste Formate entscheiden stark darüber, "
                "ob ein Titel langfristig nutzbar bleibt."
            )

        if "public domain" in lowered_text or "gemeinfrei" in lowered_text:
            return (
                "Gemeinfrei bedeutet frei nutzbar, aber nicht automatisch veröffentlichungsfertig. "
                "Korrektur, typografische Bereinigung und digitale Struktur bleiben echte Arbeit."
            )

        return "NO_COMMENT"


class CommentGenerator:
    def __init__(self) -> None:
        self.political_topic_validator = PoliticalTopicValidator()
        self.generic_compliment_validator = GenericComplimentValidator()
        self.comment_link_validator = CommentLinkValidator()
        self.comment_value_policy = CommentValuePolicy()
        self.comment_similarity_validator = CommentSimilarityValidator()
        self.comment_opening_validator = CommentOpeningValidator()
        self.draft_generator = RuleBasedCommentDraftGenerator()

    def generate(self, request: CommentGenerationRequest) -> CommentGenerationResult:
        try:
            self.political_topic_validator.validate_source(request.source_text)

            raw_comment = self.draft_generator.generate(request.source_text)

            if raw_comment == "NO_COMMENT":
                return CommentGenerationResult(
                    status="rejected",
                    comment_text=None,
                    reason="NO_COMMENT",
                )

            self.generic_compliment_validator.validate(raw_comment)
            self.comment_link_validator.validate(raw_comment)
            self.comment_value_policy.validate(raw_comment)
            self.comment_similarity_validator.validate(
                new_comment=raw_comment,
                previous_comments=request.previous_comments,
                max_similarity=0.55,
            )
            self.comment_opening_validator.validate(
                new_comment=raw_comment,
                previous_comments=request.previous_comments,
            )

            return CommentGenerationResult(
                status="suggested",
                comment_text=raw_comment,
                reason=None,
            )
        except CommentGeneratorError as exception:
            return CommentGenerationResult(
                status="rejected",
                comment_text=None,
                reason=str(exception),
            )

Beispielaufruf

from src.comment_generator import CommentGenerationRequest
from src.comment_generator import CommentGenerator


def main() -> None:
    request = CommentGenerationRequest(
        source_text=(
            "Kleine Anbieter haben oft gute Produkte, aber zu wenig Sichtbarkeit. "
            "Das ist im digitalen Markt ein strukturelles Problem."
        ),
        publisher_context=(
            "Kleiner deutscher E-Book-Verlag mit Schwerpunkt gemeinfreie Klassiker, "
            "digitale Verlagsarbeit, EPUB, KI und Automatisierung."
        ),
        previous_comments=[
            "Bei E-Books liegt ein Teil der Qualität unter der Oberfläche: Struktur, saubere Metadaten und robuste Formate entscheiden stark darüber, ob ein Titel langfristig nutzbar bleibt."
        ],
    )

    generator = CommentGenerator()
    result = generator.generate(request)

    print(result)


if __name__ == "__main__":
    main()

Ergebnis dieses Kapitels

Die Kommentarlogik definiert jetzt:

wann kommentiert wird
wann nicht kommentiert wird
welche Kommentararten erlaubt sind
wie fachlicher Zusatz erzwungen wird
warum generische Komplimente blockiert werden
warum Verkaufslinks ausgeschlossen sind
warum politische Debatten ausgeschlossen sind
wie ähnliche Kommentare vermieden werden
wie ein Kommentarvorschlag technisch erzeugt und geprüft wird

Damit erzeugt das System keine automatische Gesprächigkeit, sondern eine kleine Zahl prüfbarer, fachlich anschlussfähiger Kommentarvorschläge.

0 Kommentare