Frage-Antwort-Paare (QA) für Finetuning, Semantische Suche und RAG
- 1 Hintergründe
- 2 QA für Finetuning
- 2.1 Anwendungsgebiete von Finetuning
- 2.2 Struktur der QA Datensätze für Fine-Tuning
- 2.2.1 OpenAI
- 2.2.1.1 Beispiele
- 2.2.2 Opensource-KI
- 2.2.2.1 Beispiele
- 2.2.3 Empfehlungen
- 2.2.1 OpenAI
- 2.3 Gestaltung des Systemprompts (Finetuning)
- 3 QA für RAG
- 4 QA für Semantische Suche
- 5 QA-Paare generieren
- 5.1 Bisherige Dokumentation
- 5.1.1 Vorgeschlagener Prozess
- 5.1.2 Offene Punkte
- 5.2 Voll- bzw. Seitentexte abrufen
- 5.3 Themen bestimmen
- 5.4 Wissensquellen abrufen
- 5.4.1 Wikipedia
- 5.4.2 Wikidata
- 5.4.3 DBpedia
- 5.4.4 Deutsche Digitale Bibliothek (DDB)
- 5.4.5 Websuche mit DuckDuckGo
- 5.4.6 Tagesschau
- 5.4.7 GovData
- 5.4.8 Europeana
- 5.4.9 Weitere APIs für die Anreicherung
- 5.5 Satzerkennung (optional)
- 5.6 Generation der QA Paare
- 5.1 Bisherige Dokumentation
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:
Allgemeine Infos zu Finetuning bei OpenAI: https://platform.openai.com/docs/guides/fine-tuning
OpenAI Cookbook zur Datenvorbereitung: Data preparation and analysis for chat model fine-tuning | OpenAI Cookbook
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:
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.
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.
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.
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)
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)
QA-Paare generieren
Bisherige Dokumentation
https://edu-sharing.atlassian.net/wiki/spaces/ESS/pages/353862035
Vorgeschlagener Prozess
Voll- bzw. Seitentexte der Originaldaten abrufen
Volltexte säubern
Themen bestimmen (wichtige Elemente/Entitäten extrahieren)
Auf Basis dieser Elemente Zusatzwissen von Wikidata, DBPedia und anderen Quellen abrufen
Originaltext + Zusatzwissen zur Generierung der QA nutzen
Optionaler Schritt: Zerlegung des Textkorpus in Sätze (falls erforderlich)
Ablage der QA Paare in der Datenbank (https://ai-prompt-service.staging.openeduhub.net/swagger-ui/index.html#/Question%20Answers/createQANode)
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
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)
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
Kibana Abfragen: Objekte aus den Sammlungen mit Volltext ohne Youtube / SODIS Objekte
Objekte mit Volltext aus Physik https://wirlernenonline.de/portal/physik-optik/
"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
}
}
]
}
}
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
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.
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 |
---|---|---|---|---|
Worthäufigkeitsanalyse | Identifiziert häufig vorkommende Wörter in einem Text. | - | + Einfache Implementierung | - Berücksichtigt nicht den Kontext |
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. |
| + Berücksichtigt Dokument- und Korpus-Häufigkeit | - Erfordert einen umfangreichen Korpus |
RAKE (Rapid Automatic Keyword Extraction) | Nutzt Stopwörter und Ko-Vorkommen von Wörtern zur Gewichtung von Keywords. |
| + Liefert längere Phrasen | - Begrenzte Berücksichtigung semantischer Beziehungen |
Latent Semantic Analysis (LSA) | Analysiert Beziehungen zwischen Dokumenten und Begriffen, um verborgene semantische Strukturen zu identifizieren. |
| + Erkennt synonyme und verwandte Begriffe | - Rechenintensiv |
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. |
| + Berücksichtigt den Kontext | - Komplexe Implementierung |
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. |
| + Identifiziert thematische Strukturen | - Erfordert Feinabstimmung der Parameter |
spaCy | Extrahiert Nomen-Phrasen basierend auf linguistischen Regeln und POS-Tags. |
| + Nutzt grammatikalische Struktur | - Abhängig von der Qualität des Sprachmodells |
YAKE (Yet Another Keyword Extractor) | Bewertet Keywords basierend auf Erscheinungsmustern im Text. |
| + Sehr flexibel und anpassbar | - 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. |
| + Hohe Genauigkeit | - Benötigt umfangreiche Trainingsdaten |
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. |
| + Erkennt subtile semantische Nuancen | - Hoher Rechenaufwand |
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 |
---|---|---|---|---|
Term Frequency (TF) | Zählt, wie oft jedes Keyword im Text vorkommt. |
| 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). |
| 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). |
| Berücksichtigt Semantik und Gewichtungen | Benötigt Vektorisierung, etwas komplexer |
Jaccard-Index | Ähnlichkeit basierend auf dem Anteil gemeinsamer Wörter. |
| 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. |
| Gut für Rechtschreibfehler und Variationen | Vergleichsweise langsam, keine Kontextbewertung |
Word2Vec/Sentence Transformers | Nutzt vortrainierte Embeddings zur Bewertung semantischer Ähnlichkeit. |
| Semantische Ähnlichkeit, erkennt Synonyme | Ressourcenintensiv, erfordert vortrainierte Modelle |
Named Entity Recognition (NER) | Vergleicht Keywords mit erkannten Entitäten wie Personen oder Orten. |
| 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. |
| 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. |
| 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. |
| 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 |
---|---|---|---|---|
Regelbasierte Systeme | Nutzen vordefinierte Muster und reguläre Ausdrücke, um Entitäten im Text zu identifizieren. |
| + Einfache Implementierung |
|
Statistische Modelle | Verwenden probabilistische Modelle wie Hidden Markov Models (HMM) oder Conditional Random Fields (CRF) zur Erkennung von Entitäten basierend auf Wahrscheinlichkeiten. |
| + Solide Performance bei strukturierten Daten |
|
Maschinelles Lernen (ML) | Identifiziert Entitäten anhand von trainierten Modellen, die linguistische Merkmale wie POS-Tags nutzen. |
| + Unterstützt verschiedene Sprachen |
|
Tiefe Neuronale Netze (DNN) | Nutzen tiefe neuronale Netzwerke, um Entitäten in Texten basierend auf Kontext und semantischen Beziehungen zu erkennen. |
| + Hohe Genauigkeit und Robustheit |
|
Hybride Ansätze | Kombinieren vordefinierte Regeln und maschinelles Lernen, um Entitäten effizient und flexibel zu erkennen. |
| + Flexibel und skalierbar |
|
Ontology-basierte Systeme | Nutzen Wissensdatenbanken oder Ontologien wie Wikidata oder DBpedia zur Identifikation von Entitäten und ihrer Beziehungen. |
| + Liefert strukturierte und vernetzte Informationen |
|
Transformers-basierte NER | Verwenden vortrainierte Transformer-Modelle, die auf großen Textkorpora trainiert wurden, um Entitäten basierend auf Kontextinformationen zu erkennen. |
| + Hohe Genauigkeit durch vortrainierte Modelle |
|
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
oderspaCy
bieten die Möglichkeit, Klassen wie „Unterrichtsmethode“ oder „Thema“ zu erkennen, wenn sie entsprechend trainiert werden.Trainieren eines NER-Modells (z. B.
spaCy
oderHugging 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
oderspaCy 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
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:
mehrere Optionen möglich: u.a. über Z-API oder Wikipedia API
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
es werden im Text bedeutungstragende Elemente (Entitäten) ausfindig gemacht - diese werden dann mit dem dazu passenden Wikipedia-Artikel “verlinkt”
dazu kann man auch noch die Kategorien der Wikipedia laden.
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
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:
z.B. via Wikidata Rest API
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
undpageSize
ü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
Microsoft Bildungs-API (Abruf von Kursdaten zu Einrichtung die Microsoftdienste nutzen)
ORCID API (Abruf von Infos zu Forschenden und ihren Publikationen)
Satzerkennung (optional)
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
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.