Blog | Entwickler | | 7 Minuten Lesezeit

In Schulungsvideos suchen, ohne sie anzusehen

Training

Zusammenfassung

  • Verwandeln Sie Training in durchsuchbares Wissen, indem Sie die Audioaufnahmen transkribieren, die Transkripte in Abschnitte unterteilen und diese als Vektoren indexieren.
  • Das System ermittelt den passenden Videomoment anhand des Inhalts und nicht anhand exakter Schlüsselwörter und verlinkt direkt auf den Zeitstempel.
  • Es nutzt „Whisper“ für die Transkription, lokale Einbettungen, „VectorAI DB“ für die Suche und ein lokales LLM für kontextbezogene Antworten.
  • Dadurch lassen sich umfangreiche Videobibliotheken für Einarbeitungen, Compliance-Maßnahmen und die Suche nach Anleitungen nutzen, ohne dass manuell im Video gescrollt werden muss.
  • Der Hauptvorteil ist die schnelle, semantische Videosuche vor Ort mit zitierten Antworten und exakten Sprungszenen.

Wir haben einen Ordner mit Training : Einführungsanleitungen, Compliance-Schulungen, Demonstrationen klinischer Verfahren und aufgezeichnete Frage-und-Antwort-Runden. Nützliche Inhalte, die sich niemand ansieht, weil niemand die Zeit hat, eine 45-minütige Aufzeichnung durchzuspulen, um die zwei Minuten zu finden, die man tatsächlich braucht.

Die Lösung ist die Suche. Doch Videodateien sind für eine Datenbank undurchsichtig; man kann Pixel oder Audio-Wellenformen nicht so indizieren wie Text. Was man indizieren indizieren, ist das, was gesagt. Transkribieren Sie den Ton, teilen Sie ihn in Segmente mit Zeitstempeln auf, einbetten Segment einbetten und speichern Sie es in der Actian VectorAI DB. Nun lässt sich die Videobibliothek nach Inhalt und nicht mehr nach Dateinamen durchsuchen.

Der folgende Screenshot zeigt, wie das System mit einer echten Sammlung von 678 Transkriptabschnitten arbeitet. Eine Pflegekraft stellt eine Frage zum Protokoll zur Handhygiene. Das System findet genau das 35-Sekunden-Segment im passenden Training und verlinkt direkt darauf.

Das System in der Praxis

Videosuche

Video-Suchoberfläche – abfragen: „Protokoll zur Handhygiene vor dem Patientenkontakt“ – 678 Treffer, 2 Ergebnisse angezeigt

Die gesamte Pipeline

Die Architektur gliedert sich in zwei Pfade. Der linke Pfad läuft offline ab – Videos werden von Whisper transkribiert, in 30-Sekunden-Segmente unterteilt, eingebettet einbetten eingebettet und einmalig in der VectorAI-Datenbank gespeichert. Der rechte Pfad wird zum abfragen ausgeführt; die Frage Nutzerwird eingebettet demselben Modell eingebettet , anhand der Kosinusähnlichkeit unter Verwendung des HNSW-Index mit den gespeicherten Segmenten abgeglichen, und die besten Ergebnisse werden an llama3:8b weitergeleitet, um eine fundierte, mit einem Zeitstempel versehene Antwort zu erhalten.

Architektur der Videosuche

Architektur der Videosuche – Indizierungspipeline (links) und abfragen (rechts)

Was Sie hier sehen

Jedes Element in diesem Screenshot ist das direkte Ergebnis der semantischen Suchpipeline. Hier eine Erläuterung der einzelnen Bestandteile:

