🧠 Local LLM + RAG + CRUD

Das erste wirklich AI-native Betriebssystem

Mistral lokal auf deinem Gerät, vollständige RAG-Pipeline, CRUD-Operations als native OS-Skills. Keine Cloud. Keine API-Limits. Nur pure, lokale AI-Power.

Local LLM RAG Pipeline CRUD Skills Offline-First Zero Latency

🎯 Die Vision

💡 Das Paradigmenwechsel

Nicht "ein OS mit AI-Features", sondern ein OS, dessen Betriebssystem-Logik selbst AI ist. Das LLM ist nicht eine App – das LLM IST das Betriebssystem.

Traditionelles OS

  • Statische Menüs und Befehle
  • Hardcodierte Workflows
  • User muss Befehle kennen
  • Keine Kontext-Awareness
  • AI nur als externe App
  • Cloud-abhängig für AI

AI-Native OS (Dein System)

  • Natürliche Sprach-Interaktion
  • Adaptive, lernende Workflows
  • OS versteht Intent, nicht Syntax
  • Full-Context Awareness (RAG)
  • AI ist der Kernel-Layer
  • 100% lokal, 0ms Latenz

🏗️ Neue OS-Schichten

👤 User Intent Layer

"Zeig mir alle PDFs über Finanzen aus letztem Monat"

⬇️

🧠 LLM Layer (Mistral)

Intent → Execution Plan → System Calls

⬇️

📚 RAG Layer

Vector DB + Embeddings + Context Retrieval

⬇️

⚙️ CRUD Skills Layer

Create | Read | Update | Delete Operations

⬇️

💾 File System / Apps / Data

OPFS + IndexedDB + Browser APIs

🏗️ System-Architektur

🤖

LLM Backend

  • Ollama - LLM Server
  • Mistral 7B - Base Model
  • FastAPI - REST API
  • LangChain - Orchestration
📚

RAG Pipeline

  • ChromaDB - Vector Store
  • Sentence Transformers - Embeddings
  • LlamaIndex - Indexing
  • PyPDF - Document Parsing

Frontend Integration

  • WebSocket - Live Communication
  • Service Worker - Caching
  • IndexedDB - Local Storage
  • Web Workers - Background Processing

🔑 Warum Lokal?

✅ Vorteile
  • Keine API-Kosten
  • Keine Rate Limits
  • Volle Privatsphäre
  • Offline-funktionsfähig
  • Sub-100ms Latenz
  • Unbegrenzte Requests
  • Eigene Daten bleiben lokal
⚠️ Herausforderungen
  • RAM-Bedarf (8-16 GB)
  • GPU empfohlen (nicht zwingend)
  • Erste Antwort langsamer
  • Model-Größe (4-8 GB)
  • Setup-Komplexität höher

🚀 Mistral Local Setup

1️⃣ Ollama installieren

Ollama ist der einfachste Weg, um LLMs lokal zu betreiben.

# Linux Installation
curl -fsSL https://ollama.com/install.sh | sh

# Model downloaden (Mistral 7B)
ollama pull mistral

# Server starten
ollama serve

# Test
ollama run mistral "Hello, wie gehts?"
💾 Model-Größe: Mistral 7B = ~4.1 GB
🧠 RAM-Bedarf: Minimum 8 GB, empfohlen 16 GB
⚡ GPU: Optional (CPU funktioniert, ist nur langsamer)

2️⃣ Python Backend Setup

# Virtual Environment erstellen
python3 -m venv ai-os-env
source ai-os-env/bin/activate

# Dependencies installieren
pip install fastapi uvicorn langchain ollama chromadb sentence-transformers

3️⃣ Backend Server Code

from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from langchain.llms import Ollama
from langchain.callbacks.manager import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
import json

app = FastAPI()

# CORS für Frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Ollama LLM initialisieren
llm = Ollama(
    model="mistral",
    callback_manager=CallbackManager([StreamingStdOutCallbackHandler()])
)

