Sovereign MoE — Systemdokumentation¶
Stand: 2026-03-29 — Version 2.1.0
Projektverzeichnis:/opt/deployment/moe-infra
1. Überblick¶
Sovereign MoE ist ein vollständig selbst gehostetes Mixture-of-Experts-LLM-System. Eingehende Anfragen werden von einem Orchestrator analysiert und an spezialisierte LLM-Experten, externe Suchwerkzeuge sowie präzise Berechnungs-Tools verteilt. Die Ergebnisse werden von einem Judge-LLM synthetisiert.
Das System ist OpenAI-API-kompatibel (inkl. korrekt terminierendem Streaming) und kann als Drop-in-Ersatz in Clients wie Open WebUI eingebunden werden.
Kernprinzipien¶
- Keine Cloud-Abhängigkeit — alle LLMs laufen lokal via Ollama auf eigener GPU-Hardware
- Spezialisierung statt Generalisierung — pro Kategorie werden die besten verfügbaren Modelle eingesetzt
- Exaktheit vor LLM-Estimation — Berechnungen, Daten, Hashes deterministisch über MCP-Server
- Lernen durch Nutzung — Feedback fließt in Expert-Performance-Scores und den Wissensgraph zurück
- Persistente Hintergrundverarbeitung — Kafka entkoppelt den HTTP-Pfad von Ingest und Logging
2. Hardware & Infrastruktur¶
| Server | IP | Hardware | Status |
|---|---|---|---|
| RTX-Server | 192.168.155.224 |
5× Nvidia-GPUs, Ollama Port 11434 | aktiv |
| Tesla-Server | 192.168.155.226 |
Nvidia Tesla M10 | offline (Umbau) |
Beide Ollama-Endpoints konfigurierbar über URL_RTX / URL_TESLA in .env. Aktuell zeigen beide auf den RTX-Server.
VRAM-Verwaltung¶
asyncio.Semaphore(GPU_COUNT) (Standard: 5) verhindert CUDA-OOM. Alle LLM-Calls laufen durch diesen Semaphore. GPU-Zuteilung: Round-Robin via assign_gpu().
3. Systemarchitektur¶
flowchart TD
CLIENT["☁ Client\n(Open WebUI, curl, SDK)"]
subgraph ORCH["LangGraph Orchestrator · Port 8002"]
CACHE["🔍 cache_lookup"]
PLANNER["🧠 planner\n(Judge-LLM)"]
WORKERS["👥 workers\n(LLM-Experten)"]
RESEARCH["🌐 research\n(SearXNG)"]
MATH["∑ math\n(SymPy)"]
MCP_NODE["🔧 mcp\n(Precision Tools)"]
GRAPHRAG["🗃 graph_rag\n(Neo4j)"]
MERGER["⚖ merger\n(Judge-LLM)"]
THINKING["💭 thinking\n(CoT, bedingt)"]
CRITIC["🔎 critic\n(Faktencheck)"]
end
CLIENT -->|"POST /v1/chat/completions"| CACHE
CACHE -->|"Cache Hit"| CLIENT
CACHE -->|"Cache Miss"| PLANNER
PLANNER --> WORKERS & RESEARCH & MATH & MCP_NODE & GRAPHRAG
WORKERS & RESEARCH & MATH & MCP_NODE & GRAPHRAG --> MERGER
WORKERS -->|"Niedrige Konfidenz"| THINKING
THINKING --> MERGER
MERGER --> CRITIC
CRITIC --> CLIENT
MERGER --> CHROMADB[("ChromaDB\nPort 8001")]
MERGER --> REDIS[("Redis\nPort 6379")]
MERGER -->|"moe.ingest + moe.requests"| KAFKA[("Kafka\nPort 9092")]
KAFKA -->|"Consumer → Ingest"| NEO4J[("Neo4j\nPort 7687")]
MCP_NODE --> MCPSERVER["MCP Precision Tools\nPort 8003"]
4. Docker-Services¶
sudo docker compose up -d # alle Services starten
sudo docker compose down # stoppen
sudo docker compose logs -f <name> # Live-Logs
Service-Übersicht¶
| Container | Image / Build | Ports (Host→Container) | Funktion |
|---|---|---|---|
langgraph-orchestrator |
./Dockerfile |
8002:8000 |
Kern-Orchestrator, FastAPI |
mcp-precision |
./mcp_server/Dockerfile |
8003:8003 |
Precision Tools Server |
neo4j-knowledge |
neo4j:5-community |
7474:7474, 7687:7687 |
Knowledge Graph |
terra_cache |
redis/redis-stack-server:latest |
6379:6379 |
Redis |
chromadb-vector |
chromadb/chroma:latest |
8001:8000 |
Vektorcache |
moe-kafka |
confluentinc/cp-kafka:7.7.0 |
9092:9092 |
Kafka (KRaft) |
Host-Volumes¶
| Pfad | Inhalt |
|---|---|
/opt/moe-infra/neo4j-data |
Neo4j Daten |
/opt/moe-infra/redis-data |
Redis Persistenz |
/opt/moe-infra/chroma-data |
ChromaDB Vektordaten |
/opt/moe-infra/kafka-data |
Kafka Log-Segmente |
/opt/moe-infra/agent-logs |
Orchestrator-Logs |
5. LangGraph Pipeline¶
Pipeline-Fluss¶
flowchart TD
START([START]) --> CACHE_LOOKUP
CACHE_LOOKUP["cache_lookup_node"] -->|"cache_hit=True"| MERGER_NODE
CACHE_LOOKUP -->|"cache_hit=False"| PLANNER_NODE["planner_node"]
PLANNER_NODE --> EW["expert_worker"]
PLANNER_NODE --> RN["research_node"]
PLANNER_NODE --> MN["math_node_wrapper"]
PLANNER_NODE --> MCPN["mcp_node"]
PLANNER_NODE --> GRN["graph_rag_node"]
EW --> RFN["research_fallback_node"]
RN --> RFN
MN --> RFN
MCPN --> RFN
GRN --> RFN
RFN --> THINKING_NODE["thinking_node\n(CoT, bedingt aktiv)"]
THINKING_NODE --> MERGER_NODE["merger_node"]
MERGER_NODE --> CRITIC_NODE["critic_node\n(Faktencheck, nur medical/legal)"]
CRITIC_NODE --> END([END])
Nodes im Detail¶
cache_lookup_node¶
- Fragt ChromaDB nach 3 semantisch ähnlichsten Einträgen
- Überspringt Einträge mit
flagged=True(negatives Feedback) - Distance <
CACHE_HIT_THRESHOLD(0.15) →cache_hit=True→ gesamte Pipeline übersprungen
planner_node¶
- Judge-LLM zerlegt Anfrage in 1–4 Subtasks als JSON-Array
_sanitize_plan()validiert jeden Eintrag: muss Dict mittask+categorysein; Strings, leere Dicts und unbekannte Kategorien werden verworfen (geloggt)- Fallback auf
[{"task": input, "category": "general"}]bei JSON-Parsefehler - Kennt alle Experten-Kategorien, 16 MCP-Tools und Research-Option
Planner-Regeln (im Prompt erzwungen):
- precision_tools schlägt immer math — nie beides für dieselbe Aufgabe
- research nur bei wirklich externem/aktuellem Informationsbedarf
- Niemals Keywords oder Fragen als Tasks — immer Aufgabenbeschreibungen
expert_worker¶
- Filtert Tasks auf LLM-Experten-Kategorien (alles außer
precision_tools,research) - Two-Tier-Logik: T1 (≤20B) zuerst — bei
KONFIDENZ: hoch→ T2 übersprungen; sonst T2 eskaliert - Sortiert Experten nach Performance-Score (beste zuerst); Score < 0.3 → übersprungen
- Injiziert
chat_history(letzte 4 Runden, max. 3000 Zeichen) in alle Expert-Messages - Output-Cap:
MAX_EXPERT_OUTPUT_CHARS(2400 Zeichen ≈ 600 Tokens) - Liefert
expert_models_used(["model::category", ...])
research_node¶
- Aktiv nur bei
research-Task im Plan - Nutzt
search_queryaus dem Plan (vom Planner optimiert) - Liefert strukturierte Quellenangaben via
search.results()(Titel + URL nummeriert)
research_fallback_node¶
- Läuft nach dem Fan-in aller parallelen Nodes
- Für jedes
KONFIDENZ: niedrig-Expert-Ergebnis: gezielte Web-Recherche mit Citation Tracking - Aggregiert neue Ergebnisse in
web_research
thinking_node¶
- Bedingt aktiv: bei Plänen mit >1 Task ODER wenn mind. ein Experte
KONFIDENZ: niedrigmeldet - Magistral:24b führt 4-Schritt Chain-of-Thought durch:
- Problemzerlegung
- Quellenauswertung (welche Infos zuverlässig, Widersprüche?)
- Wissenslücken
- Schlussfolgerung
- Ausgabe als
reasoning_trace→ priorisierter Abschnitt im Merger-Prompt - Fortschritt erscheint im Open WebUI
<think>-Panel
math_node_wrapper¶
- Aktiv nur wenn
math-Task im Plan UND keinprecision_tools-Task vorhanden - SymPy-basiert (symbolisch)
mcp_node¶
- Alle
precision_tools-Tasks parallel viaasyncio.gather - HTTP-POST an MCP-Server
/invoke
graph_rag_node¶
- Parallel zu allen anderen Nodes nach Planner
- Term-Extraktion (regex, kein LLM-Call)
- 2-Hop-Traversal in Neo4j
merger_node¶
- Ruft
_dedup_by_category()— behält pro Kategorie nur das höchst-konfidente Experten-Ergebnis - Quellpriorität: Reasoning-Trace > MCP > Wissensgraph > Experten > Web > Cache
- Bei Cache-Hit: direkte Rückgabe, kein LLM-Call
- Publiziert nach Antwort (> 150 Zeichen):
- ChromaDB: neues Cache-Dokument (sync)
- Redis: Response-Metadaten (async Task)
- Kafka
moe.requests: Audit-Log (async Task) - Kafka
moe.ingest: GraphRAG-Ingest-Job (async Task)
critic_node¶
- Nur aktiv wenn Plan
medical_consultoderlegal_advisorenthält - Zweiter Judge-LLM-Pass prüft Merger-Antwort auf faktische Fehler und gefährliche Aussagen
- Antwort
BESTÄTIGT→ Antwort unverändert weiter; Fehler erkannt → korrigierte Version
State-Schema (AgentState)¶
| Feld | Typ | Beschreibung |
|---|---|---|
input |
str | Benutzeranfrage |
response_id |
str | chatcmpl-<uuid> für Feedback-Tracking |
mode |
str | default | code | concise |
plan |
List[Dict] | Subtask-Plan |
expert_results |
Annotated[list, add] | Experten-Antworten (fan-in) |
expert_models_used |
Annotated[list, add] | ["model::category", ...] |
web_research |
str | SearXNG-Ergebnis mit Quellenangaben |
cached_facts |
str | Nächster Cache-Treffer |
cache_hit |
bool | Cache-Short-Circuit ausgelöst |
math_result |
str | SymPy-Ergebnis |
mcp_result |
str | MCP Tools Ergebnis |
graph_context |
str | Neo4j Kontext-Block |
final_response |
str | Finale synthetisierte Antwort |
prompt_tokens |
Annotated[int, add] | Akkumulierte Prompt-Tokens aller LLM-Calls |
completion_tokens |
Annotated[int, add] | Akkumulierte Completion-Tokens aller LLM-Calls |
chat_history |
List[Dict] | Gesprächskontext (letzte 4 Runden) für Experten |
reasoning_trace |
str | CoT-Ausgabe des thinking_node |
6. Experten-System¶
Two-Tier-System¶
Experten werden nach Modellgröße in Tiers eingeteilt:
| Tier | Schwelle | Rolle |
|---|---|---|
| T1 | ≤ 20B Parameter | Schnelle erste Einschätzung |
| T2 | > 20B Parameter | Premium-Eskalation bei nicht-hoher Konfidenz |
T1 läuft zuerst. Gibt mindestens ein T1-Ergebnis KONFIDENZ: hoch → T2 wird übersprungen. Sonst laufen alle T2-Modelle parallel.
Konfigurierte Experten¶
| Kategorie | Modell 1 | Tier | Modell 2 | Tier |
|---|---|---|---|---|
general |
gemma3:27b |
T2 | qwen3.5:35b |
T2 |
math |
phi4:14b |
T1 | qwq:32b |
T2 |
technical_support |
deepseek-coder-v2:16b |
T1 | devstral:24b |
T2 |
creative_writer |
gemma3:27b |
T2 | qwen3.5:35b |
T2 |
code_reviewer |
devstral:24b |
T2 | qwen3-coder:30b |
T2 |
medical_consult |
phi4:14b |
T1 | gemma3:27b |
T2 |
legal_advisor |
magistral:24b |
T2 | command-r:35b |
T2 |
translation |
translategemma:27b |
T2 | qwen3.5:35b |
T2 |
reasoning |
phi4:14b |
T1 | deepseek-r1:32b |
T2 |
Judge-LLM: magistral:24b (Planner, Merger, Thinking-Node, Critic, GraphRAG-Extraktion)
System-Prompts¶
| Kategorie | Rolle & Verhalten |
|---|---|
general |
Vielseitig, faktenbasiert, strukturiert, Deutsch |
math |
Lösungsweg + LaTeX, Rückprüfung durch Rückeinsetzen |
technical_support |
IT-Ingenieur, ausführbare Schritte, konkrete Befehle |
creative_writer |
Lebendig, stilsicher, Register passend zum Kontext |
code_reviewer |
Senior SWE, Bugs/Sicherheit/Performance, konkreter Code |
medical_consult |
Sachlich, leitlinienbasiert, immer Arztbesuch empfehlen |
legal_advisor |
Deutsches Recht (§§), individuelle Beratung empfehlen |
translation |
Professionell, idiomatisch, kulturelle Besonderheiten |
reasoning |
Chain-of-Thought, Annahmen benennen, begründete Schlussfolgerung |
7. MCP Precision Tools Server¶
Port: 8003 · Datei: mcp_server/server.py
REST-Endpunkte¶
| Endpoint | Methode | Beschreibung |
|---|---|---|
/health |
GET | Status + Tool-Liste |
/tools |
GET | Tool-Beschreibungen (für Planner-Prompt) |
/invoke |
POST | {"tool": "name", "args": {...}} |
/mcp/sse |
GET | MCP SSE-Endpoint (Claude Desktop etc.) |
Alle 16 Tools¶
| Tool | Beschreibung |
|---|---|
calculate |
Exakte Arithmetik, Formeln, Prozent (Safe-AST-Evaluator) |
solve_equation |
Algebraische Gleichungen (SymPy) |
date_diff |
Exakte Datumsdifferenz (Tage, Jahre, Monate) |
date_add |
Datum-Arithmetik (Tage/Monate/Jahre addieren/subtrahieren) |
day_of_week |
Wochentag, Kalenderwoche, Jahrestag |
unit_convert |
Physikalische Einheiten (pint): km/h→m/s, °F→°C, ... |
statistics_calc |
mean, median, stdev, variance, min, max, sum, count, mode |
hash_text |
MD5, SHA1, SHA224, SHA256, SHA384, SHA512 |
base64_codec |
Base64 encode / decode |
regex_extract |
Regex-Matching mit Flags (i, m, s) |
subnet_calc |
CIDR: Netzwerk, Broadcast, Maske, Hostbereich |
text_analyze |
Wörter, Zeichen, Sätze, Absätze, Lesezeit |
prime_factorize |
Primfaktorzerlegung via SymPy |
gcd_lcm |
ggT und kgV |
json_query |
JSON-Pfad-Abfragen (key.sub, array[0]) |
roman_numeral |
Arabisch ↔ Römisch (1–3999) |
8. GraphRAG & Wissensontologie¶
Datei: graph_rag/manager.py, graph_rag/ontology.py · DB: Neo4j 5
Basis-Ontologie (beim Start geladen, idempotent)¶
- 104 Entitäten — Medical, Legal, Technical, Math/Science
- 100 Relationen — IS_A, TREATS, CAUSES, INTERACTS_WITH, CONTRAINDICATES, DEFINES, USES, IMPLEMENTS, DEPENDS_ON, EXTENDS, RELATED_TO, AFFECTS, u.a.
Kontext-Abfrage¶
- Term-Extraktion aus Anfrage (regex, bevorzugt Substantive/Eigennamen)
- Fuzzy-Suche auf
name+aliases_str(case-insensitive) - 2-Hop-Traversal: direkte + indirekte Relationen
- Ausgabe als
[Wissensgraph]-Textblock im Merger-Prompt
Hintergrund-Ingest (via Kafka)¶
- Merger-Antwort →
moe.ingest-Topic - Kafka-Consumer ruft
extract_and_ingest()auf - Judge-LLM extrahiert bis zu 8 Tripel (JSON-Format)
- Konflikt-Prüfung: TREATS vs. CAUSES/CONTRAINDICATES (und umgekehrt)
- Neue Tripel werden mit
r.verified=falsegespeichert
Feedback-Integration¶
| Rating | Neo4j |
|---|---|
| 1–2 | r.flagged=true, r.verified=false |
| 4–5 | r.verified=true, r.flagged=false |
9. Kafka Event-Streaming¶
Detaillierte Dokumentation: Kafka
Kurzübersicht¶
| Topic | Erzeuger | Consumer | Inhalt |
|---|---|---|---|
moe.ingest |
merger_node |
_kafka_consumer_loop |
GraphRAG-Ingest-Job |
moe.requests |
merger_node |
_kafka_consumer_loop (Logging) |
Audit-Log |
moe.feedback |
/v1/feedback |
— | Feedback-Events |
Kafka-Setup: confluentinc/cp-kafka:7.7.0, KRaft-Modus (kein Zookeeper), Port 9092, 7 Tage Retention.
Graceful Degradation: Bei Kafka-Ausfall funktioniert das System vollständig weiter — HTTP-Antworten, Cache, Redis unberührt.
10. Gedächtnis & Lernmechanismen¶
Vier Gedächtnisebenen¶
| Ebene | Speicher | Wächst durch | TTL |
|---|---|---|---|
| Semantischer Cache | ChromaDB | Jede Merger-Antwort > 150 Zeichen | unbegrenzt |
| Wissensgraph | Neo4j | Kafka moe.ingest Consumer |
unbegrenzt |
| Expert-Performance | Redis | POST /v1/feedback |
unbegrenzt |
| LangGraph Checkpoints | Redis | Jeden Request | unbegrenzt |
Expert-Performance-Scoring¶
Key: moe:perf:{model}:{category}
Fields: total, positive, negative
Score = (positive + 1) / (total + 2) # Laplace-Glättung
- Unter 5 Bewertungen: 0.5 (neutral)
- Score < 0.3 nach ≥ 5 Bewertungen → Experte wird übersprungen
Feedback-Wirkung¶
| Rating | ChromaDB | Expert-Score | Neo4j |
|---|---|---|---|
| 1–2 (negativ) | flagged=True |
negative++ |
flagged=true |
| 3 (neutral) | — | — | — |
| 4–5 (positiv) | — | positive++ |
verified=true |
11. OpenAI-API & Streaming¶
Streaming (SSE) — vollständig OpenAI-kompatibel¶
Jeder Chunk enthält id, object, created, model, choices:
1. Erster Chunk: delta={"role":"assistant","content":""}, finish_reason=null
2. Content-Chunks: delta={"content":"<50 Zeichen>"}, finish_reason=null
3. Stop-Chunk: delta={}, finish_reason="stop"
4. Abschluss: data: [DONE]
Der Stop-Chunk mit finish_reason: "stop" ist das Signal für Open WebUI (und alle OpenAI-kompatiblen Clients) den Stream zu schließen und LLMs freizugeben. Ohne diesen Chunk würde der Client endlos warten.
Non-Streaming¶
{
"id": "chatcmpl-<uuid>",
"object": "chat.completion",
"created": 1774783273,
"model": "moe-orchestrator",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "..."}, "finish_reason": "stop"}],
"usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
}
12. API-Referenz¶
Basis-URL: http://<host>:8002
Chat Completions¶
POST /v1/chat/completions
{"model":"moe-orchestrator","messages":[{"role":"user","content":"..."}],"stream":false}
Models¶
Feedback¶
Graph¶
13. Konfiguration & Umgebungsvariablen¶
| Variable | Standard | Beschreibung |
|---|---|---|
URL_RTX |
— | Ollama RTX-Server |
URL_TESLA |
— | Ollama Tesla-Server |
JUDGE_ENDPOINT |
RTX |
Server für Judge-LLM |
JUDGE_MODEL |
gemma3:4b |
Judge-Modell |
EXPERT_MODELS |
{} |
JSON: Kategorie → [{model, endpoint}] |
SEARXNG_URL |
— | SearXNG-Instanz |
REDIS_URL |
redis://terra_cache:6379 |
Redis |
CHROMA_HOST |
chromadb-vector |
ChromaDB-Host |
MCP_URL |
http://mcp-precision:8003 |
MCP-Server |
NEO4J_URI |
bolt://neo4j-knowledge:7687 |
Neo4j |
NEO4J_USER |
neo4j |
Neo4j-User |
NEO4J_PASS |
moe-sovereign |
Neo4j-Passwort |
KAFKA_URL |
kafka://moe-kafka:9092 |
Kafka Bootstrap |
GPU_COUNT |
5 |
VRAM-Semaphore & Round-Robin |
MAX_EXPERT_OUTPUT_CHARS |
2400 |
Output-Cap pro Experte |
CACHE_HIT_THRESHOLD |
0.15 |
Cosine-Distance-Schwellwert |
LOG_LEVEL |
INFO |
DEBUG / INFO / WARNING / ERROR |
14. Datenpersistenz¶
| Daten | Speicher | TTL | Redis-Key / ChromaDB-Collection |
|---|---|---|---|
| LangGraph-Checkpoints | Redis | unbegrenzt | langgraph:* |
| Semantischer Cache | ChromaDB | unbegrenzt | moe_fact_cache |
| Expert-Performance | Redis | unbegrenzt | moe:perf:{model}:{cat} |
| Response-Metadaten | Redis | 7 Tage | moe:response:{id} |
| Wissensgraph | Neo4j | unbegrenzt | Volume /opt/moe-infra/neo4j-data |
| Kafka-Events | Kafka | 7 Tage / 512 MB | /opt/moe-infra/kafka-data |
15. Deployment¶
Erststart¶
cd /opt/deployment/moe-infra
cp temp.env .env
# URL_RTX, SEARXNG_URL, EXPERT_MODELS eintragen
sudo mkdir -p /opt/moe-infra/{neo4j-data,neo4j-logs,redis-data,chroma-data,kafka-data,agent-logs}
sudo docker compose up -d --build
sudo docker compose logs -f langgraph-orchestrator
Nach Code-Änderungen¶
# Orchestrator
sudo docker compose build langgraph-app && sudo docker compose up -d langgraph-app
# MCP-Server
sudo docker compose build mcp-precision && sudo docker compose up -d mcp-precision
Startup-Sequenz (Orchestrator)¶
- Redis-Client
- Kafka-Producer (12 Versuche, 5–60s Backoff)
- MCP-Tool-Beschreibungen laden
- Neo4j GraphRAG (6 Versuche, 10–60s Backoff)
- Kafka-Consumer als Background-Task starten
- AsyncRedisSaver → LangGraph-Graph kompilieren
- FastAPI auf Port 8000
Health-Checks¶
curl http://localhost:8002/v1/models # Orchestrator
curl http://localhost:8002/graph/stats # GraphRAG
curl http://localhost:8003/health # MCP-Server
sudo docker exec terra_cache redis-cli ping # Redis
sudo docker exec moe-kafka kafka-topics \
--bootstrap-server localhost:9092 --list # Kafka Topics
# Neo4j Browser: http://localhost:7474
16. Projektstruktur¶
/opt/deployment/moe-infra/
│
├── main.py # LangGraph Orchestrator, FastAPI, alle Nodes, Kafka
├── math_node.py # SymPy Mathematik-Node
├── requirements.txt # Python-Abhängigkeiten
├── Dockerfile
├── docker-compose.yml # Alle 6 Services
├── .env # Konfiguration (nicht in Git)
├── temp.env # .env-Vorlage
│
├── graph_rag/
│ ├── __init__.py
│ ├── manager.py # Neo4j-Client, query_context, extract_and_ingest
│ └── ontology.py # Basis-Ontologie: 104 Entitäten, 100 Relationen
│
├── mcp_server/
│ ├── server.py # 16 Precision Tools + REST-Shim + MCP SSE
│ ├── requirements.txt
│ └── Dockerfile
│
├── README.md # Schnellstart, API-Kurzreferenz
├── SYSTEM.md # Vollständige Systemdoku (Quelldatei)
├── KAFKA.md # Kafka-Architektur, Topics, HowTo Admin & Dev
└── CHANGELOG.md # Versionshistorie
17. Qualitätsmechanismen¶
Konfidenz-Scoring¶
Alle Experten geben strukturierten Output mit Konfidenz-Selbsteinschätzung:
hoch = gesichertes Fachwissen · mittel = Nuancen möglich · niedrig = Datenlücken, Unsicherheit
Automatische Qualitätssicherungskette¶
Expert-Output
│
├─ KONFIDENZ: niedrig? → research_fallback (Web-Recherche mit Citations)
│
▼
thinking_node (wenn >1 Task ODER niedrige Konfidenz)
│ 4-Schritt CoT: Problemzerlegung → Quellen → Lücken → Schluss
▼
merger_node
│ _dedup_by_category(): beste Konfidenz pro Kategorie gewinnt
│ Quellpriorität: Reasoning > MCP > Graph > Experten > Web > Cache
▼
critic_node (nur medical_consult / legal_advisor)
│ Faktencheck: faktische Fehler / gefährliche Aussagen?
└─ BESTÄTIGT → weiter · Fehler → korrigierte Version
Open WebUI Integration¶
<think>-Panel: Fortschrittsberichte aller Nodes viacontextvars.ContextVar→ SSE-Stream → „Denke nach"-Panel- Interne Requests:
_is_openwebui_internal()erkennt Title/Follow-up/Autocomplete → Fast-Path ohne Pipeline - Token-Tracking: Akkumulierte
usage-Felder (alle LLM-Calls) in jedem Response
Output-Modi¶
| Modell-ID | Modus | Verhalten |
|---|---|---|
moe-orchestrator |
default |
Vollständige Antworten mit Erklärungen |
moe-orchestrator-code |
code |
Nur Quellcode, kein Fließtext |
moe-orchestrator-concise |
concise |
Max. 120 Wörter |
Generiert am 2026-03-29 — Version 2.1.0