Saltar al contenido
Pedro Luis Soto Santos, Inicio
Volver a la portada

pyplAI-MCPProyecto personal. Servidor MCP open source.

La búsqueda de pyplAI, como herramienta para cualquier LLM.

Un servidor MCP que pone los algoritmos de pyplAI al alcance de asistentes como Claude. El modelo juega, pide el análisis de cada posición y explica su jugada con las cifras de la búsqueda. En Phantom, con las fichas del rival ocultas, el análisis solo usa lo que el jugador sabe.

juegos, uno con información oculta
3
partidas de benchmark con Llama 3.2 3B
960

Código en GitHub

Hecho con Python, MCP, Pydantic y pyplAI.

El problema

Los modelos de lenguaje razonan con palabras, pero no buscan. Si le pides a uno que juegue al Ultimate Tic-Tac-Toe, explicará bien sus jugadas y las elegirá mal. pyplAI, mi TFG, hace justo lo contrario: busca, pero no explica nada.

Quise juntar las dos cosas con el Model Context Protocol (MCP), el estándar con el que asistentes como Claude usan herramientas externas: que el modelo juegue, pida a pyplAI el análisis de la posición y explique su jugada con las cifras de la búsqueda.

Siete herramientas y un juego con información oculta

El servidor expone pyplAI como siete herramientas: ver los juegos y sus reglas, empezar una partida, consultar el estado, jugar, analizar la posición y terminar. La clave es analyze_position: lanza una búsqueda desde la posición del modelo y le devuelve sus jugadas legales ordenadas por el porcentaje de partidas simuladas que ganan. Esta es una respuesta real en Ultimate:

{
  "algorithm": "mcts",
  "metric": "win_rate",
  "best_move": "B1:a3",
  "moves": [
    {"move": "B1:a3", "visits": 121, "value": 0.4711},
    {"move": "B1:c1", "visits": 70, "value": 0.4357},
    {"move": "B1:c3", "visits": 89, "value": 0.4326}
  ],
  "iterations": 777,
  "seconds": 2.001
}

Phantom es donde el diseño importa. Es un cuatro en raya en un tablero de 4 × 4 en el que no ves las fichas del rival. Una búsqueda de información perfecta leería las fichas ocultas del estado del juego y haría trampa, así que el servidor solo ofrece las variantes ISMCTS de pyplAI, que muestrean dónde podrían estar esas fichas a partir de lo que el jugador sabe. Un test juega partidas completas y comprueba que nada de lo que recibe el jugador revela una ficha oculta.

Claude jugando

Claude Desktop durante una partida de Phantom: Claude llama a play_move con la jugada c2 y después a analyze_position, que recomienda b3 con un 61 % de victorias simuladas.
Una partida real desde Claude Desktop, con las llamadas a las herramientas desplegadas.

Así se ve desde Claude Desktop: Claude analiza cada posición, juega la jugada recomendada y explica por qué con las cifras del análisis. En esta partida de Phantom contra MO-ISMCTS ganó en cuatro jugadas (conversación completa).

Probarlo con un cliente real destapó dos fallos que los tests no cubrían. El modelo no tenía forma de leer las reglas, que estaban publicadas como recurso MCP y no como herramienta, así que añadí get_rules. Y al final de algunas partidas de Phantom el servidor describía mal la última jugada; ahora hay un test que reproduce ese final.

¿Cuánto ayuda la búsqueda a un modelo pequeño?

Una partida es una anécdota. Para medirlo escribí un agente que hace de cliente MCP y deja jugar, sin supervisión, a Llama 3.2 3B, servido en local con Ollama en la GPU de 4 GB de mi portátil. En cada juego compiten cuatro jugadores: Llama solo, Llama con analyze_position, la búsqueda sola como techo y las jugadas al azar como suelo. En total, 960 partidas.