@app.websocket("/ws/chat")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    
    while True:
        # User Message empfangen
        data = await websocket.receive_text()
        message = json.loads(data)
        
        # LLM Response generieren
        response = llm(message["prompt"])
        
        # Response zurücksenden
        await websocket.send_json({
            "type": "response",
            "content": response
        })

@app.post("/api/chat")
async def chat(request: dict):
    """REST API Endpoint"""
    prompt = request.get("prompt", "")
    response = llm(prompt)
    
    return {
        "response": response,
        "model": "mistral-7b"
    }

# Server starten
# uvicorn main:app --host 0.0.0.0 --port 8000

4️⃣ Frontend Integration

// AI Service im Browser
class LocalAI {
  constructor() {
    this.ws = null;
    this.connect();
  }
  
  connect() {
    this.ws = new WebSocket('ws://localhost:8000/ws/chat');
    
    this.ws.onopen = () => {
      console.log('🤖 AI Connected');
    };
    
    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.handleResponse(data);
    };
  }
  
  async ask(prompt, context = {}) {
    // Message an LLM senden
    this.ws.send(JSON.stringify({
      prompt: prompt,
      context: context,
      timestamp: Date.now()
    }));
  }
  
  handleResponse(data) {
    // Response verarbeiten
    const event = new CustomEvent('ai-response', { 
      detail: data 
    });
    window.dispatchEvent(event);
  }
}

// Initialisieren
const ai = new LocalAI();

// Verwenden
ai.ask("Liste alle Dateien im /documents Ordner");

// Response lauschen
window.addEventListener('ai-response', (e) => {
  console.log('AI:', e.detail.content);
});

🎯 Alternative: Kleinere Models für schwächere Hardware

Model Größe RAM Performance Use Case
TinyLlama 637 MB 2 GB ⭐⭐ Embedded Devices
Phi-2 1.7 GB 4 GB ⭐⭐⭐ Mini PCs
Mistral 7B 4.1 GB 8 GB ⭐⭐⭐⭐ Desktop (empfohlen)
Llama 2 13B 7.3 GB 16 GB ⭐⭐⭐⭐⭐ High-End Workstations

📚 RAG Pipeline - Kontext ist König

💡 Was ist RAG?

Retrieval-Augmented Generation = Dein LLM kann auf DEINE Daten zugreifen, nicht nur auf Training-Daten.

Ohne RAG

LLM: "Ich weiß nicht, welche Dateien du hast."

Mit RAG

LLM: "Du hast 37 PDFs über Krypto im /finance Ordner, erstellt zwischen März-Juni 2024."

🏗️ RAG Architektur

1️⃣ Document Ingestion

PDF, TXT, DOCX, Code → Text Chunks

⬇️
2️⃣ Embedding Generation

Text → Vector (384/768 dimensions)

⬇️
3️⃣ Vector Storage

ChromaDB / FAISS / Pinecone

⬇️
4️⃣ Similarity Search

User Query → Top K relevante Chunks

⬇️
5️⃣ LLM + Context

Query + Retrieved Context → Answer

1️⃣ RAG Backend Setup

# Dependencies
pip install chromadb sentence-transformers pypdf langchain llama-index

2️⃣ Vector Store Setup

import chromadb
from chromadb.config import Settings
from sentence_transformers import SentenceTransformer

# ChromaDB initialisieren (persistent)
client = chromadb.Client(Settings(
    chroma_db_impl="duckdb+parquet",
    persist_directory="./chroma_db"
))

# Collection erstellen
collection = client.get_or_create_collection(
    name="os_documents",
    metadata={"description": "All user documents and system files"}
)

# Embedding Model laden
embedder = SentenceTransformer('all-MiniLM-L6-v2')

