오래된 3D 조각품을 떠올려 보자. 겉모양을 본뜬 데이터는 남았는데, "어떻게 깎아 만들었는지"를 담은 설계도는 사라졌다. CADFather는 그 사라진 설계도를 되살리는 자율 에이전트다.
일하는 방식이 남다르다. CADFather는 직접 조각칼을 들지 않고, 한 명의 감독처럼 성격이 다른 전문 도구들을 번갈아 불러 작업을 지휘한다. 중간 결과를 눈으로 확인하며 어느 도구를 부를지, 언제 끝낼지를 판단한다. 다만 결과가 쓸 만한지 재고 가장 좋은 것을 지키는 일은 감독이 아니라 별도의 채점 컴포넌트가 맡는다. 여러 도구와 여러 후보를 조율하되, 유효성 판정과 채점만은 떼어 놓은 것이다.
메시(물체 표면을 삼각형 조각으로 촘촘히 덮어 모양만 기록한 데이터)는 "이 물체가 어떻게 생겼나"는 알려주지만 "어떻게 만들었나"는 알려주지 않는다.
JPEG 사진에 빗대면 쉽다. 완성된 사진 한 장만 남고 그걸 만든 포토샵 레이어는 날아간 상태다. 레이어가 없으니 눈, 코, 배경을 따로 수정할 수 없다. 조금만 고치려 해도 처음부터 새로 그려야 한다. 메시도 똑같다. 설계 이력이 사라진 스캔 데이터, 오래된 레거시 모델 — 겉모양은 멀쩡한데 구멍 지름 하나, 벽 두께 하나를 바꾸려 해도 손댈 "레이어"가 없다.
편집 가능한 CAD 프로그램(숫자 값을 바꾸면 모양이 따라 바뀌는 설계 프로그램)으로 복원한다는 건 이 사라진 레이어를 되살리는 일이다. 구멍 지름이나 벽 두께를 숫자 하나로 꺼내 놓아, 그 값만 바꾸면 모양이 따라 바뀌게 만든다. 복원물이 쓸모 있으려면 세 가지를 만족해야 한다. 실제로 빌드(실행)되고, 속이 꽉 차고 빈틈없이 닫힌(solid) 입체로 구조가 일관되며, 나중에 편집할 수 있어야 한다.
문제는 이걸 한 도구로는 못 푼다는 데 있다. 부품 모양도 제각각, 복원 단계도 제각각이라 모든 상황에 똑같이 잘 듣는 단일 도구가 없다. 그래서 지금 이 순간 필요한 수가 "연산 하나 더 붙이기"인지, "치수만 다듬기"인지, "앞 단계로 되돌아가기"인지를 그때그때 가려 줄 지휘자가 필요하다. CADFather의 출발점이 여기다.
감독 역할은 비전-언어 어시스턴트(그림과 글을 함께 이해하는 AI)가 맡는다. 목표 모양과 지금까지의 복원물을 그림으로 받아 보고 결정한다 — 어느 후보를 키울지, 어떤 도구를 부를지, 제안을 몇 개나 받을지, 아니면 이제 끝낼지.
감독이 부리는 전문가는 세 종류다. 하나씩 보자.
1) 학습 기반 제안. 사전학습된 연산 생성기(CADENA-RL)가 지금 프로그램에 이어 붙일 "다음 연산" 후보를 한 번에 여러 개 내놓는다. 이 생성기는 CAD 모델링에 맞춰 어휘와 문법을 좁힌 전용 언어(DSL)로 설계도를 쓴다 — 범용 언어가 아니라 "CAD 작업만을 위한 좁은 언어"인 셈이다. 여기서 "여러 개"는 한 후보에 연산을 여러 개 쌓는다는 뜻이 아니라, 서로 다른 대안을 몇 개 내놓는다는 뜻이다. 그럴듯한 연산을 잘 제안하지만, 특징 하나를 통째로 빠뜨리거나 치수가 틀릴 수 있다. 몇 개를 받을지는 감독이 정하되, 남은 예산 안에서만 가능하다.
2) 알고리즘 기반 제안(CADFit 계열). 학습 모델 없이, 목표 메시의 모양에 도형을 직접 맞춰 연산을 만든다. 시작점이 비어 있으면 목표만 보고 첫 연산을 제안한다 — 회전체면 단면을 축 중심으로 돌리고(revolve·회전), 아니면 밀어 올리는(extrude·돌출) 연산을 찾는다. 이미 후보가 있으면 목표와 비교해 빠진 부분은 돌출로 채우고 남는 부분은 잘라낸다(cut). 모양에서 직접 끌어내니 단단하지만, 그것만으로 전체를 설명하진 못한다. 이 도구가 가장 빛나는 순간은 생성기가 내놓는 첫 연산이 자꾸 "닫히지 않은 표면"이라 더 쌓아 올릴 바닥이 없을 때다. 단면을 한 번 돌출시키면 적어도 딛고 설 solid가 생긴다.
3) 파라미터 최적화. 연산 구조는 그대로 두고 숫자만 바꾼다. 스케치 좌표·반지름·돌출 깊이 같은 값을 조금씩 움직여, 복원물 표면과 목표 메시 사이의 부호 있는 거리(안쪽·바깥쪽까지 가려 재는 거리) 오차가 가장 작아지는 지점을 찾는다. 어느 쪽으로 값을 밀어야 오차가 줄어드는지는, 값을 조금씩 흔들어 보고 그 변화를 비교하는 방식(유한차분)으로 가늠한다. 먼저 거칠게 맞추고 그다음 표면 근처에서 세밀하게 맞춘다. 틀이 맞을 때 치수를 정교하게 메우지만, 틀 자체가 틀렸으면 고치지 못한다. "안 바꾸는 게 가장 낫다"는 결론이 나오면 원래 숫자가 그대로 살아남기도 한다.
이 셋을 묶는 장치가 후보 풀이다. 복원 과정의 중간 산출물(후보)을 하나하나 기록해 두는 보관함이라고 보면 된다. 후보를 발전시킬 때 기존 기록을 덮어쓰지 않고 자식 후보를 새로 만든다. 그래서 감독은 최신 후보에만 매이지 않고, 앞선 유효 후보로 되돌아가거나 빈 상태에서 전혀 다른 첫 수를 다시 둘 수 있다. 한 길만 파는 대신 여러 갈래를 동시에 살려 두는 구조다. 다만 감독이 보는 건 풀 전체가 아니라 상위 후보 몇 개와 지금까지의 최선, 그리고 시작점뿐이다. 보는 정보를 좁고 일정하게 유지하는 것이다.
한 장면을 보자. 체인 링크 하나를 복원하는 중, 가장 좋은 후보는 판과 기둥을 하나씩만 가졌는데 목표는 둘씩이다. 감독은 이 후보를 학습 제안과 알고리즘 제안으로 동시에 이어 가고, 학습 제안이 두 번째 기둥을 붙인 새 후보를 만들어 낸다. 한 번의 결정이 부품 전체를 보고 이뤄지며, 한 단계에서 여러 후보에 동시에 손댈 수 있다는 점이 여기서 드러난다.
이 구조에서 눈여겨볼 지점이 하나 더 있다. 감독이 내는 건 "제안"일 뿐이라는 것이다. 별도의 실행 컴포넌트가 프로그램을 실제로 돌려 유효한지 검증하고 점수를 매긴 뒤, 감독이 그림을 보고 풀에 받아들일지 정한다. 더 중요한 건 이 실행 컴포넌트가 감독의 그때그때 선택과 무관하게 "보호된 최선"(지금까지 나온 후보 중 점수가 가장 높은 것)을 따로 지킨다는 점이다. 감독이 엉뚱한 갈래로 새더라도, 최종 산출물은 감독이 마지막에 만지던 후보가 아니라 이 보호된 최선이다.
기존 연구들이 모양을 보고 한 번에 정답을 뽑거나 한 길만 깊게 팠다면, CADFather는 여러 가능성을 동시에 탐색하며 목표 모양에 맞는 도구를 스스로 고른다는 점에서 차별화된다.
성능 결과를 보기 전에 먼저 짚어야 할 점이 있다. 이 글이 근거로 삼은 자료는 방법 설명까지이고, 특정 데이터셋에서 몇 점을 받았다는 성능·비용 수치는 그 범위 밖이다. 그래서 "어느 데이터셋에서 이겼다"는 숫자는 여기서 단정하지 않는다. 대신 평가를 어떻게 설계했는지만 봐도 이 시스템의 성격이 꽤 많이 드러난다.
평가는 여섯 개 데이터셋(DeepCAD·Fusion360·MCB의 전체 테스트셋과 CADENA-Bench·CADBench·BenchCAD)에서 이뤄진다. 재는 축은 복원 품질, 실행 유효성, 그리고 계산 비용 대비 품질이다.
품질은 두 각도에서 본다. 하나는 IoU로, 두 모양의 부피가 얼마나 겹치는지를 잰다. 다른 하나는 GMS로, 표면의 각 지점이 얼마나 비슷한 방향을 보고 있는지 — 곧 표면이 향한 쪽(법선)이 얼마나 일치하는지를 잰다. 둘 다 0~1로 맞춰 높을수록 좋다. 한 후보의 최종 점수는 쓸 수 있는 지표의 평균이다 — IoU와 GMS의 평균, 또는 IoU를 쓸 수 없는 목표라면 GMS 단독이다(IoU는 목표가 빈틈없이 닫힌 단일 입체일 때만 계산된다).
유효성 기준이 꽤 엄격하다. 프로그램이 빌드되지 않거나, 결과물이 "전체로서" 빈틈없이 닫힌 입체가 아니면 무효다. 시간 제한을 넘겨도 무효다. 비교 대상인 CADENA보다 빡빡한데, CADENA는 조각난 결과 중 한 조각만 닫혀 있어도 점수를 주지만 CADFather는 전체가 하나의 닫힌 입체여야 한다. 조각 하나로 통과시키지 않겠다는 뜻이고, "실제로 쓸 수 있는 모델"에 한 발 더 가깝다.
크기까지 맞혀야 한다. 점수를 매기기 전 목표와 후보를 같은 좌표계에 놓는데, 후보마다 제 크기에 맞춰 늘리고 줄이는 게 아니라 모두 같은 고정 변환을 쓴다. 그래서 크기가 틀린 후보는 "정규화 덕에 봐주는" 일 없이 점수가 깎인다.
여기서 한 가지 성격을 짚어야 공정하다. 최종 산출물인 "보호된 최선"은 위 점수(IoU·GMS 평균)로 고른다. 이건 여러 후보를 만들어 그중 점수가 가장 좋은 하나를 고르는 방식(흔히 best-of-N이라 부른다)이다. 치팅은 아니다 — 고를 때 정답(목표 메시) 바깥의 정보를 전혀 쓰지 않으니까. 하지만 "한 번에 최선을 뽑았다"가 아니라 "여러 번 시도해 그중 최선을 골랐다"는 성격은, 그 "여러 번"에 든 비용과 함께 읽어야 한다. 몇 번까지 시도하느냐가 품질을 좌우하기 때문이다. 평가가 비용 대비 품질을 따로 분석하는 이유가 여기 있다.
그런데 이 모든 점수는 모양이 얼마나 닮았는지를 잴 뿐, 복원물이 편집하기 좋은지는 재지 못한다. 노출된 숫자가 실제로 의미 있게 조절되는지, 연산 조합이 사람 눈에 합리적인지는 모양 점수와 다른 질문이다. 애초에 이 과제를 가치 있게 만든 건 "편집 가능성"이었는데, 채점은 그 축을 직접 보지 않는다. 그래서 "점수가 높다"는 말과 "쓰기 좋게 복원됐다"는 말 사이에는, 아직 평가가 메우지 못한 틈이 있다.
완벽히 복원 못 하는 부품이 있음을 전제한다. 작업을 끝내는 이유는 둘이다. 모든 특징을 재현하고 미세한 수치 차이만 남은 경우('shape'), 그리고 아직 틀린 특징이 있지만 최근 단계들이 더는 개선하지 못하고 달리 시도할 것도 없는 경우('stalled')다. stalled를 실패가 아니라 정상 종료로 둔 건 정직한 설계지만, 뒤집으면 구조적으로 손 못 대는 부품을 인정한다는 뜻이기도 하다.
다룰 수 있는 연산이 제한된다. 숫자를 다듬는 파라미터 최적화는 돌출·구멍(hole)·회전만 지원한다. 그 밖의 연산이 든 프로그램은 다듬지 못한다. 게다가 전체가 앞서 본 CADENA의 전용 언어(DSL)에 묶여 있어, 그 언어로 표현할 수 없는 구조는 애초에 후보가 되기 어렵다.
바닥 성능을 외부 모델에 맡긴다. 추가 학습을 안 한다는 건 장점이지만, 동시에 전체 성능이 끌어다 쓰는 사전학습 모델(연산 생성기와 비전-언어 어시스턴트)의 한계에 그대로 묶인다는 뜻이다. 지휘가 아무리 영리해도, 부릴 수 있는 전문가의 실력 이상은 나오지 않는다.
이 설계를 관통하는 원리는 하나다. 무엇을 할지 판단하는 쪽과, 그 결과를 검증·채점해 최선을 지키는 쪽을 갈라놓는 것. 끝내는 시점은 감독이 정하지만, 실제로 돌려 보고 점수를 매겨 "보호된 최선"을 지키는 일은 별도 컴포넌트에 맡긴다. 그래서 최종 산출물은 감독이 멈춘 그 후보가 아니라 채점이 가려낸 최선이다.
이 원칙은 3D 모델링에만 국한되지 않는다. 기술 미디어 온틀도 AI 에이전트를 만들며 비슷한 교훈을 얻었다. 온틀의 AI PM이 고객에게 "완료했습니다"라고 회신했는데 실제로는 빠뜨린 게 있던 '가짜 완료'를 겪고, 온틀은 PM의 말이 아니라 서버가 직접 실행하고 서버가 판정하도록 방향을 틀었다. 판정 권한을 행위자에게서 떼어 낸 것이다. 물론 CADFather의 "점수"는 모양이 목표에 얼마나 닮았는지를 재는 기하학적 척도일 뿐, 온틀의 "업무 완료" 판정과는 종류가 다르다. 또 CADFather에서 끝내는 결정은 여전히 감독의 몫이라, 온틀처럼 "완료" 판정 자체를 행위자에게서 뗀 것도 아니다 — 실제로 특징이 빠졌는데도 감독이 그 차이를 사소한 수치 오차로 오판해 멈춘 사례가 보고돼 있다. 그래도 옮겨올 수 있는 건 특정 지표가 아니라, 행위자의 선언을 최종 답으로 믿지 않고 유효성 검증·채점·최선 보존을 따로 둔다는 구조다.
여기서 자율 에이전트를 만드는 사람이 더 가져갈 만한 것을 추리면 이렇다.
점수는 복원물이 목표와 얼마나 닮았는지를 숫자 하나로 압축한다. 그러다 보니 "판이 통째로 하나 빠졌다" 같은 구조적 누락은 숫자만으로 잡아내기 어렵다. 사람이 "저기 기둥 하나가 없네" 하고 알아채는 일을 숫자가 대신하기는 어려운 것이다. 그래서 감독은 점수뿐 아니라 목표와 후보를 렌더링한 그림을 함께 본다.
이 방법은 "타깃 부품(part)"을 단위로 복원을 설명한다. 한 번의 결정 단계가 부품 전체를 보고 이뤄지고, 끝내기 역시 가지 하나가 아니라 부품 전체를 종료한다. 다부품 조립체 전체를 어떻게 다루는지는 이 글이 근거로 삼은 범위 밖이라 단정하지 않는다.
그렇다. 저장소가 공개돼 있다 — https://github.com/kulibinai/CADFather.