
0.8B, 2B, 9B 규모의 언어 모델로 체스를 두는 추론 에이전트를 훈련했다. 에이전트는 보드 상태를 추적하는 도구를 호출해 상대적으로 적은 매개변수로도 좋은 성능을 내도록 설계됐다.
데모 코드는 GitHub에서 확인할 수 있다. 프로젝트 설명에 따르면, 이 접근법은 모델이 보드 상태를 직접 추적하는 대신 도구에 맡기고 수를 어떻게 탐색할지 추론하도록 한다.
Deepseek R1 논문에 관한 글이 나온 뒤 검증 가능한 보상 기반 강화학습(RLVR)에 관심을 갖게 됐다. 해당 논문은 ‘생각’ 토큰을 사용해 언어 모델이 수학 문제처럼 검증 가능한 과제를 풀 수 있음을 보였다. 또 말이 되지 않는 사고 과정을 생성하지 않도록 지도 학습 예시로 추론 과정을 먼저 보완할 필요가 있다고 설명했다.
체스는 검증 가능한 보상을 적용하기 좋은 과제로 제시된다. 게임의 결과뿐 아니라 개별 수의 강도, 그 수를 정당화하는 개별 주장도 검증할 수 있기 때문이다. 기존 체스 엔진 연구의 주된 목표가 경기력 극대화였다면, 나는 최선의 수만 찾기보다 설명 가능하고 직관적인 수를 우선하는 엔진을 지향한다. 체스 엔진의 역사와 정성적 분석에 관한 글은 여기와 여기에서 볼 수 있다.
처음에는 도구를 쓰지 않는 순수 언어 모델을 훈련하려 했지만, RTX 4090으로 다룰 수 있는 기반 모델은 약 30억 매개변수까지였다. 작은 모델에서는 실제로 없는 위협에 반응하거나 불법 수를 두는 등 현실의 보드 상태와 맞지 않는 오류가 나타났다. 보드 상태를 별도로 추적하는 도구를 허용하면 이런 유형의 오류를 없앨 수 있다.
도구는 언어 모델이 포지션에 대한 판단을 도구에 맡기지 않고, 보드 상태를 확인하며 탐색 방법을 정하도록 설계했다. 각 도구는 사람이 체스판을 따라가며 이해할 수 있는 단순하고 원자적인 작업을 수행한다.
| 도구 호출 | 설명 |
|---|---|
piece_on(square) | 특정 칸에 있는 기물을 확인한다. |
pieces() | 양쪽 기물의 종류와 위치를 모두 확인한다. |
material() | 양쪽의 기물 가치를 폰 단위로 계산한다. |
attackers(square) | 특정 칸을 공격하는 기물을 확인한다. 해당 칸에 기물이 있으면 공격자와 수비자를 구분한다. |
targets(square) | 특정 칸의 기물이 공격하는 상대 기물과 수비하는 아군 기물을 확인한다. |
hanging(color) | 지정한 색의 기물 중 잡힐 위험이 있는 기물을 확인한다. |
pins(color) | 지정한 색의 킹을 상대로 한 핀을 확인한다. |
forcing_moves() | 현재 포지션에서 가능한 합법적인 체크·잡기·프로모션 수를 확인한다. |
legal_moves() | 현재 포지션의 모든 합법적인 수와 둘 차례인 쪽이 체크 상태인지 확인한다. |
try(move) | 한 수를 두어 한 수 더 깊이 평가한다. |
undo() | 탐색을 되돌리기 위해 직전 수를 취소한다. |
quiet_moves() | forcing_moves()에 포함되지 않는 합법적인 수를 확인한다. |
root() | 탐색 스택을 모두 되돌려 시작 포지션으로 돌아간다. |
threats() | 상대 차례라고 가정했을 때 가능한 메이트·체크·기물 이득을 동반하는 잡기를 확인한다. |
exchange(square) | 특정 칸에서 가장 좋은 첫 잡기부터 시작하는 연속 잡기의 결과를 계산한다. |
언어 모델은 도구를 호출할 때마다 호출 이유도 함께 제시해야 한다. 이렇게 하면 추론 과정이 이유 없이 도구 호출만 나열하는 형태로 흐르는 것을 막을 수 있다.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요