def add_document(text, metadata):
    """Dokument zu Vector DB hinzufügen"""
    # Text in Chunks aufteilen
    chunks = split_text(text, chunk_size=500)
    
    # Embeddings generieren
    embeddings = embedder.encode(chunks)
    
    # Zu DB hinzufügen
    collection.add(
        embeddings=embeddings.tolist(),
        documents=chunks,
        metadatas=[metadata] * len(chunks),
        ids=[f"{metadata['file_id']}_{i}" for i in range(len(chunks))]
    )

def split_text(text, chunk_size=500, overlap=50):
    """Text in überlappende Chunks aufteilen"""
    words = text.split()
    chunks = []
    
    for i in range(0, len(words), chunk_size - overlap):
        chunk = ' '.join(words[i:i + chunk_size])
        chunks.append(chunk)
    
    return chunks

3️⃣ Document Processor

from pypdf import PdfReader
import docx
import json

class DocumentProcessor:
    def __init__(self, vector_store):
        self.vector_store = vector_store
    
    def process_file(self, filepath, file_id):
        """Automatisch Datei-Typ erkennen und verarbeiten"""
        ext = filepath.split('.')[-1].lower()
        
        if ext == 'pdf':
            text = self.extract_pdf(filepath)
        elif ext == 'txt':
            text = self.extract_txt(filepath)
        elif ext == 'docx':
            text = self.extract_docx(filepath)
        elif ext == 'json':
            text = self.extract_json(filepath)
        else:
            return None
        
        # Metadata
        metadata = {
            'file_id': file_id,
            'filepath': filepath,
            'type': ext,
            'indexed_at': time.time()
        }
        
        # Zu Vector Store hinzufügen
        add_document(text, metadata)
        
        return True
    
    def extract_pdf(self, filepath):
        reader = PdfReader(filepath)
        text = ""
        for page in reader.pages:
            text += page.extract_text()
        return text
    
    def extract_txt(self, filepath):
        with open(filepath, 'r', encoding='utf-8') as f:
            return f.read()
    
    def extract_docx(self, filepath):
        doc = docx.Document(filepath)
        return '\n'.join([p.text for p in doc.paragraphs])
    
    def extract_json(self, filepath):
        with open(filepath, 'r') as f:
            data = json.load(f)
            return json.dumps(data, indent=2)

4️⃣ RAG Query System

def rag_query(user_query, top_k=5):
    """Query mit RAG-Kontext"""
    
    # 1. Query Embedding generieren
    query_embedding = embedder.encode([user_query])[0]
    
    # 2. Ähnliche Dokumente suchen
    results = collection.query(
        query_embeddings=[query_embedding.tolist()],
        n_results=top_k
    )
    
    # 3. Kontext zusammenstellen
    context = "\n\n".join(results['documents'][0])
    
    # 4. Prompt für LLM bauen
    prompt = f"""Basierend auf folgenden Informationen:

{context}

Beantworte die Frage: {user_query}

Antworte präzise und nutze nur die gegebenen Informationen.
"""
    
    # 5. LLM aufrufen
    response = llm(prompt)
    
    return {
        'answer': response,
        'sources': results['metadatas'][0],
        'context_used': context
    }

🚀 Real-World Beispiele

# User: "Zeig mir alle Rechnungen von letztem Monat"
→ RAG findet: invoice_2024_01.pdf, invoice_2024_02.pdf
→ LLM antwortet: "Ich habe 2 Rechnungen gefunden: ..."

# User: "Fasse das Projekt-Meeting zusammen"
→ RAG findet: meeting_notes_2024_03_15.txt
→ LLM antwortet: "Im Meeting wurden folgende Punkte besprochen: ..."

# User: "Welche Python-Funktionen habe ich für API-Calls?"
→ RAG findet: api_utils.py, backend.py
→ LLM antwortet: "Du hast fetch_data(), post_request() in api_utils.py..."

⚙️ CRUD Skills - LLM als OS-Controller

💡 Konzept: Function Calling / Tool Use

Das LLM kann nicht nur antworten, sondern Aktionen ausführen.

