Как я написал шахматы с LLM на Python без галлюцинаций нейросетей. ai.. ai. API.. ai. API. chess.. ai. API. chess. llm.. ai. API. chess. llm. python.

Введение

Я работаю с LLM довольно давно и застал модели времен GPT-3.5, примерно в то же время мне нужно было сделать проект по учебе в этой области, тогда я выбрал именно тему шахмат, потому-что не видел конкретно таких решений раньше, конечно ИИ в онлайн шахматах и так был практически непобедим, но мысль сыграть конкретно с нейросетью уровня Chat GPT, мне показалась интересной. Основная проблема – заставить чат бот играть в игру и не делать ничего лишнего.

В этой статье я разберу архитектуру своего проекта: шахмат на Python, где в качестве соперника выступает LLM:

  1. Как объяснить текстовой нейросети, что происходит на доске 8х8.

  2. Как заставить ее делать валидные ходы и не ломать игру.

  3. Как собрать такую систему бесплатно, используя OpenRouter.

Проблема первая: бюджет

Обычно для таких экспериментов все берут OpenAI, но гонять запросы на каждый шахматный ход в их моделях для такого проекта – это сложно и дорого. Моей целью было сделать проект с нулевым бюджетом.

Поэтому я выбрал OpenRouter. Это агрегатор нейросетей, у которого есть доступ к ряду мощных опенсорсных моделей абсолютно бесплатно (хоть и с ограничением по количеству запросов) – у них есть тег :free.

Вот как выглядит инициализация клиента в моем проекте:

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

Интерфейс библиотеки openai позволяет легко переопределить base_url, поэтому мы бесшовно подключаемся к бесплатной Llama 4 через OpenRouter, не меняя привычный код.

Проблема вторая: LLM не видит доску. Как передать контекст?

Если просто написать промпт «Ты играешь черными, твой ход такой то / такой то», модель огорчится вами и сойдет с ума. Ей нужен контекст. В шахматах есть два стандарта записи:

  • FEN (Forsyth-Edwards Notation) — слепок текущего состояния доски.

  • PGN (Portable Game Notation) — история ходов.

Чтобы минимизировать галлюцинации, я передаю в модель и FEN, и PGN, а главное — строгий список легальных ходов. Для управления логикой игры я использую библиотеку python-chess.

Вот блок кода, который собирает весь этот контекст перед отправкой запроса:

# получаем текущую позицию в FEN формате
        fen = board.fen()
        
        # получаем историю ходов в PGN формате
        pgn_moves = []
        temp_board = chess.Board()
        
        # история ходов
        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 "Начальная позиция"
        
        # получаем список легальных ходов
        legal_moves = [move.uci() for move in board.legal_moves]
        legal_moves_str = ", ".join(legal_moves)

Собрав эти данные, формируется жесткий системный промпт. Моя задача была отучить модель болтать и заставить её вернуть ровно 4 символа (например, e2e4):

prompt = f"""Ты играешь в шахматы как {'белые' if board.turn == chess.WHITE else 'черные'}.

Текущая позиция (FEN): {fen}
История ходов: {pgn_history}
Ход номер: {self.move_count}

Доступные ходы в UCI формате: {legal_moves_str}
Выбери ЛУЧШИЙ ход из доступных и верни ТОЛЬКО UCI код хода (например: e2e4, g1f3, e7e8q).
Не добавляй никаких объяснений, анализа или дополнительного текста.
Ответ должен содержать только UCI код хода."""

Третья проблема: Паттерн «AI-Рефери» и Fallback

Даже с указанием «выбери из списка легальных ходов», Llama (или любая другая модель) может выдать галлюцинацию, предложить невозможный ход или вернуть текст с рассуждениями. Если передать это напрямую в графический движок (pygame), приложение упадет с ошибкой.

Нужен слой валидации. В моем коде за это отвечает блок try/except внутри логики UI. Если LLM возвращает недопустимый ход (не проходит проверку python-chess), срабатывает Fallback-механизм – скрипт делает случайный валидный ход, чтобы игра не прерывалась.

if move_uci:
            try:
                move = chess.Move.from_uci(move_uci)
                if move in self.board.legal_moves:
                    # анимация перед выполнением хода
                    self.animate_move(move)
                    self.board.push(move)
                    self.move_history.append(move.uci())
                    self.last_ai_response = f"LLM сделал ход: {move.uci()}"
                    print(self.last_ai_response)
                else:
                    # Fallback к случайному ходу
                    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 ошибся, случайный ход: {move.uci()}"
                    print(self.last_ai_response)
            except ValueError:
                # Fallback к случайному ходу
                move = random.choice(list(self.board.legal_moves))

В консоли этот процесс выглядит так:

Запрос к LLM для хода #1...
LLM ответил: 'e7e5'
LLM сделал ход: e7e5
Запрос к LLM для хода #2...
LLM ответил: 'Хорошо, я думаю лучший ход это d7d5'
LLM дал некорректный ответ, случайный ход: a7a6

Архитектура проекта

Схема взаимодействия компонентов

Схема взаимодействия компонентов

Выводы

  • Бесплатный ИИ существует (хоть и с условностями): OpenRouter и опенсорсные модели отлично справляются с подобными проектами, позволяя не тратить деньги на API.

  • Контекст решает всё: Чем больше жестких рамок вы зададите в промпте (FEN + PGN + список легальных ходов), тем адекватнее будет ответ.

  • Защищайте свой код: Паттерн «Рефери», когда классический детерминированный код (в данном случае python-chess) стоит между LLM и состоянием приложения, – это база для построения надежных AI-систем.

P.S. Не знаю принято тут так писать или нет, но, Спасибо за внимание.

Автор: bonel1to

Источник

  • Запись добавлена: 28.03.2026 в 11:16
  • Оставлено в
Rambler's Top100