Table of Contents | ||
---|---|---|
|
Zusammenfassung
Ziel war es, zu überprüfen, ob ein LLM in der Lage ist, die Neutralität von Bildungsinhalten (basierend auf Beschreibungs- und Volltexten) in vergleichbarer Form zu bewerten, wie dies durch menschliche Akteure geschieht.
Aus der von Fachredaktionen genutzten Skala zur Einschätzung der Neutralität wurde ein Prompt entwickelt. Dann wurden ki-gestützte Bewertungen von Inhalten gebildet, für die bereits eine Einschätzung der Neutralität vorlag. Dies erfolgte mit 2000 Datensätzen in 2 Testreihen. Testreihe 1 nutzte Beschreibungstexte der Inhalte und Testreihe 2 die von den Webseiten abgerufenen Volltexte. Anschließend wurden die Werte mit Hilfe verschiedener Metriken verglichen.
Die Volltexte hatten im Schnitt 4 mal mehr Zeichen als die Beschreibungstexte, zeigten aber in einigen Metriken eine höhere Betonung von Gefühlen und höhere Anforderungen an ihr Verständnis.
...
Abstract
In dieser Untersuchung wurde geprüft, ob ein Large Language Model (LLM) die Neutralität von Bildungsinhalten ähnlich wie menschliche Experten bewerten kann.
Dabei wurden 2000 Datensätze, bestehend aus Beschreibungstexten und Volltexten, mithilfe eines angepassten Prompts durch ein KI-Modell bewertet und die Ergebnisse mit bereits vorhandenen redaktionellen Bewertungen verglichen. Die Analyse zeigte, dass die KI-Bewertung, insbesondere bei kürzeren Beschreibungstexten, eine hohe Übereinstimmung mit den menschlichen Bewertungen aufwies (MAE = 0,62). Bei den längeren und komplexeren Volltexten hingegen fiel die Abweichung größer aus (MAE = 0,92). Mögliche Ursachen für das schlechtere Abschneiden der Volltexte können Bewertungen sein, die von den Fachredaktionen in die Texte eingeflossen sind oder eine höhere Textqualität gegenüber Volltexte (trotz geringerer Zeichenlänge). Dennoch zeigt die Untersuchung weiteren Forschungsbedarf auf, insbesondere in Bezug auf die Erfassung von komplexen Inhalten in Volltexten und die Entwicklung eines besseren Messinstruments.
Erstellung des Test-Datensatzes
Die Grundlage sind Datensätze mit Bildungsinhalten der Plattform www.Wirlernenonline.de.Für eine Teilmenge der Datensätze liegen Bewertungen für Neutralität vor. dieser Untersuchung bildeten 2000 Datensätze von Bildungsinhalten, die von der Plattform http://WirLernenOnline.de abgerufen wurden und für die bereits redaktionelle Bewertungen zur Neutralität vorlagen.
Diese wurden auf einer durch die Redaktionen aufgestellten Skala von 0 bis 5 bewertet und werden zur Qualitätseinschätzung genutzt5 eingeordnet, wobei 0 für manipulative oder verfassungswidrige Inhalte und 5 für vollständig neutrale und wissenschaftlich fundierte Inhalte steht.
...
Abruf der
...
Rohdaten
Die Daten wurden über die WLO RestREST-API -Schnittstelle mit der Customsuche abgerufen. Dazu wurde eine Kombination des Felds: der Plattform extrahiert. Dabei wurde das Feld cccm:oeh_quality_neutralness mit den Werten: 0, 1, 2, 3, 4, 5 genutzt. Der Datensatz wurde als genutzt, um Inhalte nach den vorhandenen Neutralitätsscores (0-5) zu filtern. Diese Daten wurden in einer JSON-Datei gespeichert und für die weitere Analyse vorbereitet.
Anreicherung der
...
Rohdaten mit Volltexten
In den Datensätzen sind Beschreibungstexte der Bildungsinhalte enthalten. Um einen Vergleich mit Volltexten durchführen zu können, wurden die URL aus dem Feld: ccm:wwwurl ausgelesen und die Inhalte der Webseiten extrahiert.
...
Bei Datensätzen, für die Goose3 keinen Volltext generieren konnte (z.B. aufgrund eines sehr kleinen Textkorpus), wurden die Zusammenfassungen genutzt, die von Goose3 aus allen verfügbaren Infos der Webseiten gebildet werden.
Filterung der Rohdaten
Aus den zuvor erstellten Rohdaten wurde ein Test-Datensatz erstellt, der die notwendigen Kriterien erfüllt, u.a. nicht-leere Felder für die im Test relevanten Metadaten sowie eine Mindestlänge der für den Test genutzten Textfelder (Beschreibungstexte und Volltexte). Dieser Schritt soll sicherstellen, dass ausreichend Textmaterial für eine Bewertung vorliegt.
Verarbeitungsschritte für den Datensatz:
...
Zusätzlich zu den Beschreibungstexten wurden Volltexte von den zugehörigen Webseiten der Bildungsinhalte abgerufen. Die URLs, die im Feld ccm:wwwurlgespeichert sind, wurden genutzt, um die Inhalte mittels der Python-Bibliothek Goose3 zu extrahieren (basiert auf beautifulsoup). Diese Bibliothek entfernt unnötige Textbestandteile und extrahiert den Hauptinhalt der Webseiten. Für Datensätze, bei denen keine vollständigen Texte erfasst werden konnten, wurden Zusammenfassungen genutzt, die auf den verfügbaren Informationen der Webseiten basieren.
Filterung der Rohdaten: Die Rohdaten wurden gefiltert, um sicherzustellen, dass alle relevanten Felder gefüllt und die Mindestlänge der für die Bewertung genutzten Textfelder gewährleistet ist. Dabei wurden folgende Kriterien angewendet:
Entfernt wurden Datensätze, bei denen folgende Felder leer waren:
properties.cclom:general_description (Beschreibungstexte)
additional_data.full_text (Volltexte)
properties.ccm:oeh_quality_neutralness (Neutralitäts-Score der Redaktionen)
...
Zusätzlich wurden Datensätze ausgeschlossen, deren Textfelder (Beschreibungstexte und Volltexte) weniger als 60 Zeichen umfassen, um ausreichend Material für eine sinnvolle Bewertung zu haben.
properties.cclom:general_description (Beschreibungstexte)
additional_data.full_text (Volltexte)
...
Schließlich wurde die Anzahl der Datensätze auf 2000
...
reduziert und normalisiert. Dabei wurden folgende Felder zur gleichmäßigen Verteilung einbezogen:
properties.ccm:oeh_quality_neutralness
...
(Neutralitäts-Score der Redaktionen)
properties.ccm:taxonid (Disziplinen)
...
(Disziplinen) berücksichtigt, um eine ausgewogene Stichprobe der Bildungsinhalte aus unterschiedlichen Fachbereichen zu gewährleisten. Ein Round-Robin-Verfahren wurde angewandt, um sicherzustellen, dass die Disziplinen gleichmäßig vertreten sind.
Eine Gleichverteilung ist jedoch auf Grund der vorübergehend gut bewerteten Inhalte nur bedingt möglich.
LLM und Prompt
LLM-Model
Für den Test die Bewertung der Neutralität von Bildungsinhalten wurde ein aktuelles LLM-Model genutzt, das aufgrund seiner niedrigen Kosten praxisnah ist: Large Language Model (LLM) verwendet. Das Modell,gpt-4o-mini (openai).
Der Test kann auch mit den meisten anderen LLM durchgeführt werden, jedoch ohne zwangsläufig die gleichen Ergebnisse zu erzielen. Ein Test mit weiteren Modelle erscheint sinnvoll.
Es ist davon auszugehen, dass ein erneuter Durchlauf mit dem gleichen Model auch nicht immer die gleichen Ergebnisse liefern wird.
Promptentwicklung
Grundlage des Prompts ist die zuvor genannte redaktionelle Skala. Diese wurde ausformuliert, um dem LLM eine genauere Einschätzung der Stufen zu ermöglichen.
Anschließend wurde der Prompt mit dem Promptverbesserungs-Tool “Generate” auf dem openai Playground verbessert (https://platform.openai.com/playground/chat ). Dieses strukturiert den Prompt maschinenlesbar, fügt Markdown-Formatierungen und passende Rückfragen zur Selbstreflexion hinzu.
Neben dem Scoring soll der Prompt auch eine kurze Begründung seiner Bewertung ausgeben, um die Ergebnisse später nachprüfen zu könnenOpenAI), wurde ausgewählt, da es aufgrund seiner Effizienz und geringen Kosten eine praxisnahe Lösung darstellt. Das gleiche Experiment könnte auch mit anderen LLMs durchgeführt werden, allerdings können die Ergebnisse von Modell zu Modell variieren. Es wird davon ausgegangen, dass sogar mit dem gleichen Modell bei wiederholten Tests leicht unterschiedliche Ergebnisse auftreten könnten.
Promptentwicklung
Die Grundlage für den entwickelten Prompt war die redaktionelle Skala (0-5), die zur Bewertung der Neutralität von Bildungsinhalten auf der Plattform http://WirLernenOnline.de verwendet wird. Diese Skala reicht von 0 (manipulativ oder verfassungswidrig) bis 5 (vollständig neutral und wissenschaftlich fundiert). Der Prompt wurde so gestaltet, dass das LLM die Inhalte auf dieser Skala bewerten kann.
Um den Bewertungsprozess zu verbessern, wurde der Prompt auf dem OpenAI Playground mit dem Tool „Generate“ optimiert. Diese Optimierung fügte strukturierte Markdown-Formatierungen und Rückfragen zur Selbstreflexion hinzu, sodass das LLM seine Bewertung fundiert und nachvollziehbar gestalten konnte.
Der entwickelte Prompt dient nicht nur dazu, eine numerische Bewertung der Neutralität abzugeben, sondern fordert das LLM auch auf, eine kurze Begründung für die gewählte Bewertung zu liefern. Diese Begründung ermöglicht es, die Ergebnisse später zu überprüfen und die Entscheidungsfindung der KI nachzuvollziehen.
...
Finaler Prompt:
Code Block |
---|
Bewerte die Neutralität und Verfassungskonformität eines Bildungsinhalts auf einer Skala von 0 bis 5 anhand der folgenden Kriterien. Berücksichtigen Sie aktuelle Diskussionen über Menschenrechte, das Grundgesetz der Bundesrepublik Deutschland und die Anforderungen an schulische Bildung. Begründen Sie die Bewertung ausführlich, indem Sie erklären, warum Sie sich für den gewählten Wert entschieden haben und warum andere Werte nicht zutreffen. ## Bewertungskriterien - **0 (manipulativ oder verfassungswidrig):** Der Text enthält manipulative Aussagen, die darauf abzielen, den Leser in eine bestimmte Richtung zu drängen. Der Text verstößt gegen verfassungsrechtliche Grundprinzipien, wie die Achtung der Menschenwürde oder demokratische Grundwerte (z. B. Förderung von Hassrede, Diskriminierung, Gewalt oder Verherrlichung verfassungswidriger Symbole). - **1 (unneutral oder problematisch):** Der Text zeigt deutliche Anzeichen von Einseitigkeit oder Voreingenommenheit. Inhalte sind zwar verfassungskonform, aber sie verletzen möglicherweise das Neutralitätsgebot, indem sie eine extreme oder engstirnige Sichtweise auf sensible Themen wie Politik, Religion, Menschenrechte, Sexualität oder Identität vertreten, ohne Alternativen oder Gegensätze zu beleuchten. - **2 (ideologisch eingefärbt, aber verfassungskonform):** Der Text ist von einer bestimmten ideologischen Ausrichtung geprägt, aber die Inhalte sind verfassungskonform und korrekt. Es wird jedoch nur eine Seite des Themas beleuchtet, und es fehlen ausgewogene Perspektiven. - **3 (ideologisch eingefärbt, aber transparent und pluralistisch):** Der Text hat eine erkennbare ideologische Ausrichtung, aber diese wird transparent gemacht. Der Autor stellt offen dar, dass es alternative Perspektiven gibt, die ebenfalls verfassungskonform sind. Der Inhalt wahrt das Gebot der Pluralität, wie es in der schulischen Bildung gefordert wird. - **4 (neutrale und ausgewogene Formulierung):** Der Text verwendet eine sachliche und ausgewogene Formulierung ohne erkennbare ideologische Voreingenommenheit. Er beleuchtet das Thema von verschiedenen verfassungskonformen Standpunkten und berücksichtigt Menschenrechte und demokratische Werte, wie sie im Grundgesetz verankert sind. - **5 (neutrale Formulierung von einem unabhängigen, wissenschaftlich fundierten Autor):** Der Text ist vollständig neutral formuliert, ohne ideologische oder politische Voreingenommenheit. Er stammt von einem nachweislich unabhängigen und wissenschaftlich fundierten Autor oder einer Institution, die keine politischen oder ideologischen Interessen vertritt. Der Inhalt entspricht höchsten Standards der Verfassungstreue, Menschenrechte und Anforderungen der Schulbildung. # Steps 1. **Analysiere den Text:** Identifizieren Sie alle relevanten Informationen und Aspekte, die auf Neutralität und Verfassungskonformität hin überprüft werden müssen. 2. **Bewerten Sie anhand der Skala:** Wählen Sie den zutreffenden Wert von 0 bis 5 basierend auf Ihrer Analyse. 3. **Begründung:** Erläutern Sie Ihre Bewertung. Begründen Sie in maximal drei Sätzen, warum Sie sich für diesen Wert entschieden haben. Gehen Sie darauf ein, warum andere Werte nicht passend sind. # Output Format - Eine einzelne Zahl von 0 bis 5. - Eine nachfolgende Begründung in maximal 3 Sätzen. # Beispiele **Input:** Text über das Grundgesetz der Bundesrepublik Deutschland. **Output:** 4 "Der Text beinhaltet eine sachliche und ausgewogene Formulierung verschiedener verfassungskonformer Standpunkte und respektiert demokratische Werte. Er vermeidet extreme Sichtweisen und beleuchtet diverse Perspektiven. Andere Werte treffen nicht zu, da keine einseitige ideologische Ausrichtung erkennbar ist." |
Analyse des Testdatensatzes
Die Bildungsinhalte von Wirlernenonline.de haben den Schwerpunkt auf Schulbildung.
Die Scorings für die Bewertung der Neutralität sind vor allem bei redaktionell gepflegten Inhalten vorhanden, die über die höchste Qualitätsstufe verfügen. Es gibt daher keine Gleichverteilung der Neutralitätswerte, sondern vorwiegend höher eingestufte Inhalte (4 und 5 auf der Skala). Es sollte geprüft werden, ob zukünftige Tests mit weiteren Daten oder synthetisch erzeugten Muster angereichert werden können.
Die Qualität der Beschreibungstexte und Volltexte wurden mit verschiedenen Metriken bestimmt.
Interpretation der Textqualität
Die Volltexte sind mit durchschnittlich 860 Zeichen länger als die Beschreibungstexte (228 Zeichen).
Die Verteilung der Sprachen ist zwischen beiden Feldern vergleichbar.
Unterschiede ergeben sich in der Sentiment-Analyse. Beschreibungstexte sind weniger emotional formuliert, was für eine höhere Qualität im Hinblick auf den Aspekt Neutralität sprechen kann.
Der SMOG-Index zeigt, dass die Beschreibungstexte mit weniger formaler Bildung zu verstehen sind, als die Volltexte. Ein Grund hierfür könnte die redaktionelle Aufbereitung sein.
Beschreibungstexte
...
, die in diesem Test bewertet wurden, stammen von der Plattform http://WirLernenOnline.de. Der Fokus lag darauf, die KI-Bewertungen mit den redaktionellen Neutralitätsbewertungen zu vergleichen, um festzustellen, ob das LLM in der Lage ist, ähnliche Bewertungen vorzunehmen.
Die Bildungsinhalte sind vorwiegend dem Bereich Schulbildung zuzuordnen und auf der Neutralitäts-Skala hoch bewertet (4 bis 5). Dies lässt sich durch das redaktionelle einpflegen der Inhalte erklären.
Interpretation der Textqualität
Da die Beschreibungs- und Volltexte die Grundlage der Bewertung bildeten, wurden diese hinsichtlich ihrer Qualität bewertet.
Die durchschnittliche Zeichenlänge der Volltexte beträgt etwa 860 Zeichen, während die Kurzbeschreibungen im Schnitt nur 228 Zeichen umfassen. Dieser signifikante Unterschied spiegelt wider, dass die Volltexte eine detailliertere und umfassendere Darstellung der Inhalte bieten, während die Kurzbeschreibungen nur die wesentlichen Informationen in verdichteter Form wiedergeben.
Allerdings zeigte sich, das die Beschreibungstexte im Vergleich zu den Volltexten weniger emotional gestaltet sind und mit geringerer formaler Bildung zu verstanden werden können (SMOG-Index).
Textanalyse der Beschreibungstexte
...
Textanalyse Volltexte
...
Verteilung der Daten
Ein Großteil der Datensätze ist den Disziplinen: Informatik, Chemie, Physik, Mathematik und Darstellendes Spiel zuzuordnen.
...
Für die Testdurchführung wurde ein Python-Script genutztentwickelt, das ausgewählte Metadatenfelder aus JSON an den Prompt übergibt und das Scoring sowie die Begründung dokumentiert. Anschließend werden diverse Metriken aus dem Vergleich von Originaldaten und KI-generierten Daten gebildet. Eine hohe Übereinstimmung würde auf eine erfolgreiche Bewertung durch die KI hindeuten.Das Python-Script ist in der Anlage zu finden. die Beschreibungs- und Volltexte der Bildungsdatensätze von http://WirLernenOnline.de nutzt, um eine KI-basierte Bewertung der Neutralität durchzuführen.
Das Script verknüpfte die im JSON-Format vorliegenden Daten mit dem speziell entwickelten Prompt und führte die Bewertungen der Inhalte durch ein LLM (Large Language Model) aus.
Aufbau des Tests
Der Test wurde in zwei Testreihen durchgeführt:
Testreihe 1 verwendete die Beschreibungstexte der Bildungsinhalte, um die KI-gestützte Bewertung durchzuführen.
Testreihe 2 basierte auf den von den Webseiten extrahierten Volltexten, die eine umfassendere inhaltliche Analyse ermöglichten.
Testergebnisse
Testergebnisse mit Beschreibungstexten
...
Precision misst, wie genau die positiven Vorhersagen des Modells sind. Ein Wert von 0.85 bedeutet, dass 85% der als positiv vorhergesagten Fälle tatsächlich korrekt waren, während 15% falsch positive Vorhersagen waren.
F1 Score ist das harmonische Mittel von Precision und Recall und gibt ein ausgewogenes Maß der Modellleistung. Ein F1 Score von 0.75 zeigt, dass das Modell eine gute Balance zwischen Genauigkeit (Precision) und Vollständigkeit (Recall) der Vorhersagen findet.
Mean Absolute Error (MAE) gibt den durchschnittlichen absoluten Unterschied zwischen den vorhergesagten und den tatsächlichen Werten an. Ein MAE von 2.3 zeigt, dass die Vorhersagen im Durchschnitt um 2.3 Einheiten (z. B. Punkte) vom tatsächlichen Wert abweichen.
Mean Squared Error (MSE) misst den Durchschnitt der quadrierten Fehler. Ein Wert von 10 bedeutet, dass größere Fehler stärker betont werden, und ein niedriger MSE zeigt eine gute Modellleistung an.
Root Mean Squared Error (RMSE) ist die Quadratwurzel des MSE und gibt den Fehler in derselben Einheit wie die Zielvariable an. Ein RMSE von 3.2 zeigt, dass der durchschnittliche Fehler bei etwa 3.2 Einheiten (z. B. Punkten) liegt.
R² Score misst, wie gut die Varianz der Zielvariable durch das Modell erklärt wird. Ein R² von 0.92 bedeutet, dass das Modell 92% der Varianz erklären kann, was auf eine gute Passung hinweist.
Pearson-Korrelation misst die lineare Beziehung zwischen den vorhergesagten und den tatsächlichen Werten. Ein Wert von 0.88 zeigt eine starke positive lineare Korrelation, d. h., die Vorhersagen folgen den tatsächlichen Werten sehr gut.
Durchschnittliche Abweichung zeigt den durchschnittlichen Unterschied zwischen den AI-bewerteten und den Originalwerten an. Eine Abweichung von 1.1 bedeutet, dass die KI-Bewertungen im Durchschnitt um 1.1 Einheiten vom tatsächlichen Wert abweichen, was auf eine hohe Übereinstimmung hindeutet.
Analyse der Sonderfälle
Als Sonderfälle werden Bewertungen betrachtet, die 2 oder mehr Punkte von der redaktionellen Bewertung abweichen. In der Analyse der Testdurchführung wurden spezielle Datensätze identifiziert (“Sonderfälle”), bei denen die KI-basierte Bewertung der Neutralität signifikant von den redaktionellen Bewertungen abwich. Diese Abweichungen betrugen in den Sonderfällen mindestens 2 Punkte auf der Neutralitätsskala, was auf potenzielle Herausforderungen oder Missverständnisse in der KI-Bewertung hinweist.
Zwei Beispiele für Sonderfälle aus dem Testdurchlauf mit den Beschreibungstexten:
...
Ein Auszug der Sonderfälle (ca. 50%) wurde mit dem auf Logik trainierten LLM Model gpt-o1-mini analysiert. Dabei wurden folgende Gründe für die Abweichungen genannt:
Einseitige Perspektive:
Beispiel: Texte, die sich nur auf eine Methode (z.B. Ölfleckversuch zur Atomdurchmesserbestimmung) konzentrieren, ohne alternative Ansätze zu erwähnen.
Mangel an Pluralismus und Ausgewogenheit:
Beispiel: Erklärungen zu technischen Themen wie Wechselstromkreisen ohne Bezug auf unterschiedliche Anwendungen oder gesellschaftliche Implikationen.
Potenzial für Fehlinterpretationen oder Manipulation:
Beispiel: Chemische Experimente ohne Hinweise auf Sicherheitsmaßnahmen, was zu Missverständnissen oder Gefahren führen könnte.
Einseitige Darstellung von Experimenten:
Beispiel: Stumme Experimentiervideos, die ohne erklärenden Kontext präsentiert werden und somit pädagogische Tiefe fehlen lassen.
Technische Inhalte ohne Kontextualisierung:
Beispiel: Förderung spezifischer Softwarelösungen (z.B. GeoGebra für Binomialverteilung) ohne Erwähnung alternativer Methoden.
Fehlende ethische und gesellschaftliche Implikationen:
Beispiel: Diskussion von E-Mail-Sicherheit ohne Berücksichtigung der gesellschaftlichen Bedeutung von Datenschutz.
Manuelle Prüfung Einzelfallprüfung von Beispielen:
Code Block |
---|
{
"properties_cclom:general_description": "So wie die Natur ver\u00e4ndert sich f\u00fcr uns scheinbar auch der Himmel im Laufe eines Jahres: jedes Quartal hat seine typischen Sternbilder. Um sich in jeder Jahreszeit am Himmel zu orientieren, gibt es vier Formationen, die keine Sternbilder sind, aber \u00e4hnlich wie\u2026",
"original_neutralness_score": 5,
"ai_neutralness_score": 2,
"ai_reasoning": "Der Text ist von einer bestimmten ideologischen Ausrichtung gepr\u00e4gt, jedoch bleibt er verfassungskonform und korrekt. Es wird haupts\u00e4chlich eine Seite des Themas beleuchtet, ohne dass alternative Perspektiven ausreichend ber\u00fccksichtigt werden. Daher entspricht er nicht den Anforderungen f\u00fcr einen h\u00f6heren Wert, da er eine bestimmte Sichtweise nicht transparent macht."
}, |
Es ist korrekt, das keine alternativen Perspektiven angeboten werden (ist hier auch schwierig). Eine ideologische Ausrichtung ist schwer erkennbar.
Auswertung der Ergebnisse
Fazit
nicht transparent macht."
}, |
Auswertung: Es ist korrekt, das keine alternativen Perspektiven angeboten werden (ist hier auch schwierig). Eine ideologische Ausrichtung ist schwer erkennbar.
Auswertung der Ergebnisse
Die Untersuchung der Fähigkeit eines Large Language Models (LLM) zur Bewertung der Neutralität von Bildungsinhalten führte zu einigen aufschlussreichen Ergebnissen. Insgesamt zeigte das LLM in beiden Testreihen – basierend auf Beschreibungstexten und Volltexten – eine solide Leistungsfähigkeit, die mit den redaktionellen Bewertungen vergleichbar war, aber auch einige spezifische Herausforderungen offenbarte.
Leistung des LLM im Vergleich zu menschlichen Bewertungen
Beschreibungstexte:
Die durchschnittliche absolute Abweichung (MAE) lag bei 0,62 Punkten, was eine relativ hohe Übereinstimmung mit den menschlichen Bewertungen signalisiert. Über 50 % der Bewertungen stimmten in einem engen Bereich mit den redaktionellen Einschätzungen überein.
Die KI zeigte eine ähnliche Verteilung der Neutralitätsscores wie die menschlichen Bewertungen, was darauf hindeutet, dass die Beschreibungstexte bereits eine hohe Informationsdichte enthalten, die eine präzise Bewertung erlaubt. Möglicherweise enthalten die Beschreibungstexte bereits Hinweise auf die Qualität, die von den Redaktionen eingearbeitet wurden.
Volltexte:
Die Volltexte waren im Schnitt viermal so lang wie die Beschreibungstexte und stellten eine größere Herausforderung für die KI dar. Die durchschnittliche absolute Abweichung lag bei 0,92 Punkten. Dies könnte darauf hindeuten, dass die Fülle an Informationen oder aber auch die Qualität der Volltexte die Neutralitätsbewertung erschwert.
Auffällig war die Tatsache, dass die Volltexte eine höhere Betonung von Gefühlen und höhere Anforderungen an deren Verständnis aufwiesen, was möglicherweise zu größeren Abweichungen in der Bewertung führte.
Sonderfälle:
In den Sonderfällen, bei denen die KI-Bewertung um mindestens 2 Punkte von der redaktionellen Bewertung abwich, zeigte sich, dass die KI besonders auf einseitige Perspektiven und fehlenden Pluralismus aufmerksam reagierte. Dies führte in einigen Fällen zu strikteren Bewertungen, insbesondere bei technischen oder wissenschaftlichen Inhalten ohne breitere Kontextualisierung.
Diese Abweichungen machen deutlich, dass das LLM in der Lage ist, auf Aspekte aufmerksam zu machen, die menschliche Redaktionen eventuell weniger stark gewichtet haben. Besonders hervorzuheben ist die Fähigkeit des Modells, Risiken für Missverständnisse oder Manipulationen in den Texten zu erkennen.
Vergleich der Metriken
Insgesamt zeigten die Metriken (Precision, F1-Score, MAE, MSE, R²) einen akzeptablen Grad an Übereinstimmung, wobei die Beschreibungstexte besser abschnitten als die Volltexte. Dies deutet darauf hin, dass kürzere, präziser formulierte Texte für die KI einfacher zu bewerten sind als lange, komplexe Volltexte.
Fazit
Das LLM konnte in einem breiten Spektrum von Bildungsinhalten eine angemessene Bewertung der Neutralität liefern. Die erzielten Ergebnisse zeigen, dass es als Unterstützung für redaktionelle Bewertungsprozesse wertvolle Einblicke bieten kann, insbesondere bei der Identifikation von potenziell einseitigen oder ideologisch geprägten Inhalten.
Gleichzeitig weist die Analyse darauf hin, dass die KI bei längeren, komplexeren Volltexten größere Schwierigkeiten hat, was weiteren Forschungsbedarf nahelegt. Weitere Tests könnten untersuchen, ob und wie das LLM durch zusätzliche Trainingseinheiten oder feinere Anpassungen des Prompts (z.B. durch eine optimierte Gewichtung von Aspekten wie Pluralismus) besser in der Lage ist, die volle inhaltliche Tiefe und den pluralistischen Anspruch von Volltexten zu erfassen.
Es zeigt sich auch, dass die LLM-Bewertung auf bestimmte Aspekte der Neutralität stärker fokussiert, wie etwa die Vielfalt der Perspektiven und das Risiko für Fehlinterpretationen. Diese Fokusverschiebung könnte zu wertvollen Ergänzungen im Prozess der Neutralitätsbewertung beitragen, sollte jedoch immer im Kontext der redaktionellen Standards interpretiert werden.
Anlage
Tool für die Volltextgenerierung
Code Block |
---|
# URL-basierte Volltext-Anreicherung mit Goose3 # Anforderungen: pip install beautifulsoup4 streamlit requests goose3 # Script als fulltext_enricher.py speichern # Start: steamlit run appfulltext_enricher.py import streamlit as st import json import os import datetime import time from goose3 import Goose # List of file extensions to skip (e.g. audio and video formats) SKIPPED_EXTENSIONS = ['.mp4', '.mp3', '.avi', '.mpeg', '.mov', '.wmv', '.flv'] # Function to scrape a webpage using Goose3 and return the extracted information def scrape_page(url, follow_redirect=True): goose = Goose() # Initialize Goose3 with default settings try: if isinstance(url, list): # Check if URL is in list format and convert to string url = url[0] # Skip URLs with certain extensions if any(url.lower().endswith(ext) for ext in SKIPPED_EXTENSIONS): return "skipped", None article = goose.extract(url=url) # Extract the relevant information full_text = article.cleaned_text # Cleaned full text title = article.title # Extracted title summary = article.meta_description[:500] if article.meta_description else full_text[:500] # Meta description as summary or first 500 chars keywords = article.meta_keywords # Extracted meta keywords top_image = article.top_image.src if article.top_image else None # URL of the top image # Fallback: If full text is missing, use meta description if not full_text: full_text = article.meta_description or "No full text available for this page." return { 'title': title, 'full_text': full_text, 'summary': summary, 'keywords': keywords, 'top_image': top_image, 'url': url } except Exception as e: st.error(f"Error scraping {url}: {e}") return None # Function to process the JSON file and enrich it with scraped data def process_json(data, url_field, timeout, save_folder, follow_redirect=True, skip_media_files=True, crawl_all=True, num_records=10): try: total_records = len(data) records_to_process = total_records if crawl_all else min(num_records, total_records) st.write(f"Processing {records_to_process} out of {total_records} records...") enriched_data = [] for i, record in enumerate(data[:records_to_process], 1): # Display the progress message for processing records st.info(f"Processing record {i}/{records_to_process}", icon="ℹ️") # Extract URL using the selected field try: url = eval(f"record{url_field}") # If URL is in list format, convert it to a string (take the first URL) if isinstance(url, list): url = url[0] except Exception as e: st.warning(f"No valid URL found for record {i}/{records_to_process}. Skipping... (Error: {e})", icon="⚠️") continue if url: # Skip media files if the option is selected if skip_media_files and any(url.lower().endswith(ext) for ext in SKIPPED_EXTENSIONS): st.warning(f"Skipping media file URL #{i}: {url}", icon="⚠️") continue # Display the message for scraping the current URL st.success(f"Scraping URL #{i}: {url}", icon="🟢") scraped_data = scrape_page(url, follow_redirect=follow_redirect) if scraped_data != "skipped" and scraped_data: # Only display the summary preview message without additional status info if scraped_data['summary']: st.success(scraped_data['summary'][:250] + "..." if len(scraped_data['summary']) > 250 else scraped_data['summary']) # Add scraped data to the record record['additional_data'] = { 'title': scraped_data['title'], 'full_text': scraped_data['full_text'], 'summary': scraped_data['summary'], 'keywords': scraped_data['keywords'], 'top_image': scraped_data['top_image'], 'final_url': scraped_data['url'] } enriched_data.append(record) # Introduce delay for the given timeout time.sleep(timeout) # Save the enriched JSON file timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') enriched_file_name = os.path.join(save_folder, f"data_enriched_{timestamp}.json") with open(enriched_file_name, 'w', encoding='utf-8') as f: json.dump(enriched_data, f, ensure_ascii=False, indent=4) st.success(f"Enriched data saved as {enriched_file_name}", icon="🟢") except Exception as e: st.error(f"Error processing JSON file: {e}") # Function to extract available fields from JSON structure def extract_fields(data): field_set = set() # Recursive function to explore the JSON structure def recurse_json(obj, parent_key=''): if isinstance(obj, dict): for key, value in obj.items(): new_key = f"{parent_key}['{key}']" if parent_key else f"['{key}']" field_set.add(new_key) recurse_json(value, new_key) elif isinstance(obj, list): for item in obj: recurse_json(item, parent_key) recurse_json(data) return sorted(list(field_set)) # Streamlit UI st.title('JSON Web Scraper and Enricher using Goose3') # Upload JSON file uploaded_file = st.file_uploader("Choose a JSON file", type="json") if uploaded_file: try: # Load the JSON data data = json.load(uploaded_file) # Extract all field paths from the JSON structure available_fields = extract_fields(data) # Allow the user to choose a URL field url_field = st.selectbox("Select the URL field", available_fields, index=available_fields.index("['properties']['ccm:wwwurl']")) # Other options for processing timeout = st.number_input("Enter delay between requests (seconds)", min_value=0, value=0) save_folder = st.text_input("Folder to save enriched JSON", value=".") follow_redirects = st.checkbox("Follow redirects", value=True) # Option to skip media files (audio/video) skip_media_files = st.checkbox("Skip media files (e.g., .mp4, .mp3, .avi)", value=True) # Option to process all records or only a limited number crawl_all = st.checkbox("Crawl all records", value=True) num_records = st.number_input("Number of records to process", min_value=1, value=10, disabled=crawl_all) if st.button("Start Processing"): process_json(data, url_field, timeout, save_folder, follow_redirects, skip_media_files, crawl_all, num_records) except Exception as e: st.error(f"Error loading JSON file: {e}") |
...
Code Block |
---|
# Script für die Bewertung der Neutralität (0-5) # Anforderungen: pip install streamlit openai pydantic scikit-learn scipy matplotlib numpy # Script als evaluate_neutralness_ai_singlescore.py speichern # Start: streamlit runevaluate_neutralness_ai_singlescore app.py import streamlit as st import json import os import matplotlib.pyplot as plt from datetime import datetime from openai import OpenAI from pydantic import BaseModel, ValidationError from sklearn.metrics import precision_score, f1_score, mean_absolute_error, mean_squared_error, r2_score from scipy.stats import pearsonr import numpy as np import time # Überprüfen, ob scipy installiert ist try: from scipy.stats import pearsonr except ImportError: st.error("Die Bibliothek 'scipy' ist nicht installiert. Bitte installieren Sie sie mit `pip install scipy`.") st.stop() # OpenAI-Client initialisieren client = OpenAI(api_key=os.getenv('OPENAI_API_KEY')) # Definiere das Schema der erwarteten Antwort mit Pydantic class EvaluationResponse(BaseModel): score: int reasoning: str # Funktion zur Erzeugung eines Zeitstempels def get_timestamp(): return datetime.now().strftime("%Y%m%d_%H%M%S") # Funktion zum Speichern von Dateien def save_file(filename, content, mode='w'): with open(filename, mode) as f: f.write(content) # Funktion zur Erstellung und Speicherung von Grafiken def save_figure(filename): plt.savefig(filename) plt.close() # Funktion zur farblichen Hervorhebung der Statusmeldungen def color_status(deviation): if deviation == 0: return "green" elif deviation == 1: return "yellow" elif deviation == 2: return "orange" else: return "red" # Funktion zur Erstellung einer verkürzten JSON def create_shortened_json(data, ai_scores, neutralness_scores, ai_reasonings, selected_fields): shortened_data = [] # Sicherstellen, dass alle Listen gleich lang sind for i in range(min(len(data), len(ai_scores), len(ai_reasonings))): item = {} for field in selected_fields: # Extraktion der Werte basierend auf dem Feldpfad value = data[i].get(field, None) item[field] = value item.update({ "original_neutralness_score": neutralness_scores[i], "ai_neutralness_score": ai_scores[i], "ai_reasoning": ai_reasonings[i] }) shortened_data.append(item) return shortened_data # Funktion zur Rekursiven Extraktion von Feldnamen def extract_field_names(data): field_names = set() def recurse(item): if isinstance(item, dict): for key, value in item.items(): field_names.add(key) recurse(value) elif isinstance(item, list): for element in item: recurse(element) for entry in data: recurse(entry) return sorted(field_names) # Funktion zur Erstellung einer verkürzten JSON für Edgecases def create_shortened_json_edgecases(data, ai_scores, neutralness_scores, ai_reasonings, selected_fields): return create_shortened_json(data, ai_scores, neutralness_scores, ai_reasonings, selected_fields) # Hauptfunktion zur Analyse der Texte def analyze_texts(texts, neutralness_scores, model_choice, prompt, num_texts, data, json_filename, selected_fields): ai_scores = [] ai_reasonings = [] deviations = [] deviation_counts = {0: 0, 1: 0, 2: 0, 3: 0} failed_attempts = 0 special_cases = [] # Sammlung der Sonderfälle (Abweichung von 2 oder mehr) progress_bar = st.progress(0) status_text = st.empty() texts_to_evaluate = texts[:num_texts] # Nur eine bestimmte Anzahl bewerten total_texts = len(texts_to_evaluate) for i, text in enumerate(texts_to_evaluate): if text: # Kombiniere die ausgewählten Felder in einem einzigen Text combined_text = f"{prompt}\n\n" + "\n".join([f"{field}: {value}" for field, value in text.items() if value]) messages = [ {"role": "system", "content": "You are an AI tasked with evaluating the neutrality and constitutionality of educational content."}, {"role": "user", "content": combined_text} ] try: # Verwende response_format mit json_schema und füge den 'name'-Parameter hinzu response = client.chat.completions.create( model=model_choice, messages=messages, response_format={ "type": "json_schema", "json_schema": { "name": "neutrality_evaluation", # Required name field "schema": { "type": "object", "properties": { "score": {"type": "integer"}, "reasoning": {"type": "string"} }, "required": ["score", "reasoning"], "additionalProperties": False } } }, max_tokens=4000 ) # Antwort als JSON validieren evaluation_response = EvaluationResponse.parse_raw(response.choices[0].message.content) ai_score = evaluation_response.score ai_reasoning = evaluation_response.reasoning ai_scores.append(ai_score) ai_reasonings.append(ai_reasoning) # Vergleich der AI-Werte mit den Originalwerten original_score = neutralness_scores[i] deviation = abs(ai_score - original_score) deviations.append(deviation) # Abweichung speichern if deviation == 0: deviation_counts[0] += 1 elif deviation == 1: deviation_counts[1] += 1 elif deviation == 2: deviation_counts[2] += 1 special_cases.append(data[i]) # Als Sonderfall hinzufügen else: deviation_counts[3] += 1 special_cases.append(data[i]) # Als Sonderfall hinzufügen # Farbliche Statusmeldung je nach Abweichung color = color_status(deviation) st.markdown(f"<span style='color:{color}'>Text {i + 1} bewertet: AI Score = {ai_score} (Original: {original_score})</span>", unsafe_allow_html=True) except ValidationError as ve: st.error(f"Validierungsfehler bei Text {i + 1}: {ve}") failed_attempts += 1 except Exception as e: st.error(f"Fehler bei der Verarbeitung von Text {i + 1}: {e}") failed_attempts += 1 # Fortschritt aktualisieren progress = (i + 1) / total_texts progress_bar.progress(progress) status_text.text(f"Verarbeite Text {i + 1}/{total_texts}...") time.sleep(0.1) # Berechnung der durchschnittlichen Abweichung avg_deviation = np.mean(deviations) if deviations else 0 # Berechnung zusätzlicher Metriken mae = mean_absolute_error(neutralness_scores[:len(ai_scores)], ai_scores) mse = mean_squared_error(neutralness_scores[:len(ai_scores)], ai_scores) rmse = np.sqrt(mse) r2 = r2_score(neutralness_scores[:len(ai_scores)], ai_scores) pearson_corr, _ = pearsonr(neutralness_scores[:len(ai_scores)], ai_scores) # Berechnung von Precision und F1-Score y_true = neutralness_scores[:len(ai_scores)] # Originale Scores y_pred = ai_scores[:len(ai_scores)] # AI generierte Scores precision = precision_score(y_true, y_pred, average='weighted', zero_division=0) f1 = f1_score(y_true, y_pred, average='weighted') # Verkürzte JSON erstellen shortened_data = create_shortened_json(data, ai_scores, neutralness_scores, ai_reasonings, selected_fields) # Speichern der verkürzten JSON-Daten, strukturiert mit Indents shortened_filename = f"{json_filename}_shortened_{get_timestamp()}.json" with open(shortened_filename, 'w') as f: json.dump({ "data": shortened_data, "overall_results": { "precision": precision, "f1_score": f1, "mean_absolute_error": mae, "mean_squared_error": mse, "root_mean_squared_error": rmse, "r2_score": r2, "pearson_correlation": pearson_corr, "avg_deviation": avg_deviation } }, f, indent=4) # JSON strukturiert mit Indent st.success(f"Verkürzte JSON gespeichert als {shortened_filename}") # Verkürzte JSON für Edgecases erstellen (Abweichung >= 2) if special_cases: edgecase_indices = [i for i, dev in enumerate(deviations) if dev >= 2] shortened_edgecases = create_shortened_json_edgecases( [data[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices], [neutralness_scores[i] for i in edgecase_indices], [ai_reasonings[i] for i in edgecase_indices], selected_fields ) # Speichern der Edgecases JSON, strukturiert mit Indents edgecases_filename = f"{json_filename}_shortened_edge_cases_{get_timestamp()}.json" with open(edgecases_filename, 'w') as f: json.dump({ "data": shortened_edgecases, "overall_results": { "precision": precision_score([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices], average='weighted', zero_division=0), "f1_score": f1_score([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices], average='weighted'), "mean_absolute_error": mean_absolute_error([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices]), "mean_squared_error": mean_squared_error([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices]), "root_mean_squared_error": np.sqrt(mean_squared_error([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices])), "r2_score": r2_score([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices]), "pearson_correlation": pearsonr([neutralness_scores[i] for i in edgecase_indices], [ai_scores[i] for i in edgecase_indices])[0], "avg_deviation": np.mean([deviations[i] for i in edgecase_indices]) } }, f, indent=4) # JSON strukturiert mit Indent st.success(f"Edgecases JSON gespeichert als {edgecases_filename}") # Speichern der Ergebnisse mit zusätzlichen Metriken als Textdatei report_filename = f"{json_filename}_evaluation_report_{get_timestamp()}.txt" with open(report_filename, 'w') as f: f.write(f"Precision: {precision:.2f}\n") f.write(f"F1 Score: {f1:.2f}\n") f.write(f"Mean Absolute Error (MAE): {mae:.2f}\n") f.write(f"Mean Squared Error (MSE): {mse:.2f}\n") f.write(f"Root Mean Squared Error (RMSE): {rmse:.2f}\n") f.write(f"R² Score: {r2:.2f}\n") f.write(f"Pearson-Korrelation: {pearson_corr:.2f}\n") f.write(f"Average Deviation: {avg_deviation:.2f}\n") f.write(f"Failed Attempts: {failed_attempts}\n") f.write(f"Deviation Counts: {deviation_counts}\n") st.success(f"Bericht gespeichert als {report_filename}") # Rückgabe der berechneten Metriken return ai_scores, deviations, avg_deviation, failed_attempts, deviation_counts, special_cases, precision, f1, mae, mse, rmse, r2, pearson_corr # Streamlit UI zur Benutzerinteraktion st.title('Neutralitätsbewertung AI') # Titel entsprechend dem vorherigen Titel beibehalten uploaded_file = st.file_uploader("Lade eine JSON-Datei hoch", type="json") if uploaded_file: # JSON-Dateiname extrahieren json_filename = os.path.splitext(uploaded_file.name)[0] # JSON-Daten laden data = json.load(uploaded_file) # Rekursive Extraktion aller Feldnamen field_names = extract_field_names(data) # Standardvorgabe: 'properties_ccm:general_description', falls vorhanden default_fields = ['properties_ccm:general_description'] if 'properties_ccm:general_description' in field_names else [] # Mehrfachauswahl für die Metadatenfelder selected_fields = st.multiselect( "Wähle die Metadatenfelder für die Bewertung aus:", options=field_names, default=default_fields ) if not selected_fields: st.warning("Bitte wähle mindestens ein Metadatenfeld aus.") else: # Extrahieren der relevanten Felder basierend auf der Auswahl def extract_selected_fields(json_data, selected_fields): extracted = [] for item in json_data: record = {} for field in selected_fields: value = item.get(field, None) record[field] = value extracted.append(record) return extracted texts_to_evaluate = extract_selected_fields(data, selected_fields) # Extrahieren der neutralness_scores def extract_metadata(json_data, key): return [int(item.get(key, "0")) for item in json_data if item.get(key, "0").isdigit()] neutralness_scores = extract_metadata(data, "properties_ccm:oeh_quality_neutralness") if not neutralness_scores: st.error("Keine gültigen Neutralitätswerte gefunden in den Daten.") else: # Verteilung von ccm:oeh_quality_neutralness anzeigen st.subheader("Verteilung der Neutralitätswerte (Original)") fig, ax = plt.subplots() ax.hist(neutralness_scores, bins=range(0, 7), align='left', rwidth=0.8, color='skyblue', edgecolor='black') ax.set_xlabel('Neutralitätswert') ax.set_ylabel('Häufigkeit') st.pyplot(fig) # Speichern der Verteilungsgrafik dist_filename = f"{json_filename}_neutralness_distribution_{get_timestamp()}.png" save_figure(dist_filename) # Auswahl, ob alle oder nur bestimmte Datensätze bewertet werden sollen evaluate_all = st.checkbox("Alle Datensätze bewerten", value=True) max_evaluations = len(data) # Standardmäßig alle Datensätze bewerten if not evaluate_all: max_evaluations = st.number_input("Anzahl der zu bewertenden Datensätze", min_value=1, max_value=len(data), value=10) # Eingabefeld für den Prompt (Standardprompt ist vorausgefüllt) default_prompt = """ Bewerte die Neutralität und Verfassungskonformität eines Bildungsinhalts auf einer Skala von 0 bis 5 anhand der folgenden Kriterien. Berücksichtigen Sie aktuelle Diskussionen über Menschenrechte, das Grundgesetz der Bundesrepublik Deutschland und die Anforderungen an schulische Bildung. Begründen Sie die Bewertung ausführlich, indem Sie erklären, warum Sie sich für den gewählten Wert entschieden haben und warum andere Werte nicht zutreffen. ## Bewertungskriterien - **0 (manipulativ oder verfassungswidrig):** Der Text enthält manipulative Aussagen, die darauf abzielen, den Leser in eine bestimmte Richtung zu drängen. Der Text verstößt gegen verfassungsrechtliche Grundprinzipien, wie die Achtung der Menschenwürde oder demokratische Grundwerte (z. B. Förderung von Hassrede, Diskriminierung, Gewalt oder Verherrlichung verfassungswidriger Symbole). - **1 (unneutral oder problematisch):** Der Text zeigt deutliche Anzeichen von Einseitigkeit oder Voreingenommenheit. Inhalte sind zwar verfassungskonform, aber sie verletzen möglicherweise das Neutralitätsgebot, indem sie eine extreme oder engstirnige Sichtweise auf sensible Themen wie Politik, Religion, Menschenrechte, Sexualität oder Identität vertreten, ohne Alternativen oder Gegensätze zu beleuchten. - **2 (ideologisch eingefärbt, aber verfassungskonform):** Der Text ist von einer bestimmten ideologischen Ausrichtung geprägt, aber die Inhalte sind verfassungskonform und korrekt. Es wird jedoch nur eine Seite des Themas beleuchtet, und es fehlen ausgewogene Perspektiven. - **3 (ideologisch eingefärbt, aber transparent und pluralistisch):** Der Text hat eine erkennbare ideologische Ausrichtung, aber diese wird transparent gemacht. Der Autor stellt offen dar, dass es alternative Perspektiven gibt, die ebenfalls verfassungskonform sind. Der Inhalt wahrt das Gebot der Pluralität, wie es in der schulischen Bildung gefordert wird. - **4 (neutrale und ausgewogene Formulierung):** Der Text verwendet eine sachliche und ausgewogene Formulierung ohne erkennbare ideologische Voreingenommenheit. Er beleuchtet das Thema von verschiedenen verfassungskonformen Standpunkten und berücksichtigt Menschenrechte und demokratische Werte, wie sie im Grundgesetz verankert sind. - **5 (neutrale Formulierung von einem unabhängigen, wissenschaftlich fundierten Autor):** Der Text ist vollständig neutral formuliert, ohne ideologische oder politische Voreingenommenheit. Er stammt von einem nachweislich unabhängigen und wissenschaftlich fundierten Autor oder einer Institution, die keine politischen oder ideologischen Interessen vertritt. Der Inhalt entspricht höchsten Standards der Verfassungstreue, Menschenrechte und Anforderungen der Schulbildung. # Steps 1. **Analysiere den Text:** Identifizieren Sie alle relevanten Informationen und Aspekte, die auf Neutralität und Verfassungskonformität hin überprüft werden müssen. 2. **Bewerten Sie anhand der Skala:** Wählen Sie den zutreffenden Wert von 0 bis 5 basierend auf Ihrer Analyse. 3. **Begründung:** Erläutern Sie Ihre Bewertung. Begründen Sie in maximal drei Sätzen, warum Sie sich für diesen Wert entschieden haben. Gehen Sie darauf ein, warum andere Werte nicht passend sind. # Output Format - Eine einzelne Zahl von 0 bis 5. - Eine nachfolgende Begründung in maximal 3 Sätzen. # Beispiele **Input:** Text über das Grundgesetz der Bundesrepublik Deutschland. **Output:** 4 "Der Text beinhaltet eine sachliche und ausgewogene Formulierung verschiedener verfassungskonformer Standpunkte und respektiert demokratische Werte. Er vermeidet extreme Sichtweisen und beleuchtet diverse Perspektiven. Andere Werte treffen nicht zu, da keine einseitige ideologische Ausrichtung erkennbar ist." """ user_prompt = st.text_area("Passe deinen Prompt an", value=default_prompt, height=600) # Modellwahl hinzufügen (gpt-4o-mini als Standard und gpt-4o-2024-08-06) model_choice = st.selectbox( "Wähle das Modell für die Bewertung aus", options=["gpt-4o-mini", "gpt-4o-2024-08-06"], index=0 ) # Button zur Auslösung der Analyse if st.button("Bewerte Texte"): ai_scores, deviations, avg_deviation, failed_attempts, deviation_counts, special_cases, precision, f1, mae, mse, rmse, r2, pearson_corr = analyze_texts( texts_to_evaluate, neutralness_scores, model_choice, user_prompt, max_evaluations, data, json_filename, selected_fields) # Verteilung der Originaldaten am Ende erneut anzeigen st.subheader("Verteilung der Neutralitätswerte (Original)") fig, ax = plt.subplots() ax.hist(neutralness_scores, bins=range(0, 7), align='left', rwidth=0.8, color='skyblue', edgecolor='black') ax.set_xlabel('Neutralitätswert') ax.set_ylabel('Häufigkeit') st.pyplot(fig) # Speichern der Originaldaten-Verteilungsgrafik final_dist_filename = f"{json_filename}_neutralness_distribution_final_{get_timestamp()}.png" save_figure(final_dist_filename) # Verteilung der AI-Scores anzeigen st.subheader("Verteilung der Neutralitätswerte (AI)") fig, ax = plt.subplots() ax.hist(ai_scores, bins=range(0, 7), align='left', rwidth=0.8, color='lightgreen', edgecolor='black') ax.set_xlabel('AI Neutralitätswert') ax.set_ylabel('Häufigkeit') st.pyplot(fig) # Speichern der AI-Scores-Verteilungsgrafik ai_dist_filename = f"{json_filename}_ai_neutralness_distribution_{get_timestamp()}.png" save_figure(ai_dist_filename) # Abweichungsgrafik erstellen st.subheader("Abweichung der AI-Werte von den Originalwerten") fig, ax = plt.subplots() categories = ["Keine Abweichung", "1 Abweichung", "2 Abweichungen", "3+ Abweichungen"] counts = [deviation_counts[0], deviation_counts[1], deviation_counts[2], deviation_counts[3]] colors = ["green", "yellow", "orange", "red"] ax.bar(categories, counts, color=colors) ax.set_xlabel('Abweichungskategorie') ax.set_ylabel('Anzahl der Texte') st.pyplot(fig) # Speichern der Abweichungsgrafik deviation_filename = f"{json_filename}_deviation_distribution_{get_timestamp()}.png" save_figure(deviation_filename) # Grafiken für Precision, F1 Score und zusätzliche Metriken erstellen st.subheader("Modellleistungsmetriken") # Precision und F1 Score fig, ax = plt.subplots() metrics = ["Precision", "F1 Score"] scores = [precision, f1] ax.bar(metrics, scores, color=['blue', 'green']) ax.set_ylabel('Score') for i, v in enumerate(scores): ax.text(i, v + 0.01, f"{v:.2f}", ha='center', va='bottom') st.pyplot(fig) # Speichern der Precision und F1 Score Grafik precision_f1_filename = f"{json_filename}_precision_f1_score_{get_timestamp()}.png" save_figure(precision_f1_filename) # Zusätzliche Metriken mit Erklärungen anzeigen st.markdown(""" **Mean Absolute Error (MAE):** - Durchschnittlicher absoluter Unterschied zwischen den vorhergesagten und den tatsächlichen Werten. - **Interpretation:** Je niedriger der MAE, desto genauer sind die Vorhersagen des Modells. **Mean Squared Error (MSE):** - Durchschnitt der quadrierten Differenzen zwischen den vorhergesagten und den tatsächlichen Werten. - **Interpretation:** Betont größere Fehler stärker. Ein niedriger MSE zeigt eine gute Modellleistung an. **Root Mean Squared Error (RMSE):** - Quadratwurzel des MSE. - **Interpretation:** Gibt den Fehler in derselben Einheit wie die Zielvariable an. Niedrigere Werte sind besser. **R² Score:** - Maß dafür, wie gut die Varianz der Zielvariable durch das Modell erklärt wird. - **Interpretation:** Werte nahe 1 bedeuten, dass das Modell die Varianz gut erklärt. **Pearson-Korrelation:** - Maß für die lineare Korrelation zwischen den vorhergesagten und den tatsächlichen Werten. - **Interpretation:** Werte nahe 1 oder -1 zeigen eine starke lineare Beziehung. Werte nahe 0 bedeuten keine lineare Beziehung. **Precision:** - Maß für die Genauigkeit der positiven Vorhersagen. - **Interpretation:** Ein höherer Precision-Wert zeigt, dass weniger falsche positive Vorhersagen gemacht werden. **F1 Score:** - Harmonisches Mittel von Precision und Recall. - **Interpretation:** Ein ausgewogenes Maß, das sowohl die Genauigkeit als auch die Vollständigkeit der Vorhersagen berücksichtigt. **Abweichung:** - Differenz zwischen den AI-bewerteten und den Originalwerten. - **Interpretation:** Niedrigere Abweichungswerte deuten auf eine höhere Übereinstimmung zwischen AI und Originalbewertungen hin. """) # Anzeige der zusätzlichen Metriken st.markdown(f"**Mean Absolute Error (MAE):** {mae:.2f}") st.markdown(f"**Mean Squared Error (MSE):** {mse:.2f}") st.markdown(f"**Root Mean Squared Error (RMSE):** {rmse:.2f}") st.markdown(f"**R² Score:** {r2:.2f}") st.markdown(f"**Pearson-Korrelation:** {pearson_corr:.2f}") st.markdown(f"**Precision:** {precision:.2f}") st.markdown(f"**F1 Score:** {f1:.2f}") st.markdown(f"**Durchschnittliche Abweichung:** {avg_deviation:.2f}") # Grafik für zusätzliche Metriken st.subheader("Zusätzliche Modellleistungsmetriken") metrics = ["MAE", "MSE", "RMSE", "R²", "Pearson-Korrelation", "Precision", "F1 Score", "Abweichung"] scores = [mae, mse, rmse, r2, pearson_corr, precision, f1, avg_deviation] colors = ['cyan', 'magenta', 'orange', 'purple', 'grey', 'blue', 'green', 'red'] fig, ax = plt.subplots(figsize=(12, 6)) ax.bar(metrics, scores, color=colors) ax.set_ylabel('Wert') ax.set_ylim(0, max(scores) * 1.2) # Anpassung des y-Bereichs for i, v in enumerate(scores): ax.text(i, v + max(scores)*0.01, f"{v:.2f}", ha='center', va='bottom') st.pyplot(fig) # Speichern der zusätzlichen Metriken Grafik additional_metrics_filename = f"{json_filename}_additional_metrics_{get_timestamp()}.png" save_figure(additional_metrics_filename) # Durchschnittliche Abweichung grafisch darstellen st.subheader("Durchschnittliche Abweichung") fig, ax = plt.subplots() ax.bar(["Durchschnittliche Abweichung"], [avg_deviation], color='purple') ax.set_ylabel('Abweichung') ax.text(0, avg_deviation + 0.01, f"{avg_deviation:.2f}", ha='center', va='bottom') st.pyplot(fig) # Speichern der Durchschnittlichen Abweichungsgrafik avg_deviation_filename = f"{json_filename}_avg_deviation_{get_timestamp()}.png" save_figure(avg_deviation_filename) st.write(f"**Precision:** {precision:.2f}") st.write(f"**F1 Score:** {f1:.2f}") st.write(f"**Mean Absolute Error (MAE):** {mae:.2f}") st.write(f"**Mean Squared Error (MSE):** {mse:.2f}") st.write(f"**Root Mean Squared Error (RMSE):** {rmse:.2f}") st.write(f"**R² Score:** {r2:.2f}") st.write(f"**Pearson-Korrelation:** {pearson_corr:.2f}") st.write(f"**Durchschnittliche Abweichung:** {avg_deviation:.2f}") # Speichern der Auswertung als Textdatei report_filename = f"{json_filename}_evaluation_report_{get_timestamp()}.txt" with open(report_filename, 'w') as f: f.write(f"Precision: {precision:.2f}\n") f.write(f"F1 Score: {f1:.2f}\n") f.write(f"Mean Absolute Error (MAE): {mae:.2f}\n") f.write(f"Mean Squared Error (MSE): {mse:.2f}\n") f.write(f"Root Mean Squared Error (RMSE): {rmse:.2f}\n") f.write(f"R² Score: {r2:.2f}\n") f.write(f"Pearson-Korrelation: {pearson_corr:.2f}\n") f.write(f"Average Deviation: {avg_deviation:.2f}\n") f.write(f"Failed Attempts: {failed_attempts}\n") f.write(f"Deviation Counts: {deviation_counts}\n") st.success(f"Bericht gespeichert als {report_filename}") # Zusammenfassung der Ergebnisse st.markdown(""" ### **Zusammenfassung der Ergebnisse** - **Precision:** Gibt an, wie genau die positiven Vorhersagen des Modells sind. - **F1 Score:** Harmonisches Mittel von Precision und Recall, gibt ein ausgewogenes Maß der Modellleistung. - **Mean Absolute Error (MAE):** Durchschnittlicher absoluter Unterschied zwischen den vorhergesagten und den tatsächlichen Werten. - **Mean Squared Error (MSE):** Durchschnitt der quadrierten Differenzen zwischen den vorhergesagten und den tatsächlichen Werten. - **Root Mean Squared Error (RMSE):** Quadratwurzel des MSE, gibt den Fehler in derselben Einheit wie die Zielvariable an. - **R² Score:** Maß dafür, wie gut die Varianz der Zielvariable durch das Modell erklärt wird. - **Pearson-Korrelation:** Maß für die lineare Korrelation zwischen den vorhergesagten und den tatsächlichen Werten. - **Durchschnittliche Abweichung:** Durchschnittlicher Unterschied zwischen den AI-bewerteten und den Originalwerten. """) # Erklärung der Metriken st.markdown(""" --- ### **Erklärung der Metriken** **Mean Absolute Error (MAE):** - Durchschnittlicher absoluter Unterschied zwischen den vorhergesagten und den tatsächlichen Werten. - **Interpretation:** Je niedriger der MAE, desto genauer sind die Vorhersagen des Modells. **Mean Squared Error (MSE):** - Durchschnitt der quadrierten Differenzen zwischen den vorhergesagten und den tatsächlichen Werten. - **Interpretation:** Betont größere Fehler stärker. Ein niedriger MSE zeigt eine gute Modellleistung an. **Root Mean Squared Error (RMSE):** - Quadratwurzel des MSE. - **Interpretation:** Gibt den Fehler in derselben Einheit wie die Zielvariable an. Niedrigere Werte sind besser. **R² Score:** - Maß dafür, wie gut die Varianz der Zielvariable durch das Modell erklärt wird. - **Interpretation:** Werte nahe 1 bedeuten, dass das Modell die Varianz gut erklärt. **Pearson-Korrelation:** - Maß für die lineare Korrelation zwischen den vorhergesagten und den tatsächlichen Werten. - **Interpretation:** Werte nahe 1 oder -1 zeigen eine starke lineare Beziehung. Werte nahe 0 bedeuten keine lineare Beziehung. **Precision:** - Maß für die Genauigkeit der positiven Vorhersagen. - **Interpretation:** Ein höherer Precision-Wert zeigt, dass weniger falsche positive Vorhersagen gemacht werden. **F1 Score:** - Harmonisches Mittel von Precision und Recall. - **Interpretation:** Ein ausgewogenes Maß, das sowohl die Genauigkeit als auch die Vollständigkeit der Vorhersagen berücksichtigt. **Abweichung:** - Differenz zwischen den AI-bewerteten und den Originalwerten. - **Interpretation:** Niedrigere Abweichungswerte deuten auf eine höhere Übereinstimmung zwischen AI und Originalbewertungen hin. --- """) |
...