Klassisch

User: "Erstelle eine Datei"
OS: "Befehl nicht erkannt"

AI-Native

User: "Erstelle eine Datei notes.txt"
LLM: Führt create_file('notes.txt') aus
OS: "✓ Datei erstellt"

CREATE

Dateien, Ordner, Apps erstellen

📖
READ

Dateien lesen, durchsuchen, analysieren

✏️
UPDATE

Dateien bearbeiten, umbenennen

🗑️
DELETE

Dateien löschen, aufräumen

1️⃣ Tool Definition (LangChain)

from langchain.tools import Tool
from langchain.agents import initialize_agent, AgentType
import os
import json

# CRUD Tools definieren
class FileSystemTools:
    
    @staticmethod
    def create_file(filename: str, content: str = "") -> str:
        """Erstellt eine neue Datei"""
        try:
            with open(f"./user_files/{filename}", 'w') as f:
                f.write(content)
            return f"✓ Datei {filename} erstellt"
        except Exception as e:
            return f"✗ Fehler: {str(e)}"
    
    @staticmethod
    def read_file(filename: str) -> str:
        """Liest eine Datei"""
        try:
            with open(f"./user_files/{filename}", 'r') as f:
                return f.read()
        except Exception as e:
            return f"✗ Fehler: {str(e)}"
    
    @staticmethod
    def update_file(filename: str, content: str) -> str:
        """Aktualisiert eine Datei"""
        try:
            with open(f"./user_files/{filename}", 'w') as f:
                f.write(content)
            return f"✓ Datei {filename} aktualisiert"
        except Exception as e:
            return f"✗ Fehler: {str(e)}"
    
    @staticmethod
    def delete_file(filename: str) -> str:
        """Löscht eine Datei"""
        try:
            os.remove(f"./user_files/{filename}")
            return f"✓ Datei {filename} gelöscht"
        except Exception as e:
            return f"✗ Fehler: {str(e)}"
    
    @staticmethod
    def list_files(directory: str = "./user_files") -> str:
        """Listet alle Dateien auf"""
        try:
            files = os.listdir(directory)
            return json.dumps(files, indent=2)
        except Exception as e:
            return f"✗ Fehler: {str(e)}"
    
    @staticmethod
    def search_files(query: str) -> str:
        """Durchsucht Dateien nach Inhalt"""
        results = []
        for filename in os.listdir("./user_files"):
            try:
                with open(f"./user_files/{filename}", 'r') as f:
                    content = f.read()
                    if query.lower() in content.lower():
                        results.append(filename)
            except:
                continue
        return json.dumps(results, indent=2)

2️⃣ Tools zu Agent hinzufügen

from langchain.agents import initialize_agent, Tool, AgentType

# Tools definieren
tools = [
    Tool(
        name="CreateFile",
        func=FileSystemTools.create_file,
        description="Erstellt eine neue Datei. Input: filename, content"
    ),
    Tool(
        name="ReadFile",
        func=FileSystemTools.read_file,
        description="Liest den Inhalt einer Datei. Input: filename"
    ),
    Tool(
        name="UpdateFile",
        func=FileSystemTools.update_file,
        description="Aktualisiert eine bestehende Datei. Input: filename, content"
    ),
    Tool(
        name="DeleteFile",
        func=FileSystemTools.delete_file,
        description="Löscht eine Datei. Input: filename"
    ),
    Tool(
        name="ListFiles",
        func=FileSystemTools.list_files,
        description="Listet alle Dateien auf"
    ),
    Tool(
        name="SearchFiles",
        func=FileSystemTools.search_files,
        description="Durchsucht Dateien nach Text. Input: query"
    )
]

