第一次看到的解法
我在[关于](/zh/about/)页面中写到的场景,就是这个模型。解数独的AI从第一个格子开始,横向一个接一个地填入答案。就像一个早已知道答案的小孩子。
用答案表做的训练数据
第一批训练数据是用dataset_sudoku.py制作的。引擎同时生成谜题和答案,把在盘面最前面的空格(从左上角开始按横向顺序)写入正确数字作为一道题保存下来。填上那个格子后再移到下一个空格,反复进行直到盘面填满。
从简单、普通、困难共300局中得到了13,497道题,用LoRA在Qwen3-VL-2B-Instruct上进行了训练(lora_stoku)。
提示词中也加入了可走着法的列表。但正确答案总是第一个空格。即使(0,3)里5和9都能填,只要答案表上是9,9就是正确答案。至于为什么是9,数据中哪里都没有。

那一刻是能解出的格子吗
我们仅凭当时的盘面,重新检查了13,497道题的正确答案格子。
- 候选数字只有一个的格子:9,502个(70%)
- 在行、列、宫内该数字只有一个位置可填的格子:2,127个(16%)
- 两种方法都无法确定、必须依靠答案表的格子:1,868个(14%)
必须依靠答案表的格子,在困难中约占21%,在普通中约占12%,在简单中约占5%。如果是人,会跳过这样的格子,先填确定的格子。而模型学会的是在同样的位置写下答案表上的数字。

这一步的实际代码
这是生成第一批训练数据的函数。empties[0]是从左上角开始数的第一个空格,值取自engine.solution。
dataset_sudoku.py
def generate_game_samples(
engine: SudokuEngine,
difficulty: str,
game_id: int,
image_dir: Path,
) -> list[dict]:
engine.new_game(difficulty)
board = [row[:] for row in engine.puzzle]
given_mask = [[engine.is_given(r, c) for c in range(9)] for r in range(9)]
samples: list[dict] = []
step = 0
while True:
empties = [(r, c) for r in range(9) for c in range(9) if board[r][c] == 0]
if not empties:
break
r, c = empties[0]
value = engine.solution[r][c]
img = board_to_image(board, given_mask)
img_name = f"g{game_id:05d}_s{step:02d}.png"
img_path = image_dir / img_name
img.save(img_path)
answer = json.dumps({"row": r, "col": c, "value": value}, ensure_ascii=False)
prompt = build_sudoku_prompt(board, given_mask)
samples.append(
{
"id": f"g{game_id:05d}_s{step:02d}",
"image_path": str(img_path.resolve()),
"prompt": prompt,
"answer": answer,
"difficulty": difficulty,
}
)
board[r][c] = value
step += 1
return samples下一篇是“2. 靠试错学不会”。
COMMENTS · CHAPTER 01
像知道答案的孩子一样解题的AI 评论 0
还没有评论。阅读时有疑问或想补充的内容,欢迎留言。
发表评论前,请用 Google 开始并登记昵称和邮箱。
用 Google 开始