UI-Element Bezeichnung Was das bedeutet
Obere Leiste 678 Blöcke Gesamtzahl der in allen Training indizierten Transkriptsegmente. Jeder Abschnitt entspricht einem „PointStruct“ in der VectorAI-Datenbank.
Obere Leiste llama3:8b Das LLM, das die Antwort aus den abgerufenen Textabschnitten zusammenstellt. Wird lokal über Ollama ausgeführt.
Seitenleiste Schnellsuche In der UI-Konfiguration gespeicherte vordefinierte Abfragen. Durch Anklicken einer Abfrage wird sofort eine Vektorsuche gestartet.
Abfrage-Sprechblase Protokoll zur Handhygiene vor dem Patientenkontakt Die Rohdaten Nutzer abfragen. Genau dieser Text wird eingebettet einbetten in einen 1024-dimensionalen Vektor eingebettet .
Ergebnis-Überschrift „VIDEO-SUCHE“-Badge Bestätigt, dass diese Antwort über den Transkript-Abrufpfad stammt und nicht aus einem Fallback.
Antworttext Fundierte Antwort Die Antwort des LLM, die auf der Grundlage des abgerufenen Transkripttextes generiert wurde – nicht auf der Grundlage seiner Training .
Quellenangabe 5 Momente der Handhygiene.mp4 @ 00:38–01:13 Der genaue Dateiname und der Zeitstempelbereich wurden aus der Nutzlast entnommen, die zusammen mit dem Vektor gespeichert wurde.
Ergebniskarte 00:38 – 01:13 | 79 % Zeitbereich (start_time / end_time aus der Nutzlast) und Kosinus-Ähnlichkeitswert (0,79).
Auszug aus dem Transkript Das hilft uns, uns daran zu erinnern… Der in der Nutzlast gespeicherte Rohtext, der als Vorschau angezeigt wird, damit Nutzer vor dem Klicken die Relevanz überprüfen können.
Zum Öffnen hier klicken Zum Öffnen bei 00:38 hier klicken Direkter Link unter Verwendung des HTML5-URL-Fragments #t=38. Öffnet das Video genau an dieser Sekunde.
Zweite Karte 02:16 – 02:49 | 79 % Ein zweiter relevanter Ausschnitt aus demselben Video – eine andere Szene, die einen damit zusammenhängenden Teil des Themas behandelt.

Wie dieses Ergebnis ermittelt wurde

Die im Screenshot gezeigte Antwort stammte weder aus einem Stichwortverzeichnis noch aus einer FAQ-Liste. Sie wurde in vier einzelnen Schritten ermittelt.

Schritt 1 – Das abfragen einem Vektor

Wenn der Nutzer „Handhygieneprotokoll vor dem Patientenkontakt“ Nutzer , wird dieser Text über Ollama aneinbetten lokal ausgeführteeinbetten weitergeleitet. Das Modell gibt eine Liste von 1.024 Gleitkommazahlen aus, einen Vektor, der die semantische Bedeutung der abfragen kodiert:

query = "hand hygiene protocol before patient contact"
r = requests.post('http://localhost:11434/api/embeddings',
    json={"model": "mxbai-embed-large", "prompt": query})
query_vector = r.json()["embedding"]  # 1024 floats
# e.g. [0.142, -0.831, 0.623, ..., -0.044]

Das Modell weiß nicht, was Handhygiene ist. Es weiß lediglich, dass der Begriff in dem hochdimensionalen Raum, auf den es trainiert wurde, in der Nähe anderer Begriffe aus dem Bereich der klinischen Sicherheit liegt. Diese Nachbarschaftsbeziehung wird bei der Suche genutzt.

Schritt 2 – VectorAI DB ermittelt die am besten passenden Chunks

Der abfragen wird über den Python an die Actian VectorAI-Datenbank gesendet. Der HNSW-Index vergleicht ihn anhand der Kosinus-Ähnlichkeit mit allen 678 gespeicherten Transkript-Chunk-Vektoren und gibt die besten Übereinstimmungen zurück:

results = client.points.search(

collection_name="video_transcripts",

query_vector=query_vector,

limit=5,

with_payload=True  # return text, filename, timestamps

)

# Result #1:

# id=87  score=0.79

# payload: {

#   "source":     "5 Moments of Hand Hygiene.mp4"

#   "start_time": 38.2,   "end_time": 73.6

#   "start_fmt":  "0:38"

#   "text":       "It helps us to remember all the five moments..."

# }

Der in der Ergebniskarte angezeigte Wert von 79 % entspricht diesem Kosinus-Ähnlichkeitswert. Das bedeutet, dass der abfragen und der Chunk-Vektor im 1024-dimensionalen Raum nahezu in dieselbe Richtung weisen und semantisch nahe beieinander liegen. Es fand keine Übereinstimmung mit Schlüsselwörtern statt. Der Chunk-Text enthält nicht die Phrase „Handhygiene-Protokoll“ – er spricht von „den fünf Momenten“ und „vor dem Berühren eines Patienten“. Das Modell hat erkannt, dass beide Ausdrücke dasselbe bedeuten.

Schritt 3 – Das LLM generiert eine Antwort

Der abgerufene Textabschnitt wird als Kontext an llama3:8b übergeben. Das LLM wird angewiesen, seine Antwort ausschließlich auf das bereitgestellte Transkript zu stützen, die Quelle anzugeben und keine über das Gesagte hinausgehenden Erfindungen zu machen:

prompt = f"""

You are a helpful assistant. Answer using ONLY the transcript below.

Cite the video and timestamp in your answer.

Transcript:

[5 Moments of Hand Hygiene.mp4 @ 00:38-01:13]

{results[0].payload['text']}

Question: {query}

"""

response = ollama.chat(model="llama3:8b", messages=[{"role": "user", "content": prompt}])