# Agent initialisieren
agent = initialize_agent(
    tools=tools,
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

# Agent verwenden
response = agent.run("Erstelle eine Datei todo.txt mit Inhalt 'Projekt fertigstellen'")
print(response)

3️⃣ Erweiterte System-Skills

class SystemTools:
    """Erweiterte OS-Operationen"""
    
    @staticmethod
    def execute_shell(command: str) -> str:
        """Führt Shell-Befehle aus (SICHER!)"""
        # Whitelist von erlaubten Befehlen
        allowed = ['ls', 'pwd', 'date', 'whoami']
        cmd = command.split()[0]
        
        if cmd not in allowed:
            return f"✗ Befehl '{cmd}' nicht erlaubt"
        
        import subprocess
        try:
            result = subprocess.run(
                command, 
                shell=True, 
                capture_output=True, 
                text=True,
                timeout=5
            )
            return result.stdout
        except Exception as e:
            return f"✗ Fehler: {str(e)}"
    
    @staticmethod
    def get_system_info() -> str:
        """Gibt System-Informationen zurück"""
        import platform
        info = {
            'os': platform.system(),
            'version': platform.version(),
            'architecture': platform.machine(),
            'processor': platform.processor()
        }
        return json.dumps(info, indent=2)
    
    @staticmethod
    def open_app(app_name: str) -> str:
        """Öffnet eine App"""
        # Hier würdest du deine App-Launcher-Logik einbauen
        return f"✓ App '{app_name}' geöffnet"
    
    @staticmethod
    def close_app(app_name: str) -> str:
        """Schließt eine App"""
        return f"✓ App '{app_name}' geschlossen"

# Als Tools registrieren
system_tools = [
    Tool(
        name="ExecuteShell",
        func=SystemTools.execute_shell,
        description="Führt Shell-Befehle aus (nur sichere Befehle)"
    ),
    Tool(
        name="GetSystemInfo",
        func=SystemTools.get_system_info,
        description="Gibt System-Informationen zurück"
    ),
    Tool(
        name="OpenApp",
        func=SystemTools.open_app,
        description="Öffnet eine Anwendung. Input: app_name"
    ),
    Tool(
        name="CloseApp",
        func=SystemTools.close_app,
        description="Schließt eine Anwendung. Input: app_name"
    )
]

🎯 Real-World Agent-Interaktionen

👤 User: "Erstelle mir eine Shopping-Liste"
🤖 AI: [Ruft CreateFile('shopping.txt', '') auf]
     ✓ Datei shopping.txt erstellt

👤 User: "Füge Milch und Brot hinzu"
🤖 AI: [Ruft UpdateFile('shopping.txt', 'Milch\nBrot') auf]
     ✓ Datei shopping.txt aktualisiert

👤 User: "Was steht auf der Liste?"
🤖 AI: [Ruft ReadFile('shopping.txt') auf]
     Auf deiner Shopping-Liste stehen:
     - Milch
     - Brot

👤 User: "Zeig mir alle Text-Dateien"
🤖 AI: [Ruft ListFiles() auf]
     Ich habe folgende Dateien gefunden:
     - shopping.txt
     - notes.txt
     - todo.txt

👤 User: "Durchsuche alle Dateien nach 'Projekt'"
🤖 AI: [Ruft SearchFiles('Projekt') auf]
     'Projekt' wurde gefunden in:
     - todo.txt
     - notes.txt

🚀 Deployment & Integration

🖥️ Desktop Deployment

┌─────────────────────────┐
│   Linux Kiosk Mode      │
│   (Chromium Fullscreen) │
└────────┬────────────────┘
         │
         ├─ Frontend (Browser)
         │  └─ Web-OS UI
         │
         ├─ Backend (localhost:8000)
         │  ├─ Ollama (Mistral)
         │  ├─ FastAPI Server
         │  ├─ ChromaDB
         │  └─ LangChain Agent
         │
         └─ File System
            └─ /user_files/
  • Boot → Linux startet → Ollama auto-start
  • Backend startet automatisch (systemd)
  • Chromium Kiosk öffnet Frontend
  • Alles lokal, kein Internet nötig

📱 Mobile Deployment

┌─────────────────────────┐
│  Android WebView App    │
└────────┬────────────────┘
         │
         ├─ Frontend (WebView)
         │  └─ Web-OS UI
         │
         ├─ Backend (Remote/Cloud)
         │  ├─ Ollama Server
         │  ├─ REST API
         │  └─ Vector DB
         │
         └─ Local Storage
            └─ IndexedDB
  • WebView lädt lokales HTML
  • Backend auf Mini-Server (Raspberry Pi)
  • LAN-Verbindung zum Server
  • Offline-Modus mit Caching

1️⃣ Systemd Service (Auto-Start)

# /etc/systemd/system/ai-os-backend.service

[Unit]
Description=AI OS Backend Server
After=network.target

[Service]
Type=simple
User=ai-user
WorkingDirectory=/home/ai-user/ai-os
ExecStart=/home/ai-user/ai-os-env/bin/uvicorn main:app --host 0.0.0.0 --port 8000
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

# Aktivieren
sudo systemctl enable ai-os-backend
sudo systemctl start ai-os-backend

2️⃣ Ollama Auto-Start

# /etc/systemd/system/ollama.service

[Unit]
Description=Ollama LLM Server
After=network.target

[Service]
Type=simple
User=ai-user
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=10
Environment="OLLAMA_MODELS=/home/ai-user/.ollama/models"

[Install]
WantedBy=multi-user.target

# Aktivieren
sudo systemctl enable ollama
sudo systemctl start ollama

3️⃣ Kiosk Auto-Start (komplettes Setup)

# ~/.config/autostart/ai-os-kiosk.desktop

[Desktop Entry]
Type=Application
Name=AI OS Kiosk
Exec=/usr/bin/chromium --kiosk --noerrdialogs --disable-infobars http://localhost:3000
X-GNOME-Autostart-enabled=true
X-GNOME-Autostart-Delay=10

⚡ Performance-Optimierung

CPU-Only Mode
# Für Geräte ohne GPU
export OLLAMA_NUM_GPU=0
ollama run mistral
GPU Acceleration (CUDA)
# Für NVIDIA GPUs
export OLLAMA_NUM_GPU=1
ollama run mistral

📊 Hardware-Empfehlungen

Konfiguration CPU RAM Storage LLM Model Performance
Budget 4 Cores 8 GB 32 GB SSD TinyLlama ⭐⭐
Standard 6-8 Cores 16 GB 128 GB SSD Mistral 7B ⭐⭐⭐⭐
High-End 8+ Cores 32 GB 256 GB NVMe Llama 2 13B ⭐⭐⭐⭐⭐
Pro (+ GPU) 8+ Cores 32 GB 512 GB NVMe Llama 2 70B ⭐⭐⭐⭐⭐

💡 Killer Use Cases

📝

Intelligenter Datei-Manager

User: "Sortiere meine Dateien 
       nach Projekt"

AI:   Analysiert alle Dateien
      Erkennt Projekt-Bezüge
      Erstellt Ordner
      Verschiebt Dateien
      ✓ 47 Dateien sortiert
💻

Code Assistant

User: "Zeig mir alle Funktionen
       mit Bugs"

AI:   Durchsucht Code-Files
      Analysiert mit RAG
      Findet potenzielle Bugs
      Schlägt Fixes vor
      ✓ 3 Probleme gefunden
📚

Persönliche Wissensbasis

User: "Was habe ich über 
       Kubernetes gelernt?"

AI:   Durchsucht Notizen
      Extrahiert mit RAG
      Fasst zusammen
      Verlinkt Quellen
      ✓ Zusammenfassung bereit

🚀 Das macht dein OS einzigartig

✅ 100% Lokal

Keine Cloud, keine API-Keys, keine Limits

✅ Vollständiger Kontext

RAG kennt alle deine Dateien und Apps

✅ Echte Aktionen

CRUD-Skills führen echte OS-Operationen aus