Frage-Antwort-Paare (QA) für Finetuning, Semantische Suche und RAG

Frage-Antwort-Paare (QA) für Finetuning, Semantische Suche und RAG

Hintergründe

Frage-Antwort-Paare (QA-Paare) sind in der KI und Suche von zentraler Bedeutung:

  • Feinabstimmung (Fine-Tuning): Durch Training mit QA-Paaren wird ein vortrainiertes Modell auf spezifische Aufgaben oder Domänen angepasst, um präzisere Antworten zu liefern.

  • Semantische Suche: QA-Paare dienen als Referenz, um semantisch ähnliche Anfragen zu identifizieren und relevante Antworten bereitzustellen.

  • Retrieval Augmented Generation (RAG): In RAG-Systemen werden QA-Paare genutzt, um generative Modelle mit spezifischem Wissen zu versorgen, wodurch kontextbezogene und genaue Antworten generiert werden.

QA für Finetuning

Anwendungsgebiete von Finetuning

  • Integration domänenspezifischen Wissens: Anpassung an Fachbereiche wie Bildung oder Medizin.

  • Training spezifischen Verhaltens: Optimierung von Chatbots für bestimmte Interaktionen.

  • Anpassung des Kommunikationsstils: Generierung von Antworten in gewünschten Stilen, z. B. förmlich oder humorvoll.

  • Formatierung der Ausgaben: Bereitstellung von Antworten in definierten Formaten, etwa JSON.

  • Verbesserte Klassifikationen: Präzisere Bewertung von Metadaten.

  • Optimierte Bildanalyse: Steigerung der Genauigkeit in multimodalen Modellen.

  • Erhöhung der Aufgabenpräzision: Verbesserte Leistung bei spezifischen Aufgaben.

Zum Weiterlesen: https://platform.openai.com/docs/guides/fine-tuning/create-a-fine-tuned-model

Struktur der QA Datensätze für Fine-Tuning

Dies hängt von KI-Model und der Art des Fine-Tunings ab.

OpenAI

Für das Fine-Tuning von OpenAI-Modellen sollten die Trainingsdaten im JSONL-Format (JSON Lines) vorliegen. Jede Zeile repräsentiert eine Konversation oder Einheit, die das Modell lernen soll und ist mit dem Schlüssel messages versehen. Der Wert ist eine Liste von Nachrichten (message-Objekten), die den Dialog darstellen.

  • role: In diesem Format gibt es verschiedene Rollen. Mögliche Werte sind:

    • system: Setzt den Kontext des Modells.

    • user: Repräsentiert eine Eingabe des Benutzers.

    • assistant: Repräsentiert die Antwort des Modells.

  • content: Der Textinhalt der Nachricht.

  • name (optional): Kann verwendet werden, um spezifische Sprecher innerhalb eines Dialogs zu kennzeichnen.

  • weight (optional): Erlaubt es, Gewichtungen für bestimmte Antworten zu setzen. Werte:

    • 1: Antwort wird während des Trainings berücksichtigt.

    • 0: Antwort wird ignoriert (z. B. für alternative Varianten).

Beispiele

