
Memo bundles llama.cpp as its native inference engine. It is managed as a subprocess by the Go backend with automatic lifecycle handling, GPU offloading, and port coordination.
The Go backend manages llama.cpp as a child process with full lifecycle control:
Go Backend (main process)
│
├─▶ llama.cpp Server (port 8081) — Chat inference
├─▶ llama.cpp Embedding (port 8082) — Vector embeddings
└─▶ Health checker (goroutine) — Periodic ping + restart
[STOPPED] ──start()──▶ [STARTING] ──health_ok──▶ [RUNNING]
│ │
└──timeout──▶ [DEAD] │ crash
restart() │
loop ───────┘
llama.cpp is launched with GPU layer offloading configured per detected hardware:
| Platform | Backend | Flag | Detection |
|---|---|---|---|
| NVIDIA | CUDA | --n-gpu-layers N |
nvidia-smi + CUDA lib |
| AMD | ROCm | --n-gpu-layers N |
rocm-smi + ROCm lib |
| Apple Silicon | Metal | --n-gpu-layers N |
MPS device check |
| CPU-only | — | --n-gpu-layers 0 |
Fallback |
The number of offloaded layers is calculated automatically based on available VRAM and model size. Users can override in Settings.
# Example: NVIDIA with 8GB VRAM, llama-3.1-8b Q4_K_M
llama-server \
--model models/llama-3.1-8b-instruct-q4_k_m.gguf \
--n-gpu-layers 33 \
--host 127.0.0.1 \
--port 8081 \
--ctx-size 8192
llama.cpp binaries are bundled with the application package. On first launch:
llama-server and llama-embedding binaries--version)No manual compilation or dependency installation is required.
A health goroutine polls the llama.cpp HTTP endpoints every 5 seconds:
GET /health → 200 OK → RUNNING
GET /health → timeout → mark DEAD → restart
GET /health → 500 → log warning → retry after 15s
func (e *LlamaEngine) healthLoop() {
ticker := time.NewTicker(5 * time.Second)
for range ticker.C {
if !e.isHealthy() {
e.restart()
}
}
}
Memo uses a fixed port allocation to avoid conflicts:
| Service | Default Port | Config Key |
|---|---|---|
| Chat Inference | 8081 |
llama.chat_port |
| Embedding Server | 8082 |
llama.embed_port |
| API Server | 8090 |
server.port |
Ports are checked at startup. If a port is occupied, Memo attempts the next available port and logs a warning.
The embedding server runs as a separate llama.cpp instance with its own model (default: nomic-embed-text-v1.5):
llama-embedding \
--model models/nomic-embed-text-v1.5.gguf \
--host 127.0.0.1 \
--port 8082 \
--embd-normalize 2 \
--ctx-size 2048
If llama.cpp fails to start or crashes irrecoverably:
Running llama.cpp models larger than available RAM will cause severe performance degradation due to swap thrashing. Always check the hardware compatibility badge before downloading.