Files
Homme/HOEMMA_Projekt_Dokumentation.md
Mohammad Zwaib daf48f3f91 WordPress
2026-07-15 20:47:58 +02:00

9.6 KiB
Raw Permalink Blame History

HOEMMA Human Library Ruhr · Projektdokumentation

Stand: 15.07.2026 Projekt: HOEMMA KI-basierter Gesprächsbegleiter der Machbarschaft Borsig11 (Dortmund) Stack: Spring Boot 3.5.7 · Java 17 · PostgreSQL + pgvector · Azure AI Foundry (Mistral, Cohere-Embedding, GPT-5-Agent)


1. Was das System macht (Überblick)

HOEMMA ist ein RAG-System (Retrieval-Augmented Generation), das:

  1. Interviews & Dateien aus Humbee holt (Word/.docx, .txt),
  2. die Transkripte per Mistral bereinigt (Sprecherlabels & Zeitstempel entfernen),
  3. den Text in Chunks zerlegt,
  4. für jeden Chunk ein Embedding (Cohere embed-v4.0) berechnet und in pgvector speichert,
  5. bei einer Nutzerfrage die semantisch nächsten Chunks sucht,
  6. bei fehlendem lokalem Kontext eine Web-Suche (Azure-Agent, GPT-5) auslöst,
  7. die Antwort im HOEMMA-Charakter (warm, Ruhrgebiet-Ton, „Du") per Mistral formuliert.

2. Architektur / Datenfluss

                         ┌─────────────────────────────┐
   Humbee (Interviews)   │  POST /knowledge-base/build │
   Word / .txt Dateien ──►  HumbeeService.build...     │
                         │   → readWordFile (decodeBytes: UTF-8/UTF-16)
                         │   → PromptService (Mistral: bereinigen)
                         │   → DocumentChunckService (Chunks)
                         │   → AzureEmbeddingService (input_type=document)
                         │   → DocumentStorageService (speichern in pgvector)
                         └─────────────────────────────┘

   Nutzerfrage           ┌─────────────────────────────┐
   POST /chat/ask ───────►  RagService.answerQuestion  │
                         │   1. Embedding (input_type=query)
                         │   2. findNearst (pgvector <=> Distanz)
                         │   3. Distanz <= Schwelle?
                         │        ja  → Human-Library-Chunks
                         │        nein→ AzureWebSearchAgentService (Web)
                         │   4. SYSTEM_PROMPT (HOEMMA) + <runtime_context>-Template
                         │   5. AzureMistralService.askMistral → Antwort
                         └─────────────────────────────┘

3. Wichtige Komponenten

Klasse Aufgabe
HumbeeController POST /knowledge-base/build stößt den Import an
HumbeeService Login, Datei-Links extrahieren, herunterladen, buildKnowledgeBase() (parallel)
PromptService Transkript-Bereinigung via Mistral (chunk-parallel)
DocumentChunckService Text in Chunks zerlegen (chunkSize, overlap)
DocumentStorageService Chunks + Embeddings speichern (input_type=document)
AzureEmbeddingService Cohere embed-v4.0 Aufruf, unterstützt input_type
AzureMistralService Chat-Completion (Mistral) mit Retry auf 429
RagService Kern der Frage-Antwort-Logik (Embedding → Suche → Schwelle → Antwort)
AzureWebSearchAgentService Web-Recherche über Foundry-Agent (GPT-5), Managed/CLI-Identity
SearchController GET/POST /chat/ask

4. Gelöste Probleme (Chronik)

4.1 Azure Mistral 429 (Too Many Requests)

  • Ursache: Ganzes Transkript in einem Request + ungedrosselte Parallel-Schleife.
  • Lösung: Chunking vor dem LLM-Call, Drosselung/sleep, Retry mit Backoff, .onRetryExhaustedThrow (Original-Fehler durchreichen statt „Retries exhausted").

4.2 Langsame Verarbeitung

  • Ursache: Zu kleine Chunks (viele Calls) + sequenzielle Verarbeitung.
  • Lösung: Größere Chunks, Parallelisierung auf Datei-Ebene (buildKnowledgeBase) und Chunk-Ebene (PromptService), da die meisten Dateien nur 1 Chunk haben.

4.3 pgvector: „column embedding is of type vector but expression is of type bytea"

  • Ursache: hibernate-vector-Dependency fehlte in pom.xml.
  • Lösung: org.hibernate.orm:hibernate-vector (Version ${hibernate.version}) ergänzt.

4.4 „Unable to access lob stream"

  • Ursache: @Lob auf String-Feldern (Document.rawText/cleanText) + Lesen außerhalb einer Transaktion.
  • Lösung: @Lob entfernen, nur @Column(columnDefinition = "TEXT"); Suche @Transactional(readOnly = true).

4.5 Chunk-Text enthielt Zahlen statt Text (z. B. 25569)

  • Ursache: @Lob auf DocumentChunck.chunckText → PostgreSQL speicherte die OID eines Large Objects (eine Zahl), nicht den Text.
  • Lösung: @Lob vom Text-Feld entfernen → echter Text wird gespeichert.

4.6 .txt-Dateien: unlesbarer Text mit Leerzeichen zwischen jedem Zeichen

  • Ursache: Dateien in UTF-16, als UTF-8 gelesen.
  • Lösung: decodeBytes(byte[]) BOM-Erkennung (UTF-8 / UTF-16LE / UTF-16BE) + Heuristik.

4.7 Web-Suche-Agent: Authentifizierung

  • 422 „Missing api-version" → api-version bzw. korrekten /openai/v1/responses-Pfad geklärt (kein v1 im Modell-Call).
  • 401 „audience incorrect" → Scope; per jwt.ms bestätigt: aud = https://ai.azure.com. Scope https://ai.azure.com/.default ist korrekt.
  • Lokal: az login nötig; Eclipse/Spring Tools sieht az nur mit angepasstem PATH (Run Config → Environment) oder Start aus Terminal.
  • Container in Azure-VM: Managed Identity via --network host oder Service Principal (AZURE_TENANT_ID/CLIENT_ID/CLIENT_SECRET).

4.8 429 „gpt-5-mini exceeded rate limit" beim Build (obwohl Mistral konfiguriert)

  • Ursache: In AzureMistralService war das Modell hart codiert als "gpt-5-mini-datazone" (statt deployment), zusätzlich reasoning_effort und max_completion_tokens (GPT-5-Parameter).
  • Lösung: "model", deployment + "temperature", 0.5 + "max_tokens", maxTokens.

4.9 Passwort / .env auf dem Server

  • Ursache: .env wird von Spring nicht automatisch gelesen (keine dotenv-Dependency).
  • Lösung: Secrets als echte Umgebungsvariablen setzen (Docker -e, Azure App Settings). .env gehört nicht nach src/main/resources (landet im JAR).

5. Prompt-Integration (v2.0)

  • system-Message: statische Rolle & Regeln (HOEMMA-Charakter, Sicherheits-/Datenschutzregeln, Quellenhierarchie).
  • user-Message: dynamischer, gekapselter Laufzeitkontext:
<runtime_context> current_date, channel, is_first_contact, address_mode=Du, ... </runtime_context>
<retrieved_context> ...Chunks aus der DB... </retrieved_context>
<web_results_optional> ...oder "Kein Webkontext verfuegbar." </web_results_optional>
<current_user_message> ...Nutzerfrage... </current_user_message>
  • Parameter: temperature = 0.5, max_tokens = 350, Ansprache durchgehend „Du".
  • Kapselung schützt zusätzlich vor Prompt Injection (Inhalte = nur Informationsquelle, nie Anweisung).

6. Wissensbasis: atomare Fakten-Dateien

Statt einer Sammeldatei → eine Datei = ein Thema = ein sauberer Chunk:

  • Borsig11_Oeffnungszeiten.docx
  • Borsig11_Adresse.docx
  • Borsig11_Kontakt.docx
  • Borsig11_UeberUns.docx
  • HOEMMA_UeberDasProjekt.docx

Grund: Eine gemischte Datei ergibt ein „verwässertes" Embedding → schlechte Treffer. Atomare Chunks matchen die jeweilige Frage viel schärfer.


7. Offenes Thema: Retrieval-Distanzen

input_type (query / document) ist jetzt korrekt implementiert (das Deployment akzeptiert nur text, query, document), verbessert die Distanzen aber nur gering:

Frage bestDistance Status
Wie sind eure Öffnungszeiten? 0.57 true
Wann habt ihr geöffnet? 0.67 false → Web
Kann ich morgen um 9 Uhr vorbeikommen? 0.66 false → Web

Nächste, wirksamere Schritte:

  1. Fakten-Dateien mit Frage-Varianten anreichern (z. B. „Wann habt ihr geöffnet?", „um 9 Uhr vorbeikommen", „vormittags") → senkt die Distanz real.
  2. Schwelle moderat anheben (DISTANCE_THRESHOULD = 0.68) lokale Fragen (0.570.67) greifen, externe (Borsig11 ~0.77) gehen weiter an die Web-Suche.
  3. Web-Agent funktioniert als Fallback zuverlässig (200 OK, ~10 s).

8. Wichtige Endpoints

Methode Pfad Zweck
POST /knowledge-base/build Import & Verarbeitung aller Humbee-Dateien
GET/POST /chat/ask?question=... Frage stellen (RAG + ggf. Web)
POST /interview/transcription Audio → Text (Azure Speech)
POST /interview/save Interview als .docx erzeugen, hochladen, verarbeiten

9. Rebuild-Prozedur (bei Embedding-Änderungen)

Immer komplett neu aufbauen, sonst mischen sich alte/neue Embeddings:

DELETE FROM document_chunck;
DELETE FROM document;
Anwendung: Stop → Clean → Run
POST /knowledge-base/build

Empfohlen für pgvector-Performance:

CREATE INDEX ON document_chunck USING hnsw (embedding vector_cosine_ops);

10. TODO vor Produktivbetrieb

  • Debug-Ausgaben entfernen (System.out.println: Key, >>> MODELL, root =, $$$, EMBED …).
  • Mistral-API-Key rotieren (war im Log sichtbar).
  • Secrets aus dem Code/.env → Umgebungsvariablen / Azure Key Vault.
  • spring.jpa.hibernate.ddl-auto von update auf validate stellen.
  • TestController entfernen oder absichern; Logging auf INFO.
  • Managed Identity (Azure) statt az login für den Web-Agent.
  • Vollständigen HOEMMA-System-Prompt (Demenz, Notfälle, Datenschutz) einsetzen.
  • Doppelte .txt.txt-Dateien in Humbee bereinigen.