同一道谜题,两种方式

我们用第3篇中的8B LoRA(15个周期)把一道简单谜题(35个空格)解了两次。

  • 第1次:从数字1到9依次由VLM写出不能填的格子,然后填上只剩一个位置的格子。
  • 第2次:方式相同,但每填一个格子,代码就立即填上只剩一个空格的宫、行、列。

第1次:剩2个空格时停住

在16次判定中给出了38手,其中33手正确。剩下2个空格时再也找不到可以填的地方。一个不漏地答对不能填格子的判定,在16次中有9次。

答错的5手,全都是因为把能填的格子误写成了不能填。多划掉一个位置后,错误的格子就成了唯一剩下的位置。演示中没有把错误的着法放到盘面上,只是做了记录。

第2次:10次判定就完成

第2次用10次判定填满了全部35个格子。靠VLM判定填了15格,代码接着填了20格,没有填错的格子。一个不漏地答对的判定在10次中有8次,但漏掉的格子并没有改变答案。

用数字2填了两个格子之后,出现了只剩一个空格的宫、行、列,代码连续填了五个格子。在数字7和第二轮的数字3上,也各自连续填了五个格子。需要判定的事情少了,模型出错的机会也就少了。

第2次解题中填格子的顺序。金色是VLM判定,绿色是代码
第2次解题中填格子的顺序。金色是VLM判定,绿色是代码

前面的答案造就下一个答案

第1篇中的模型是从左上角开始横向填写的,不会把前面填好的答案当作下一个格子的依据。第2次解题则是在盘面上东一处西一处地填,刚刚填好的格子会成为下一个格子的依据。这和人解题的顺序是一样的。

同一道谜题中随判定次数变化的剩余空格数
同一道谜题中随判定次数变化的剩余空格数

这一步的实际代码

这是第2次解题中在VLM判定之后运行的代码。如果宫、行、列中只剩一个空格,就用缺少的数字填上。

vlm_digit_strategy.pypython · 55 行
def _missing_one(values: list[int]) -> int | None:
    present = {v for v in values if v != 0}
    miss = [d for d in range(1, 10) if d not in present]
    return miss[0] if len(miss) == 1 else None


def last_empty_unit_moves(
    board: list[list[int]],
) -> list[tuple[int, int, int, str]]:
    """박스·행·열에 빈칸이 정확히 1개면 빠진 숫자로 채움."""
    found: dict[tuple[int, int], tuple[int, str]] = {}

    def add(r: int, c: int, digit: int, reason: str) -> None:
        key = (r, c)
        if key not in found:
            found[key] = (digit, reason)
        elif found[key][0] == digit:
            prev = found[key][1]
            if reason not in prev:
                found[key] = (digit, f"{prev}+{reason}")

    for br in range(3):
        for bc in range(3):
            cells = [
                (r, c)
                for r in range(br * 3, br * 3 + 3)
                for c in range(bc * 3, bc * 3 + 3)
            ]
            empties = [(r, c) for r, c in cells if board[r][c] == 0]
            if len(empties) != 1:
                continue
            digit = _missing_one([board[r][c] for r, c in cells])
            if digit is not None:
                add(empties[0][0], empties[0][1], digit, "code_last_box")

    for r in range(9):
        empties = [(r, c) for c in range(9) if board[r][c] == 0]
        if len(empties) != 1:
            continue
        digit = _missing_one([board[r][c] for c in range(9)])
        if digit is not None:
            add(empties[0][0], empties[0][1], digit, "code_last_row")

    for c in range(9):
        empties = [(r, c) for r in range(9) if board[r][c] == 0]
        if len(empties) != 1:
            continue
        digit = _missing_one([board[r][c] for r in range(9)])
        if digit is not None:
            add(empties[0][0], empties[0][1], digit, "code_last_col")

    return [
        (r, c, digit, reason)
        for (r, c), (digit, reason) in sorted(found.items())
    ]

下一篇是“5. 帮助人的 AI”。