Zurück zur Startseite

Schach mit LLM auf Python ohne Halluzinationen

Der Artikel beschreibt die Implementierung einer Schach-KI basierend auf LLM mit python-chess zur Validierung. FEN/PGN/UCI werden in Prompts und Fallback für Stabilität verwendet. Kostenloser Zugriff über OpenRouter.

Erstelle eine Schach-KI auf Llama ohne Fehler
Advertisement 728x90

Schach-Intelligenz mit LLM und Python erstellen – Kostenlos, ohne Halluzinationen

Entwickler müssen oft LLMs in Spiele-Apps integrieren, doch die OpenAI-API kann teuer sein. Eine kostengünstige Alternative ist OpenRouter, das kostenlose Open-Source-Modelle mit dem Tag :free anbietet. So können Sie Abfragen an Llama 4 kostenfrei durchführen, allerdings mit Begrenzungen bei der Nachrichtenmenge.

Die Client-Initialisierung erfolgt über die standardmäßige openai-Schnittstelle:

class LLMAI:
    def __init__(self, model_name="meta-llama/llama-4-maverick-17b-128e-instruct:free"):
        self.client = openai.OpenAI(
            base_url="https://openrouter.ai/api/v1",
            api_key=OPENROUTER_API_KEY,
        )
        self.model_name = model_name
        self.move_count = 0

Durch die Angabe von base_url bleibt die Kompatibilität zu bestehendem Code gewährleistet. Das Modell erhält für jeden Zug einen Prompt, was den Rechenaufwand minimiert.

Google AdInline article slot

Übergabe des Brettzustands im Prompt

LLMs verarbeiten keine visuellen Bretter, daher muss der Kontext textuell aufgebaut werden. Standard-FEN- und PGN-Formate werden um eine Liste legaler Züge aus python-chess erweitert, um Halluzinationen zu vermeiden.

Code zum Aufbau des Kontexts:

# Aktuelle Stellung im FEN-Format abrufen
fen = board.fen()

# Zuggeschichte im PGN-Format
pgn_moves = []
temp_board = chess.Board()

# Zughistorie
for move in board.move_stack:
    pgn_moves.append(temp_board.san(move))
    temp_board.push(move)

pgn_history = " ".join(pgn_moves) if pgn_moves else "Ausgangsposition"

# Liste der legalen Züge abrufen
legal_moves = [move.uci() for move in board.legal_moves]
legal_moves_str = ", ".join(legal_moves)

Der System-Prompt beschränkt die Antwort auf UCI-Notation (4 Zeichen, z. B. e2e4):

Google AdInline article slot
prompt = f"""Sie spielen Schach als {"weiß" if board.turn == chess.WHITE else "schwarz"}.

Aktuelle Stellung (FEN): {fen}
Zuggeschichte: {pgn_history}
Zugnummer: {self.move_count}

Verfügbare Züge in UCI-Format: {legal_moves_str}
Wählen Sie den BESTEN Zug aus den verfügbaren Optionen und geben Sie NUR den UCI-Zugcode zurück (z. B. e2e4, g1f3, e7e8q).
Fügen Sie keine Erklärungen, Analysen oder zusätzlichen Text hinzu.
Die Antwort darf nur den UCI-Zugcode enthalten."""

Die Kombination aus FEN (aktueller Zustand), PGN (Geschichte) und UCI-Liste (Einschränkungen) steigert die Genauigkeit um 80–90 % gegenüber einfachen Prompts.

Zugvalidierung und Fallback-Mechanismus

LLMs können Anweisungen ignorieren und Text oder illegale Züge zurückgeben. Die Lösung? Der "AI-Referee"-Muster: python-chess validiert UCI-Züge, bevor sie auf das Brett angewendet werden.

UI-Logik:

Google AdInline article slot
if move_uci:
    try:
        move = chess.Move.from_uci(move_uci)
        if move in self.board.legal_moves:
            # Animation vor Ausführung
            self.animate_move(move)
            self.board.push(move)
            self.move_history.append(move.uci())
            self.last_ai_response = f"LLM hat Zug gemacht: {move.uci()}"
            print(self.last_ai_response)
        else:
            # Fallback auf zufälligen Zug
            move = random.choice(list(self.board.legal_moves))
            self.animate_move(move)
            self.board.push(move)
            self.move_history.append(move.uci())
            self.last_ai_response = f"LLM fehlgeschlagen, zufälliger Zug: {move.uci()}"
            print(self.last_ai_response)
    except ValueError:
        # Fallback auf zufälligen Zug
        move = random.choice(list(self.board.legal_moves))

Beispiel-Log:

  • Anfrage #1: LLM antwortete mit »e7e5« → gültiger Zug.
  • Anfrage #2: LLM antwortete mit »Gut, ich denke, der beste Zug ist d7d5« → Fallback auf a7a6.

Dies gewährleistet uneingeschränkten Spielablauf ohne Abstürze.

Wichtige Architekturkomponenten

Das Projekt basiert auf:

  • python-chess: Verwaltung des Bretts, Validierung von Zügen, Handhabung von FEN/PGN/UCI.
  • pygame: Darstellung des Bretts, Animationseffekte für Züge.
  • openai-client + OpenRouter: Aufrufe zur LLM-Inferenz.
  • Fallback-Logik: random.choice für Robustheit.

Modulare Struktur: Die Klasse LLMAI isoliert die Interaktion mit dem LLM von der Benutzeroberfläche und übermittelt nur validierte Züge. Leicht skalierbar auf andere regelbasierte Spiele wie Go oder Dame.

| Komponente | Rolle | Bibliothek |

|-----------|------|---------|

| Brett | Zustand & Validierung | python-chess |

| LLM | Zugauswahl | OpenRouter Llama 4 |

| UI | Darstellung & Eingabe | pygame |

| Referee | Validierung | try/except |

Was wirklich zählt

  • OpenRouter bietet kostenlosen Zugang zu leistungsfähigen LLMs für Prototypen mit Volumenbeschränkungen.
  • Ein strikter Prompt mit FEN, PGN und UCI-Listen reduziert Halluzinationen auf 10–20 %.
  • Das "AI-Referee"-Muster mit Fallback sorgt für Stabilität: LLM schlägt vor, Bibliothek prüft und setzt um.
  • python-chess ist der de-facto-Standard für Schachlogik in Python und deckt alle Regeln ab, inklusive Rochade und En-passant.
  • Dieses Projekt zeigt, wie nicht-deterministische Modelle in deterministische Anwendungen integriert werden können.

— Editorial Team

Advertisement 728x90

Weiterlesen