Misty + Claude: Wie wir unserem Roboter mit Python und Reinforced Prompts ein Gehirn geben

    Zurück zum Blog
    Embodied AIEmpfohlen

    Misty + Claude: Wie wir unserem Roboter mit Python und Reinforced Prompts ein Gehirn geben

    Alles über Microsoft Power Pages: Externe Webseiten ohne Code erstellen, Dataverse-Daten sicher publizieren und Formulare für Kunden bereitstellen.

    1. März 202615 min Lesezeit
    Marcel Haas

    Marcel Haas

    Solution Architect, CEO

    marcel.haas@cnext.ch
    20+ JahreErfahrung·6×Microsoft Applied Skills·SharePoint & Microsoft Copilot
    6x Microsoft Applied Skills
    CNEXT AI Agent

    Kurzantwort

    Alles über Microsoft Power Pages: Externe Webseiten ohne Code erstellen, Dataverse-Daten sicher publizieren und Formulare für Kunden bereitstellen.

    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

    1. Immer Confidence erzwingen — Ohne Confidence-Score gibt es keine Entscheidungsschwellen. Ohne Schwellen gibt es keine Sicherheit.
    2. Immer Alternativen verlangen — Claude muss für jede Entscheidung einen Plan B haben. Das verhindert, dass der Roboter in Sackgassen läuft.
    3. Selbstbewertung vor der nächsten Aktion — Der Reinforcement-Loop funktioniert nur, wenn Claude seine vorherige Entscheidung bewertet, bevor er die nächste trifft.
    4. Harte Grenzen im System-Prompt — «Nie schneller als X», «Nie auf Treppen zu» — diese Regeln dürfen durch keinen Reinforcement-Loop überschrieben werden.
    5. 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:

    MetrikVorher (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ächeOKDeutlich besser
    Sicherheitsvorfälle2 (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:

    Embodied AIClaudeSchweiz
    Teilen:

    Dieser Artikel wurde mit Unterstützung von KI erstellt und von unserem Team geprüft. Wir setzen KI-Tools ein, um hochwertige Inhalte effizient zu produzieren — die fachliche Verantwortung liegt immer bei unseren Experten.

    Marcel Haas

    Marcel Haas

    Solution Architect, CEO

    6x Microsoft Applied Skills

    Haben Sie Fragen zu diesem Thema?

    Unsere Experten beraten Sie gerne – kostenlos und unverbindlich.