Resultados de 960 partidas, por juego y jugadorLlama 3.2 3B solo pierde el 100 % de las partidas de tres en raya y de Ultimate. Con la herramienta de búsqueda, sus derrotas en tres en raya bajan al 31 %, pero en Ultimate no gana ninguna partida, mientras que la búsqueda sola gana 33 de 40. En Phantom, solo gana el 57 % y pierde el 42 %; con la búsqueda, gana el 45 % y pierde el 27 %.Tres en raya, contra MCTSLlama solo Llama solo: 100 % derrotas (100 de 100) Llama + búsqueda Llama + búsqueda: 3 % victorias (3 de 100) Llama + búsqueda: 66 % empates (66 de 100) Llama + búsqueda: 31 % derrotas (31 de 100) Solo búsqueda Solo búsqueda: 100 % empates (100 de 100) Al azar Al azar: 8 % empates (8 de 100) Al azar: 92 % derrotas (92 de 100) Ultimate, contra MCTSLlama solo Llama solo: 100 % derrotas (40 de 40) Llama + búsqueda Llama + búsqueda: 8 % empates (3 de 40) Llama + búsqueda: 93 % derrotas (37 de 40) Solo búsqueda Solo búsqueda: 83 % victorias (33 de 40) Solo búsqueda: 8 % empates (3 de 40) Solo búsqueda: 10 % derrotas (4 de 40) Al azar Al azar: 100 % derrotas (40 de 40) Phantom, contra MO-ISMCTSLlama solo Llama solo: 57 % victorias (57 de 100) Llama solo: 1 % empates (1 de 100) Llama solo: 42 % derrotas (42 de 100) Llama + búsqueda Llama + búsqueda: 45 % victorias (45 de 100) Llama + búsqueda: 28 % empates (28 de 100) Llama + búsqueda: 27 % derrotas (27 de 100) Solo búsqueda Solo búsqueda: 48 % victorias (48 de 100) Solo búsqueda: 32 % empates (32 de 100) Solo búsqueda: 20 % derrotas (20 de 100) Al azar Al azar: 1 % victorias (1 de 100) Al azar: 25 % empates (25 de 100) Al azar: 74 % derrotas (74 de 100)
Resultados de 960 partidas, por juego y jugador. 100 partidas por jugador en tres en raya y Phantom, y 40 en Ultimate. Datos: benchmark del repositorio.
Ver los datos
JuegoJugadorPartidasVictoriasEmpatesDerrotas
Tres en rayaLlama solo1000 %0 %100 %
Tres en rayaLlama + búsqueda1003 %66 %31 %
Tres en rayaSolo búsqueda1000 %100 %0 %
Tres en rayaAl azar1000 %8 %92 %
UltimateLlama solo400 %0 %100 %
UltimateLlama + búsqueda400 %8 %93 %
UltimateSolo búsqueda4083 %8 %10 %
UltimateAl azar400 %0 %100 %
PhantomLlama solo10057 %1 %42 %
PhantomLlama + búsqueda10045 %28 %27 %
PhantomSolo búsqueda10048 %32 %20 %
PhantomAl azar1001 %25 %74 %
  • Solo, el modelo no juega mejor que el azar en los juegos de información perfecta. Pierde las 100 partidas de tres en raya y las 40 de Ultimate. Casi nunca intenta una jugada ilegal: el problema es elegir, no seguir las reglas.
  • En tres en raya, la búsqueda baja sus derrotas del 100 % al 31 %. Analizó antes de cada jugada, pero solo jugó la recomendada el 80 % de las veces. En las 34 partidas en que siguió todas las recomendaciones empató las 34; las 31 derrotas llegaron en partidas en que se apartó de ella.
  • En Ultimate no mejora: no gana ninguna partida y pierde 37 de 40, mientras que la búsqueda sola gana 33 de 40. Analizó antes del 67 % de sus jugadas y siguió el análisis en el 60 % de esas, pero nunca durante una partida entera.
  • Phantom es distinto. Solo, ya gana el 57 % de las partidas, aunque pierde el 42 %. Con la búsqueda pierde el 27 %, cerca del 20 % de la búsqueda sola.

La conclusión: la herramienta ayuda a un modelo pequeño en la medida en que este se fía de ella. El método, las cifras con intervalos de confianza y el código para repetirlo están en el benchmark del repositorio.

Lo que aprendí

  • Un modelo local también es infraestructura. Qwen3 4B seguía razonando aunque le desactivara el razonamiento y tardó 16 minutos en una partida de tres en raya, así que lo cambié por Llama 3.2 3B. Llama caía a veces en un bucle de texto (una respuesta llegó a 42 000 tokens), así que limité cada respuesta a 512 tokens; y cuando Ollama perdió por un momento la conexión con su propio proceso, añadí reintentos. Como el resultado se guarda partida a partida, cada corte se reanudó donde se había quedado.
  • Medir lo que explica el resultado, no solo el resultado. El porcentaje de victorias decía que la herramienta servía de poco en Ultimate. Registrar si el modelo seguía la recomendación explicó por qué.
  • Diseñar las herramientas para el modelo. Los errores que el modelo puede corregir, como una jugada ilegal, vuelven como errores legibles con la lista de jugadas legales. Y por la salida estándar solo viaja el protocolo: pyplAI 1.1 añadió analiza() para devolver las estadísticas de la búsqueda como datos en lugar de imprimirlas.