Files
localRAG/EINSTIEG.md
T
Philipp MockandClaude Opus 5.5 ce9a863a87 Load bge-m3 as safetensors for x86; update README, add EINSTIEG.md
- EMBEDDING_REVISION pins the official safetensors conversion of bge-m3, so the x86
  env (torch 2.2.2) can load it; identical vectors, no index rebuild
- README rewritten for the current state (personas, providers, retrieval, environments)
- EINSTIEG.md: short German guide to running and configuring the chat

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:26:29 +01:00

157 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kafka-Chat: Einstieg
Stand: Oktober 2026. Ausführliche englische Referenz: [README.md](README.md).
## Starten
**Conda-Umgebungen**
| Umgebung | Architektur | Einsatz |
|---|---|---|
| `docling` | arm64 (Apple Silicon), Python 3.12, torch 2.14 | Standard. Auch für Docling (`prepare_corpus.py`). |
| `local_rag` | x86_64 (Intel-Mac oder Rosetta), Python 3.10, torch 2.2.2 | Alternative für x86. Chat und Suche getestet; Indexbau sollte gehen (gleiches Embedding), ungetestet. Docling nicht. |
- **Warum bge-m3 auf x86 nur über safetensors lädt:** Für macOS x86 gibt es höchstens torch 2.2.2. `transformers` lädt `.bin`-Gewichte aber erst ab torch 2.6, und bge-m3 hat im Hauptzweig nur `pytorch_model.bin`.
- **Die Lösung im Code:** `local_rag.py` lädt deshalb die offizielle safetensors-Konvertierung (`EMBEDDING_REVISION`). Die Gewichte sind dieselben, die Vektoren in beiden Umgebungen identisch, und dieselben Indizes funktionieren in beiden.
- **Geschwindigkeit unter Rosetta:** Spürbar langsamer. Im Test brauchte die Suche gut 5 statt gut 1 Sekunde, der Serverstart war dagegen nicht langsamer.
**Voraussetzungen (einmalig)**
- Ollama mit dem Modell: `ollama pull gemma4:12b`.
- Für ChatGPT und Realtime eine Datei `.env` im Projektordner mit `OPENAI_API_KEY=sk-...`. Sie ist git-ignoriert, am besten mit `chmod 600` schützen. Ohne Key sind beide Einträge im Menü ausgegraut.
- Die beiden Vektorspeicher `vectorstore_pypdf_2000/` und `vectorstore_primary_pypdf_2000/`. Sie sind nicht im Git; Neubau siehe unten.
**Server starten**
```bash
cd /Users/Philipp/Desktop/workspace/diverses/local_rag
conda activate docling # auf x86: conda activate local_rag
uvicorn server:app --port 8010
```
Dann im Browser http://localhost:8010 öffnen. Der Start dauert etwa eine Minute: Embedding-Modell, Reranker und Stichwortindex werden geladen. Danach ist auch die erste Frage schnell.
- Optionen: `--reload` startet den Server bei Codeänderungen neu, `--log-level debug` zeigt mehr Details.
- Ohne `--reload` braucht jede Änderung an `.py`-Dateien einen Neustart. Bei `templates/chat.html` reicht es, die Seite neu zu laden.
**Was im Terminal steht, pro Frage**
```
[RAG] User question: '…'
[Zeit] LLM-Aufruf 1: 6.86s (Suche angefordert)
[RAG] Tool search '…': 5 chunk(s)
[Zeit] Suche 1.37s (davon Reranker 1.21s)
[Zeit] LLM-Aufruf 2: 15.31s (Antwort)
[Zeit] Gesamt 23.54s
```
Danach folgen die gefundenen Chunks mit Quelle, Seite und Score sowie die vollständige Antwort.
## Aufbau
```
Browser (templates/chat.html)
│ POST /api/chat {message, history, persona, llm_provider}
▼
server.py ── wählt Figur (personas.py) und RAG-Instanz (Anbieter × Vektorspeicher)
▼
local_rag.py · LocalRAG.query_with_history
│ Systemprompt + Verlauf + Frage an das LLM, Such-Werkzeug angeboten
│ ┌─ LLM ruft search_kafka_corpus(query) auf (höchstens 3 Runden)
│ │ retrieve(): FAISS (bge-m3) + BM25 → Fusion (RRF) → 25 Kandidaten
│ │ → Reranker (bge-reranker-v2-m3) → beste 5 Chunks
│ └─ LLM antwortet mit den Auszügen
▼
Antwort + gefundene Chunks + Suchanfragen → Browser
```
**Dateien**
| Datei | Inhalt |
|---|---|
| [server.py](server.py) | FastAPI-Server, Modellwahl, eine RAG-Instanz pro Anbieter und Vektorspeicher, Konsolenausgabe |
| [personas.py](personas.py) | die drei Figuren: Texte, Bilder, Systemprompts, Werkzeugbeschreibung, Vektorspeicher |
| [local_rag.py](local_rag.py) | Laden der Modelle, Suche (`retrieve`), Werkzeugschleife (`query_with_history`), Indexbau |
| [realtime_chat.py](realtime_chat.py) | Anbindung der OpenAI Realtime API (WebSocket, nur Text) als LangChain-Modell |
| [templates/chat.html](templates/chat.html) | Oberfläche, Menüs für Figur und Modell |
| `templates/visuals/` | Bilder (`*.png` Vorlagen, `*.jpg` Webversionen, `*_avatar.jpg`) |
| [add_pdfs.py](add_pdfs.py) | Vektorspeicher aus einem PDF-Ordner bauen |
| [eval_retrieval.py](eval_retrieval.py) | Suchqualität auf einem Goldset messen (Recall@k, MRR, optional LLM-Judge) |
## Stellschrauben
### Verhalten der Figuren: [personas.py](personas.py)
Pro Figur ein Eintrag in `PERSONAS`; eine neue Figur ist ein neuer Eintrag mit eigenem Bild.
| Feld | wirkt auf |
|---|---|
| `system_prompt` | Ton, Rolle, Regeln für Suche und Belege |
| `tool_description` | was das Modell über das Such-Werkzeug erfährt (ohne Feld gilt `SEARCH_TOOL_DESCRIPTION`) |
| `vectorstore` | welcher Index durchsucht wird |
| `label`, `topic`, `name`, `role`, `place`, `status`, `greeting`, `suggestions` | Texte in der Oberfläche |
| `image`, `image_position`, `image_alt`, `avatar` | Bilder |
- Die Regeln zur Suche für Zeitgenosse und Autor stehen gemeinsam in `_TOOL_RULES`.
- Der Prompt der Forscherin ist `SYSTEM_PROMPT` in `local_rag.py`.
### Sprachmodelle: [server.py](server.py) und [local_rag.py](local_rag.py)
| Einstellung | aktuell | wo |
|---|---|---|
| lokales Modell (Ollama) | `gemma4:12b`, denkt standardmäßig (`reasoning` nicht gesetzt) | `OLLAMA_MODEL` in server.py, `ChatOllama(...)` in local_rag.py |
| ChatGPT | `gpt-6.1-sol` | `OPENAI_MODEL` in server.py |
| Denkaufwand ChatGPT | `low`, über die Responses API | `ChatOpenAI(...)` in local_rag.py |
| Realtime | `gpt-realtime-2.1-mini` | `REALTIME_MODEL` in server.py |
| Voreinstellung im Menü | ChatGPT | `selected` in chat.html |
- **gpt-6.1-sol:** kennt keinen Denkaufwand `none`. Werkzeuge funktionieren nur über die Responses API, deshalb steht `use_responses_api=True`.
- **Realtime:** öffnet pro Modellaufruf eine eigene WebSocket-Sitzung.
### Suche: Konstanten oben in [local_rag.py](local_rag.py)
| Konstante | aktuell | Bedeutung |
|---|---|---|
| `RETRIEVAL_K` | 5 | Chunks pro Suche an das LLM |
| `RETRIEVAL_MODE` | `hybrid` | `dense` (nur Vektoren), `hybrid` (Vektoren + BM25, RRF), `union` |
| `CANDIDATES_K` | 25 | Kandidaten vor dem Reranker. 25 war schneller und nicht schlechter als 50. |
| `RERANKER_MODEL` | `BAAI/bge-reranker-v2-m3` | `None` schaltet das Reranking ab. Läuft auf der GPU in fp16. |
| `MAX_TOOL_ROUNDS` | 3 | Suchen pro Nachricht, danach muss das Modell antworten |
| `SEARCH_TOOL_DESCRIPTION` | Text | Werkzeugbeschreibung für die Forscherin |
Die Suche dauert etwa 1 bis 1,5 Sekunden pro Aufruf, fast nur der Reranker. Den größten Teil der Antwortzeit brauchen die Modellaufrufe.
### Index: Neubau nötig bei Änderung
| Konstante | aktuell |
|---|---|
| `EMBEDDING_MODEL` | `BAAI/bge-m3` (normalisierte Vektoren) |
| `CHUNK_SIZE` / `CHUNK_OVERLAP` | 2000 / 400 Zeichen |
| `PDF_LOADER` | `pypdf`; `docling` war im Goldset-Vergleich nicht besser |
| `CHUNK_HEADERS` | `False` |
Neubau der beiden Indizes. `data_primary/` enthält nur einen Verweis auf `data/Kafka_Die_Verwandlung_.pdf`.
```bash
python add_pdfs.py --data data --index ./vectorstore_pypdf_2000 --loader pypdf --no-headers
```
```bash
python add_pdfs.py --data data_primary --index ./vectorstore_primary_pypdf_2000 --loader pypdf --no-headers
```
Jeder Index speichert seine Einstellungen in `index_info.json`. Passt das Embedding-Modell nicht zum Code, verweigert `LocalRAG` das Laden.
### Suchqualität messen
```bash
python eval_retrieval.py --goldset eval/goldset_kafka_human.csv --report eval/mein_bericht.txt
```
- `--judge gpt-6-luna` lässt zusätzlich ein LLM prüfen, ob die Antwort in den Top 5 steht; das braucht den Key.
- Stand auf dem menschlichen Goldset (30 Fragen): R@5 0,73, MRR 0,68.
## Gut zu wissen
- **Speicher:** Embedding-Modell, Reranker und BM25-Index gibt es pro Prozess nur einmal, auch bei mehreren Anbietern. Ollama braucht zusätzlich etwa 8 bis 10 GB für gemma4:12b.
- **Nicht im Git:** Korpus-PDFs (`data/`), Vektorspeicher, `.env` und Schlüsseldateien.