Files
groot e0bf42bf32
mega-ci / static-release-gates (push) Failing after 11s
release-tag / release-image (push) Successful in 6m46s
mega-ci / go-quality (services/control) (push) Successful in 10m7s
mega-ci / go-quality (platform/neuroforge) (push) Successful in 10m20s
mega-ci / go-quality (services/agent) (push) Successful in 11m1s
mega-ci / go-quality (services/knowledge) (push) Successful in 11m13s
mega-ci / docker-build (push) Has been skipped
update
2026-09-09 11:10:31 +02:00

393 lines
16 KiB
Markdown
Raw Permalink 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.
# NeuroForge v0.8.3
NeuroForge ist eine persistente, assoziativ lernende KI-Schicht in Go. Ollama und optional OpenAI liefern Inferenz/Embeddings; NeuroForge besitzt den dauerhaften Wissenszustand: Vektoren, HNSW/Disk-PQ-Recall, Synapsen, Rewards, Provenance, Konflikte, Konsolidierung, Goals und Learning Cycles.
**v0.8.3 übernimmt den v0.8.2-Funktionsumfang und härtet große Bulk-/Graph-Workloads gegen Speicher- und Recovery-Spitzen. v0.8.2 erweitert den Production-/Explainability-Stand um einen source-grounded Lernpfad, Dokument-/Text-Ingestion, SearXNG-Research und ein vollständig neu gestaltetes CSS/Vanilla-JS-Admin-UI mit responsive Knowledge-Graph und Level-of-Detail (LOD).** Wissen soll nicht nur gespeichert, sondern als Kette `Quelle → Evidence → Recall → Learning` nachvollziehbar sein.
## Neu in v0.8.2: Live Research pro Goal
Im Admin-Bereich **Ziele & Autonomie** kann für jedes Research-Goal die Ansicht **Live Research** geöffnet werden. Ein autonomer oder manuell gestarteter Research-Lauf wird als persistenter, bounded Run mit sequenzierten Events nachvollziehbar:
```text
Query-Planung
↓
SearXNG Queries
↓
Treffer / URLs
↓
Downloads / Dokumenterkennung
↓
Claim-Kandidaten / Evidence-Chunks
↓
Embedding + Dedup
↓
neu gelernt / corroborated / verworfen
↓
Run abgeschlossen
```
Die Oberfläche zeigt live Treffer, laufende/abgeschlossene Downloads, Claim-/Evidence-Kandidaten, neue Memories, Duplikate, unabhängige Bestätigungen sowie verworfene Quellen und Fehler. Claim-Kandidaten sind bewusst **keine automatisch als wahr markierten Fakten**: Sie sind kurze, transparente Auszüge aus den tatsächlich extrahierten Source-Chunks; Verifikation entsteht weiterhin über Source-Provenance, Dedup/Korroboration, Confidence und den normalen Lernpfad.
Die Live-API ist inkrementell und scannt nicht den Wissensbestand:
```text
GET /api/v1/goals/{id}/research/live?run_id=<run>&after=<seq>
GET /api/v1/goals/{id}/research/history?limit=10
```
Der Browser pollt nur Events nach der letzten Sequenznummer. Pro Run werden höchstens 600 Event-Zeilen als Audit-Tail gehalten; Run-Historie ist ebenfalls begrenzt. Live-Events verursachen **keinen WAL-fsync pro Event**: autoritative Source-/Memory-Writes behalten ihre normale Durability, während der Research-Trace beim Run-Abschluss kompakt persistiert wird. Nach einem Crash wird ein zuvor laufender Trace als `interrupted` markiert.
## Neu in v0.8.1: Goal-Steuerung & SearXNG-Dokumente
- Goals lassen sich im Admin-Dashboard **pausieren**, **fortsetzen** und **löschen**. Pausierte Goals besitzen keinen nächsten Scheduler-Termin und werden von Autonomie vollständig übersprungen. Beim Fortsetzen wird ein Auto-Goal wieder eingeplant. Das Löschen eines Goals löscht **nicht** bereits gelerntes Wissen.
- SearXNG-Dateitreffer werden beim aktivierten Abruf als Dokumente erkannt und über die normale Dokument-Ingestion verarbeitet. Unterstützt sind PDF, DOCX, TXT, Markdown, CSV/TSV, JSON und YAML; Erkennung erfolgt über SearXNG-Dateimetadaten, URL, `Content-Disposition` und den tatsächlichen HTTP-Content-Type.
- Remote-Dokumente behalten Source-URI, Dateiname, MIME-Typ und Provenance. Wenn `ingestion.store_original=true` ist, wird auch die Originaldatei im Source-Blob-Store abgelegt.
## Neu in v0.8: Quellenbasierte Wissensanreicherung
Der bevorzugte Lernpfad für externes Wissen ist jetzt:
```text
Text / Dokument / SearXNG
↓
Knowledge Source + Provenance
↓
Extraktion / Normalisierung
↓
überlappende Chunks
↓
Embedding + Duplicate-Suppression
↓
Evidence Memories
↓
Recall / Goal Research
↓
Evaluate / Consolidate / Learn
```
Unter **Quellen & Import** können Text sowie TXT, Markdown, HTML, JSON, CSV/TSV, DOCX und PDF hochgeladen werden. PDF-Extraktion verwendet `pdftotext` aus Poppler; das Server-Containerimage enthält `poppler-utils`. Originaldateien können zusätzlich unter `data/sources/` gespeichert werden. Jedes Evidence-Memory trägt Source-ID, URI/Titel, Chunk-Nummer, Content-Hash sowie verwendetes Embedding-Modell/-Node. Nahezu identische Evidenz aus einer **anderen** Quelle wird nicht einfach verworfen: NeuroForge verknüpft sie als unabhängige Korroboration mit dem bestehenden Evidence-Memory und erhöht dessen Confidence vorsichtig; dieselbe Source zählt nicht doppelt.
REST:
```text
POST /api/v1/ingest/text
POST /api/v1/ingest/document
GET /api/v1/sources
GET /api/v1/sources/{id}
POST /api/v1/research
```
### SearXNG Research
Im Admin-Reiter **Research** wird eine private SearXNG-Instanz als Suchbackend konfiguriert. NeuroForge fragt deren JSON-API ab, kann ausgewählte Trefferseiten abrufen und speichert Such-Snippets/Webseiten ausschließlich als quellengebundene Evidence. Web-/Dokumenttext wird in LLM-Prompts als **untrusted data** behandelt; darin enthaltene Anweisungen dürfen nicht als System-/Tool-Anweisungen ausgeführt werden. Private/Loopback/Link-Local-Ziele aus Suchtreffern sind standardmäßig blockiert (`allow_private_targets=false`).
Für eine SearXNG-Instanz muss JSON-Ausgabe aktiviert sein. Ein minimales Override liegt unter `deploy/searxng/settings.yml.example`. Die SearXNG-URL selbst darf intern sein, z. B. `http://searxng:8080`; nur die von Suchergebnissen ausgehenden Seitenabrufe unterliegen dem SSRF-Guard.
### Goal Research
Autonome Ziele haben jetzt einen **eigenen Zeitplan** (`auto_run`, `interval_minutes`, `next_cycle_at`) und können Research pro Ziel aktivieren. Bei einem fälligen Zyklus läuft optional:
```text
Research Queries → SearXNG → Web Evidence → Recall → Predict → Evaluate → Learn
```
Neue Ziele können mit `autonomy.run_on_goal_create=true` sofort fällig werden. `research.goal.search_every_cycle` steuert, ob bei jedem Zyklus neu gesucht wird. Fehler erzeugen Backoff statt einen aggressiven Retry-Loop.
### Responsive Knowledge Graph mit LOD
Das neue Admin-UI benötigt keine JS/CSS-Frameworks. Der Canvas-Graph wechselt abhängig vom Zoomlevel automatisch zwischen:
- **Übersicht:** aggregierte Memory-Typ-Cluster,
- **Mittel:** einzelne Knoten + reduzierte starke Kanten,
- **Detail:** mehr Kanten, Labels und selektierter Kontext.
Pan/Zoom und Knoteninspektion laufen clientseitig; der Server liefert weiterhin begrenzte Graph-Fenster statt Millionen Knoten in den Browser zu drücken.
## Schnellstart
```bash
ollama pull <DEIN_CHAT_MODELL>
ollama pull <DEIN_EMBEDDING_MODELL>
go run ./cmd/server -data ./data
```
Admin: `http://localhost:8080/admin`
Der Admin-Token wird im Production-Default **nicht ins Log geschrieben**. Setze ihn vorzugsweise selbst:
```bash
export NEUROFORGE_ADMIN_TOKEN='lange-zufällige-Zeichenfolge'
export NEUROFORGE_APP_API_KEY='lange-zufällige-Zeichenfolge'
export NEUROFORGE_WORKER_TOKEN='lange-zufällige-Zeichenfolge'
export NEUROFORGE_METRICS_TOKEN='lange-zufällige-Zeichenfolge'
```
Ohne `NEUROFORGE_ADMIN_TOKEN` wird beim ersten Start einer erzeugt und lokal mit Modus `0600` in `data/secrets.json` abgelegt.
## Wissen nachvollziehen
Im Admin-Reiter **Wissen & Lernen** findest du:
- eine Pipeline `Input → Embedding → Recall → Actor → Learn → Reward → Synapsen → Konsolidierung`
- Verteilung nach episodischem, semantischem, prozeduralem und Working Memory
- Status `active`, `conflicted`, `superseded`, `archived`
- Herkunft/Provenance jedes neuen v0.7-Memorys
- responsiver Synapsen-/Memory-Graph mit Canvas-LOD und bounded server-side graph window
- Parent-/Child-, Konsolidierungs- und Truth-Version-Beziehungen
- persistente Learning Timeline
- Explainable Recall: echte Score-Zerlegung pro Treffer
Recall wird erklärt als:
```text
score = similarity × salience_factor × type_weight × confidence_factor + graph_boost
```
Zusätzlich wird gezeigt, ob ein Kandidat aus `hnsw`, `disk-pq`, `scan` oder einer `synapse`-Expansion stammt. Der endgültige Similarity-Wert wird gegen den Originalvektor berechnet, sofern er verfügbar ist.
Legacy-Memories aus älteren Versionen bleiben lesbar. Für Provenance, die damals nicht erfasst wurde, zeigt das UI ausdrücklich `legacy/unknown`, statt Herkunft zu erfinden.
## Learning Policy
Die Learning Policy wird direkt im Knowledge Explorer konfiguriert. Sie steuert:
- globales Auto-Learn
- Chat-Eingaben speichern: ja/nein
- Chat-Antworten speichern: ja/nein
- explizites `POST /api/v1/learn` erlauben
- Imports erlauben
- Goal-Cycles dauerhaft lernen lassen
- minimale Confidence
- Duplicate-Similarity-Schwelle
- Mindestzahl bestätigender Episoden vor semantischer Konsolidierung
- minimale semantische Confidence
- automatisches Archivieren stark negativ bewerteter Assistant-Memories
- maximale Memory-Textlänge
- Quellenvertrauen für `chat.input`, `chat.response`, `api.learn`, `api.import`, `ingest.text`, `ingest.document`, `web.search`, `web.page`, `goal-cycle`, `consolidation`
Fast identische Memories werden bei aktivierter Duplicate-Schwelle nicht erneut angelegt (Truth-Key-Versionierungen bleiben davon ausgenommen). Learning-Policy-Entscheidungen erscheinen in der Timeline.
Admin API:
```text
GET /admin/api/learning-policy
PUT /admin/api/learning-policy
```
## Ollama / Modellrollen
Unter **Modelle & Routing** lassen sich mehrere Ollama-Server konfigurieren. Jeder Node besitzt getrennte Chat- und Embedding-Modellfelder. Logical Roles können zusätzlich fest gepinnt werden:
- Actor / Chat
- Embedding
- Critic (LLM Auto-Reward)
- Consolidator
- Goal-Learning
Ungepinnte Ollama-Routen verwenden gewichtetes Failover. Ein expliziter Node-Pin ist absichtlich strikt, damit eine Qualitätsrolle nicht still auf ein anderes Modell fällt.
Beispiel:
```json
{
"routing": {
"chat_provider": "ollama",
"embedding_provider": "ollama",
"chat_node_id": "brain-01",
"embedding_node_id": "brain-01",
"critic": {"provider":"ollama","node_id":"critic-01"},
"consolidator": {"provider":"ollama","node_id":"brain-01"}
},
"ollama": [
{
"id": "brain-01",
"name": "Primary Brain",
"base_url": "http://10.0.0.11:11434",
"chat_model": "<CHAT_MODEL>",
"embedding_model": "<EMBED_MODEL>",
"weight": 1,
"enabled": true,
"request_timeout_seconds": 0,
"num_ctx": 8192,
"num_predict": 0,
"think": "off",
"chat_keep_alive": "30m",
"embedding_keep_alive": "5m"
}
]
}
```
Direkt verwendbar über `PUT /admin/api/model-routing` mit `X-Admin-Token`.
### Long-running Ollama inference
Ab v0.7.3 gibt es keinen globalen 120-Sekunden-Client-Timeout mehr. Pro Ollama-Node gilt:
- `request_timeout_seconds: 0` = keine zusätzliche Inferenz-Deadline; Request endet nur durch Client-Abbruch/Server-Shutdown oder einen explizit gesetzten Timeout.
- `num_ctx` wird als Ollama-Runtime-Option weitergereicht; `0` lässt Ollama/Modell entscheiden.
- `num_predict` wird als Ollama-Runtime-Option weitergereicht; `0` erbt das NeuroForge-Output-Limit.
- `think` erlaubt `off`, `on`, `low`, `medium`, `high`, `max`.
- `chat_keep_alive` und `embedding_keep_alive` steuern getrennt, wie lange Ollama die jeweiligen Modelle geladen hält.
Für wirklich unbegrenzte Browser-Requests zusätzlich `http.write_timeout_seconds: 0` setzen. `0` deaktiviert nur das Response-Write-Limit; Header-/Read-/Idle-/Shutdown-Schutz bleibt separat konfigurierbar.
**Embedding-Modell nicht unkoordiniert wechseln.** Ein anderes Embedding-Modell kann einen anderen Vektorraum erzeugen; bestehendes Wissen sollte dann kontrolliert re-embedded/reindexed werden.
## Production HTTP
Neu in v0.7:
```text
GET /livez Prozess lebt
GET /readyz Config/Routes/Cluster sind betriebsbereit
GET /healthz Kompatibilitätsalias zu /livez
GET /version
GET /metrics Prometheus, Bearer Metrics-Token
```
`/readyz` führt absichtlich **keinen Netzwerk-Call zu Ollama/OpenAI** pro Probe aus. Provider-Liveness wird explizit über „Verbindungen prüfen“ getestet; so macht Kubernetes/Docker-Healthchecking die Modellserver nicht selbst zum Lastgenerator.
HTTP-Härtung:
- `ReadHeaderTimeout`, `ReadTimeout`, `WriteTimeout`, `IdleTimeout`
- maximales Request-Body- und Header-Limit
- globale Concurrent-Request-Grenze mit `503 + Retry-After`
- Security Header + CSP
- Constant-Time Tokenvergleich
- graceful SIGTERM/SIGINT shutdown + finaler Checkpoint
- Admin-Secrets standardmäßig maskiert
- Secret-Reveal standardmäßig deaktiviert
## Docker
```bash
cp .env.example .env
# starke Tokens in .env eintragen
docker compose up --build -d
```
Der Compose-Default bindet den HTTP-Port nur auf `127.0.0.1:8080`; für externen Zugriff einen TLS-Reverse-Proxy davor setzen. Der Container läuft non-root, mit read-only Root-Filesystem, `no-new-privileges` und gedroppten Capabilities.
## Prometheus
```yaml
scrape_configs:
- job_name: neuroforge
static_configs:
- targets: ['neuroforge:8080']
authorization:
credentials: '<METRICS_TOKEN>'
```
Beispiel-Alerts: `deploy/prometheus-alerts.yml`.
Metrics vermeiden Memory-/Goal-/Session-IDs und Inhalte als Labels. Der reguläre `/metrics`-Scrape verwendet O(1)-artige Store-Zähler statt eines Vollscans über alle Memories.
## Storage
Typisches Datenverzeichnis:
```text
data/
├── state.json
├── secrets.json
├── vector-journal.nfv
├── wal/
├── memory-segments/
├── hnsw-index/
├── disk-ann/
├── sources/ # Originale, falls store_original=true
└── cluster/
```
Die segmentierten Memory-Dateien sind Source of Truth für ausgelagerte Bodies/Vektoren. Disk-PQ ist ein abgeleiteter ANN-Index und kann neu gebaut werden, darf bei einer Disaster-Recovery-Sicherung aber gern mitgesichert werden, um Rebuild-Zeit zu sparen.
`vector-journal.nfv` ist weiterhin ein rebuildbarer Beschleunigungs-Cache. Neue Journale verwenden `NFVJ2`: gleichdimensionale Vektoren werden blockweise gespeichert und ab 64 KiB automatisch mit einem SQAR-abgeleiteten 2D-Transform + DEFLATE verglichen. Nur eine tatsächlich kleinere Darstellung wird übernommen; kleine Blöcke bleiben roh. Bestehende `NFVJ1`-Dateien werden beim Öffnen atomar auf V2 migriert und bleiben bei einem fehlgeschlagenen Upgrade weiterhin lesbar.
Relevante Storage-Konfiguration:
```json
{
"storage": {
"vector_journal": {
"compression": "sqar-auto",
"block_vectors": 128,
"min_block_bytes": 65536,
"min_savings_pct": 0.01
}
}
}
```
Mit `compression: "off"` werden neue V2-Blöcke ohne Kompression geschrieben. Die Memory-Segmente selbst bleiben absichtlich unverändert, damit mmap und per-record Random Access nicht durch eine Ganzdatei-Kompression verschlechtert werden.
## API-Auswahl
Application API (`Authorization: Bearer <APP_API_KEY>`):
```text
POST /api/v1/chat
POST /api/v1/learn
POST /api/v1/search
POST /api/v1/search/vector
POST /api/v1/memory/import
POST /api/v1/feedback
POST /api/v1/ingest/text
POST /api/v1/ingest/document
GET /api/v1/sources
GET /api/v1/sources/{id}
POST /api/v1/research
GET /api/v1/stats
GET /api/v1/goals
POST /api/v1/goals
POST /api/v1/goals/{id}/cycle
GET /api/v1/learning-cycles
GET /api/v1/conflicts
```
Explainability/Admin (`X-Admin-Token`):
```text
GET /admin/api/knowledge/summary
GET /admin/api/knowledge/memories
GET /admin/api/knowledge/memory/{id}
GET /admin/api/knowledge/graph
GET /admin/api/knowledge/events
POST /admin/api/knowledge/search
GET /admin/api/learning-policy
PUT /admin/api/learning-policy
GET /admin/api/model-routing
PUT /admin/api/model-routing
GET /admin/api/research
PUT /admin/api/research
POST /admin/api/research/test
```
Vollständig: `openapi.yaml`.
## Cluster-Hinweis
Der Cluster besitzt persistente Terms/Votes, Heartbeats und quorum-durable Prepare/Commit-Logik. Er ist **Raft-artig**, aber nicht als vollständige Raft-Implementierung zu bezeichnen: vollständiges Log-Matching/Membership-Consensus sind weiterhin Grenzen. Cluster-Endpunkte gehören in ein privates Netz und dürfen nicht direkt ins öffentliche Internet.
## Backup / Restore
Siehe `PRODUCTION.md`. Kurzfassung: Vor einem konsistenten Dateibackup Schreibverkehr stoppen oder einen storage-seitigen atomaren Snapshot verwenden; vorher `POST /admin/api/checkpoint` auslösen. Mindestens `state.json`, `secrets.json`, `vector-journal.nfv`, `wal/`, `memory-segments/`, `hnsw-index/`, bei gespeicherten Originalen `sources/` und bei Clusterbetrieb `cluster/` sichern.
## Validierung
Release-Prüfung:
```bash
go test ./...
go vet ./...
go test -race ./internal/store
go test -race ./internal/brain
go test -race ./internal/httpapi
go test -race ./internal/vector
```
Der konkrete Release-Stand und Smoke-Tests stehen in `VALIDATION-v0.8.2.txt`.