Construyendo una IA de ajedrez con LLM y Python — Sin coste, sin alucinaciones
Los desarrolladores a menudo necesitan integrar modelos de lenguaje (LLM) en aplicaciones de juegos, pero la API de OpenAI puede ser cara. Una alternativa asequible es OpenRouter, que ofrece modelos de código abierto gratuitos etiquetados como :free. Esto permite ejecutar consultas a Llama 4 sin costo alguno, con límites en el volumen de mensajes.
La inicialización del cliente utiliza la interfaz estándar de openai:
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
Establecer base_url garantiza compatibilidad con el código existente. El modelo recibe un prompt por cada movimiento, minimizando la carga computacional.
Pasando el estado del tablero al prompt
Los LLM no procesan tableros visuales, por lo que el contexto debe construirse en formato de texto. Los formatos estándar FEN y PGN se mejoran con una lista de movimientos legales desde python-chess para evitar alucinaciones.
Código para construir el contexto:
# Obtener posición actual en formato FEN
fen = board.fen()
# Historial de movimientos en formato PGN
pgn_moves = []
temp_board = chess.Board()
# Historia de movimientos
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 "Posición inicial"
# Obtener lista de movimientos legales
legal_moves = [move.uci() for move in board.legal_moves]
legal_moves_str = ", ".join(legal_moves)
El sistema de prompts limita las respuestas a notación UCI (4 caracteres, por ejemplo, e2e4):
prompt = f"""Eres un jugador de ajedrez como {'blancas' if board.turn == chess.WHITE else 'negras'}.
Posición actual (FEN): {fen}
Historial de movimientos: {pgn_history}
Número de movimiento: {self.move_count}
Movimientos disponibles en formato UCI: {legal_moves_str}
Elige el MEJOR movimiento entre las opciones disponibles y devuelve SOLO el código UCI (por ejemplo, e2e4, g1f3, e7e8q).
No añadas explicaciones, análisis ni texto adicional.
La respuesta debe contener únicamente el código UCI."""
Combinar FEN (estado actual), PGN (historia) y lista UCI (restricciones) aumenta la precisión entre un 80 % y un 90 % frente a prompts básicos.
Validación de movimientos y mecanismo de respaldo
Los LLM pueden ignorar instrucciones, devolviendo texto o movimientos ilegales. La solución? Usar el patrón "Árbitro de IA": python-chess valida los movimientos UCI antes de aplicarlos al tablero.
Lógica del bucle de interfaz:
if move_uci:
try:
move = chess.Move.from_uci(move_uci)
if move in self.board.legal_moves:
# Animación antes de ejecutar el movimiento
self.animate_move(move)
self.board.push(move)
self.move_history.append(move.uci())
self.last_ai_response = f"IA generó el movimiento: {move.uci()}"
print(self.last_ai_response)
else:
# Respuesta de emergencia con movimiento aleatorio
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"IA falló, movimiento aleatorio: {move.uci()}"
print(self.last_ai_response)
except ValueError:
# Respuesta de emergencia con movimiento aleatorio
move = random.choice(list(self.board.legal_moves))
Ejemplo de registro:
- Solicitud #1: IA respondió con 'e7e5' → movimiento válido.
- Solicitud #2: IA respondió con 'Bien, creo que el mejor movimiento es d7d5' → fallback a a7a6.
Esto asegura un juego continuo sin fallos.
Componentes clave de la arquitectura
El proyecto se basa en:
- python-chess: gestión del tablero, validación de movimientos, manejo de FEN/PGN/UCI.
- pygame: renderizado del tablero, animaciones de movimientos.
- openai-client + OpenRouter: llamadas de inferencia del LLM.
- Lógica de respaldo:
random.choicepara resiliencia.
Diseño modular: la clase LLMAI aísla la interacción con el LLM de la interfaz, pasando solo movimientos validados. Fácilmente escalable a otros juegos basados en reglas como Go o damas.
| Componente | Rol | Biblioteca |
|-----------|------|---------|
| Tablero | Estado y validación | python-chess |
| LLM | Selección de movimiento | OpenRouter Llama 4 |
| Interfaz | Renderizado e input | pygame |
| Árbitro | Validación | try/except |
Lo que más importa
- OpenRouter ofrece acceso gratuito a LLM potentes para prototipado, con límites de volumen de solicitudes.
- Un prompt estricto usando FEN, PGN y listas UCI reduce las alucinaciones al 10–20 %.
- El patrón "Árbitro de IA" con respaldo garantiza estabilidad: el LLM sugiere, la biblioteca verifica y aplica.
- python-chess es el estándar de facto para lógica de ajedrez en Python, cubriendo todas las reglas incluyendo enroque y jaque en passant.
- Este proyecto demuestra cómo integrar modelos no deterministas en aplicaciones deterministas.
— Editorial Team
Aún no hay comentarios.