4.3 Prompt Engineering - был basic, стал advansic

Чекер для судоку. 🔢 

Мы хотим научить модель решать Судоку и применить для этого  метод Tree of Thoughts. Для этого нам необходимо написать класс-проверщик (Checker), который будет проверять в правильном направлении модель строит рассуждения или нет.

Для начала посмотрим на промпт для судоку 4 х 4:

sudoku_puzzle = "3,*,*,2|1,*,3,*|*,1,*,3|4,*,*,1"
sudoku_solution = "3,4,1,2|1,2,3,4|2,1,4,3|4,3,2,1"
problem_description = f"""
{sudoku_puzzle}
- Это головоломка Судоку размером 4x4.
- Символ * обозначает ячейку, которую тебе нужно заполнить.
- Символ | разделяет строки.
- На каждом шаге замени одну или несколько * цифрами от 1 до 4.
- Напиши текущее состояние пазла с добавленными цифрами
- Ни в одной строке, столбце или 2x2 подсетке не должно быть одинаковых цифр.
- Сохраняй полученные цифры из предыдущих успешных мыслей на своих местах.
- Каждая мысль может быть промежуточным или окончательным решением.
""".strip()
print(problem_description)

Как можно понять из промпта, мы хотим, чтобы на каждом шаге заменялась одна или несколько звездочек . Но при этом модели нужно понимать в верную ли сторону произошла замена. Может быть предыдущий шаг был неверный, и стоит вернуться с этой ветки размышлений на шаг назад и попробовать заменить другой пропуск или заменить пропуск на другое число. На помощь придут ToTChecker и ThoughtValidity.

Немного пояснений:

Нам нужно взять поледнее рассуждение (мысль), они хранятся в переменной thoughts.

Далее мы проверим соответствует ли предложенная мысль верному ответу. Т.е. если мысль равна переменной sudoku_solution, значит мы нашли верное решение.  В таком случае чекер должен вернуть ThoughtValidity.VALID_FINAL.

Если наше решение не содержит ошибок, но при этом в нем есть незаполненные клетки, мы вернем ThoughtValidity.VALID_INTERMEDIATE. Проверим, является ли наше решение частичным с помощью регулярных выражений.

Символы "*" и "|" являются специальными.  "*" нам нужно будет заменить на специальный символ в регулярных выражениях, обозначающий любой одиночный символ, а "|" должен восприниматься в регулярном выражении не как специальный символ, а как элемент в нашей строке. Т.е. если мы оставили клетки незаполненными, при этом все значения в заполненных нами клетках совпадают с правильным решением, то наше решение будет матчится регуляркой с правильным решением.

Если в какой-то клетке содержится неверная цифра - мы возвращаем ThoughtValidity.INVALID. Мы можем считать, что решение неверное, если оно не является верным или частичным решением.

 

Ноутбук с тестами для проверки работы чекера ссылка.

Выберете одну или несколько верных реализаций нашего класса.

A.

class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        if eval(thoughts) == 10:
            return ThoughtValidity.VALID_FINAL
        elif eval(thoughts) in [9,8,7,6]:
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALID

B.

import re
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        last_thought = thoughts[-1]
        clean_solution = last_thought.replace(" ", "").replace('"', "")
        regex_solution = clean_solution.replace("*", ".").replace("|", "\\|")
        if sudoku_solution in clean_solution:
            return ThoughtValidity.VALID_FINAL
        elif re.search(regex_solution, sudoku_solution):
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALID

C.

import re
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        solution = thoughts[-1].replace(" ", "").replace('"', "")
        if sudoku_solution in solution:
            return ThoughtValidity.VALID_FINAL
        elif re.search(solution, sudoku_solution):
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALID

 

D.

import re
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        last_thought = thoughts[-1]
        clean_solution = last_thought.replace(" ", "").replace('"', "")
        regex_solution = clean_solution.replace("*", ".")
        if sudoku_solution in clean_solution:
            return ThoughtValidity.VALID_FINAL
        elif re.search(regex_solution, sudoku_solution):
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALID

Нет обсуждений. Начните первое.