This commit is contained in:
@@ -4,6 +4,7 @@ Ein einziges Go-/Docker-Image für zwei Rollen auf derselben JSON-Wissensbasis:
|
||||
|
||||
1. **Editor-Modus** – vollständiger Einzel- und Masseneditor mit Backups.
|
||||
2. **Google-Modus** – moderne, schreibgeschützte interne Helpdesk-Suche mit Artikel-Viewer.
|
||||
3. **Optionaler Ollama-Fallback** – nur bei 0 Treffern einen strukturierten KI-Entwurf erzeugen und getrennt im Staging ablegen.
|
||||
|
||||
Der Betriebsmodus wird ausschließlich über `APP_MODE` gewählt. Es ist kein zweiter Build und kein anderes Image nötig.
|
||||
|
||||
@@ -47,6 +48,8 @@ Reiner Helpdesk-/Viewer-Modus:
|
||||
- automatisches Neu-Einlesen des Dateiindex (standardmäßig alle 60 Sekunden)
|
||||
- **keine Bearbeitungsoberfläche**
|
||||
- **PUT-/Bulk-/Reload-Endpunkte werden serverseitig mit HTTP 403 gesperrt**
|
||||
- optionaler Ollama-Fallback bei exakt 0 KB-Treffern
|
||||
- KI-Ergebnisse werden als ungeprüfte JSON-Artikel in einem separaten Staging-Verzeichnis gespeichert
|
||||
|
||||
`viewer` und `search` werden zusätzlich als Alias für `google` akzeptiert. Für Deployments sollte aus Gründen der Eindeutigkeit `editor` oder `google` verwendet werden.
|
||||
|
||||
@@ -109,6 +112,106 @@ Für den Google-Modus wird `KB_DATA_MOUNT_MODE=ro` empfohlen. Damit existieren z
|
||||
|
||||
Der Backup-Pfad wird im Google-Modus nicht benutzt; er bleibt nur Teil derselben Compose-Konfiguration.
|
||||
|
||||
## Optionaler Ollama-Fallback mit Staging
|
||||
|
||||
Der KI-Fallback ist standardmäßig **aus**. Wird er im Google-Modus aktiviert, ist der Ablauf:
|
||||
|
||||
```text
|
||||
Suchanfrage
|
||||
│
|
||||
├─ normale KB hat Treffer ─────────────► normale Trefferliste
|
||||
│
|
||||
└─ normale KB hat 0 Treffer
|
||||
│
|
||||
▼
|
||||
POST /api/ai/fallback
|
||||
│
|
||||
▼
|
||||
Ollama /api/chat
|
||||
stream=false + JSON-Schema
|
||||
│
|
||||
▼
|
||||
STAGING_DIR/*.json
|
||||
│
|
||||
▼
|
||||
GET /api/staging/{id}
|
||||
│
|
||||
▼
|
||||
Artikel-Viewer mit
|
||||
"AI-STAGING · UNGEPRÜFT"
|
||||
```
|
||||
|
||||
Beispiel `.env` für den Search-Container:
|
||||
|
||||
```dotenv
|
||||
APP_MODE=google
|
||||
KB_DATA_MOUNT_MODE=ro
|
||||
|
||||
AI_FALLBACK_ENABLED=true
|
||||
OLLAMA_BASE_URL=http://ollama:11434
|
||||
OLLAMA_MODEL=dein-bereits-gepulltes-modell
|
||||
OLLAMA_TIMEOUT=10m
|
||||
OLLAMA_MAX_CONCURRENT=1
|
||||
|
||||
KB_STAGING_PATH=./staging
|
||||
OLLAMA_STAGING_AUTO_REPLY=false
|
||||
OLLAMA_STAGING_MIN_SCORE=0.78
|
||||
```
|
||||
|
||||
`OLLAMA_MODEL` hat absichtlich keinen hartcodierten Standard. Bei aktiviertem Fallback muss ein auf deiner Ollama-Instanz vorhandenes Modell angegeben werden.
|
||||
|
||||
### Docker-Netzwerk zu Ollama
|
||||
|
||||
`OLLAMA_BASE_URL=http://ollama:11434` funktioniert, wenn der Search-Container den Ollama-Container im selben Docker-Netzwerk unter dem Service-/Containernamen `ollama` erreichen kann.
|
||||
|
||||
Wenn Ollama in einem anderen Compose-Stack läuft, verbindest du beide Stacks am einfachsten mit demselben externen Docker-Netzwerk und verwendest dort den Ollama-Service-Namen. Alternativ kann `OLLAMA_BASE_URL` auf einen anderen vom Search-Container erreichbaren Host gesetzt werden.
|
||||
|
||||
Der Browser spricht **nie direkt mit Ollama**. Nur das Go-Backend kennt `OLLAMA_BASE_URL`.
|
||||
|
||||
### Warum ein getrenntes Staging-Verzeichnis?
|
||||
|
||||
Das produktive `DATA_DIR` bleibt im Google-Modus read-only. KI-Ergebnisse werden ausschließlich in `STAGING_DIR` geschrieben. Der Pfad darf weder innerhalb von `DATA_DIR` liegen noch `DATA_DIR` enthalten; die Anwendung verweigert sonst den Start. Dadurch werden ungeprüfte KI-Entwürfe nicht durch den normalen Index aufgenommen.
|
||||
|
||||
Ein Staging-Artikel verwendet dasselbe JSON-Format wie die restliche Wissensbasis, zum Beispiel:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "KB-AI-STAGING-20260729-120000-A1B2C3D4",
|
||||
"title": "...",
|
||||
"text": "...",
|
||||
"answer": "...",
|
||||
"auto_reply": false,
|
||||
"min_score": 0.78,
|
||||
"categories": ["AI-Staging", "Windows"],
|
||||
"keywords": ["..."],
|
||||
"source": "Ollama / modellname (AI-Staging)",
|
||||
"source_uri": "",
|
||||
"language": "de-DE",
|
||||
"communication_style": "formal"
|
||||
}
|
||||
```
|
||||
|
||||
`auto_reply` ist im Staging standardmäßig bewusst `false`. Das kann über `OLLAMA_STAGING_AUTO_REPLY=true` geändert werden, wird für ungeprüfte KI-Inhalte aber nicht empfohlen.
|
||||
|
||||
### 10-Minuten-Timeout
|
||||
|
||||
`OLLAMA_TIMEOUT=10m` ist der Standard. Der Timeout wird im Request-Kontext und im Go-HTTP-Client durchgesetzt. Zusätzlich passt der Server seinen HTTP-`WriteTimeout` an, damit eine erlaubte 10-Minuten-Generierung nicht bereits nach dem normalen 60-Sekunden-Timeout abgebrochen wird.
|
||||
|
||||
Im Browser bleibt der Fetch-Request offen. Währenddessen zeigt die Oberfläche einen Laufzeitzähler und einen Staging-Status. Nach erfolgreicher Generierung lädt der Browser den gespeicherten Artikel erneut über die Staging-API und öffnet ihn automatisch.
|
||||
|
||||
### Schutz vor Missbrauch
|
||||
|
||||
Der KI-Endpunkt ist kein freier Chat-Proxy. Das Backend:
|
||||
|
||||
- akzeptiert nur eine Suchanfrage,
|
||||
- begrenzt deren Länge,
|
||||
- prüft unmittelbar vor Ollama erneut, dass die produktive KB wirklich `0` Treffer hat,
|
||||
- begrenzt parallele Generierungen über `OLLAMA_MAX_CONCURRENT`,
|
||||
- fordert von Ollama Structured Output nach einem festen JSON-Schema,
|
||||
- setzt kritische Metadaten wie ID, Sprache, Quelle, `auto_reply` und `min_score` serverseitig,
|
||||
- speichert atomar über Temp-Datei + Rename,
|
||||
- lässt Ollama keine angeblichen Quellen/URLs in diese Metadaten schreiben.
|
||||
|
||||
## Ein Image, zwei Container
|
||||
|
||||
Als fertiges Beispiel liegt `docker-compose.dual.yml` bei. Es startet denselben Build gleichzeitig als Editor auf Port 8080 und als read-only Helpdesk-Suche auf Port 8081:
|
||||
@@ -168,6 +271,15 @@ Beide Container lesen damit denselben Bestand. Im Google-Modus wird der Dateiind
|
||||
| `KB_DATA_MOUNT_MODE` | `rw` | `rw` für Editor, empfohlen `ro` für Google-Modus |
|
||||
| `KB_BACKUP_PATH` | `./backups` | Hostpfad für Backups |
|
||||
| `KB_EDITOR_PORT` | `8080` | veröffentlichter Host-Port |
|
||||
| `KB_STAGING_PATH` | `./staging` | Hostpfad für ungeprüfte KI-Entwürfe |
|
||||
| `STAGING_DIR` | neben `DATA_DIR` als `staging` | Staging-Pfad im Prozess/Container |
|
||||
| `AI_FALLBACK_ENABLED` | `false` | Ollama-Fallback im Google-Modus aktivieren |
|
||||
| `OLLAMA_BASE_URL` | `http://ollama:11434` | Vom Go-Container erreichbare Ollama-Basis-URL |
|
||||
| `OLLAMA_MODEL` | leer / erforderlich wenn aktiv | Modellname auf der Ollama-Instanz |
|
||||
| `OLLAMA_TIMEOUT` | `10m` | Maximale Dauer einer Ollama-Anfrage |
|
||||
| `OLLAMA_MAX_CONCURRENT` | `1` | Maximale parallele KI-Generierungen, 1–16 |
|
||||
| `OLLAMA_STAGING_AUTO_REPLY` | `false` | `auto_reply` für neu erzeugte Staging-Artikel |
|
||||
| `OLLAMA_STAGING_MIN_SCORE` | `0.78` | `min_score` für Staging-Artikel |
|
||||
|
||||
## Suche und Ranking im Google-Modus
|
||||
|
||||
@@ -189,7 +301,7 @@ Die Such-URL ist teilbar:
|
||||
/?q=0x80070005
|
||||
```
|
||||
|
||||
Ein geöffneter Artikel erhält zusätzlich `doc=<interner-key>` und kann so intern direkt verlinkt werden.
|
||||
Ein geöffneter produktiver Artikel erhält zusätzlich `doc=<interner-key>`. Ein KI-Staging-Artikel verwendet stattdessen `staging=<staging-id>` und kann damit ebenfalls intern direkt verlinkt werden.
|
||||
|
||||
## Tastatur
|
||||
|
||||
@@ -251,6 +363,11 @@ Lesend in beiden Modi:
|
||||
- `GET /api/facets?limit=10`
|
||||
- `GET /api/items/{key}`
|
||||
|
||||
Optional bei aktiviertem Ollama-Fallback:
|
||||
|
||||
- `POST /api/ai/fallback` mit `{"query":"..."}` – nur zulässig, wenn die normale KB 0 Treffer liefert
|
||||
- `GET /api/staging/{key}` – gespeicherten Staging-Entwurf laden
|
||||
|
||||
Nur im Editor-Modus:
|
||||
|
||||
- `PUT /api/items/{key}`
|
||||
@@ -269,7 +386,9 @@ Das Compose-Setup:
|
||||
- entfernt Linux-Capabilities,
|
||||
- setzt `no-new-privileges`,
|
||||
- verwendet `/tmp` als kleines tmpfs,
|
||||
- kann den Knowledge-Mount im Google-Modus zusätzlich read-only einbinden.
|
||||
- kann den Knowledge-Mount im Google-Modus zusätzlich read-only einbinden,
|
||||
- mountet bei aktiviertem KI-Fallback nur das getrennte Staging-Verzeichnis schreibbar,
|
||||
- verbindet den Browser nicht direkt mit Ollama.
|
||||
|
||||
Die Oberfläche hat keine externen CDN-/JavaScript-Abhängigkeiten.
|
||||
|
||||
@@ -292,6 +411,18 @@ APP_SUBTITLE="Interne Wissenssuche" \
|
||||
go run ./cmd/server -data /pfad/zum/knowledge
|
||||
```
|
||||
|
||||
Google-Modus mit Ollama-Fallback:
|
||||
|
||||
```bash
|
||||
APP_MODE=google \
|
||||
AI_FALLBACK_ENABLED=true \
|
||||
OLLAMA_BASE_URL=http://127.0.0.1:11434 \
|
||||
OLLAMA_MODEL=dein-modell \
|
||||
OLLAMA_TIMEOUT=10m \
|
||||
STAGING_DIR=/pfad/zum/staging \
|
||||
go run ./cmd/server -data /pfad/zum/knowledge
|
||||
```
|
||||
|
||||
Tests/Build:
|
||||
|
||||
```bash
|
||||
@@ -315,10 +446,13 @@ go build -o kb-helpdesk ./cmd/server
|
||||
│ ├── index.html
|
||||
│ ├── app.js
|
||||
│ └── style.css
|
||||
├── internal/aifallback/ # Ollama-Client + Structured Output
|
||||
├── internal/staging/ # atomisches Speichern/Laden ungeprüfter Entwürfe
|
||||
├── internal/store/
|
||||
│ ├── store.go
|
||||
│ └── store_test.go
|
||||
├── knowledge/
|
||||
├── staging/
|
||||
├── backups/
|
||||
├── Dockerfile
|
||||
├── docker-compose.yml
|
||||
|
||||
Reference in New Issue
Block a user