Reward Rover Playground: Technische Dokumentation
Wichtige Klarstellung: RAG vs. RL
Das Projekt implementiert kein RAG-System, sondern einen Reinforcement Learning (RL) Agenten.
| Feature | RAG (Dein Knowledge Vault) | Reinforcement Learning (Reward Rover) |
|---|---|---|
| Kern-Prinzip | Retrieval + Generation | Trial & Error (Belohnung/Bestrafung) |
| Datenbasis | Vektor-Datenbank (Embeddings) | Q-Table (State-Action Values) |
| Ziel | Textgenerierung / Antwort | Entscheidungsfindung / Pfadoptimierung |
| Modell | LLM (Claude/OpenAI) | Q-Learning Algorithmus (Mathematisch) |
1. Architektur-Γberblick
π‘ Vergleich zum RAG-Projekt: Die Grundstruktur ist identisch (React Frontend + Express Backend), was deine Konsistenz in der Architekturentscheidung beweist.
Plaintext
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FRONTEND (React) β
β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββββββ β
β β RLGame.tsx β β Tile.tsx β β EnvironmentBrowser.tsx β β
β β (307KB) β β (Memoized) β β (Level-Auswahl) β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββββββ β
β β β
β βββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ β
β β lib/rl/ (getestet) β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββ β β
β β β qLearning.tsβ β gridUtils.tsβ β portalUtils.ts β β β
β β β (26 Tests) β β (27 Tests) β β (24 Tests) β β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HTTP/REST
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BACKEND (Express) β
β ββββββββββββββ ββββββββββββββ βββββββββββββββββββββββββββ β
β β index.js β β auth.js β β daily.js β β
β β (API Routen)β β (JWT) β β (Daily Challenges) β β
β ββββββββββββββ ββββββββββββββ βββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SQLite (db.js) β β
β β Users β SavedStates β DailyChallenges β Submissions β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Der Q-Learning Algorithmus (KernstΓΌck)
Im Gegensatz zum RAG-System, das externe Intelligenz (APIs) nutzt, lΓ€uft hier die βIntelligenzβ lokal im Browser ab.
2.1 Die Bellman-Gleichung
Parameter:
-
(Learning Rate): 0.1 β Wie schnell ΓΌberschreibt neues Wissen altes Wissen?
-
(Discount Factor): 0.85 β Wie wichtig sind zukΓΌnftige Belohnungen gegenΓΌber sofortigen?
-
(Exploration Rate): Balance zwischen Erkunden (Zufall) und Nutzen (Wissen).
2.2 Implementierung (qLearning.ts)
TypeScript
// Die Q-Wert Update-Funktion (Zeile 138-146)
export const updateQValue = (
currentQValue: number,
reward: number,
maxNextQ: number,
alpha: number,
gamma: number
): number => {
return currentQValue + alpha * (reward + gamma * maxNextQ - currentQValue);
};
2.3 Epsilon-Greedy Aktionsauswahl
TypeScript
// chooseAction in qLearning.ts (Zeile 35-76)
export const chooseAction = (
grid: TileState[][],
pos: Position,
explorationRate: number,
biasDirection?: Position | null
): Position => {
const possible = getPossibleActions(grid, pos);
// 1. Optional: Bias-Richtung (35% Chance zum Ziel)
if (biasDirection && Math.random() < 0.35) {
return biasMatch;
}
// 2. Exploration: ZufΓ€llige Aktion mit Wahrscheinlichkeit Ξ΅
if (Math.random() < explorationRate) {
return possible[Math.floor(Math.random() * possible.length)];
}
// 3. Exploitation: Beste Q-Wert Aktion
let best = possible[0];
let bestQ = grid[best.y][best.x].qValue;
// ... finde beste Aktion (Code gekΓΌrzt)
return best;
};
2.4 Reward-Struktur (constants.ts)
TypeScript
export const STEP_PENALTY = -1; // Jeder Schritt kostet
export const REWARD_VALUE = 12; // Belohnungs-Feld
export const PUNISHMENT_VALUE = -15; // Bestrafungs-Feld
export const OBSTACLE_PENALTY = -20; // Wand-Kollision
export const GOAL_REWARD = 24; // Ziel erreicht
export const PORTAL_COOLDOWN_STEPS = 4; // Portal-Wartezeit
3. Frontend-Architektur
3.1 Tech Stack
JSON
{
"react": "^18.3.1",
"react-router-dom": "^6.26.2",
"@tanstack/react-query": "^5.56.2", // Server-State
"tailwindcss": "^3.4.11", // Styling
"zod": "^3.23.8", // Validierung
"recharts": "^2.12.7", // Diagramme
"vite": "^5.4.1", // Build-Tool
"vitest": "^4.0.10" // Testing
}
3.2 Drei Spielmodi
-
Playground Mode: Eigene Umgebungen bauen, Hyperparameter live anpassen, Q-Werte visualisieren.
-
Random Mode: Prozedural generierte Level, Bonus-System, Speedrun.
-
Comparison Mode: Zwei Agenten parallel trainieren um Parameter zu vergleichen.
3.3 State Management
Die Trennung von Daten und UI ist hier kritisch, da sich der State (grid) extrem schnell Γ€ndert (bei jedem Schritt des Agenten).
TypeScript
// Playground State Interface (RLGame.tsx ~1024-1036)
interface PlaygroundState {
agent: Position;
goal: Position;
grid: TileState[][]; // 2D Array mit Q-Werten
isRunning: boolean;
episode: number;
totalReward: number;
currentSteps: number;
episodeHistory: EpisodeStats[];
spawn: Position;
portalCooldowns: Record<string, number>;
}
4. Backend-Architektur
π‘ Vergleich zum RAG-Projekt: Beide nutzen Express.js. WΓ€hrend der RAG-Server hauptsΓ€chlich als Proxy zu OpenAI/Anthropic dient, hat dieses Backend eigene komplexe Logik (Auth, Seeds, DB-Sync).
4.1 Express Server Setup
JavaScript
import express from "express";
import cors from "cors";
// ... imports
const app = express();
app.use(cors({ origin: process.env.CORS_ORIGIN || "*" }));
app.use(express.json({ limit: "2mb" }));
4.2 Authentifizierung (Erweitert)
Im Gegensatz zum simplen Passwortschutz des RAG-Vaults nutzt Reward Rover echtes OAuth (Google/Apple) und JWT.
JWT Token Erstellung:
JavaScript
const createToken = (user) => {
return jwt.sign(
{ id: user.id, username: user.username, role: user.role },
JWT_SECRET,
{ expiresIn: "7d" },
);
};
OAuth Flow (Google):
JavaScript
app.post(`${API_PREFIX}/auth/oauth/google`, async (req, res) => {
const ticket = await googleClient.verifyIdToken({
idToken,
audience: GOOGLE_CLIENT_ID,
});
// ... user resolve logic ...
const token = createToken(user);
return res.json({ token, user });
});
4.3 API-Endpunkte
| Endpunkt | Methode | Auth | Beschreibung |
|---|---|---|---|
/api/auth/* | POST | - | Login/Register/OAuth |
/api/save | POST | JWT | Umgebung speichern |
/api/load | GET | JWT | Eigene Umgebungen laden |
/api/daily/current | GET | - | Tages-Challenge holen (Seed) |
/api/daily/submit | POST | JWT | Score einreichen |
/api/leaderboard | GET | - | Highscores |
5. Datenbank-Schema (SQLite)
π‘ Unterschied zum RAG-Projekt: Der RAG-Ansatz nutzt eine JSON-Datei als Vektor-Store. Hier wird eine relationale Datenbank (SQLite) benΓΆtigt, um Benutzerbeziehungen und Highscores abzubilden.
SQL
-- Benutzer mit OAuth-UnterstΓΌtzung
CREATE TABLE Users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'user',
provider TEXT NOT NULL DEFAULT 'local', -- 'local', 'google', 'apple'
provider_id TEXT,
email TEXT
);
-- TΓ€gliche Herausforderungen (Deterministisch)
CREATE TABLE DailyChallenges (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date_key TEXT NOT NULL UNIQUE, -- '2024-01-15'
seed INTEGER NOT NULL, -- Deterministischer Seed
config_json TEXT NOT NULL -- Grid-Konfiguration
);
-- Performance Optimierungen
PRAGMA foreign_keys = ON;
PRAGMA journal_mode = WAL; -- Write-Ahead Logging fΓΌr Concurrency
6. Daily Challenge System (Fairness durch Mathe)
Ein Highlight ist die Reproduzierbarkeit der Level durch Seeded RNG.
1. Hash vom Datum:
JavaScript
const hashDateToSeed = (dateKey) => { /* Wandelt String '2026-01-15' in Integer Hash */ };
- Mulberry32 PRNG:
Ein extrem schneller Pseudo-Random-Number-Generator. Er garantiert, dass random() fΓΌr denselben Seed immer die exakt gleiche Sequenz an Zahlen liefert.
Warum wichtig? Jeder User bekommt weltweit das exakt gleiche Level fΓΌr den gleichen Tag. Das macht das Leaderboard fair.
7. Testing-Strategie
π‘ Vergleich: Das RAG-Projekt ist schwer zu testen (nicht-deterministische LLM-Antworten). Reward Rover hingegen ist rein algorithmisch und daher perfekt durch Unit-Tests abgedeckt (77 Tests).
Struktur:
-
qLearning.test.ts(26 Tests) -
gridUtils.test.ts(27 Tests) -
portalUtils.test.ts(24 Tests)
Beispiel-Test (Q-Learning):
TypeScript
describe('updateQValue', () => {
it('should update Q-value using Bellman equation', () => {
// Q = 0 + 0.1 * (10 + 0.9 * 5 - 0) = 1.45
const newQ = updateQValue(0, 10, 5, 0.1, 0.9);
expect(newQ).toBeCloseTo(1.45);
});
});
8. Deployment
π‘ Gemeinsamkeit: Beide Projekte laufen auf demselben Hetzner VPS (91.99.236.172) und nutzen PM2 zur Prozessverwaltung.
Frontend (Netlify):
Wird als statische Site gebaut (npm run build) und via netlify.toml konfiguriert (Redirects fΓΌr React Router).
Backend (VPS):
Deployment via rsync Script. Nginx dient als Reverse Proxy, PM2 hΓ€lt den Node-Prozess am Leben.
9. Potenzielle Interview-Fragen
Q: Was ist der Unterschied zwischen Exploration und Exploitation?
A: Exploration () probiert zufΓ€llige Aktionen, um neue Wege zu entdecken. Exploitation () nutzt das bereits gelernte Wissen (Q-Table), um die Belohnung zu maximieren.
Q: Warum brauchst du einen Discount Factor ()?
A: Ohne wΓΌrde der Agent nur den sofortigen Schritt optimieren (gierig). Mit berΓΌcksichtigt er auch zukΓΌnftige Rewards, was wichtig ist, um z.B. erst einen Umweg zu gehen, um spΓ€ter eine groΓe Belohnung zu erhalten.
Q: Warum SQLite statt PostgreSQL?
A: FΓΌr die erwartete Last ist SQLite im WAL-Modus absolut ausreichend. Es vereinfacht das Deployment (kein separater DB-Server-Prozess), Backups sind einfach (Datei kopieren) und die Latenz ist minimal, da es im selben Prozessraum liegt.
Q: Vergleich zum RAG-Projekt: Wann nutzt du was?
A: Wenn ich faktisches Wissen abrufen und sprachlich verarbeiten muss, nutze ich RAG (Vektorsuche + LLM). Wenn ich ein System brauche, das Strategien lernt und Entscheidungen in einer definierten Umgebung treffen muss, nutze ich Reinforcement Learning (Q-Learning).
See also
-
RAG Knowledge Base (Vergleichsprojekt)
-
Created: 2026-01-15
see also
Type:
Tags:
Status:
Location:
Created: 2026-01-15 17:24