Add CPU embeddings for OpenClaw memory

This commit is contained in:
Mikei386
2026-09-21 08:31:45 +02:00
parent de3f8fd7aa
commit 302b08e051
13 changed files with 231 additions and 7 deletions
+2
View File
@@ -20,6 +20,8 @@ ULTRA_MODEL_FILE=qwen-pure/qwen3.8-27b-IQ4_XS-pure.gguf
UNCENSORED_MODEL_FILE=qwen3.8-27b-abliterated/Qwen3.8-27B-ABLITERATED-Q4_K_M.gguf
UNCENSORED_PROJECTOR_FILE=qwen3.8-27b-abliterated/mmproj-Qwen3.8-27B-ABLITERATED-F16.gguf
VISION_PROJECTOR_FILE=qwen/mmproj-BF16.gguf
EMBEDDING_MODEL_FILE=embeddinggemma/embeddinggemma-300m-qat-Q8_0.gguf
EMBEDDING_THREADS=8
FAST_CONTEXT=76800
FAST_BATCH_SIZE=2048
+2
View File
@@ -23,6 +23,7 @@ Sie betreibt:
- FLUX.2 Klein 9B FP8 Beta für Textbilder und Referenzbild-Bearbeitung,
- Qwen3-TTS und TTS-Gateway für Sprache,
- Whisper.cpp und die WebRTC-Brücke für OpenClaw Talk,
- EmbeddingGemma auf der CPU für OpenClaws semantische Memory-Suche,
- die GPU-lose Mikes-Applio-UI als gesonderten Checkout,
- das Athena-Dashboard,
- Portainer CE als optionale Ansicht auf die laufenden Docker-Container,
@@ -92,6 +93,7 @@ nicht direkt. Kein automatischer Host-Neustart ist vorgesehen.
- FLUX.2 Klein 9B FP8 Beta: Bildgenerierung und Editing; Qwen wird dafür kurz entladen und danach
automatisch wiederhergestellt
- Qwen3-TTS 1.7B: RTX 3060; kein Piper-Fallback
- EmbeddingGemma 300M Q8: CPU, OpenAI-kompatibel auf Port 8082; kein GPU-Zugriff
Die geprüften Live-Werte stehen in [docs/LIVE_STATE.md](docs/LIVE_STATE.md).
`config/profile-matrix.json` und `docs/STANDARD_PROFILE_MATRIX.md` im Repository
+7
View File
@@ -24,6 +24,7 @@ dokumentieren den ausgerollten Stand, reduzierte Statuslatenzen und Tests.
- FLUX.2 Klein 9B FP8 Beta: Transformer/VAE auf RTX 5080, Textencoder auf RTX 3060
- Qwen3-TTS 1.7B auf der RTX 3060 hinter dem TTS-Gateway; kein Piper-Fallback
- Whisper.cpp `small` auf der CPU für lokale deutsche Spracherkennung
- EmbeddingGemma 300M Q8 auf der CPU für OpenClaws hybride Memory-Suche
- Live-Dashboard mit 21 Tagen Detailhistorie für GPUs und Slot-Kontextbelegung auf Port 8099
- Portainer CE als optionale Container-Ansicht auf Port 9443
- WireGuard-Gateway, Datenbackup und Athena-Operator
@@ -129,6 +130,7 @@ Prefills konkurrieren weiterhin um Rechenleistung und den gemeinsamen KV-Pool.
## Endpunkte
- Router: `http://192.168.1.212:8081/v1`
- Embeddings: `http://192.168.1.212:8082/v1`
- Athena-Dashboard: `http://192.168.1.212:8099`
Der Router stellt Sprache OpenAI-kompatibel bereit: Sprachausgabe über
@@ -148,6 +150,11 @@ OpenClaw wird über den Provider **llama.cpp → Existing llama-server** mit
erkennt OpenClaw die vollständige Auswahl automatisch, während Laden,
Entladen und Umschalten weiterhin ausschließlich der Athena Profile Router
übernimmt.
OpenClaws Memory-Suche verwendet den separaten CPU-Dienst
`mike-ai-embedding`. Dadurch bleiben die GPUs vollständig für Qwen, Vision
und TTS verfügbar. Die verbindliche Konfiguration, Prüfung und
Wiederherstellung stehen in [OpenClaw Memory](docs/OPENCLAW_MEMORY.md).
- Portainer: `https://192.168.1.212:9443`
- Hermes-Dashboard auf Unraid: `http://192.168.1.2:9119`
+59
View File
@@ -88,6 +88,65 @@ services:
cap_drop: [ALL]
security_opt: ["no-new-privileges:true"]
# Dedicated CPU-only embedding endpoint for OpenClaw memory search. It
# shares the WireGuard namespace so the API is reachable only through
# Athena's private VPN address, without consuming scarce GPU memory.
embedding:
build:
context: .
dockerfile: platform/docker/llama-cpp-cpu/Dockerfile
args:
LLAMA_CPP_COMMIT: ${LLAMA_CPP_COMMIT:-b29c606}
image: ${LLAMA_CPU_IMAGE:-mike-ai/llama.cpp-cpu:local}
container_name: mike-ai-embedding
restart: unless-stopped
network_mode: "service:wireguard-gateway"
read_only: true
tmpfs:
- /tmp:size=256m,mode=1777
volumes:
- "${MODEL_DIR:-/srv/mike-ai/models}:/models:ro"
command:
- --model
- "/models/${EMBEDDING_MODEL_FILE:?EMBEDDING_MODEL_FILE is required}"
- --alias
- embeddinggemma
- --embedding
- --pooling
- mean
- --ctx-size
- "4096"
- --batch-size
# OpenClaw's chunks plus embedding control tokens must fit in both the
# logical and physical batch. 256 rejected valid index chunks.
- "4096"
- --ubatch-size
- "1024"
- --parallel
- "4"
- --threads
- "${EMBEDDING_THREADS:-8}"
- --threads-batch
- "${EMBEDDING_THREADS:-8}"
- --n-gpu-layers
- "0"
- --host
- 0.0.0.0
- --port
- "8082"
- --no-ui
depends_on:
wireguard-gateway:
condition: service_healthy
cap_drop: [ALL]
security_opt: ["no-new-privileges:true"]
healthcheck:
test: [CMD, curl, -fsS, "http://127.0.0.1:8082/health"]
interval: 10s
timeout: 5s
retries: 30
start_period: 10s
llama-fast:
<<: *llama-common
container_name: mike-ai-llama-fast
+4
View File
@@ -75,6 +75,10 @@ UNCENSORED_PROJECTOR_SHA256=2284099ce864f1023d721e6ef5eaef32bb56abdbc1dc561c6d91
VISION_PROJECTOR_FILE=qwen/mmproj-BF16.gguf
VISION_PROJECTOR_URL=https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/mmproj-BF16.gguf
VISION_PROJECTOR_SHA256=83ee4f4f205fa514161778c41df1ea14144faa0f713510893b63c2395f5c2d53
EMBEDDING_MODEL_FILE=embeddinggemma/embeddinggemma-300m-qat-Q8_0.gguf
EMBEDDING_MODEL_URL=https://huggingface.co/ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/resolve/main/embeddinggemma-300m-qat-Q8_0.gguf
EMBEDDING_MODEL_SHA256=6fa0c02a9c302be6f977521d399b4de3a46310a4f2621ee0063747881b673f67
EMBEDDING_THREADS=8
DEFAULT_REASONING_EFFORT=off
# All standard profiles use the MTP tensor embedded in their GGUF. A separate
# draft-model artifact is neither downloaded nor passed to llama-server.
+3 -2
View File
@@ -1,8 +1,8 @@
# Container-Inventar auf Athena
Stand: 20. September 2026 (lesender Docker-Abgleich)
Stand: 21. September 2026
Athena hatte beim lesenden Abgleich 30 Docker-Container. Nicht jeder Container enthält
Athena hat 31 reguläre Docker-Container. Nicht jeder Container enthält
ein KI-Modell: Router, Oberflächen, Netzwerk, Steuerung und Sicherung sind
gewöhnliche Dienste. Die rechenintensiven GPU-Worker werden absichtlich nur bei
Bedarf gestartet. Ein Container im Zustand `Created` oder `Exited (0)` ist daher
@@ -11,6 +11,7 @@ nicht automatisch ein ungenutzter Rest.
| Container | Modell oder wesentliche Komponente | Aufgabe |
|---|---|---|
| `mike-ai-backup` | kein Modell; Offen Docker Volume Backup `v2` (Digest vom 15. September 2026) | Sichert `/data`, `/etc/mike-ai`, den Stack und die persistenten Docker-Volumes im Fünf-Stunden-Takt. |
| `mike-ai-embedding` | EmbeddingGemma 300M QAT Q8 | Dauerhafter CPU-only-Endpunkt für OpenClaws semantische und hybride Memory-Suche; teilt ausschließlich den privaten Netzwerk-Namespace des WireGuard-Gateways. |
| `mike-ai-bonsai2-ab` | Bonsai-2-Vergleichsmodell | Gestoppter, reproduzierbar dokumentierter A/B-Testcontainer; kein Produktivprofil. |
| `mike-ai-applio-studio` | Applio/RVC; Stimmenmodelle werden nutzerseitig ergänzt | Vollständige RVC-Oberfläche für Inferenz, Modellverwaltung und Training auf der RTX 5080. Für eine Konvertierung ist ein importiertes oder trainiertes `.pth`-Modell nötig; eine Referenzaufnahme allein reicht nicht. |
| `mike-ai-image-worker` | FLUX.2 Klein 9B FP8, Qwen3-8B NF4 Textencoder und VAE | Erzeugt und bearbeitet Bilder transaktional; nutzt während eines Auftrags RTX 5080 und RTX 3060. |
+11 -2
View File
@@ -1,6 +1,6 @@
# Geprüfter Live-Stand auf Athena
Stand: **20. September 2026**. Quelle: lesender SSH-Abgleich von Docker,
Stand: **21. September 2026**. Quelle: lesender SSH-Abgleich von Docker,
Compose-Dateien, Git-Inhalten, Images, Health-Endpunkten und Backup-Timern.
Containerzustände sind Momentaufnahmen; der Controller darf Profile danach
umschalten. Es wurde für diesen Abgleich kein Dienst neu gestartet.
@@ -45,6 +45,15 @@ nicht mehr den aktuellen Containerzustand.
1280 × 1280 lief im Test in CUDA-OOM.
- Qwen3-TTS 1.7B auf 3060 hinter dem TTS-Gateway; kein Piper-Fallback.
- Whisper.cpp `ggml-small` auf CPU über `/v1/audio/transcriptions`.
- `mike-ai-embedding` stellt EmbeddingGemma 300M Q8 CPU-only über den privaten
WireGuard-Endpunkt `http://192.168.1.212:8082/v1/embeddings` bereit. Eine
Probe mit zwei deutschen Texten lieferte zwei Vektoren mit je 768 Dimensionen.
Gemessen wurden rund 86 MiB RAM im Leerlauf, rund 1,1 GiB beim vollständigen
Indexaufbau und 0,044 Sekunden für die abschließende Netzwerkprobe. OpenClaw
indexierte 107 Dateien mit 1.139 Chunks vollständig; die semantische Suche
und der 768-dimensionale Vektorindex sind aktiv. Der
GPU-Versuch war zwar schneller (0,077 Sekunden), ließ im Ultra-Profil aber
nur 372 MB VRAM auf der RTX 3060 frei und wurde deshalb verworfen.
- Der gesunde Dienst `mike-ai-realtime-voice` vermittelt OpenClaw Talk über
WebRTC zwischen Whisper, dem normalen OpenClaw-Agenten und Qwen3-TTS.
Er braucht keine GPU und keinen Profilwechsel. Das Plugin liegt in
@@ -59,7 +68,7 @@ nicht mehr den aktuellen Containerzustand.
trotzdem Status, Modelle und vorbereitende Aufgaben anzeigen; eine echte
Konvertierung verlangt den Applio-Modus.
Der vollständige Bestand der **30** angelegten Docker-Container steht im
Der vollständige Bestand der **31** angelegten Docker-Container steht im
[Container-Inventar](CONTAINER_INVENTORY.md). `Created` oder `Exited` bei
Spezialworkern bedeutet nicht automatisch einen zu entfernenden Testrest.
+90
View File
@@ -0,0 +1,90 @@
# OpenClaw Memory über Athena
Stand: **21. September 2026**
OpenClaw verwendet für seine Memory-Suche einen eigenen, dauerhaft laufenden
Embedding-Dienst auf Athena. Der Chat-Router auf Port 8081 bleibt unverändert;
Embeddings laufen getrennt auf Port 8082.
## Aufbau
- Container: `mike-ai-embedding`
- Modell: `ggml-org/embeddinggemma-300m-qat-q8_0-GGUF`, Q8_0
- Datei: `/data/models/embeddinggemma/embeddinggemma-300m-qat-Q8_0.gguf`
- SHA-256: `6fa0c02a9c302be6f977521d399b4de3a46310a4f2621ee0063747881b673f67`
- Laufzeit: eigener, auf Athenas CPU nativ optimierter CPU-only-Build von
llama.cpp ohne CUDA-Abhängigkeit, zusätzlich erzwungen durch
`--n-gpu-layers 0`
- API: `http://192.168.1.212:8082/v1/embeddings`
- Zugriff: privater WireGuard-Netzwerk-Namespace; kein öffentlicher Host-Port
- Ergebnisdimension: 768
- vier CPU-Slots mit insgesamt 4096 Kontexttoken
- logische Batchgröße 4096 und physische Micro-Batchgröße 1024; damit passen
auch größere OpenClaw-Memory-Chunks in einen Slot und mehrere Chunks werden
beim Indexaufbau gemeinsam verarbeitet
Der Dienst benötigt im Leerlauf rund 86 MiB und während eines vollständigen
Indexaufbaus rund 1,1 GiB RAM. Die abschließende Netzwerkprobe von Unraid aus
lag bei 0,044 Sekunden. Ein Betrieb auf der RTX 3060
wurde verworfen: Im Ultra-Profil blieben nur 372 MB VRAM Reserve, während der
Zeitgewinn lediglich rund 0,06 Sekunden betrug.
## OpenClaw-Konfiguration
OpenClaw nutzt den offiziellen generischen Anbieter `openai-compatible`. Die
bestehenden Quellen-, Scope- und Chunking-Einstellungen unter `memory.search`
bleiben dabei erhalten.
```json5
{
memory: {
search: {
provider: "openai-compatible",
model: "embeddinggemma",
fallback: "none",
remote: {
baseUrl: "http://192.168.1.212:8082/v1",
apiKey: "local"
}
}
}
}
```
`local` ist hier nur ein nicht geheimes Kompatibilitätskennwort. Der Dienst
liegt im privaten VPN und llama.cpp verlangt selbst keinen Schlüssel.
## Prüfung
Auf Athena:
```bash
docker inspect -f '{{.State.Health.Status}}' mike-ai-embedding
docker exec mike-ai-embedding curl -fsS \
-H 'Content-Type: application/json' \
-d '{"model":"embeddinggemma","input":["Athena Speicherprobe"]}' \
http://127.0.0.1:8082/v1/embeddings
```
Auf Unraid:
```bash
docker exec OpenClaw openclaw memory status --deep --agent main
docker exec OpenClaw openclaw memory index --force --agent main
docker exec OpenClaw openclaw memory search --agent main "GPU-Aufteilung"
```
Nach einem Wechsel von Anbieter oder Modell muss der Index ausdrücklich neu
aufgebaut werden. OpenClaw erledigt das absichtlich nicht still im Hintergrund.
Der produktive Neuaufbau am 21. September umfasste 107 Dateien und 1.139
Chunks. Danach meldete OpenClaw `dirty: false`, einen vollständigen
768-dimensionalen Vektorindex, aktive semantische Suche und eine erfolgreiche
Anbieterprobe. Eine Suchprobe lieferte drei Treffer.
## Wiederherstellung
Der Athena-Installer lädt das Modell anhand der fest hinterlegten URL und
Prüfsumme. Danach startet `./manage.sh deploy core` den Embedding-Dienst mit.
Auf Unraid werden die vier oben dokumentierten `memory.search`-Werte gesetzt
und anschließend der Index erzwungen neu aufgebaut. Weder API-Schlüssel noch
Memory-Inhalte liegen in diesem Git-Repository.
+3
View File
@@ -20,6 +20,9 @@ Quelle ist im Git-Repository unter `integrations/openclaw-athena-talk` erfasst.
Piper-Daten sind kein aktueller Sicherungsbestand. Modellgewichte unter
`/data/models` und das reproduzierbare Whisper-Volume gehören nicht zu diesen
Backup-Mounts. Ein Backup ausschließlich auf `/data` schützt nicht vor deren Ausfall.
Das gilt auch für das reproduzierbare EmbeddingGemma-Gewicht unter
`/data/models/embeddinggemma`; URL und SHA-256 stehen in
`config/install.env.example`, sodass der Installer es erneut laden und prüfen kann.
Die verschlüsselten Notfallpakete über `athena-export-backup.timer` laufen
ebenfalls im Fünf-Stunden-Takt; beim Abgleich war der Timer aktiv und der
+8 -2
View File
@@ -49,7 +49,8 @@ required=(AI_HOSTNAME ADMIN_USER MODEL_DIR FAST_MODEL_FILE
UNCENSORED_MODEL_FILE UNCENSORED_MODEL_URL UNCENSORED_MODEL_SHA256
UNCENSORED_PROJECTOR_FILE UNCENSORED_PROJECTOR_URL
UNCENSORED_PROJECTOR_SHA256
VISION_PROJECTOR_FILE VISION_PROJECTOR_URL VISION_PROJECTOR_SHA256)
VISION_PROJECTOR_FILE VISION_PROJECTOR_URL VISION_PROJECTOR_SHA256
EMBEDDING_MODEL_FILE EMBEDDING_MODEL_URL EMBEDDING_MODEL_SHA256)
for name in "${required[@]}"; do
[[ -n "${!name:-}" ]] || die "Pflichtwert $name fehlt."
done
@@ -343,6 +344,8 @@ ULTRA_MODEL_FILE=$ULTRA_MODEL_FILE
UNCENSORED_MODEL_FILE=$UNCENSORED_MODEL_FILE
UNCENSORED_PROJECTOR_FILE=$UNCENSORED_PROJECTOR_FILE
VISION_PROJECTOR_FILE=$VISION_PROJECTOR_FILE
EMBEDDING_MODEL_FILE=$EMBEDDING_MODEL_FILE
EMBEDDING_THREADS=${EMBEDDING_THREADS:-8}
FAST_CONTEXT=${FAST_CONTEXT:-76800}
FAST_BATCH_SIZE=${FAST_BATCH_SIZE:-64}
FAST_UBATCH_SIZE=${FAST_UBATCH_SIZE:-32}
@@ -442,6 +445,7 @@ $ULTRA_MODEL_FILE|$ULTRA_MODEL_URL|$ULTRA_MODEL_SHA256
$UNCENSORED_MODEL_FILE|$UNCENSORED_MODEL_URL|$UNCENSORED_MODEL_SHA256
$UNCENSORED_PROJECTOR_FILE|$UNCENSORED_PROJECTOR_URL|$UNCENSORED_PROJECTOR_SHA256
$VISION_PROJECTOR_FILE|$VISION_PROJECTOR_URL|$VISION_PROJECTOR_SHA256
$EMBEDDING_MODEL_FILE|$EMBEDDING_MODEL_URL|$EMBEDDING_MODEL_SHA256
EOF
}
@@ -517,6 +521,8 @@ build_and_start() {
cd "$STACK_DIR"
docker build --progress=plain --build-arg LLAMA_CPP_COMMIT="$commit" \
-f platform/docker/llama-cpp/Dockerfile -t mike-ai/llama.cpp:local .
docker build --progress=plain --build-arg LLAMA_CPP_COMMIT="$commit" \
-f platform/docker/llama-cpp-cpu/Dockerfile -t mike-ai/llama.cpp-cpu:local .
docker compose --env-file "$SECRETS_DIR/stack.env" --profile image build image-worker
local flux_components=${FLUX_COMPONENT_DIR:-/data/models/FLUX.2-klein-9B-components}
local flux_transformer=${FLUX_TRANSFORMER_DIR:-/data/models/FLUX.2-klein-9B-fp8}
@@ -549,7 +555,7 @@ build_and_start() {
docker compose --env-file "$SECRETS_DIR/stack.env" --profile image create image-worker
docker volume inspect portainer_data >/dev/null 2>&1 || docker volume create portainer_data >/dev/null
docker compose --env-file "$SECRETS_DIR/stack.env" up -d --build \
wireguard-gateway qwen3-tts tts-gateway profile-controller router llama-dashboard portainer backup
wireguard-gateway embedding qwen3-tts tts-gateway profile-controller router llama-dashboard portainer backup
if [[ ${WIREGUARD_MODE:-container} == container ]]; then
systemctl restart mike-ai-container-vpn-guard.service
fi
+1 -1
View File
@@ -52,7 +52,7 @@ case "$command" in
[[ $# -eq 0 ]] || { echo "core akzeptiert keine weiteren Services" >&2; exit 2; }
run "$ROOT_DIR/platform/mcp/install-tools.sh"
run "${compose[@]}" up -d --build \
wireguard-gateway qwen3-tts tts-gateway profile-controller router llama-dashboard portainer backup
wireguard-gateway embedding qwen3-tts tts-gateway profile-controller router llama-dashboard portainer backup
else
run "${compose[@]}" up -d --build --no-deps "$@"
fi
+32
View File
@@ -0,0 +1,32 @@
FROM debian:13-slim AS build
ARG DEBIAN_FRONTEND=noninteractive
ARG LLAMA_CPP_COMMIT
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential ca-certificates cmake git libcurl4-openssl-dev libopenblas-dev \
ninja-build pkg-config && \
rm -rf /var/lib/apt/lists/*
RUN test -n "$LLAMA_CPP_COMMIT"
RUN git clone --filter=blob:none https://github.com/ggml-org/llama.cpp /src/llama.cpp && \
git -C /src/llama.cpp checkout "$LLAMA_CPP_COMMIT"
RUN cmake -S /src/llama.cpp -B /src/llama.cpp/build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_NATIVE=ON \
-DGGML_BLAS=ON \
-DGGML_BLAS_VENDOR=OpenBLAS && \
cmake --build /src/llama.cpp/build --target llama-server -j "$(nproc)"
FROM debian:13-slim
ARG DEBIAN_FRONTEND=noninteractive
ARG LLAMA_CPP_COMMIT
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl libcurl4 libgomp1 libopenblas0-pthread python3 && \
rm -rf /var/lib/apt/lists/* && \
useradd --system --uid 10003 --home /nonexistent --shell /usr/sbin/nologin llama
COPY --from=build /src/llama.cpp/build/bin/ /opt/llama/bin/
LABEL org.opencontainers.image.source="https://github.com/ggml-org/llama.cpp" \
com.mike-ai.llama-cpp-commit="$LLAMA_CPP_COMMIT" \
com.mike-ai.llama-cpp-backend="cpu-openblas"
ENV LD_LIBRARY_PATH=/opt/llama/bin
USER 10003:10003
ENTRYPOINT ["/opt/llama/bin/llama-server"]
+9
View File
@@ -26,6 +26,7 @@ healthy() {
for name in \
mike-ai-wireguard-gateway \
mike-ai-profile-controller \
mike-ai-embedding \
mike-ai-router \
mike-ai-qwen3-tts \
mike-ai-tts-gateway \
@@ -36,6 +37,14 @@ for name in \
done
pass "Athena-Kerndienste sind gesund"
docker exec mike-ai-embedding curl -fsS \
-H 'Content-Type: application/json' \
-d '{"model":"embeddinggemma","input":["Athena Speicherprobe"]}' \
http://127.0.0.1:8082/v1/embeddings | \
python3 -c 'import json,sys; data=json.load(sys.stdin); assert len(data["data"][0]["embedding"]) == 768' || \
fail "CPU-Embedding-Endpunkt liefert keinen 768-dimensionalen Vektor"
pass "CPU-Embedding-Endpunkt funktioniert"
for name in mike-ai-llama-dashboard mike-ai-portainer; do
network_mode=$(docker inspect -f '{{.HostConfig.NetworkMode}}' "$name" 2>/dev/null || true)
[[ $network_mode != container:* ]] || \