Die im Screenshot gezeigte Antwort – „Der erste Moment ist vor der Berührung eines Patienten. Die Handhygiene in diesem Moment verhindert die Übertragung von Mikroorganismen aus der Umgebung auf den Patienten durch die unreinen Hände eines Mitarbeiters im Gesundheitswesen“ –ist ein direktes Zitat aus dem Transkriptabschnitt. Das LLM hat es ausgewählt und formatiert; es hat es nicht erfunden.

Schritt 4 – Die Benutzeroberfläche erstellt den anklickbaren Zeitstempel-Link

Der Dateiname und die Zeitstempel sind in der Nutzlast enthalten, die mit jedem Vektor gespeichert wird. Die Benutzeroberfläche verwendet den Wert „start_time“, um mithilfe des Fragments #t=seconds einen HTML-Deep-Link zu erstellen:

p = results[0].payload

url = f"http://localhost:8001/videos/{p['source']}#t={int(p['start_time'])}"

# http://localhost:8001/videos/5 Moments of Hand Hygiene.mp4#t=38

# Browser opens the video and jumps directly to 0:38

# No scrubbing. No searching the timeline.

Das ist der Link „Zum Öffnen um 00:38 Uhr hier klicken“ in der Ergebniskarte. Ein Klick, genau im richtigen Moment.

Die abfragen „Protokoll zur Handhygiene vor dem Patientenkontakt.“ Der passende Textabschnitt lautete: „Die fünf Momente der Handhygiene“ und „vor dem Berühren eines Patienten“. Es gab keine übereinstimmenden Schlüsselwörter. Das Modell erkannte, dass beide Aussagen dasselbe bedeuteten.

Was der Index tatsächlich enthält

Jeder der 678 Chunks in der Sammlung entspricht einem 30-Sekunden-Segment eines Training . Die zusammen mit jedem Vektor gespeicherte Nutzlast enthält genau das, was die Benutzeroberfläche benötigt:

Feld „Nutzlast“ Beispielwert Zweck
Quelle 5 Momente der Handhygiene.mp4 Wählen Sie die Videodatei aus, die geöffnet werden soll
Text Das hilft uns, uns an alle fünf Momente zu erinnern… Wird als Auszug aus dem Transkript in der Ergebniskarte angezeigt
start_time 38.2 Wird zum Erstellen des URL-Fragments #t= für Deep-Linking verwendet
end_time 73.6 Definiert das Ende des Zeitstempel-Symbols auf der Ergebniskarte
start_fmt 0:38 Im Kopfbereich der Ergebniskarte angezeigter, für Menschen lesbarer Zeitstempel

Warum die Stichwortsuche hier gescheitert wäre

Die abfragen „Protokoll zur Handhygiene vor dem Patientenkontakt“. Der entsprechende Textabschnitt enthält keine dieser Wörter in genau dieser Kombination. Ein Schlüsselwortindex – selbst ein guter mit Stemming und Stopwort-Filterung – hätte keine Übereinstimmung gefunden oder nur eine sehr schlechte zurückgegeben.

Stichwortsuche Semantische Suche
Sucht nach exakten Wörtern oder Wortstämmen Sucht nach einer ähnlichen Bedeutung
„protocol“ nicht im Chunk enthalten → keine Übereinstimmung „fünf Momente“ ≈ „Protokoll“ (bedeutungsmäßig) → Übereinstimmung
Gibt bei „vor dem Kontakt mit dem Patienten“ nichts zurück Gibt genau das Segment zurück, das dies erklärt
Erfordert manuell erstellte Synonymlisten Aus Training automatisch erlernte Synonyme
Fehler bei der Paraphrase und bei klinischen Abkürzungen Beherrscht Paraphrasen, Kurzformen und Kontext

Nutzer eine abfragenNutzer .einbetten wandelt diese in einen Vektor mit 1024 Dimensionen um. Der HNSW-Index von VectorAI DB ermittelt anhand der Kosinus-Ähnlichkeit die 5 am besten passenden Transkript-Chunks. Die Nutzdaten jedes Chunks enthalten den Videodateinamen und den Zeitstempel. Das LLM liest den Text des Abschnitts und generiert eine fundierte Antwort unter Angabe der Quelle. Die Benutzeroberfläche erstellt einen Deep-Link im Format #t=Sekunden, sodass der Nutzer direkt zum richtigen Zeitpunkt springen Nutzer . 678 Abschnitte, Abruf in unter 50 ms, läuft vollständig On-Premises.

Alle angezeigten Ergebnisse stammen aus der Videotranskript-Sammlung (678 Segmente).einbetten über Ollama 0.24.0, Whisper-Basismodell, llama3:8b, Actian VectorAI-Datenbank.