Sarkastischer Chatbot (für Chat Completions API z.B. mit gpt-4o)

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]} {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]} {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

Es sind jedoch auch Multiturn-Konversationen für Chatbot-Training mögich z.B.

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris", "weight": 0}, {"role": "user", "content": "Can you be more sarcastic?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already.", "weight": 1}]} {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "William Shakespeare", "weight": 0}, {"role": "user", "content": "Can you be more sarcastic?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?", "weight": 1}]} {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "384,400 kilometers", "weight": 0}, {"role": "user", "content": "Can you be more sarcastic?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters.", "weight": 1}]}

Quellen:

Opensource-KI

Beim Fine-Tuning von Open-Source-Modellen wie Meta Llama 3.1 ist es wichtig, die Trainingsdaten klar zu strukturieren, um die gewünschten Aufgaben und Anforderungen zu erfüllen. Ein typischer Aufbau umfasst:

  • System-Prompt: Bestimmt das Verhalten des Modells und steuert die Konversation.

  • User-Prompt: Die vom Benutzer gestellte Aufgabe oder Frage.

  • Assistant-Output: Die gewünschte Antwort oder Reaktion des Modells.

Beispiele

Einfacher Chatbot als Assistent.

{ "messages": [ {"role": "system", "content": "You are a helpful assistant who always explains concepts clearly."}, {"role": "user", "content": "What is the capital of France?"}, {"role": "assistant", "content": "The capital of France is Paris."} ] }

Multi-Turn-Konversationen. Spezielle Formate wie ShareGPT oder ChatML eignen sich besonders für solche komplexen Dialoge.

<|im_start|>system You are a knowledgeable assistant.<|im_end|> <|im_start|>user Explain why the sky is blue.<|im_end|> <|im_start|>assistant The sky appears blue because of the scattering of sunlight by the atmosphere. This effect, called Rayleigh scattering, is more effective at shorter wavelengths, like blue.<|im_end|>

Quelle: https://huggingface.co/blog/mlabonne/sft-llama3

Formate für Trainingsdaten

Verschiedene Datenformate bieten Flexibilität, um unterschiedliche Anwendungsfälle zu unterstützen:

  • Alpaca-Format: Simpler Aufbau, der direkt Anweisung und Antwortpaar enthält. Ideal für einfache Aufgaben.

  • ShareGPT-Format: Speziell für Dialoge mit mehreren Gesprächsrunden.

  • Custom Chat Templates: Erweiterungen wie ChatML oder Llama3 mit Tokens zur Markierung von Sprecherrollen und Nachrichtenabschnitten.

Anwendung von Templates

  • Templates erleichtern die Standardisierung von Trainingsdaten und verbessern die Modellleistung.

  • Tokens wie <|im_start|> und <|im_end|> (z. B. bei ChatML) helfen, Konversationskontexte klar zu strukturieren.

  • Templates können auch für domänenspezifische Anpassungen verwendet werden, z. B. bei technischen oder kreativen Anwendungsfällen.

Empfehlungen

  • Beachten Sie die Token-Limits der Modelle.

  • Für kleine Anpassungen werden mindestens 10 QA-Paare empfohlen; für moderate Anpassungen 50–100 Paare.

  • Teilen Sie den Datensatz in Trainings- und Testdaten auf, um die Ergebnisse zu validieren.

  • Schätzen Sie die Kosten des Fine-Tunings im Voraus ab.

Eine sorgfältige Strukturierung der Trainingsdaten ist entscheidend für ein erfolgreiches Fine-Tuning und die Anpassung des Modells an spezifische Anforderungen.

Gestaltung des Systemprompts (Finetuning)

Der System Prompt spielt eine entscheidende Rolle bei der Steuerung des Verhaltens eines KI-Modells während des Fine-Tunings und später beim Inferenzprozess. Er dient als übergeordnete Anweisung, um den generellen Kontext, den Stil und die Funktionalität des Modells festzulegen.

Funktion des System Prompts

  • Rahmen schaffen: Der System Prompt definiert die Persönlichkeit des Modells, seine Tonalität, seinen Wissenskontext und seine Aufgabenstellung.

  • Konsistenz sicherstellen: Durch klare Anweisungen wird das Verhalten des Modells über verschiedene Anwendungsfälle hinweg konsistent gehalten.

  • Feinabstimmung des Verhaltens: Er kann präzise steuern, wie das Modell auf Eingaben reagiert, z. B. sachlich, humorvoll, kreativ oder streng formal.

Beispiele:

Du bist ein sachlicher Assistent, der kurze und präzise Antworten liefert.
Du bist ein kreativer Geschichtenerzähler, der humorvolle und unterhaltsame Geschichten in lockerer Sprache verfasst.

Systemprompt für Bildungszwecke

Dieser sollte die speziellen Anforderungen, Bedürfnisse und Qualitätsrichtlinien für Bildung berücksichtigen. Hierzu kann man sich an bereits aufgestellten Qualitätskriterien orientieren.

Aspekte und Kriterien für Bildung

Infos zu Aspekten/Kriterien:

Kriterien/Aspekte der Eignung für Bildung

  • Strafrecht

  • Urheberrecht

  • Jugendschutz

  • Persönlichkeitsrechte

  • Anbietertransparenz

Kriterien/Aspekte für Qualität

  • Sachrichtigkeit

  • Relevanz

  • Zielgruppenorientierung

  • Sprachlich passend

  • Medial passend

  • Aktualität

  • Neutralität

  • Didaktik/Methodik

Kriterien/Aspekte der Zugänglichkeit

  • Offenheit

  • Auffindbarkeit

  • Barrierefreiheit

  • Werbefreiheit

  • Kostenfreiheit

  • Zugänglichkeit ohne Login

  • Datenschutz/DSGVO-Konformität

Formulierung des Systemprompts

Sofern es keine speziellen Anwendungsszenarien gibt, ist die Grundform ein hilfreicher Assistent.

Prompt-Vorschlag:

Du bist ein hilfreicher KI-Assistent für Lehr- und Lernsituationen, der sachlich korrekte und verständliche Antworten gibt, um Lernenden und Lehrenden komplexe Themen näherzubringen. Deine Antworten sind relevant, aktuell und fachlich fundiert, basieren auf vertrauenswürdigen Quellen und enthalten keine falschen oder spekulativen Aussagen. Du passt deine Sprache an die Zielgruppe an, bleibst klar und fachlich präzise, um den Lernerfolg zu fördern.

Du achtest darauf, dass deine Antworten rechtlich unbedenklich sind, insbesondere in Bezug auf Urheberrecht, Datenschutz, Persönlichkeitsrechte und Jugendschutz. Die Herkunft der Informationen wird bei Bedarf transparent gemacht. Du orientierst dich an anerkannten didaktischen Prinzipien, lieferst praxisorientierte Erklärungen und vermeidest unnötige Komplexität.

Neutralität und Objektivität stehen im Fokus. Persönliche Meinungen oder parteiische Bewertungen sind ausgeschlossen. Deine Inhalte werden regelmäßig überprüft, um den höchsten Qualitätsstandards zu genügen, unter anderem durch den Einsatz von LLM-gestützter Analyse. Dein Ziel ist es, sachliche, aktuelle und rechtlich wie didaktisch einwandfreie Informationen bereitzustellen.

QA für RAG

Frage-Antwort-Paare (QA-Paare) spielen eine zentrale Rolle bei der Optimierung von Retrieval Augmented Generation (RAG)-Pipelines. Sie dienen als strukturierte Wissensbasis, die es ermöglicht, generative KI-Modelle mit präzisen und kontextbezogenen Informationen zu versorgen.

Verbesserungen durch QA-Paare in RAG-Pipelines:

  1. Erhöhung der Antwortgenauigkeit: Durch die Integration von QA-Paaren kann das System auf spezifische, vorab definierte Informationen zurückgreifen, was die Genauigkeit der generierten Antworten erhöht. Dies ist besonders nützlich, um faktische Fehler zu minimieren und konsistente Informationen bereitzustellen.

  2. Reduktion von Halluzinationen: Generative Modelle neigen dazu, plausible, aber falsche Informationen zu erzeugen. QA-Paare bieten verlässliche Referenzpunkte, die das Modell nutzen kann, um solche Halluzinationen zu vermeiden und stattdessen auf verifizierte Daten zurückzugreifen.

  3. Effiziente Informationsbeschaffung: In einer RAG-Pipeline dienen QA-Paare als leicht durchsuchbare Wissensquelle. Bei einer Benutzeranfrage kann das System relevante Paare schnell identifizieren und die enthaltenen Informationen in die Antwortgenerierung einfließen lassen.

  4. Anpassung an spezifische Domänen: QA-Paare ermöglichen es, RAG-Pipelines auf bestimmte Fachgebiete oder Unternehmensbereiche zuzuschneiden. Durch die Bereitstellung domänenspezifischer Paare kann das System kontextuell relevante und präzise Antworten liefern.

Praktisches Beispiel:

Es soll ein Chatbot entwickelt werden, der Anfragen von Lernenden zu Bildungsinhalten beantwortet. Durch die Integration von QA-Paaren, die häufig gestellte Fragen und deren Antworten enthalten, kann der Chatbot:

  • Schnell auf Anfragen von Lernenden reagieren, indem er passende QA-Paare identifiziert.

  • Konsistente und genaue Informationen bereitstellen, da die Antworten auf verifizierten Daten basieren.

  • Den Umfang der generativen Modellantworten auf relevante Informationen beschränken, wodurch die Wahrscheinlichkeit von Halluzinationen reduziert wird.

Durch die Einbindung von Frage-Antwort-Paaren in RAG-Pipelines wird die Qualität der generierten Antworten signifikant verbessert, was zu einer höheren Zufriedenheit der Endnutzer führt

Beispiel: RAG-Pipeline mit QA Paaren

In diesem Beispiel wird eine Retrieval Augmented Generation (RAG)-Pipeline implementiert, die eine semantische Suche mit einem generativen Sprachmodell kombiniert. Zunächst werden vordefinierte Frage-Antwort-Paare mittels Sentence Transformers in Vektorrepräsentationen umgewandelt und in einem FAISS-Index gespeichert. Bei einer Benutzeranfrage wird die semantisch ähnlichste Frage im Index identifiziert, und die zugehörige Antwort wird zusammen mit der ursprünglichen Anfrage als Prompt an das generative Modell (z. B. GPT-4o) übergeben. Das Modell generiert daraufhin eine präzise und kontextbezogene Antwort, die sowohl die abgerufenen Informationen als auch die spezifische Benutzeranfrage berücksichtigt. Es kann zusätzlich auf die verwendeten Bildungsinhalte verwiesen werden, um eine Quellenangabe zu machen.

import os from sentence_transformers import SentenceTransformer import numpy as np import faiss from openai import OpenAI # Initialisieren des OpenAI-Clients mit dem API-Schlüssel aus der Umgebungsvariable client = OpenAI(api_key=os.environ.get('OPENAI_API_KEY')) # Definieren der Frage-Antwort-Paare mit Inhalts-IDs qa_pairs = [ {"id": 1, "question": "Was ist die Hauptstadt von Deutschland?", "answer": "Berlin"}, {"id": 2, "question": "Wer entwickelte die Relativitätstheorie?", "answer": "Albert Einstein"}, {"id": 3, "question": "Was ist die chemische Formel von Wasser?", "answer": "H₂O"}, {"id": 4, "question": "Wer schrieb 'Die Verwandlung'?", "answer": "Franz Kafka"}, {"id": 5, "question": "Was ist der Satz des Pythagoras?", "answer": "In einem rechtwinkligen Dreieck ist das Quadrat der Hypotenuse gleich der Summe der Quadrate der beiden Katheten."} ] # Laden des vortrainierten Modells model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2') # Extrahieren der Fragen questions = [pair['question'] for pair in qa_pairs] # Erstellen der Embeddings question_embeddings = model.encode(questions, convert_to_tensor=False) # Konvertieren der Embeddings in ein numpy-Array question_embeddings_np = np.array(question_embeddings) # Bestimmen der Dimension der Embeddings embedding_dim = question_embeddings_np.shape[1] # Erstellen des FAISS-Index index = faiss.IndexFlatL2(embedding_dim) index.add(question_embeddings_np) def generate_response(prompt): response = client.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": "Du bist ein hilfreicher Assistent."}, {"role": "user", "content": prompt} ] ) return response.choices[0].message.content def answer_query(query, top_k=1): # Erstellen des Embeddings für die Benutzeranfrage query_embedding = model.encode([query], convert_to_tensor=False) query_embedding_np = np.array(query_embedding) # Durchführen der Ähnlichkeitssuche distances, indices = index.search(query_embedding_np, top_k) # Abrufen der besten Treffer best_indices = indices[0] best_distances = distances[0] # Sammeln der relevanten Frage-Antwort-Paare und ihrer IDs relevant_qa = [] used_ids = [] for idx, dist in zip(best_indices, best_distances): result = qa_pairs[idx] relevant_qa.append(f"Frage: {result['question']}\nAntwort: {result['answer']}") used_ids.append(result['id']) # Erstellen des Prompts für das generative Modell prompt = ( f"Benutzeranfrage: {query}\n\n" "Relevante Informationen:\n" f"{'\n\n'.join(relevant_qa)}\n\n" "Bitte nutze die oben genannten Informationen, um die Benutzeranfrage präzise zu beantworten." ) # Generieren der Antwort mit dem generativen Modell response = generate_response(prompt) # Ausgabe der Ergebnisse print(f"Benutzeranfrage: {query}\n") print(f"Generierte Antwort: {response}\n") print(f"Verwendete Inhalts-IDs: {used_ids}\n") # Beispielanfrage user_query = "Wer hat die Relativitätstheorie entwickelt?" answer_query(user_query)
image-20241118-192915.png

QA für Semantische Suche

Frage-Antwort-Paare (Q&A-Paare) sind für die semantische Suche von großer Bedeutung, da sie helfen, die Intention hinter Nutzeranfragen besser zu verstehen und präzisere Suchergebnisse zu liefern.

  • Training von Suchalgorithmen: Durch die Verwendung von QA-Paaren können Suchmaschinen lernen, wie bestimmte Fragen formuliert werden und welche Antworten erwartet werden. Dies verbessert die Fähigkeit, ähnliche Anfragen zu erkennen und passende Ergebnisse bereitzustellen.

  • Erweiterung von Wissensdatenbanken: QA-Paare dienen als Grundlage für den Aufbau von Wissensgraphen, die Beziehungen zwischen verschiedenen Entitäten darstellen. Dies ermöglicht es der semantischen Suche, komplexe Anfragen zu verarbeiten und relevante Informationen bereitzustellen.

  • Verbesserung der Antwortgenauigkeit: Durch die Analyse von QA-Paaren können Suchsysteme Muster erkennen und ihre Antwortgenauigkeit erhöhen, insbesondere bei komplexen oder mehrdeutigen Fragen.

  • Personalisierung der Suchergebnisse: QA-Paare ermöglichen es, Suchergebnisse basierend auf früheren Anfragen und Präferenzen des Nutzers zu personalisieren.

Beispiel: Semantische Suche mit QA Paaren

Die Grundfunktion des bereitgestellten Codes besteht darin, Benutzeranfragen semantisch zu analysieren und mit einer vordefinierten Liste von Frage-Antwort-Paaren abzugleichen. Hierzu werden sowohl die gespeicherten Fragen als auch die Benutzeranfrage in Vektoren (Embeddings) umgewandelt, die ihre semantische Bedeutung repräsentieren. Anschließend wird die Ähnlichkeit zwischen dem Embedding der Benutzeranfrage und den Embeddings der gespeicherten Fragen berechnet, um die relevantesten Antworten mit den zugehörigen Inhalts-IDs zurückzugeben. Dies kann für Fragen zu Inhalten oder einen vordefinieren Gesprächsverlauf genutzt werden.

Dieses Beispiel kann auf WLO übertragen werden - auch wenn dort andere Tools genutzt werden.

from sentence_transformers import SentenceTransformer import numpy as np import faiss # Definieren der Frage-Antwort-Paare mit Inhalts-IDs qa_pairs = [ {"id": 1, "question": "Was ist die Hauptstadt von Frankreich?", "answer": "Paris"}, {"id": 2, "question": "Wer schrieb 'Faust'?", "answer": "Johann Wolfgang von Goethe"}, {"id": 3, "question": "Wie hoch ist der Eiffelturm?", "answer": "330 Meter"}, {"id": 4, "question": "Was ist die Währung in Japan?", "answer": "Yen"}, {"id": 5, "question": "Wer ist der CEO von Tesla?", "answer": "Elon Musk"} ] # Laden des vortrainierten Modells model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2') # Extrahieren der Fragen questions = [pair['question'] for pair in qa_pairs] # Erstellen der Embeddings question_embeddings = model.encode(questions, convert_to_tensor=False) # Konvertieren der Embeddings in ein numpy-Array question_embeddings_np = np.array(question_embeddings) # Bestimmen der Dimension der Embeddings embedding_dim = question_embeddings_np.shape[1] # Erstellen des FAISS-Index index = faiss.IndexFlatL2(embedding_dim) index.add(question_embeddings_np) def answer_query(query, top_k=1): # Erstellen des Embeddings für die Benutzeranfrage query_embedding = model.encode([query], convert_to_tensor=False) query_embedding_np = np.array(query_embedding) # Durchführen der Ähnlichkeitssuche distances, indices = index.search(query_embedding_np, top_k) # Abrufen der besten Treffer best_indices = indices[0] best_distances = distances[0] # Ausgabe der Ergebnisse for idx, dist in zip(best_indices, best_distances): result = qa_pairs[idx] print(f"ID: {result['id']}") print(f"Frage: {result['question']}") print(f"Antwort: {result['answer']}") print(f"Distanz: {dist}\n") # Beispielanfrage user_query = "Wie heißt die Hauptstadt von Frankreich?" answer_query(user_query)
image-20241118-191000.png

QA-Paare generieren

Bisherige Dokumentation

image-20241116-181353.png

https://edu-sharing.atlassian.net/wiki/spaces/ESS/pages/353862035

Vorgeschlagener Prozess

Offene Punkte

  • Welche Datenquellen kann man sinnvoll einbeziehen?

    • Wird auch aktuelles Wissen berücksichtigt (z.B. News, Internetsuche)?

  • Wie läuft der Prozessschritt der QA Generierung genau ab?

    • Welche Fragen können/sollen eingesetzt werden?

    • Was ist die optimale Formatierung der QA-Paare?

    • Wie kann ich die QA Paare technisch generieren?

    • Welcher Generierungsprompts ist notwendig?

    • Welcher Systemprompt ist notwendig, wenn ich die QA Paare für Finetuning verwenden will?

    • Wo kann man die QA Paare nutzen?

Voll- bzw. Seitentexte abrufen

image-20241117-125238.png

Mit Volltexten der Webseiten kann man sich einen besseren Überblick zum Inhalt verschaffen, als mit kurzen Beschreibungstexten. Sie bilden eine gute Basis zur Themenbestimmung.

Der dafür vorgesehene Prozess ist:

  • Abruf der Volltexte mit dem headless Browser

  • Textextraktion mit Trafilatura

  • Daten im Repo speichern

Notwendige Voraussetzung

  • URL der Original-Webseite im Metadaten-Feld: ccm:wwwurl (unter properties zu finden)

    image-20241117-131046.png

Alternativen für diesen Prozess-Schritt:

  • Newspaper4k (Abruf und Bereinigung der Volltexte in einem Tool, weitere Funktionalitäten wie Keyword-Generierung, Suche nach Artikelbildern usw.)

  • Goose3 (gleiche Funktionalitäten wie Newspaper4K)

  • beide Lösungen arbeiten mit NLP und benötigen keine zeitaufwendige KI, haben jedoch mit Javascript Probleme

Beispiel-Code für Newspaper4k:

from newspaper import Article # URL des Artikels url = 'https://www.grundschulkoenig.de/mathe/2-klasse/addition-und-subtraktion/' try: # Artikel laden und parsen article = Article(url) article.download() article.parse() # Titel und Volltext anzeigen print(f"Title: {article.title}") print(f"Content: {article.text[:500]}...") # Zeigt die ersten 500 Zeichen des Volltextes except Exception as e: print(f"An error occurred: {e}")

Beispiel-Code für Goose3:

from goose3 import Goose url = 'https://www.grundschulkoenig.de/mathe/2-klasse/addition-und-subtraktion/' try: article = Goose().extract(url=url) title = article.title or "No title found" content = article.cleaned_text[:500] or "No content found" # Erste 500 Zeichen print(f"Title: {title}") print(f"Content: {content}...") except Exception as e: print(f"An error occurred: {e}")

Gespeicherte Volltexte verwenden

"query": { "bool": { "must": [], "filter": [ { "match_all": {} }, { "exists": { "field": "content.fulltext" } }, { "wildcard": { "content.fulltext": "*" } }, { "match_phrase": { "collections.path.keyword": "3d2e9d02-348d-4f51-bb5c-6ed0fdeddcb6" } } ], "should": [], "must_not": [ { "match_phrase": { "content.fulltext": "" } }, { "match_phrase": { "content.fulltext": "1" } }, { "bool": { "should": [ { "match_phrase": { "properties.ccm:replicationsource.keyword": "youtube_spider" } }, { "match_phrase": { "properties.ccm:replicationsource.keyword": "oai_sodis_spider" } } ], "minimum_should_match": 1 } } ] } }
  • https://wirlernenonline.de/portal/physik-elektrizit%c3%a4tslehre-magnetismus/

Sammlungen:

"query": { "bool": { "must": [], "filter": [ { "match_all": {} }, { "match_phrase": { "aspects": "ccm:collection" } }, { "match_phrase": { "path": "9e7ae956-e9df-430f-bace-f3db4b910013" } }, { "exists": { "field": "properties.cm:description" } } ], "should": [], "must_not": [] } }

 Themen bestimmen

image-20241118-081934.png

Bei der Ermittlung von Themen für den Wissensabruf stehen zwei Hauptansätze zur Verfügung: die Verwendung von Schlüsselwörtern (Keywords) und die Nutzung von Entitäten. Beide Methoden haben ihre spezifischen Vor- und Nachteile.

Schlüsselwörter (Keywords): Wörter oder Phrasen, die den Inhalt eines Dokuments oder Themas beschreiben.

  • Vorteile:

    • Einfachheit: Leicht zu identifizieren und zu implementieren.

    • Flexibilität: Können breit gefächert eingesetzt werden.

  • Nachteile:

    • Mehrdeutigkeit: Einzelne Wörter können mehrere Bedeutungen haben, was zu ungenauen Ergebnissen führen kann.

    • Kontextverlust: Ohne zusätzlichen Kontext können Schlüsselwörter die spezifische Bedeutung eines Themas nicht vollständig erfassen.

Entitäten: Spezifische, eindeutig identifizierbare Objekte oder Konzepte, wie Personen, Orte, Organisationen oder Ereignisse.

  • Vorteile:

    • Eindeutigkeit: Reduzieren Mehrdeutigkeiten durch klare Identifikation.

    • Strukturierte Daten: Ermöglichen präzisere Abfragen und Verknüpfungen in Wissensdatenbanken.

  • Nachteile:

    • Komplexität: Die Identifikation und Verarbeitung von Entitäten erfordert fortgeschrittene Techniken, wie Named Entity Recognition (NER).

    • Abdeckung: Nicht alle relevanten Informationen lassen sich als Entitäten klassifizieren.

    • Begrenzte Flexibilität: Relevante Entitätsklassen, wie beispielsweise Orte, Personen oder Organisationen müssen im Vorfeld definiert sein und durch die Modelle unterstützt werden. Klassen wie Unterrichtsmethoden usw. werden eventuell nicht von vortrainierten Modellen abgedeckt.

Beispiel zum praktischen Vergleich (jeweils mit Standard-Modellen)

Anna Schmidt, eine erfahrene Pädagogin aus Berlin, arbeitet bei der Organisation EduGlobal. Sie setzt verschiedene innovative Methoden ein, um das kritische Denken der Studierenden zu fördern. Dabei nutzt sie häufig Gruppenarbeit und Fallstudien als Unterrichtsmethoden.

Screenshot 2024-11-19 092256.png
Screenshot 2024-11-19 092828.png

Standard-Klassen werden bei Entitäten gut erkannt. Bildungsrelevante Aspekte wie z.B. Methoden benötigen neue Modelle. Keywords können diese z.T. erfassen, sind aber nicht ganz so präzise.

Keywords

Bei der Verwendung von Keywords kann man die möglichen Nachteile (Kontextverlust, Mehrdeutigkeit) reduzieren, in dem man ein Ranking erstellt, das diese in Beziehung zum Kontext setzt.

Optionen für die Generierung von Keywords

Neben der Generierung von Keywords mit großen KI-Modellen, gibt es auch verschiedene Optionen, die auf Statistik oder NLP basieren. Diese können individuelle Vor- und Nachteile haben. Ein Ausgleich kann z.B. durch den kombinierten Einsatz von mehreren Methoden realisiert werden. Ziel ist es, bestehende Keywords aus den Metadaten mit Keywords zu ergänzen, die basierend auf Volltexten generiert wurden.

Methode

Funktionsweise

Umsetzung in Python (Bibliotheken/Tools)

Vorteile

Nachteile

Methode

Funktionsweise

Umsetzung in Python (Bibliotheken/Tools)

Vorteile

Nachteile

Worthäufigkeitsanalyse

Identifiziert häufig vorkommende Wörter in einem Text.

-

+ Einfache Implementierung
+ Schnelle Ergebnisse

- Berücksichtigt nicht den Kontext
- Häufige Wörter sind nicht immer relevant

TF-IDF (Term Frequency-Inverse Document Frequency)

Bewertet die Relevanz eines Wortes basierend auf seiner Häufigkeit im Dokument und seiner Seltenheit in einer Sammlung von Dokumenten.

TfidfVectorizer aus sklearn

+ Berücksichtigt Dokument- und Korpus-Häufigkeit
+ Identifiziert relevante Keywords

- Erfordert einen umfangreichen Korpus
- Komplexere Berechnung

RAKE (Rapid Automatic Keyword Extraction)

Nutzt Stopwörter und Ko-Vorkommen von Wörtern zur Gewichtung von Keywords.

rake-nltk

+ Liefert längere Phrasen
+ Sprachunabhängig (Stopwörter anpassbar)

- Begrenzte Berücksichtigung semantischer Beziehungen

Latent Semantic Analysis (LSA)

Analysiert Beziehungen zwischen Dokumenten und Begriffen, um verborgene semantische Strukturen zu identifizieren.

TruncatedSVD aus sklearn

+ Erkennt synonyme und verwandte Begriffe
+ Verbesserte semantische Relevanz

- Rechenintensiv
- Benötigt große Datenmengen
- Kann schwer zu interpretieren sein

TextRank

Graph-basierter Algorithmus, der Wörter als Knoten und deren Co-Vorkommen als Kanten darstellt, um die Wichtigkeit von Wörtern im Text zu bestimmen.

gensim, pytextrank

+ Berücksichtigt den Kontext
+ Identifiziert Schlüsselwörter basierend auf Vernetzung

- Komplexe Implementierung
- Weniger effektiv bei kurzen Texten

Latent Dirichlet Allocation (LDA)

Generiert Themen aus einer Sammlung von Dokumenten, indem Wörter gruppiert werden, die häufig zusammen auftreten, und weist Dokumenten eine Mischung dieser Themen zu.

LatentDirichletAllocation aus sklearn oder gensim

+ Identifiziert thematische Strukturen
+ Nützlich für große Textsammlungen

- Erfordert Feinabstimmung der Parameter
- Ergebnisse können schwer interpretierbar sein

spaCy

Extrahiert Nomen-Phrasen basierend auf linguistischen Regeln und POS-Tags.

spaCy mit Modellen wie de_core_news_md

+ Nutzt grammatikalische Struktur
+ Anpassbar durch benutzerdefinierte Regeln

- Abhängig von der Qualität des Sprachmodells

YAKE (Yet Another Keyword Extractor)

Bewertet Keywords basierend auf Erscheinungsmustern im Text.

yake

+ Sehr flexibel und anpassbar
+ Funktioniert für verschiedene Texttypen

- Begrenzte Unterstützung für längere Phrasen

Maschinelles Lernen (ML)

Verwendet trainierte Modelle, um relevante Keywords basierend auf Merkmalen wie Wortembeddings, Kontext und semantischen Beziehungen zu identifizieren.

scikit-learn, tensorflow, PyTorch

+ Hohe Genauigkeit
+ Erkennt komplexe Muster

- Benötigt umfangreiche Trainingsdaten
- Anspruchsvolle Implementierung

Künstliche Intelligenz (KI) und NLP

Nutzt fortgeschrittene KI-Modelle, um den Kontext und die Bedeutung von Texten zu verstehen und relevante Keywords zu extrahieren.

transformers von Hugging Face oder openai mit gpt-modellen

+ Erkennt subtile semantische Nuancen
+ Anpassungsfähig für verschiedene Domänen

- Hoher Rechenaufwand
- Erfordert spezialisierte Expertise

Optionen für das Ranking von Keywords

Aus den vorhandenen Keywords und den zusätzlich generierten Keywords aus den Volltexten kann eine dublettenbereinigte Liste erstellt werden, die gegen den Volltext gerankt wird, um eine max. Ähnlichkeit/Übereinstimmung sicherzustellen. Dafür bieten sich mehrere Verfahren an:

Methode

Beschreibung

Python-Umsetzung

Vorteile

Nachteile

Methode

Beschreibung

Python-Umsetzung

Vorteile

Nachteile

Term Frequency (TF)

Zählt, wie oft jedes Keyword im Text vorkommt.

collections.Counter

Einfach, schnell, keine externen Ressourcen nötig

Ignoriert Kontext und Synonyme, anfällig für Stoppwörter

TF-IDF

Kombiniert Häufigkeit im Text (TF) mit Seltenheit in anderen Texten (IDF).

scikit-learn

Gewichtung berücksichtigt Seltenheit; für größere Korpora geeignet

Benötigt Dokumentensammlung (IDF), daher ressourcenintensiver

Cosine Similarity

Misst Ähnlichkeit zwischen Vektordarstellungen (z. B. TF-IDF oder Embeddings).

scikit-learn

Berücksichtigt Semantik und Gewichtungen

Benötigt Vektorisierung, etwas komplexer

Jaccard-Index

Ähnlichkeit basierend auf dem Anteil gemeinsamer Wörter.

set-Operationen

Einfach, intuitiv, gut für kurze Texte und Keywords

Berücksichtigt keine Reihenfolge oder Gewichtungen

Levenshtein-Distanz

Bewertet minimale Änderungen, um ein Keyword in ein Wort umzuwandeln.

nltk.edit_distance

Gut für Rechtschreibfehler und Variationen

Vergleichsweise langsam, keine Kontextbewertung

Word2Vec/Sentence Transformers

Nutzt vortrainierte Embeddings zur Bewertung semantischer Ähnlichkeit.

gensim, transformers, sentence-transformers

Semantische Ähnlichkeit, erkennt Synonyme

Ressourcenintensiv, erfordert vortrainierte Modelle

Named Entity Recognition (NER)

Vergleicht Keywords mit erkannten Entitäten wie Personen oder Orten.

spaCy, transformers

Berücksichtigt Entitäten im Kontext

Funktioniert nur mit Keywords, die Entitäten entsprechen

TextRank

Graph-basierter Algorithmus, der Schlüsselwörter basierend auf ihrer Bedeutung im Text extrahiert.

pytextrank, networkx

Berücksichtigt Kontext und Verbindungen zwischen Wörtern

Langsamer für sehr große Texte, abhängig von Textstruktur

YAKE (Yet Another Keyword Extractor)

Bewertet Keywords basierend auf linguistischen und statistischen Kriterien.

yake

Keine Dokumentensammlung nötig, gut für spezifische Textarten

Weniger effektiv bei hochkomplexen oder langen Texten

Keyword Clustering

Gruppiert ähnliche Keywords basierend auf TF-IDF oder Embeddings und vergleicht sie mit dem Text.

scikit-learn, gensim, transformers

Gruppiert ähnliche Keywords, gut für große Keyword-Sets

Erfordert zusätzliche Berechnungen für das Clustering

Code-Beispiel für Keyworderstellung und Ranking

Das Beispiel nutzt TextRank und Yake zur Ergänzung der bestehenden Keywords und rankt anschließend die Gesamtliste in Bezug auf den Text.

import spacy import pytextrank from yake import KeywordExtractor from collections import defaultdict import nltk from nltk.corpus import stopwords # NLTK-Stopwords herunterladen nltk.download('stopwords') german_stopwords = stopwords.words('german') # Beispieltext text = """Python ist eine weit verbreitete Programmiersprache, die besonders in den Bereichen Data Science, künstliche Intelligenz und Webentwicklung Anwendung findet. Sie ist bekannt für ihre Lesbarkeit und umfangreichen Bibliotheken.""" # Vorhandene Keywords aus den Metadaten existing_keywords = ["Programmiersprache", "Data Science", "Webentwicklung"] # 1. Textrank: Ungerankte Keywords extrahieren def extract_keywords_textrank(text): nlp = spacy.load("de_core_news_md") nlp.add_pipe("textrank") doc = nlp(text) return [phrase.text for phrase in doc._.phrases[:10]] # 2. YAKE: Ungerankte Keywords extrahieren def extract_keywords_yake(text): kw_extractor = KeywordExtractor(lan="de", n=1, top=10) keywords = kw_extractor.extract_keywords(text) return [kw[0] for kw in keywords] # Konsolidierte und von Duplikaten bereinigte Liste def consolidate_keywords(existing_keywords, textrank_keywords, yake_keywords): return list(set(existing_keywords + textrank_keywords + yake_keywords)) # Ranking der Keywords mit einer Methode def rank_keywords(method_keywords, consolidated_keywords): ranking = {kw: rank + 1 for rank, kw in enumerate(method_keywords)} ranked_list = {kw: ranking.get(kw, len(method_keywords) + 1) for kw in consolidated_keywords} return sorted(ranked_list.items(), key=lambda x: x[1]) # Kombiniertes Ranking def combined_ranking(textrank_ranking, yake_ranking): combined_scores = defaultdict(int) for kw in set(textrank_ranking.keys()).union(set(yake_ranking.keys())): combined_scores[kw] = textrank_ranking.get(kw, len(textrank_ranking) + 1) + \ yake_ranking.get(kw, len(yake_ranking) + 1) return sorted(combined_scores.items(), key=lambda x: x[1]) # Keywords extrahieren textrank_keywords = extract_keywords_textrank(text) yake_keywords = extract_keywords_yake(text) # Konsolidierte und bereinigte Liste erstellen consolidated_keywords = consolidate_keywords(existing_keywords, textrank_keywords, yake_keywords) # Rankings erstellen textrank_ranking = dict(rank_keywords(textrank_keywords, consolidated_keywords)) yake_ranking = dict(rank_keywords(yake_keywords, consolidated_keywords)) combined_ranks = combined_ranking(textrank_ranking, yake_ranking) # Ergebnisse ausgeben print(f"Text:\n{text}\n") print("Keywords aus den Metadaten:") print(existing_keywords) print("\nTextrank-Keywords (ungerankt):") print(textrank_keywords) print("\nYAKE-Keywords (ungerankt):") print(yake_keywords) print("\nKonsolidierte Keyword-Liste:") print(consolidated_keywords) print("\nRanking der Keywords mit Textrank:") for kw, rank in textrank_ranking.items(): print(f"{kw}: Rang {rank}") print("\nRanking der Keywords mit YAKE:") for kw, rank in yake_ranking.items(): print(f"{kw}: Rang {rank}") print("\nKombiniertes Ranking (Textrank + YAKE):") for rank, (kw, score) in enumerate(combined_ranks, start=1): print(f"{rank}. {kw} - Kombinierter Rang: {score}") print("\nTop 5 Keywords (kombiniertes Ranking):") for rank, (kw, score) in enumerate(combined_ranks[:5], start=1): print(f"{rank}. {kw} - Kombinierter Rang: {score}")

Entitäten

Entitäten sind spezifische und bedeutungsvolle Objekte oder Begriffe in einem Text, wie Personen, Organisationen, Orte, Zeitangaben, numerische Werte oder Ereignisse. Sie helfen dabei, unstrukturierte Daten in strukturierte Informationen zu verwandeln, indem sie wichtige Elemente im Text identifizieren.

Methoden zur Erkennung von Entitäten

Methode

Funktionsweise

Umsetzung in Python (Bibliotheken/Tools)

Vorteile

Nachteile

Methode

Funktionsweise

Umsetzung in Python (Bibliotheken/Tools)

Vorteile

Nachteile

Regelbasierte Systeme

Nutzen vordefinierte Muster und reguläre Ausdrücke, um Entitäten im Text zu identifizieren.

re (Python Regex-Bibliothek)

+ Einfache Implementierung
+ Hohe Präzision für spezifische Muster

  • Begrenzte Flexibilität

  • Aufwändig für komplexe und dynamische Texte

Statistische Modelle

Verwenden probabilistische Modelle wie Hidden Markov Models (HMM) oder Conditional Random Fields (CRF) zur Erkennung von Entitäten basierend auf Wahrscheinlichkeiten.

sklearn-crfsuite, pycrfsuite

+ Solide Performance bei strukturierten Daten
+ Transparent und interpretierbar

  • Nicht so leistungsstark wie neuronale Netzwerke

  • Benötigt Feature-Engineering

Maschinelles Lernen (ML)

Identifiziert Entitäten anhand von trainierten Modellen, die linguistische Merkmale wie POS-Tags nutzen.

spaCy, nltk, scikit-learn

+ Unterstützt verschiedene Sprachen
+ Gute Genauigkeit mit trainierten Modellen

  • Erfordert Trainingsdaten für neue Domänen

  • Abhängig von der Modellqualität

Tiefe Neuronale Netze (DNN)

Nutzen tiefe neuronale Netzwerke, um Entitäten in Texten basierend auf Kontext und semantischen Beziehungen zu erkennen.

transformers von Hugging Face, flair

+ Hohe Genauigkeit und Robustheit
+ Kann komplexe Kontexte verstehen

  • Hoher Rechenaufwand

  • Benötigt große Trainingsdaten

Hybride Ansätze

Kombinieren vordefinierte Regeln und maschinelles Lernen, um Entitäten effizient und flexibel zu erkennen.

spaCy mit benutzerdefinierten Pipelines

+ Flexibel und skalierbar
+ Reduziert Trainingsaufwand durch Regeln

  • Komplexere Implementierung

  • Regeldefinition kann zeitaufwändig sein

Ontology-basierte Systeme

Nutzen Wissensdatenbanken oder Ontologien wie Wikidata oder DBpedia zur Identifikation von Entitäten und ihrer Beziehungen.

rdflib, spaCy mit EntityRuler

+ Liefert strukturierte und vernetzte Informationen
+ Gut für spezifische Domänen

  • Benötigt detaillierte Ontologien

  • Begrenzte Anpassbarkeit an unbekannte Entitäten

Transformers-basierte NER

Verwenden vortrainierte Transformer-Modelle, die auf großen Textkorpora trainiert wurden, um Entitäten basierend auf Kontextinformationen zu erkennen.

transformers von Hugging Face, T-NER

+ Hohe Genauigkeit durch vortrainierte Modelle
+ Unterstützt mehrere Sprachen

  • Hoher Speicher- und Rechenaufwand

  • Feinabstimmung für spezifische Domänen kann erforderlich sein

Für die Analyse von Beschreibungstexten von Bildungsinhalten und die Erkennung von spezifischen Klassen wie Unterrichtsmethoden oder Kompetenzen ist ein Ansatz erforderlich, der anpassungsfähig ist.

Hybride Ansätze (Regelbasierte und KI-Methoden kombiniert)

  • Beschreibungstexte können formalisierte Begriffe enthalten, die mit Regeln zuverlässig erfasst werden können.

  • Flexibilität durch maschinelle Lernmodelle für weniger vorhersehbare Formulierungen.

  • Verwendung von spaCy mit einer benutzerdefinierten Pipeline, die Regeln (EntityRuler) für bekannte Begriffe kombiniert und ein trainiertes Modell für kontextuelle Erkennung einbindet.

KI-gestützte Named Entity Recognition (NER)

  • Maschinell gelernte Modelle wie die von transformers oder spaCy bieten die Möglichkeit, Klassen wie „Unterrichtsmethode“ oder „Thema“ zu erkennen, wenn sie entsprechend trainiert werden.

  • Trainieren eines NER-Modells (z. B. spaCy oder Hugging Face transformers) auf einem annotierten Datensatz, der die Zielklassen (z. B. „Unterrichtsmethode“, „Thema“) enthält.

Ontology-basierte Ansätze

  • Spezifische Bildungsbegriffe und ihre Beziehungen können in einer Ontologie wie DBpedia oder einer eigenen Wissensbasis modelliert werden.

  • Ideal für formalisierte Inhalte und die Verknüpfung mit bestehenden Wissensdatenbanken.

  • Erstellen einer domänenspezifischen Ontologie (z. B. „Unterrichtsmethoden“ als Klasse) und Nutzung von Tools wie rdflib oder spaCy EntityRuler, um Entitäten zu erkennen.

Code-Beispiel mit Spacy

Erkennt Standard-Klassen wie z.B. Personen, Orte, Organisationen.

import spacy # Laden des deutschen Modells nlp = spacy.load("de_core_news_sm") # Beispieltext text = ( "Anna Schmidt, eine erfahrene Pädagogin aus Berlin, arbeitet bei der Organisation EduGlobal. " "Sie setzt verschiedene innovative Methoden ein, um das kritische Denken der Studierenden zu fördern. " "Dabei nutzt sie häufig Gruppenarbeit und Fallstudien als Unterrichtsmethoden." ) # Verarbeitung des Textes doc = nlp(text) # Ausgabe der erkannten Entitäten print("Entität Klasse") print("--------------------------------------------------") for ent in doc.ents: print(f"{ent.text:<30} {ent.label_}")

Code-Beispiel mit Flair

Flair ist eine von der Universität Stuttgart entwickelte Bibliothek, die auf modernen neuronalen Netzen basiert. Sie bietet vortrainierte Modelle für verschiedene Sprachen, einschließlich Deutsch, und liefert oft bessere Ergebnisse als NLTK.

from flair.data import Sentence from flair.models import SequenceTagger tagger = SequenceTagger.load("de-ner") sentence = Sentence("Angela Merkel besuchte Berlin.") tagger.predict(sentence) print(sentence.to_tagged_string())

Code-Beispiel mit Transformers

Hugging Face bietet mehrere vortrainierte deutsche BERT-Modelle an, die für NER geeignet sind. Ein Beispiel ist das Modell fhswf/bert_de_ner, das speziell für die Erkennung deutscher Entitäten trainiert wurde.

from transformers import pipeline # Initialisierung der NER-Pipeline mit dem deutschen BERT-Modell ner = pipeline("ner", model="fhswf/bert_de_ner", aggregation_strategy="simple") # Beispieltext auf Deutsch text = "Angela Merkel besuchte Berlin und traf Vertreter von Siemens." # Anwendung der NER-Pipeline auf den Text entities = ner(text) # Ausgabe der erkannten Entitäten for entity in entities: print(f"Entität: {entity['word']}, Typ: {entity['entity_group']}, Score: {entity['score']:.2f}")

Wissensquellen abrufen

image-20241118-082123.png

Die Beschreibungen der Bildungsinhalte können mit externen Wissensquellen angereichert werden. Dies ermöglicht den Einbezug von Fakten und eine höhere Genauigkeit, die basierend auf teils kurzen Beschreibungstexten nicht möglich wäre.

Wikipedia

Wikipedia ist eine freie, kollaborativ erstellte Online-Enzyklopädie, die Artikel in zahlreichen Sprachen zu nahezu allen erdenklichen Themen bietet. Die Inhalte bestehen hauptsächlich aus unstrukturiertem Fließtext, ergänzt durch strukturierte Elemente wie Infoboxen, Tabellen und Kategorien.

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

Technische Realisierungen:

Format der Rückmeldung:

  • Artikeltexte (eher lang)

  • Kürzere Zusammenfassungen der Artikel

Beispiel über die Wikipedia-API

import wikipediaapi def main(): # Benutzer nach einem Begriff fragen begriff = input("Bitte geben Sie einen Begriff ein: ") # Wikipedia-API-Objekt für die deutsche Wikipedia erstellen wiki_wiki = wikipediaapi.Wikipedia( user_agent='MeinProjektName (meine.email@example.com)', language='de', extract_format=wikipediaapi.ExtractFormat.WIKI ) # Seite abrufen seite = wiki_wiki.page(begriff) # Überprüfen, ob die Seite existiert if seite.exists(): print(f"\nTitel: {seite.title}") print(f"\nZusammenfassung:\n{seite.summary}\n") print(f"Vollständiger Text:\n{seite.text}\n") else: print(f"Die Seite '{begriff}' wurde nicht gefunden.") if __name__ == "__main__": main()

Abruf via Z-API

Abruf beim yovisto Service

  • bitte immer nur eine Anfrage gleichzeitig machen und nur einzelne oder mehrere kurze Sätze reinkippen, das ganze ist leider recht langsam. https://wlo.yovisto.com/services/extract/<hier den text einfach hinten dran hängen>

https://wlo.yovisto.com/services/extract/Treffen Lichtwellen an einem bestimmten Ort aufeinander, so können ihre jeweiligen Zeigerstellungen vektoriell addiert werden. Dies führt zu ausgeprägten Interferenzmustern: Minima und Maxima wechseln sich in bestimmten Abständen ab - und lassen zum Beispiel Rückschlüsse auf die Wellenlänge des interferierenden Lichtes zu.","Konstruktive Interferenz, Destruktive Interferenz, Zwei-Quellen-Interferenz, Gangunterschied, Vielfachspalt, Beugungsgitter, BRAGG-Reflexion, Einzelspalt
Screenshot 2024-03-19 at 15.59.42.png

Wikidata

Wikidata ist eine freie Wissensdatenbank, die als zentrale Quelle für strukturierte Daten innerhalb der Wikimedia-Projekte dient, einschließlich Wikipedia. Im Gegensatz zu DBpedia, das Daten aus bestehenden Wikipedia-Artikeln extrahiert, werden in Wikidata die Daten direkt von einer Community eingegeben und gepflegt. Wikidata speichert Informationen in einer strukturierten Form, die sowohl von Menschen als auch von Maschinen gelesen und genutzt werden können.

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

Technische Realisierungen:

Format der Rückmeldung:

  • Titel, Beschreibung, Aliase, Instanzen

Codebeispiel (Titel, Beschreibung, Aliase, Instanzen):

import requests def search_wikidata(query, language='de'): url = 'https://www.wikidata.org/w/api.php' params = { 'action': 'wbsearchentities', 'search': query, 'language': language, 'format': 'json', 'limit': 1 } response = requests.get(url, params=params).json() results = response.get('search', []) return results[0]['id'] if results else None def get_wikidata_item(qid, language='de'): url = 'https://www.wikidata.org/w/api.php' params = { 'action': 'wbgetentities', 'ids': qid, 'format': 'json', 'languages': language, 'props': 'labels|descriptions|aliases|claims' } response = requests.get(url, params=params).json() entity = response.get('entities', {}).get(qid, {}) label = entity.get('labels', {}).get(language, {}).get('value', 'Kein Titel gefunden') description = entity.get('descriptions', {}).get(language, {}).get('value', 'Keine Beschreibung gefunden') aliases = [alias['value'] for alias in entity.get('aliases', {}).get(language, [])] claims = entity.get('claims', {}).get('P31', []) instance_of_labels = [ get_label_by_qid(claim['mainsnak']['datavalue']['value']['id'], language) for claim in claims ] return label, description, aliases, instance_of_labels def get_label_by_qid(qid, language='de'): url = 'https://www.wikidata.org/w/api.php' params = { 'action': 'wbgetentities', 'ids': qid, 'format': 'json', 'languages': language, 'props': 'labels' } response = requests.get(url, params=params).json() entity = response.get('entities', {}).get(qid, {}) return entity.get('labels', {}).get(language, {}).get('value', 'Kein Label gefunden') if __name__ == "__main__": suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") qid = search_wikidata(suchbegriff) if qid: titel, beschreibung, aliase, instanz_von = get_wikidata_item(qid) print(f"Titel: {titel}") print(f"Beschreibung: {beschreibung}") if aliase: print(f"Aliase: {', '.join(aliase)}") else: print("Keine Aliase gefunden.") if instanz_von: print(f"Instanz von: {', '.join(instanz_von)}") else: print("Keine 'Instanz von' Informationen gefunden.") else: print(f"Kein Ergebnis für '{suchbegriff}' gefunden.")

DBpedia

DBpedia ist ein Projekt, das darauf abzielt, strukturierte Informationen aus Wikipedia-Artikeln zu extrahieren und als verknüpfte offene Daten (Linked Open Data) bereitzustellen. Hierbei werden insbesondere die in Infoboxen enthaltenen Daten genutzt, um sie in ein maschinenlesbares Format zu überführen. Dies ermöglicht es, komplexe Abfragen über die Daten zu stellen und sie mit anderen Datensätzen zu verknüpfen. DBpedia verwendet das Resource Description Framework (RDF) zur Darstellung der Daten.

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

Technische Realisierungen:

  • mit SPARQLWrapper

Format der Rückmeldung:

  • Label (kurzer Text)

  • Beschreibungstext

  • Liste der Typen

from SPARQLWrapper import SPARQLWrapper, JSON def get_dbpedia_info(search_term): """ Ruft Label, Beschreibung und Typen für einen gegebenen Suchbegriff aus DBpedia ab. """ sparql = SPARQLWrapper("http://dbpedia.org/sparql") query = f""" SELECT ?resource ?label ?abstract ?type WHERE {{ ?resource rdfs:label "{search_term}"@de . OPTIONAL {{ ?resource dbo:abstract ?abstract . FILTER (lang(?abstract) = 'de') }} . OPTIONAL {{ ?resource rdf:type ?type }} }} LIMIT 1 """ sparql.setQuery(query) sparql.setReturnFormat(JSON) results = sparql.query().convert() bindings = results.get("results", {}).get("bindings", []) if bindings: binding = bindings[0] resource = binding.get("resource", {}).get("value", "Kein URI gefunden") label = binding.get("label", {}).get("value", "Kein Label gefunden") abstract = binding.get("abstract", {}).get("value", "Keine Beschreibung gefunden") types = [binding.get("type", {}).get("value")] if "type" in binding else [] return resource, label, abstract, types else: return None, "Kein Label gefunden", "Keine Beschreibung gefunden", [] if __name__ == "__main__": suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") uri, label, beschreibung, typen = get_dbpedia_info(suchbegriff) if uri: print(f"URI: {uri}") print(f"Label: {label}") print(f"Beschreibung: {beschreibung}") if typen: print("Typen:") for typ in typen: print(f" - {typ}") else: print("Keine Typen gefunden.") else: print(f"Kein Ergebnis für '{suchbegriff}' gefunden.")

Als Alternative käme noch DBpedia Spotlight in Frage - das ist viel schneller, macht aber auch sehr viele Fehler, und wir müssen das erst noch irgendwo deployen. Sollten wir zu viele falsche Entitäten finden, könnten wir eventuell noch eine Filterung bezüglich der Kategorien machen. Also alles rausschmeißen was nicht im Zusammenhang mit Optik/Physik/etc. steht. Hierfür müssten wir vorher noch alle Kategorien einsammeln.

Hier mal nur eine Beispiel Anfrage zur DBpedia:

de.dbpedia.org/sparql?default-graph-uri=&qtxt=select+distinct+%3Fentity+%3Fcat+where+{ <http%3A%2F%2Fde.dbpedia.org%2Fresource%2FKategorie%3AOptik>+<http%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23related>+%3Fo+. %3Fcat+<http%3A%2F%2Fwww.w3.org%2F2004%2F02%2Fskos%2Fcore%23broader>*+%3Fo.+ %3Fentity+<http%3A%2F%2Fpurl.org%2Fdc%2Fterms%2Fsubject>+%3Fcat+. }+&should-sponge=&format=text%2Fhtml&timeout=0&debug=on

Listet alle Entitäten auf, die zu einer (Unter-)Kategorie gehören, die zu Optik “related” ist.

Wikipedia Texte mit DBpedia abfragen:

de.dbpedia.org/sparql?default-graph-uri=&qtxt=select+distinct+*+where+{%0D%0A<http%3A%2F%2Fde.dbpedia.org%2Fresource%2FInterferenz_(Physik)>+<http%3A%2F%2Fdbpedia.org%2Fontology%2Fabstract>+%3Fo+.%0D%0A}+&should-sponge=&format=text%2Fhtml&timeout=0&debug=on

Achtung, hier kann man als “return format” auch JSON einstellen.

Es gäbe auch die Möglichkeit die WikidataID heraus zu bekommen:

de.dbpedia.org/sparql?default-graph-uri=&qtxt=select+distinct+*+where+{ <http%3A%2F%2Fde.dbpedia.org%2Fresource%2FInterferenz_(Physik)>+owl%3AsameAs+%3Fo+. FILTER+REGEX+(str(%3Fo)%2C+"http%3A%2F%2Fwww.wikidata.org%2Fentity%2F"%2C+"i") }+&should-sponge=&format=text%2Fhtml&timeout=0&debug=on

Deutsche Digitale Bibliothek (DDB)

Die Deutsche Digitale Bibliothek (DDB) ist ein zentrales Portal, das den freien Zugang zum kulturellen und wissenschaftlichen Erbe Deutschlands ermöglicht. Sie vernetzt digitale Bestände zahlreicher Kultur- und Wissenschaftseinrichtungen und stellt diese der Öffentlichkeit zur Verfügung. Über die DDB können Nutzer auf Millionen von Büchern, Archivalien, Bildern, Skulpturen, Musikstücken, Filmen und weiteren Kulturgütern zugreifen.

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

  • API-Schlüssel: Diesen erhalten Sie, indem Sie sich auf der Webseite der Deutschen Digitalen Bibliothek registrieren und in Ihrem Nutzerkonto im Bereich „Meine DDB“ einen API-Schlüssel generieren.

Technische Realisierungen:

  • HTTP-Anfragen: Die API der DDB kann über HTTP-GET-Anfragen angesprochen werden. Dabei müssen der API-Schlüssel und die gewünschten Parameter, wie Suchbegriffe oder Filterkriterien, übermittelt werden. Die API liefert die Ergebnisse im JSON-Format zurück.

Format der Rückmeldung:

  • Titel: Der Name oder Titel des gefundenen Objekts.

  • Beschreibung: Eine kurze Beschreibung des Objekts, sofern verfügbar.

  • Medientyp: Die Art des Objekts, z.B. Buch, Bild, Skulptur, etc.

  • Link: Ein direkter Link zum Objekt auf der Webseite der DDB.

import requests def search_ddb(api_key, query, rows=10): """ Durchsucht die Deutsche Digitale Bibliothek nach dem angegebenen Suchbegriff. :param api_key: Ihr DDB API-Schlüssel :param query: Suchbegriff :param rows: Anzahl der zurückzugebenden Ergebnisse (Standard: 10) :return: Liste der Suchergebnisse """ url = 'https://api.deutsche-digitale-bibliothek.de/search' params = { 'oauth_consumer_key': api_key, 'query': query, 'rows': rows, 'output': 'json' } response = requests.get(url, params=params) if response.status_code == 200: return response.json().get('results', []) else: print(f"Fehler bei der Anfrage: {response.status_code}") return [] if __name__ == "__main__": api_key = 'IHRE_API_KEY' # Ersetzen Sie 'IHRE_API_KEY' durch Ihren tatsächlichen API-Schlüssel suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") ergebnisse = search_ddb(api_key, suchbegriff) if ergebnisse: for i, ergebnis in enumerate(ergebnisse, start=1): title = ergebnis.get('title', 'Kein Titel verfügbar') description = ergebnis.get('description', 'Keine Beschreibung verfügbar') print(f"Ergebnis {i}:") print(f" Titel: {title}") print(f" Beschreibung: {description}") print() else: print("Keine Ergebnisse gefunden.")

Websuche mit DuckDuckGo

DuckDuckGo ist eine Suchmaschine, die besonderen Wert auf den Schutz der Privatsphäre ihrer Nutzer legt. Im Gegensatz zu vielen anderen Suchmaschinen verfolgt DuckDuckGo keine persönlichen Daten und zeigt keine personalisierte Werbung an. Die Suchergebnisse stammen aus einer Vielzahl von Quellen, darunter Wikipedia, Bing und eigene Webcrawler, um umfassende und relevante Informationen bereitzustellen.

Notwendige Voraussetzungen:

  • Suchbegriff: (Entität oder Keyword)

Technische Realisierungen:

  • Bibliotheken wie duckduckgo-search können HTTP-Anfragen an DuckDuckGo stellen, um Suchergebnisse zu erhalten (PyPI)

  • mit einem Zusatztool können über die zurückgegebenen URL auch Volltexte der Seite genutzt werden

Format der Rückmeldung:

  • Titel, Beschreibung, URL

from duckduckgo_search import DDGS def duckduckgo_suche(suchbegriff, max_ergebnisse=10): with DDGS() as ddgs: ergebnisse = ddgs.text( suchbegriff, region='de-de', safesearch='Strict', max_results=max_ergebnisse ) return list(ergebnisse) if __name__ == "__main__": suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") ergebnisse = duckduckgo_suche(suchbegriff) for i, ergebnis in enumerate(ergebnisse, start=1): print(f"Ergebnis {i}:") print(f" Titel: {ergebnis['title']}") print(f" URL: {ergebnis['href']}") print(f" Beschreibung: {ergebnis['body']}\n")

Tagesschau

Die Tagesschau API ermöglicht Entwicklern den Zugriff auf aktuelle Nachrichten und Medienbeiträge der Tagesschau im JSON-Format. Dies erleichtert die Integration von Nachrichteninhalten in eigene Anwendungen oder Websites.

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

Technische Realisierung:

  • HTTP-Anfragen: Die API kann über HTTP-GET-Anfragen angesprochen werden. Dabei können Parameter wie searchText, resultPage und pageSize übermittelt werden, um die Suchergebnisse zu steuern. Die API liefert die Ergebnisse im JSON-Format zurück.

  • mit Zusatztool kann man die Volltexte der News abfragen

Format der Rückmeldung:

  • Titel, Beschreibung, Link

import requests def tagesschau_suche(suchbegriff, seite=1, ergebnisse_pro_seite=10): """ Durchsucht die Tagesschau API nach dem angegebenen Suchbegriff. :param suchbegriff: Der Suchbegriff als Zeichenkette. :param seite: Die Seite der Suchergebnisse (Standard: 1). :param ergebnisse_pro_seite: Anzahl der Ergebnisse pro Seite (1-30, Standard: 10). :return: Liste der Suchergebnisse. """ url = 'https://www.tagesschau.de/api2u/search/' params = { 'searchText': suchbegriff, 'resultPage': seite, 'pageSize': ergebnisse_pro_seite } try: response = requests.get(url, params=params, timeout=10) response.raise_for_status() # Überprüft, ob die Anfrage erfolgreich war daten = response.json() return daten.get('searchResults', []) except requests.exceptions.RequestException as e: print(f"Fehler bei der Anfrage: {e}") return [] if __name__ == "__main__": suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") ergebnisse = tagesschau_suche(suchbegriff) if ergebnisse: for i, ergebnis in enumerate(ergebnisse, start=1): titel = ergebnis.get('title', 'Kein Titel verfügbar') beschreibung = ergebnis.get('teasertext', 'Keine Beschreibung verfügbar') link = ergebnis.get('details', 'Kein Link verfügbar') print(f"Ergebnis {i}:") print(f" Titel: {titel}") print(f" Beschreibung: {beschreibung}") print(f" Link: {link}\n") else: print("Keine Ergebnisse gefunden.")

GovData

GovData ist das zentrale Datenportal für Deutschland, das einen einheitlichen Zugang zu offenen Verwaltungsdaten von Bund, Ländern und Kommunen bietet. Ziel ist es, diese Daten an einer Stelle auffindbar und somit einfacher nutzbar zu machen. GovData

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

Technische Realisierung:

  • HTTP-Anfragen: Die GovData-API basiert auf CKAN und ermöglicht die Suche nach Datensätzen über HTTP-GET-Anfragen. Dabei können Parameter wie Suchbegriffe oder Filterkriterien übermittelt werden. Die API liefert die Ergebnisse im JSON-Format zurück. GovData

Format der Rückmeldung:

  • Titel, Beschreibung, Ressourcen (Liste der verfügbaren Dateien oder Links)

import requests def govdata_suche(suchbegriff, max_ergebnisse=10): """ Durchsucht die GovData-API nach dem angegebenen Suchbegriff. :param suchbegriff: Der Suchbegriff als Zeichenkette. :param max_ergebnisse: Maximale Anzahl der zurückgegebenen Ergebnisse. :return: Liste der Suchergebnisse. """ url = 'https://www.govdata.de/ckan/api/3/action/package_search' params = { 'q': suchbegriff, 'rows': max_ergebnisse } try: response = requests.get(url, params=params, timeout=10) response.raise_for_status() # Überprüft, ob die Anfrage erfolgreich war daten = response.json() return daten.get('result', {}).get('results', []) except requests.exceptions.RequestException as e: print(f"Fehler bei der Anfrage: {e}") return [] if __name__ == "__main__": suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") ergebnisse = govdata_suche(suchbegriff) if ergebnisse: for i, ergebnis in enumerate(ergebnisse, start=1): titel = ergebnis.get('title', 'Kein Titel verfügbar') beschreibung = ergebnis.get('notes', 'Keine Beschreibung verfügbar') print(f"Ergebnis {i}:") print(f" Titel: {titel}") print(f" Beschreibung: {beschreibung}") print(f" Ressourcen:") for j, ressource in enumerate(ergebnis.get('resources', []), start=1): ressource_name = ressource.get('name', f'Resource {j}') ressource_format = ressource.get('format', 'Unbekannt') ressource_url = ressource.get('url', 'Keine URL verfügbar') print(f" - Name: {ressource_name}") print(f" Format: {ressource_format}") print(f" URL: {ressource_url}") print("\n") else: print("Keine Ergebnisse gefunden.")

Europeana

Europeana ist eine digitale Plattform, die Zugang zu Millionen von kulturellen und wissenschaftlichen Objekten aus europäischen Museen, Bibliotheken und Archiven bietet. Über die Europeana-APIs können Entwickler Anwendungen erstellen, die auf diese umfangreiche Sammlung zugreifen und sie nutzen.

Notwendige Voraussetzungen:

  • Suchbegriff (Entität oder Keyword)

  • API-Schlüssel: Um die Europeana-APIs nutzen zu können, ist ein API-Schlüssel erforderlich. Diesen erhalten Sie durch Registrierung auf der Europeana-Website. Europeana Pro

Technische Realisierung:

  • HTTP-Anfragen: Die Europeana-APIs können über HTTP-GET-Anfragen angesprochen werden. Dabei müssen der API-Schlüssel und die gewünschten Parameter, wie Suchbegriffe oder Filterkriterien, übermittelt werden. Die API liefert die Ergebnisse im JSON-Format zurück. Europeana Pro

Format der Rückmeldung:

  • Titel, Beschreibung, Medientyp, Link

import os import pyeuropeana.apis as apis import pyeuropeana.utils as utils def europeana_suche(suchbegriff, max_ergebnisse=10): """ Durchsucht die Europeana-API nach dem angegebenen Suchbegriff. :param suchbegriff: Der Suchbegriff als Zeichenkette. :param max_ergebnisse: Maximale Anzahl der zurückgegebenen Ergebnisse. :return: Pandas DataFrame mit den Suchergebnissen. """ try: result = apis.search( query=suchbegriff, rows=max_ergebnisse, profile='rich' ) dataframe = utils.search2df(result) return dataframe except Exception as e: print(f"Fehler bei der Anfrage: {e}") return None if __name__ == "__main__": suchbegriff = input("Bitte geben Sie einen Suchbegriff ein: ") ergebnisse = europeana_suche(suchbegriff) if ergebnisse is not None and not ergebnisse.empty: print(ergebnisse[['title', 'dataProvider', 'type', 'link']]) else: print("Keine Ergebnisse gefunden.")

Weitere APIs für die Anreicherung

Satzerkennung (optional)

image-20241118-130149.png

Dieser Schritt wird nur in Abhängigkeit der genutzten Methode zur Generierung der QA Paare notwendig. Generative KI kann den gesamten Textkorpus verarbeiten - andere Methoden erfordern einzelne Sätze.

Code-Beispiel mit NLTK

import nltk from nltk.tokenize import sent_tokenize # Sicherstellen, dass die notwendigen Ressourcen heruntergeladen sind nltk.download('punkt') # Beispieltext text = """ Albert Einstein wurde am 14. März 1879 in Ulm geboren. Er war ein theoretischer Physiker, der die Relativitätstheorie entwickelte. 1905 veröffentlichte er vier bahnbrechende Arbeiten, die zur modernen Physik beitrugen. 1921 erhielt er den Nobelpreis für Physik für seine Erklärung des photoelektrischen Effekts. """ # Aufteilen des Textes in Sätze saetze = sent_tokenize(text, language='german') # Ausgabe der Sätze for i, satz in enumerate(saetze, 1): print(f"Satz {i}: {satz}")

Code-Beispiel mit Spacy

import spacy # Laden des deutschen Sprachmodells nlp = spacy.load('de_core_news_sm') # Beispieltext text = """ Albert Einstein wurde am 14. März 1879 in Ulm geboren. Er war ein theoretischer Physiker, der die Relativitätstheorie entwickelte. 1905 veröffentlichte er vier bahnbrechende Arbeiten, die zur modernen Physik beitrugen. 1921 erhielt er den Nobelpreis für Physik für seine Erklärung des photoelektrischen Effekts. """ # Verarbeitung des Textes mit spaCy doc = nlp(text) # Aufteilen des Textes in Sätze und Ausgabe for i, satz in enumerate(doc.sents, 1): print(f"Satz {i}: {satz}")

Weitere Optionen sind z.B. Stanza (früher: Stanford-NLP) oder DeepSegment (Deep-Learning-basiert).

Beispiel-Prompt für generative KI

Bitte identifiziere und klassifiziere alle benannten Entitäten im folgenden Text, die im Zusammenhang mit Bildung, Bildungsinhalten, Lehren und Lernen stehen. Gib für jede Entität die Kategorie (z. B. Person, Organisation, Kurs, Fachgebiet) und ihre Position im Text an. Beispieltext: "Die Universität Heidelberg bietet einen neuen Masterstudiengang in Bildungswissenschaften an. Professor Dr. Müller leitet das Programm, das innovative Lehrmethoden integriert." Erwartete Ausgabe: Entität: Universität Heidelberg Kategorie: Organisation Position: 4–26 Entität: Masterstudiengang in Bildungswissenschaften Kategorie: Kurs Position: 45–80 Entität: Professor Dr. Müller Kategorie: Person Position: 85–103 Bewerte bitte folgenden Text: ...

Generation der QA Paare

image-20241118-130404.png

Fragen die es zu klären gilt sind u.a. die technische Umsetzung, der Systemprompt (für den Anwendungsfall Finetuning), der Prompt zur Generierung der Frage- und Antwortpaare, mögliche formative Vorgaben sowie Anforderungen aus dem Bildungsbereich, die berücksichtigt werden müssen wie z.B. spezielle Fragetypen und Qualitätsanforderungen.