{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Playing Valid Chess Moves\n",
"\n",
"!!! note\n",
" To download this example as a Jupyter notebook, click [here](https://github.com/guardrails-ai/guardrails/blob/main/docs/examples/valid_chess_moves.ipynb).\n",
"\n",
"!!! warning\n",
" This example is currently under development (it cannot be used to play a full chess game yet).\n",
"\n",
"In this example, we will use Guardrails to play chess with an LLM and ensure that it makes valid moves.\n",
"\n",
"## Objective\n",
"\n",
"We want to generate a valid chess moves for a given board state."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/dtam/.pyenv/versions/3.12.3/envs/litellm/lib/python3.12/site-packages/sentence_transformers/cross_encoder/CrossEncoder.py:13: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)\n",
" from tqdm.autonotebook import tqdm, trange\n"
]
}
],
"source": [
"import guardrails as gd\n",
"from rich import print"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"! pip install chess --quiet"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 1: Create the RAIL Spec\n",
"\n",
"Ordinarily, we would create an RAIL spec in a separate file. For the purposes of this example, we will create the spec in this notebook as a string following the RAIL syntax. For more information on RAIL, see the [RAIL documentation](/docs/how_to_guides/rail). We will also show the same RAIL spec in a code-first format using a Pydantic model."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First we define a custom Validator:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"from guardrails.validators import (\n",
" Validator,\n",
" register_validator,\n",
" ValidationResult,\n",
" PassResult,\n",
" FailResult,\n",
")\n",
"\n",
"from typing import Dict, Any\n",
"\n",
"import chess\n",
"\n",
"BOARD = chess.Board()\n",
"\n",
"\n",
"@register_validator(name=\"is-valid-chess-move\", data_type=\"string\")\n",
"class IsValidChessMove(Validator):\n",
" board = BOARD\n",
"\n",
" def validate(self, value: Any, metadata: Dict) -> ValidationResult:\n",
" global BOARD\n",
" try:\n",
" # Push the move onto the board.\n",
" BOARD.push_san(value)\n",
" except Exception as e:\n",
" # If the move is invalid, raise an error.\n",
" return FailResult(\n",
" error_message=f\"Value {value} is not a valid chess move. {e}\"\n",
" )\n",
"\n",
" return PassResult()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we can define our RAIL spec either as XML:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"rail_str = \"\"\"\n",
"
\n",
"Generate a move for the chess board. Do not repeat any moves in the following state. The board is currently in the \n",
"following state:\n",
"Starting position.\n",
"\n",
"Given below is XML that describes the information to extract from this document and the tags to extract it into.\n",
"\n",
"<output>\n",
" <string description=\"A move in standard algebraic notation.\" format=\"is-valid-chess-move\" name=\"move\" \n",
"required=\"true\"></string>\n",
"</output>\n",
"\n",
"ONLY return a valid JSON object (no other text is necessary), where the key of the field in JSON is the `name` \n",
"attribute of the corresponding XML, and the value is of the type specified by the corresponding XML's tag. The JSON\n",
"MUST conform to the XML format, including any types and format requests e.g. requests for lists, objects and \n",
"specific types. Be correct and concise. If you are unsure anywhere, enter `null`.\n",
"\n",
"Here are examples of simple (XML, JSON) pairs that show the expected behavior:\n",
"- `<string name='foo' format='two-words lower-case' />` => `{'foo': 'example one'}`\n",
"- `<list name='bar'><string format='upper-case' /></list>` => `{\"bar\": ['STRING ONE', 'STRING TWO', etc.]}`\n",
"- `<object name='baz'><string name=\"foo\" format=\"capitalize two-words\" /><integer name=\"index\" format=\"1-indexed\" \n",
"/></object>` => `{'baz': {'foo': 'Some String', 'index': 1}}`\n",
"\n",
"\n",
"\n"
],
"text/plain": [
"\n",
"Generate a move for the chess board. Do not repeat any moves in the following state. The board is currently in the \n",
"following state:\n",
"Starting position.\n",
"\n",
"Given below is XML that describes the information to extract from this document and the tags to extract it into.\n",
"\n",
"\u001b[1m<\u001b[0m\u001b[1;95moutput\u001b[0m\u001b[39m>\u001b[0m\n",
"\u001b[39m