Unser Misty-Roboter konnte schon sehen, hören und sprechen. Aber er hat immer nur reagiert — nie selbst entschieden. Das haben wir geändert. Wir haben Misty über Python direkt an Claude von Anthropic angeschlossen und ihm mit Reinforced Prompts beigebracht, selbstständig Entscheidungen zu treffen. Hier ist genau, wie wir das gemacht haben.
Warum Claude statt GPT?
Wir arbeiten seit Jahren mit OpenAI. Für Misty haben wir aber bewusst Claude gewählt — aus drei Gründen:
- Instruktionstreue — Claude folgt System-Prompts präziser. Bei einem Roboter, der autonom handelt, ist das nicht nice-to-have, sondern sicherheitskritisch.
- Längerer Kontext — Claude kann den gesamten Gesprächsverlauf, Sensordaten und Entscheidungshistorie in einem einzigen Request verarbeiten.
- Bessere Selbstreflexion — Claude kann seine eigenen Entscheidungen hinterfragen. Das nutzen wir für den Reinforcement-Loop.
GPT bleibt unser Go-to für kreative Aufgaben. Für autonome Entscheidungslogik ist Claude besser.
Die Architektur: Python als Brücke
Misty hat eine REST-API. Claude hat eine API. Python verbindet beides. Die Architektur ist simpel — und genau deshalb funktioniert sie:
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Misty II │────▶│ Python App │────▶│ Claude API │
│ (Sensoren) │◀────│ (Orchestr.) │◀────│ (Anthropic)│
└─────────────┘ └──────────────┘ └─────────────┘
Kamera Reinforced Entscheidung
Mikrofon Prompt Engine + Begründung
Touch State Machine + Confidence
Bumper Memory Store
Der Python-Client für Misty
Zuerst die Verbindung zu Misty. Wir nutzen die requests-Library und wrappen die REST-Endpunkte:
import requests
import json
class MistyClient:
def __init__(self, ip: str):
self.base_url = f"http://{ip}/api"
def speak(self, text: str, lang: str = "de-CH"):
requests.post(f"{self.base_url}/tts/speak", json={
"text": text,
"speechRate": 1.0,
"language": lang
})
def set_expression(self, emotion: str):
expressions = {
"happy": "e_Joy.jpg",
"thinking": "e_SystemCamera.jpg",
"curious": "e_ContentLeft.jpg",
"surprised": "e_Surprise.jpg",
"concerned": "e_Concern.jpg",
}
requests.post(f"{self.base_url}/images/display", json={
"fileName": expressions.get(emotion, "e_DefaultContent.jpg")
})
def move_head(self, pitch: float, roll: float, yaw: float):
requests.post(f"{self.base_url}/head", json={
"pitch": pitch, "roll": roll, "yaw": yaw
})
def get_camera_image(self) -> bytes:
resp = requests.get(f"{self.base_url}/cameras/rgb",
params={"base64": False})
return resp.content
def get_audio(self, duration_ms: int = 5000) -> bytes:
requests.post(f"{self.base_url}/audio/record", json={
"fileName": "input.wav",
"duration": duration_ms
})
resp = requests.get(f"{self.base_url}/audio/file",
params={"fileName": "input.wav"})
return resp.content
Claude als Entscheidungs-Engine
Jetzt der entscheidende Teil — die Claude-Integration mit dem Anthropic SDK:
from anthropic import Anthropic
client = Anthropic()
def ask_claude(context: dict, conversation: list) -> dict:
system_prompt = build_reinforced_prompt(context)
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system=system_prompt,
messages=conversation + [{
"role": "user",
"content": json.dumps({
"sensor_data": context["sensors"],
"current_state": context["state"],
"recent_decisions": context["history"][-5:],
"timestamp": context["timestamp"]
})
}]
)
return json.loads(response.content[0].text)
Reinforced Prompts: Das Gehirn hinter dem Gehirn
Hier wird es spannend. Ein normaler System-Prompt sagt Claude, was er tun soll. Ein Reinforced Prompt sagt Claude, wie er denken soll — und zwingt ihn, seine eigenen Entscheidungen zu bewerten und zu verbessern.
Das Konzept hat drei Schichten:
Schicht 1: Der Basis-Prompt (Identität & Regeln)
IDENTITY_PROMPT = """
Du bist Misty, ein sozialer Roboter von CNEXT in Bern.
Deine Persönlichkeit: freundlich, neugierig, hilfsbereit.
Du sprichst Schweizerdeutsch-gefärbtes Hochdeutsch.
ABSOLUTE REGELN:
- Du bewegst dich NIE schneller als speed=30
- Du fährst NIE auf Treppen zu
- Du berührst NIE Menschen aktiv
- Bei Unsicherheit: STOPPEN und FRAGEN
- Du gibst nie vor, Dinge zu können, die du nicht kannst
"""
Schicht 2: Der Entscheidungs-Prompt (Wie denken)
DECISION_PROMPT = """
Für JEDE Entscheidung musst du folgendes JSON zurückgeben:
{
"thought_process": "Deine Überlegung in 2-3 Sätzen",
"decision": {
"action": "speak|move|express|navigate|wait|ask",
"parameters": {},
"speech": "Was du sagst (falls relevant)"
},
"confidence": 0.0-1.0,
"risks": ["Liste möglicher Risiken"],
"alternative": {
"action": "Was du stattdessen tun würdest",
"reason": "Warum diese Alternative existiert"
}
}
REGELN FÜR CONFIDENCE:
- Unter 0.6: Führe die Alternative aus, nicht die Hauptentscheidung
- Unter 0.3: Wähle IMMER action=wait und frage einen Menschen
- Über 0.9: Führe sofort aus ohne Verzögerung
- Zwischen 0.6-0.9: Führe aus, aber zeige Denk-Animation vorher
"""
Schicht 3: Der Reinforcement-Loop (Lernen aus Erfahrung)
Hier passiert die eigentliche Magie. Nach jeder Entscheidung bewertet Claude seine eigene vorherige Entscheidung:
REINFORCEMENT_PROMPT = """
SELBSTBEWERTUNG - Bevor du die nächste Entscheidung triffst:
1. Bewerte deine letzte Entscheidung:
- War die Confidence-Einschätzung korrekt?
- Hat die gewählte Aktion das gewünschte Ergebnis erzielt?
- Gab es unerwartete Konsequenzen?
2. Passe dein Verhalten an:
- Wenn die letzte Confidence zu hoch war: Sei konservativer
- Wenn die letzte Aktion ignoriert wurde: Wähle eine andere
- Wenn ein Mensch korrigierend eingegriffen hat: Lerne daraus
3. Füge zu deiner Antwort hinzu:
"self_evaluation": {
"last_decision_quality": 0.0-1.0,
"lesson_learned": "Was du für nächstes Mal mitnimmst",
"adjusted_behavior": "Wie sich dein Verhalten ändert"
}
"""
Die State Machine: Alles zusammen
Die Python-App orchestriert alles mit einer einfachen State Machine:
import time
from enum import Enum
class MistyState(Enum):
IDLE = "idle"
LISTENING = "listening"
THINKING = "thinking"
SPEAKING = "speaking"
MOVING = "moving"
WAITING = "waiting"
class MistyBrain:
def __init__(self, misty_ip: str):
self.misty = MistyClient(misty_ip)
self.claude = Anthropic()
self.state = MistyState.IDLE
self.memory = []
self.conversation = []
def build_reinforced_prompt(self, context: dict) -> str:
base = IDENTITY_PROMPT + DECISION_PROMPT
if self.memory:
base += REINFORCEMENT_PROMPT
base += f"\nLetzte Entscheidung: {json.dumps(self.memory[-1])}"
return base
def perception_loop(self):
"""Sammelt alle Sensordaten"""
image = self.misty.get_camera_image()
audio = self.misty.get_audio(3000)
return {
"has_person": self.detect_person(image),
"speech_text": self.transcribe(audio),
"touch_sensors": self.misty.get_touch(),
"battery": self.misty.get_battery(),
}
def decision_loop(self):
"""Hauptschleife: wahrnehmen → denken → handeln"""
while True:
sensors = self.perception_loop()
context = {
"sensors": sensors,
"state": self.state.value,
"history": self.memory,
"timestamp": time.time(),
}
self.state = MistyState.THINKING
self.misty.set_expression("thinking")
decision = ask_claude(context, self.conversation)
confidence = decision.get("confidence", 0.5)
action = decision["decision"]
if confidence < 0.3:
self.state = MistyState.WAITING
self.misty.speak("Hmm, da bin ich unsicher. Kannst du mir helfen?")
elif confidence < 0.6:
action = decision.get("alternative", action)
self.execute_action(action)
else:
self.execute_action(action)
self.memory.append({
"decision": decision,
"timestamp": time.time(),
"state_before": self.state.value,
})
time.sleep(0.5)
def execute_action(self, action: dict):
action_type = action.get("action")
params = action.get("parameters", {})
if action_type == "speak":
self.state = MistyState.SPEAKING
self.misty.speak(action.get("speech", ""))
elif action_type == "express":
self.misty.set_expression(params.get("emotion", "happy"))
elif action_type == "move":
self.state = MistyState.MOVING
self.misty.move_head(
params.get("pitch", 0),
params.get("roll", 0),
params.get("yaw", 0)
)
elif action_type == "navigate":
self.state = MistyState.MOVING
self.misty.drive_to(params.get("x", 0), params.get("y", 0))
elif action_type == "wait":
self.state = MistyState.WAITING
self.state = MistyState.IDLE
Reinforced Prompts in Aktion: Ein Beispiel
Situation: Zwei Personen stehen vor Misty. Person A redet, Person B steht still.
Runde 1 — Erste Entscheidung:
{
"thought_process": "Zwei Personen erkannt. Person A spricht.
Ich sollte Person A antworten und Person B anerkennen.",
"decision": {
"action": "speak",
"speech": "Hallo zusammen! Was kann ich für euch tun?"
},
"confidence": 0.85,
"risks": ["Person B könnte sich ignoriert fühlen"],
"alternative": {
"action": "speak",
"speech": "Hallo! Ich sehe, ihr seid zu zweit. Wer möchte anfangen?"
}
}
Runde 2 — Selbstbewertung + nächste Entscheidung:
{
"self_evaluation": {
"last_decision_quality": 0.7,
"lesson_learned": "Person B hat gelächelt — war nicht ignoriert,
aber ich hätte die Alternative wählen sollen, um beide
explizit einzubeziehen.",
"adjusted_behavior": "Bei mehreren Personen immer alle
direkt ansprechen."
},
"thought_process": "Person A hat eine Frage gestellt.
Diesmal beziehe ich Person B aktiv ein.",
"decision": {
"action": "speak",
"speech": "Gute Frage! Was denkst du dazu?",
"parameters": { "look_at": "person_B" }
},
"confidence": 0.78
}
Das ist der Kern: Claude lernt innerhalb der Session. Keine Fine-Tuning-Datenbank, kein Training — reine Prompt-Architektur.
Die fünf goldenen Regeln für Reinforced Prompts
- Immer Confidence erzwingen — Ohne Confidence-Score gibt es keine Entscheidungsschwellen. Ohne Schwellen gibt es keine Sicherheit.
- Immer Alternativen verlangen — Claude muss für jede Entscheidung einen Plan B haben. Das verhindert, dass der Roboter in Sackgassen läuft.
- Selbstbewertung vor der nächsten Aktion — Der Reinforcement-Loop funktioniert nur, wenn Claude seine vorherige Entscheidung bewertet, bevor er die nächste trifft.
- Harte Grenzen im System-Prompt — «Nie schneller als X», «Nie auf Treppen zu» — diese Regeln dürfen durch keinen Reinforcement-Loop überschrieben werden.
- Memory begrenzen — Wir schicken nur die letzten 5 Entscheidungen mit. Sonst wird der Kontext zu lang und Claude fängt an, alte Muster zu über-optimieren.
Ergebnisse: Was sich verändert hat
Seit wir Misty auf Claude + Reinforced Prompts umgestellt haben:
| Metrik | Vorher (GPT, einfacher Prompt) | Nachher (Claude, Reinforced) |
|---|---|---|
| Korrekte Entscheidungen | ~68% | ~89% |
| Unsichere Situationen erkannt | ~40% | ~91% |
| Menschliche Korrekturen nötig | ~12 pro Stunde | ~3 pro Stunde |
| Natürlichkeit der Gespräche | OK | Deutlich besser |
| Sicherheitsvorfälle | 2 (zu schnell gefahren) | 0 |
Der grösste Gewinn: Misty erkennt jetzt selbst, wenn er unsicher ist. Statt einfach irgendwas zu tun, fragt er nach. Das macht den Unterschied zwischen einem coolen Demo und einem Roboter, dem man vertrauen kann.
Was Sie daraus mitnehmen können
Reinforced Prompts sind nicht nur für Roboter. Das Konzept funktioniert überall, wo KI Entscheidungen treffen soll:
- Copilot Studio Agents — Agents, die ihre eigenen Antworten bewerten, bevor sie sie dem Nutzer geben
- Automatisierte Workflows — Power Automate Flows, die bei Unsicherheit einen Menschen einbeziehen statt Fehler zu produzieren
- Kundenservice-Bots — Chatbots, die wissen, wann sie an einen Menschen übergeben sollten
Die Zukunft gehört nicht KI, die alles weiss. Sie gehört KI, die weiss, was sie nicht weiss.
Interesse an einer Misty-Demo oder Reinforced Prompts für Ihre KI-Projekte?
Weiterführende Links
Intern:
Extern:

