생성형 모델과 코딩 에이전트를 활용해 거대한 아이소메트릭 픽셀 아트 뉴욕시 지도를 만든 과정, 한계, 그리고 배운 점.
![]()
아이소메트릭 NYC
몇 달 전, 나는 Google New York 9th St 오피스 13층 발코니에 서서 로어맨해튼을 바라보고 있었다. Nano Banana와 Veo를 사용하는 비밀 프로젝트에 깊이 몰두해 있었고, 이 새로운 모델들이 창의성의 미래에 무엇을 의미하는지 골똘히 생각하고 있었다.
AI와 창의성에 관한 흔한 대화는 꽤 지루하게 느껴진다. 우리는 _카메라_와 _샘플링_에 관해 이미 수년간 이야기해 왔고, 그 모든 것의 도덕성과 경제성이라는 진창에 빠지고 싶지는 않다. 내가 정말 관심 있는 질문은 하나뿐이다.
이전에는 불가능했지만 이제 가능한 것은 무엇인가?
어릴 때 나는 비디오게임을 정말 많이 했고, 그중에서도 _SimCity 2000_이나 Rollercoaster Tycoon 같은 세계 구축 게임을 가장 좋아했다. 중년에 빠르게 다가가는 정통 밀레니얼 세대인 나는 90년대 후반 / 2000년대 초반 게임의 향수 어린 분위기에 약하다. 도시를 내려다보며, 어린 시절 기억 속의 그 스타일로 도시가 보인다면 어떨지 상상하지 않을 수 없었다.
그래서 아이디어는 이렇다. 뉴욕시의 거대한 아이소메트릭 픽셀 아트 지도를 만들겠다. 그리고 이를 최신 생성형 모델과 코딩 에이전트의 한계를 강하게 밀어붙일 구실로 삼겠다.
최선의 경우 멋진 무언가를 만들고, 최악의 경우 많은 것을 배우게 될 것이다.
📒 참고 - 지금부터 모든 AI 코딩 도구를 통틀어 “에이전트”라고 부르겠다. Claude Code, Gemini CLI, Cursor를 많이 오가며 사용했고(Opus 4.5와 Gemini 3 Pro 모두 사용), 내 기준에서는 모두 꽤 잘 작동했다.
가장 큰 결론부터 말하겠다. 이 프로젝트에서 내가 직접 작성한 코드는 거의 없다. 이 프로젝트를 시작하기에 이보다 더 좋은 시점은 없었을 것이다. Gemini 3와 Opus 4.5의 출시, 그리고 Cursor와 Claude Code의 성숙은 소프트웨어 제작 기술에 진정한 변곡점을 만들었다.
지난 몇 년간 에이전트 기반 코딩을 깊이 파고들었지만, 이 프로젝트 뒤에는 소프트웨어에 대한 내 이해를 대폭 재조정해야 했다.
하지만 코드 한 줄보다 먼저 아이디어가 있었고, 대략 이런 내용이었다.
Nano Banana를 사용해 위성 이미지로부터 타일 단위의 픽셀 아트 지도를 생성하자.
그래서 나는 이제 거의 모든 프로젝트를 시작하는 방식으로 이 프로젝트를 시작했다. Gemini에게 물어보는 것이다.
💭 잠깐 덧붙이자면, AI를 활용하는 내가 가장 좋아하는 방식 중 하나는 이전에는 불가능했던 규모로 작업을 수행하는 것이다. 나폴레옹은 “양에는 그 자체의 질이 있다”라고 말했을지도 모른다. 오디오 클립을 정밀하게 옮기는 데 적어도 10,000시간을 쓴 전자음악가 출신으로서, 나는 특히 수많은 아이디어를 실질적으로 불가능하게 만드는 고된 반복 작업을 확장하는 데 관심이 있다.
초기 전략은 여러 출처의 3D CityGML 데이터를 사용해 개별 타일의 “화이트박스” 뷰를 렌더링하는 것이었다. 몇 가지 출처(NYC 3D, 3DCityDB, NYC CityGML)를 찾아 데이터를 내려받고, Cursor가 렌더러를 만들도록 설정했다. 그러자 아주 빠르게 꽤 잘 작동하는 결과물이 나왔다.
이것이 얼마나 대단한 일인지 아무리 강조해도 부족하다. 나는 이전에 CityGML 데이터를 다뤄본 적이 없고, GIS는 악명 높을 정도로 까다롭고 복잡하다. 좌표 투영 시스템과 지오메트리 라벨링 스키마를 에이전트와 여러 번 주고받으며 수정한 끝에, 실제 도시 지오메트리를 위성 이미지 위에 겹친 아이소메트릭(직교) 렌더를 출력하는 렌더러를 상당히 빠르게 구축할 수 있었다.

도시 지오메트리와 위성 텍스처를 결합한 화이트박스 렌더
Nano Banana Pro로 계획을 시험하기 위해 빠르게 marimo 노트북을 구성했고, 여러 문제를 발견했다. 요약하면 “화이트박스” 지오메트리와 상단 시점 위성 이미지 사이에 불일치가 조금 많았고, Nano Banana는 이 차이를 해소하는 과정에서 지나치게 환각을 일으키기 쉬웠다.
그래서 Gemini과 상의하며 다시 조사했고, Google Maps 3D tiles API가 정확히 내가 필요로 한 것이었다. 정밀한 지오메트리 그리고 텍스처를 하나의 렌더러에서 제공한다. 물론 정밀한 타일의 지오메트리를 내려받고, 웹 렌더러에서 직교 카메라로 렌더링하고, 기존 화이트박스 렌더와 정확히 일치하는 타일로 내보낼 방법이 필요했다. 그리고 약간의 대화 끝에 에이전트가 그것을 만들어 주었다.

Google Maps 3D tiles의 도시 지오메트리를 결합한 아이소메트릭 웹 렌더
프롬프트를 약간 조정한 후, Nano Banana Pro가 선호하는 스타일의 타일을 꽤 안정적으로 생성하게 할 수 있었다.

Nano Banana Pro로 생성한 픽셀 아트 이미지
하지만 Nano Banana로 이미지 에셋을 생성하는 데에는 몇 가지 큰 문제가 있다.
그래서 더 작고 빠르며 저렴한 모델을 미세 조정하기로 했다. 훌륭한 oxen.ai 서비스에서 Qwen/Image-Edit 모델을 미세 조정해 보기로 했고, 약 40개의 입력/출력 쌍으로 학습 데이터셋을 만들었다. 미세 조정에는 약 4시간과 약 12달러가 들었으며, 결과에 꽤 만족했다!

Qwen/Image-Edit 미세 조정을 위한 입력/출력 쌍
Qwen/Image-Edit 모델이 선호 스타일의 타일 생성을 학습할 수 있음을 확인한 뒤, 모든 타일을 생성할 접근 방식을 계획하기 시작했다. 모든 타일은 이음새 없이 이어져야 하므로 “인필” 전략을 구현하기로 했다. 완전한 1024x1024 웹 렌더 → 생성된 픽셀 아트 타일로 단순히 가는 대신, 대상 생성 이미지의 일정 비율을 “마스킹”한 입력 이미지로 데이터셋을 만들었다. 이렇게 하면 이미 생성된 타일에 인접한 타일 콘텐츠를 생성하며 생성 순서를 “엇갈리게” 할 수 있다. 그리고 다시 한번 Qwen/Image-Edit는 이 작업을 학습할 수 있는 듯했다.

인필 쌍 이미지 / 다이어그램
직접 코드를 작성하지 않더라도 소프트웨어 엔지니어링 모범 사례를 따르는 일은 중요하다. 실제로 코드는 매우 싸고 빠르므로, 그 어느 때보다 실천하기 쉬워졌다. 이 주제만으로도 에세이가 될 만하지만, 요약하면 다음과 같다.
이를 염두에 두고, 타일 생성 과정을 돕는 엔드투엔드 생성 애플리케이션을 설계하기로 했다. 경험상 엣지 케이스는 곧바로 맞닥뜨리게 되므로(실제로 그랬다), 규모를 키우기 전 작게 시작하는 것이 좋다. 사양을 빠르게 작성하고 에이전트에게 생성을 구동할 단순한 시스템을 만들게 했다.
그러자 약간의 대화만으로 타일 데이터를 점진적으로 생성하는 작동하는 웹 애플리케이션이 생겼다.
AI 이전에 소프트웨어를 만들어 본 사람이라면 시스템의 일부를 분석하거나 디버그하기 쉽게 해 줄 도구가 필요했던 감각을 안다. 하던 일을 멈추고 뭔가를 급히 만들 준비를 하다가, 생각보다 훨씬 까다로운 문제라는 사실을 깨닫는다. 조금 더 파고들어 만드는 데 몇 시간, 며칠, 몇 주가 걸릴 것을 받아들이고 풀이 죽어 주 작업으로 돌아간다. 속으로 절대 완료되지 않을 것을 아는 할 일을 등록할지도 모른다.
AI 에이전트는 모든 것을 바꾼다. 상상할 수 있는 어떤 마이크로 도구든 몇 가지 지시만 있으면 된다. 심지어 에이전트는 격리된 작업 브랜치의 백그라운드 스레드에서 그것을 만들 수도 있다. 그리고 몇 분 안에 끝난다.
애플리케이션 전반에 걸쳐 이런 마이크로 도구를 매우 다양하게 만들었다. 즉시 떠오르는 몇 가지는 다음과 같다.

생성된 타일을 보여 주는 디버그 지도
이 도구 모음을 만들며 발견한 패턴은 다음과 같다.
CLI 도구 → 라이브러리 → 애플리케이션
CLI 도구는 에이전트가 사용하고, 테스트하고, 디버그하기 매우 쉽다. 또한 단순한 경계를 장려하고 강한 결합을 억제한다. 더 큰 시스템이나 애플리케이션에 통합할 때가 되면, 에이전트에게 기능을 공유 라이브러리로 추상화해 달라고 하는 일은 간단하다.
소프트웨어를 해 본 사람이라면 누구나 아는 감각이다. 모든 문제를 해결할 결정적 도구를 막 만들었다. 수많은 테스트 케이스를 던져도 계속 작동하고, 프로젝트의 90%를 끝냈다고 확신한다. 그러다 엣지 케이스를 만나고, 마지막 10%의 작업이 시간의 90%를 차지한다는 사실을 또다시 깨닫는다.
여기서 제대로 다룰 수 없을 만큼 엣지 케이스는 많았지만, 이후에 많은 어려움을 일으킨 두 문제, 즉 물과 나무에 집중하겠다.
뉴욕시에는 물이 정말 많다. Hudson River와 East River는 New York Harbor와 Bay로 흘러들고, Jamaica Bay와 Long Island Sound도 섬, 모래톱, 습지 같은 해양 지형이 많은 큰 수역이다.
생성해야 할 물의 양도, 그리고 더 중요하게는 미세 조정 모델이 이를 처리하기 얼마나 어려울지도 예상하지 못했다.

물과 나무는 모델에 많은 문제를 일으켰다
잠시 덧붙이면, 모델 미세 조정은 어렵다. 특히 이미지 모델에는 특정 작업을 처리하기 매우 어렵게 만드는 많은 특성이 있다. 구조와 텍스처를 분리하는 것은 고전적인 문제다.
미세 조정 이미지 모델을 재학습하기 위해 무엇을 하든, 물을 안정적으로 생성하게 할 수 없었다. 그리고 _나무_는 훨씬 나빴다. 이 모델에 거의 완벽한 병리적 사용 사례였다.
거의 모든 창의적 AI 프로젝트에는 모델이 필요한 작업을 해낼 수 없는 지점이 온다. 자신의 지능을 투입해 이런 엣지 케이스를 끈질기게 해결해야 하며, 이 시점에는 최대한 쉽고 일관되게 만드는 도구가 필수적이다. 다행히 우리는 에이전트가 상상하는 거의 모든 도구를 만들어 줄 수 있는 시대에 살고 있다.
이 작업을 쉽게 해 주기 위해 다음을 포함한 여러 마이크로 도구를 만들었다.
하지만 결국 마지막 10%는 언제나 시간의 90%를 차지하며, 늘 그렇듯 충분히 좋은 것과 훌륭한 것의 차이는 작업에 쏟는 애정의 양이다. 그래서 결국 소매를 걷어붙이고 이 엣지 케이스를 수동으로 고치는 데 많은 시간을 쏟았다.
Oxen.ai는 훌륭한 서비스다. 미세 조정과 모델 배포, 학습 데이터 관리의 번거로운 세부 사항을 자동화하고 추상화한다. 하지만 플랫폼을 통한 추론은 꽤 비싸고 느렸다. NYC 지도 _전체_를 생성하도록 과정을 확장하려면 모델을 훨씬 빠르게, 또는 더 병렬화 가능하게, 그리고 저렴하게 만들어야 했다.
그래서 Lambda AI(또 하나의 환상적인 서비스)를 사용해 Oxen의 가중치를 내가 임대한 GPU+VM으로 내보내기로 했다. 나는 모델을 학습하고 배포한 지 _오래_되었고, 범용 하드웨어에서 모델을 실행시키던 공포도 기억한다. 하지만 이 과정 역시 AI 코딩 에이전트가 마법처럼 해결하는 긴 목록에 추가할 수 있다.
H100이 장착된 VM을 부팅하고 Cursor로 ssh 접속한 뒤, 에이전트에게 웹 생성 앱에서 호출할 수 있는 추론 서버를 설정하라고 프롬프트했다. 예전에는 고통스럽고 느린 디버깅에 몇 시간이나 며칠이 걸리던 일이 이제는 말 그대로 몇 분이면 된다.
이제 n개의 모델을 병렬 실행하고 지도의 넓은 구간을 생성할 수 있었다. 매일 밤 어느 타일을 생성할지 계획하는 데 몇 분을 쓰고 모델을 밤새 실행했다. 시간당 3달러 미만, 시간당 200회 이상의 생성으로 이 프로젝트는 시간과 비용 모두에서 실현 가능해졌다.
물론 이제 재시도 로직, 병렬 모델 큐, 타일 계획 인프라를 비롯해 이 규모를 관리할 도구를 많이 만들어야 했지만, 에이전트는 다른 모든 것만큼 쉽게 이를 처리했다.
💭 다시 말하지만 AI 시대에도 소프트웨어 엔지니어링은 사라지지 않는다. 단지 추상화 사다리의 위쪽으로 이동할 뿐이다. 모든 미묘한 도메인별 로직을 포함하는 생성 큐와 로직의 동작을 여전히 명세해야 했지만, 그것을 구현하는 어떤 코드도 더는 신경 쓰지 않았다. 진심이다. 한 번도 들여다보지 않았다.
생성 규모를 확장하고 일부 엣지 케이스를 해결한 뒤, 가능한 한 많은 작업을 자동화하기 시작했다. 안타깝게도 여기서 프로젝트와 모델은 가장 크게 실패했다.
흥미롭게도 에이전트에게 효율적인 타일링 알고리즘을 구현하고 이해시키는 일은 극도로 어려웠다. 생성 규칙은 꽤 단순하다. “이음새”가 생기는 방식으로는 어떤 사분면도 생성하면 안 된다.

이음새를 피하기 위한 타일 생성 규칙 예시
하지만 제약이 단순함에도 생성 로직을 명세하고, 그 로직을 테스트하고, 상위 계획 / 최적화 알고리즘으로 유용하게 만드는 일은 매우 어려웠다. 전반적으로 여기서 많은 반복을 했고, 계획 알고리즘을 만드는 방법을 에이전트가 이해하도록 하려는 헛된 노력도 많이 들였다. 그러나 많은 시도와 반복 끝에 약간의 수동 안내만으로 충분히 잘 작동하는 결과를 얻었다.
한 가지 교훈은 일부 알고리즘은 환원 불가능하게 복잡하며, 명세 문서와 지시라는 형편없는 매체를 통해 이러한 매우 똑똑한 모델에게도 그 뒤의 핵심 로직을 이해시키는 일은 여전히 어렵다는 것이다.
앱이 지도의 넓은 구간에 대한 “계획”을 안정적으로 생성하게 되자, 대규모 생성 배치를 시작해 밤새 실행했다. 결과는 대체로 좋았지만, 모델은 여전히 여러 실패 양상을 보였다. 특히 물과 지형에서 그랬다.
완벽한 세계라면 생성 결과가 기준에 맞는지 확인할 AI 검토 과정을 추가했을 것이다. 하지만 대부분의 경우 Gemini 3 pro 같은 가장 똑똑한 이미지 모델조차 이음새나 잘못된 나무 생성 같은 실패 양상을 안정적으로 평가하지 못했다. 모델이 이런 문제를 평가할 수 있는 경우에도, 과정을 실현 불가능하게 만들지 않는 규모와 속도로 안정적으로 배포할 방법은 없었다.
그래서 결국 지도 전체의 생성을 수동 검토, 표시, 보정하는 노력을 들여야 한다는 것을 받아들였다. 정말 많은 작업이 들었지만(프로젝트에 쓸 계획이었던 것보다 훨씬 많았다), 이를 쉽게 만드는 맞춤형 마이크로 도구를 구축하는 AI 에이전트의 능력은 매우 귀중했다.
타일 생성 과정이 원활하게 돌아가자, 생성된 타일을 모든 줌 수준에서 표시할 최종 애플리케이션을 만들고 싶었다. 단순할 것 같았지만, 코딩 에이전트가 처리하기 가장 어려운 작업 중 하나가 되었다.
운 좋게도 나는 Google Brain에서 첫해에 맞춤형 타일 기반 기가픽셀 이미지 뷰어를 만들었기에, 이 문제 영역의 과제를 잘 안다. 오픈 소스 OpenSeaDragon 라이브러리를 사용하기로 했지만, 수없이 발생한 줌/좌표 공간 및 캐싱/성능 문제에는 내 전문성에 의존해야 했다. 특히 이런 종류의 앱은 오늘날 세대의 코딩 에이전트에 매우 병리적인 과제처럼 보인다. 많은 수동 터치 상호작용이 있는 고성능 그래픽은 어떤 브라우저 제어 도구로도 잘 처리되지 않는다.
하지만 상당한 디버깅 끝에 앱을 실행하고 배포할 수 있었다.
이 프로젝트의 가장 큰 즐거움은 생각의 속도로 도구를 만들 수 있다는 점이었다. 소프트웨어 개발자로서 나는 갖고 싶은 작은 도구를 백만 가지쯤 생각하지만, 만들려면 하루나 일주일이 걸린다. Claude나 Cursor가 있으면 5분 만에 만들 수 있다. 이는 절대적으로 혁신적이다. 무한한 도구 상자를 가진 것과 같다.
물론 소프트웨어 엔지니어링 규칙은 여전히 적용된다. 엔트로피가 모든 것이다. 기능을 추가하면 복잡성은 커지고, 아키텍처가 없으면 기술 부채가 쌓인다. 하지만 디버거, 시각화 도구, 스크립트 실행기 같은 일회용 도구에서는 코드 품질이 실제로는 그다지 중요하지 않다.
내 생성 앱 코드가 얼마나 형편없는지 안다. 직접이라면 절대 작성하지 않을 명령형 JavaScript와 뒤얽힌 이벤트 리스너의 난장판이다. 하지만 고객에게 나가는 제품이 아니다. 확장될 필요도 없다. 사용자는 나뿐이고, 비용이 아주 적었던 것을 고려하면 버그도 감수할 만하다. 싸고 빠르다는 사실이 그리 훌륭하지 않다는 사실을 충분히 상쇄한다.
일반적으로 조합 가능성은 매우 중요하며, 바이브 코딩 맥락에서는 더 큰 가치를 가진다. 한 가지를 잘하는 작고 모듈식 프로그램이라는 Unix 철학은 작은 도구를 상위 애플리케이션에서 재사용할 수 있는 유틸리티 함수로 쉽게 조합하게 해 준다. 기능 조각을 모듈식으로 설계하면 코딩 에이전트를 가장 효과적으로 활용할 수 있다. 단순한 동작은 명세하기 쉽고, 에이전트도 이 모듈식 조각을 만들고 디버그하고 테스트하기 쉬우며, 나중에 이를 더 높은 수준의 앱으로 엮기도 쉽다. 이는 표준적인 소프트웨어 엔지니어링 모범 사례이며, 코드 비용이 0에 가까워지는 지금 더 관련성이 크다.
이 프로젝트는 텍스트/코드 생성과 이미지 생성 사이의 거대한 격차도 보여 주었다.
에이전트에게 소프트웨어를 작성하라고 하면, 코드를 실행하고, 스택 트레이스를 읽고, 오류를 보고, 스스로 수정할 수 있다. 긴밀한 피드백 루프가 있다. 구축 중인 시스템을 이해한다.
이미지 모델은 아직 그렇지 않다. 인간 아티스트를 관리한다면 “이 나무는 이 특정 스타일로 만들어야 해”라고 말할 수 있고, 아티스트는 실행할 것이다. 모델도 할 수는 있지만 안정적으로 하지는 못한다. Gemini 3 Pro처럼 똑똑한 모델조차 출력물을 보고 “여기에 이음새가 있다” 또는 “이 나무 텍스처는 잘못됐다”라고 안정적으로 말하지 못한다. 실패 양상을 안정적으로 “볼” 수 없으므로 QA 과정을 자동화할 수 없었다. 모델이 스스로의 실수를 이해할 수 없었기에 완전 자동 생성을 포기해야 했다.
미세 조정은 여전히 그 어느 때처럼 불안정하다. 모델을 학습해 본 사람은 이것들이 외계의 지능이라는 것을 깊이 이해한다. 모델은 종종 매우 반직관적인 방식으로 무언가를 배우며, 많은 경우 당면 과제를 해내도록 안정적으로 학습시키려면 ML 이론에 대한 깊은 이해와 모델 구현에 대한 강한 직관이 필요하다.
여기에는 근본적으로 잘못된 무언가가 있다. 사람은 대조 학습(실수로부터 배우기)과 연속 학습(진행하며 배우기)을 충분히 할 수 있지만, 대부분의 AI 에이전트는 연관을 통해서만 학습되고 완전히 무상태다. 다만 이 분야에서 진전이 있을 것이라고 낙관하며, 그러려면 모델 아키텍처와 학습 체계의 근본적 변화가 필요할 것이다.
이런 실패 양상은 이미지 모델에서 특히 뚜렷하다. pdf 추출 작업의 결과를 읽고 평가하는 데는 1분이 걸릴 수 있지만, 생성 이미지의 잘못된 세부 사항은 수 밀리초 만에 볼 수 있다.
마지막으로, 생성형 모델의 인터페이스는 텍스트에 비해 매우 허술하다.
코드에서는 특정 줄을 가리킬 수 있다. 모든 것이 텍스트이므로 프롬프트는 자기 참조적일 수 있다. 이미지에서는 “이미지 C를 보고 저 나무를 복사해”라고 안정적으로 말할 수 없다. 모델은 “저 나무”라는 개념이 없다. 가리킬 수도 없고 텍스트로 안정적으로 참조할 수도 없다. “이미지 C”가 어느 이미지를 말하는지조차 모를 수 있다.
더 나쁜 점은 이미지를 제대로 편집할 수도 없다는 것이다. 코딩 에이전트에게 버그를 고치라고 하면 파일을 수정한다. 이미지 모델에게 나무를 고치라고 하면 확산을 통해 전체 이미지를 처음부터 다시 꿈꿔 내야 한다. 토큰 안으로 들어가 변수 하나만 조정할 안정적인 방법은 없다.
퓨샷 프롬프팅 같은 기본적인 지시 기법을 사용할 방법도 없고, 편집을 위해 이미지에 주석을 달 방법도 없다. 마스킹도 없고 투명도도 없다. 생성형 이미지 모델의 진화에서는 아직 너무 이른 단계다. 이미 많은 일을 할 수 있지만, 갈 길은 멀다.
고역의 종말
나는 전자음악가로 10년을 보내며 화면 위의 작은 상자를 끌어다 놓는 데 말 그대로 수천 시간을 썼다. 창작 작업의 상당 부분은 이런 지루한 노동으로 정의된다.
예를 들어 여러 파트의 보컬 하모니를 녹음한 뒤 믹스에서 무언가를 바꾸면, 한 구절이 15밀리초 어긋난 것처럼 느껴질 수 있다. 이를 고치려면 모든 레이어를 조정해야 한다. 재료에 플러그인이나 다른 처리를 사용 중이라면 더 복잡해진다.
이것은 창작이 아니다. 그냥 고된 일이다. 애니메이션, 비디오, 소프트웨어 등 모든 창작 분야에는 이런 지루한 작업이 가득하다. 물론 이 수작업 자체가 직관을 정교하게 만든다는 주장은 가능하다. 하지만 나는 그것이 무엇보다 “그저 그러하다”는 이야기라고 생각한다. 결국 예술의 품질은 결정의 품질로 정의된다. 무언가에 들인 작업량은 얼마나 신경 쓰는지, 얼마나 할 말이 많은지를 나타내는 대리 지표일 뿐이다.
규모의 해방
이 프로젝트는 완벽과 거리가 멀지만, 생성형 모델 없이는 존재할 수 없었다. 혼자서 이만큼의 작업을 해낼 방법은 없으며, 뉴욕시의 모든 건물을 손으로 픽셀 아트로 그릴 만큼 큰 아티스트 팀을 고용하는 것도 불가능했을 것이다.
AI 에이전트는 이전에는 상상할 수 없었던 창의적 프로젝트의 우주를 연다.
슬롭과 예술
버튼을 누르고 콘텐츠를 얻을 수 있다면, 그 콘텐츠는 상품이다. 가치는 거의 0이다.
직관에 반하지만, 그것이 내가 AI와 창의성에 대해 낙관하는 가장 큰 이유다. 어려운 부분이 쉬워지면, 차별점은 애정이 된다.
북동부 지역에 찾아온 거친 겨울을 기념하기 위해 지도에 “레이어”를 추가하면 재미있겠다고 생각했다. 지도 전체를 다시 손으로 생성하는 고역을 겪을 생각은 전혀 없었기에, 첫 번째 지도 버전에서 배운 모든 교훈을 바탕으로 과정을 최대한 자동화하기 시작했다. 물론 핵심 프로젝트 인프라를 지루하게 리팩터링해야 했지만, 핵심적으로 해결해야 할 몇 가지 막힌 문제가 있었다.
대규모 생성의 가장 큰 문제는 생성 결과 간 불일치가 지도 전체의 드리프트로 이어진다는 점이다. “인필” 모델은 이를 처리하기 매우 어렵다. 서로 다른 색상/스타일을 지닌 인접 사분면 사이에서 “혼합”하도록 모델을 명시적으로 학습시키지 않으면, 모델은 대조적인 두 스타일 중 하나를 선택하게 되고 장면이 만들어진다.
해결책은 꽤 단순했다. 모델 학습에 사용되는 모든 타일의 색상을 생성 _전_에 정규화하고, 생성 후 “앵커” 타일의 색상도 정규화하는 것이다. 전자는 단순하지만 후자는 조금 더 미묘하다. 생성된 2x2 사분면 타일의 색상을 적절히 균형 잡으려면 _물_은 무시해야 한다. 물의 색상 때문이다.

생성 일관성을 보장하기 위한 디버그 도구
타일 생성에서 가장 일관되게 발생하는 문제 중 하나는 _물_이다. 이미지 편집 모델은 위성 렌더의 “입자 같은” 텍스처이든 이미 스타일화된 타일의 평평하고 단순한 색상이든, 물을 “이해”하지 못한다. 내 대략적인 설명은 편집 과정을 입력 정보에 노이즈를 추가한 뒤 디노이징하는 것으로 볼 수 있기 때문에, 모델 관점에서 평평한 색상은 순수 노이즈와 구별하기 어렵고 따라서 순수한 물 타일에 무작위 정보를 환각하는 경향이 있다는 것이다.
이를 해결하기 위한 전략은 두 갈래였다. 먼저 1부에서 사용한 물 마스크 시스템을 가져와 두 가지 일을 하게 했다. 학습 데이터에서는 모든 물에 2x2 체커보드 격자 패턴을 증강했다. 이 구조화된 정보는 모델이 물이 무엇인지, 순수한 색상으로 채워져야 한다는 것을 학습하기에 충분했다. 또한 물 마스크로 물이 포함된 타일을 감지하고, 그 타일의 물 색상을 자동으로 “보정”했다. 생성 결과는 생성 간에 미묘한 색상 드리프트가 발생하는 경향이 있었기 때문이다.
지형 생성 문제는 순수한 데이터 증강으로 해결했다. 비례적으로 더 많은 물 + 지형을 포함한 데이터셋으로 모델을 학습시키면 이런 특성을 관리하는 방법을 배울 수 있었다. 이 과정은 과학이라기보다 예술에 가까웠다. 여러 다른 특성 균형으로 여러 변형을 학습했고, 생성이 끝난 뒤에도 약간의 수동 보정이 필요했다.

왼쪽: 체커보드 패턴은 모델이 물 생성법을 학습하게 했다 | 오른쪽: 모델은 순수한 물 타일에서 무작위 사물을 환각한다
지도 v1을 생성하는 가장 큰 병목 중 하나는 GPU 추론 처리량이었다. 다행히 첫 번째 지도를 완성할 무렵 놀라운 modal.com 서비스를 발견했다. 나는 유료 홍보자가 아니라고 맹세하지만, 이 플랫폼은 아무리 말해도 부족하다. 한번 사용해 보면 서버리스 GPU 추론이라는 개념이 명백히 미래라는 것을 알게 된다. modal을 사용해 미세 조정한 Qwen/Image-Edit 모델의 병렬 인스턴스 50개를 쉽게 띄우고, 몇 시간 만에 아주 적은 비용으로 수만 개 타일을 생성할 수 있었다. 덕분에 훨씬 빠르게 실험할 수 있었고, 사실상 지도 전체를 한 번에 생성할 수 있었다. 마지막에는 여전히 몇 시간의 수동 정리가 필요했지만, 생성 결과를 확인하는 자동화를 조금 더 추가하면 지도 생성 전 과정을 사실상 엔드투엔드로 자동화하는 것도 가능하다.

자동 생성 계획과 진행 중인 생성 추적의 나란히 비교
물론 눈 덮인 지도에 _눈_이 없다면 무슨 의미가 있겠는가? 프로젝트의 다른 모든 것과 마찬가지로, 몇 분 만에 설정을 조절할 완전한 디버그 도구까지 갖춘 눈 셰이더를 아주 쉽게 만들 수 있었다. 아무리 반복해도 부족하지만, 무언가를 만드는 사람이 되기에 이보다 좋은 때는 정말 없었다. 상상할 수 있는 모든 도구를 필요할 때 만들 수 있다. 나는 다른 글에서 이것이 소프트웨어 산업혁명의 시작이라고 주장했으며, 이는 소프트웨어의 본질을 근본적으로 바꾸고 있다.
이를 보여 주는 구체적 일화가 하나 있다. 엔드투엔드 생성 스크립트를 만들다가, 코딩 에이전트가 더 수동적인 생성 앱을 위해 이미 구축했던 모든 타일링 로직(이음새 확인, 최적 패킹 계획 생성 등)을 _다시 구현했다_는 것을 발견했다. 이는 코딩 에이전트의 흔한 함정이다. 문자 그대로 자신이 만든 것을 기억하지 못하며, 상당한 관리 없이는 종종 엉뚱한 방향으로 갈 수 있다. 하지만 문제없다. 에이전트에게 타일링 로직을 별도의 공유 라이브러리로 리팩터링하게 하고, 더 나아가 모든 경우를 포괄하고 내가 정확히 원하는 대로 작동하는지 엄격히 테스트하면 된다. 물론 에이전트는 기꺼이 그 작업을 수행했다. 하지만 라이브러리가 의도대로 작동하는지 어떻게 검증할 수 있을까? 에이전트는 포괄적인 단위 테스트 모음을 작성했지만, 이제 ASCII 독스트링 다이어그램으로 기능을 설명하려는 수천 줄의 python 단위 테스트를 봐야 했다. 시스템을 이해하는 최선의 방식은 아니었다!
그래서 내가 계속 반복해서 하게 된 일을 했다. _마이크로 도구_를 만들었다. 에이전트에게 모든 테스트에 기능을 추가해, 테스트 모음이 실행될 때 테스트되는 상황과 테스트 결과를 정확히 보여 주는 이미지를 생성하게 했다. 실제 데이터를 사용해 이미 생성된 타일, 선택된 타일, 생성형 모델로 전송될 이미지 템플릿 또는 오류 상태를 설명했다. 그런 다음 이 아티팩트를 정적 디버그 html 페이지에 호스팅했고, 코드를 한 줄씩 읽는 것보다 극적으로 나은 방식으로 의도된 동작을 한눈에 빠르게 검증할 수 있었다.

타일링 로직 테스트 모음이 생성한 검증 이미지 한 쌍
다른 사람들도 이와 같은 패턴을 발견하고 있다. 새 기능의 gif를 자동으로 만들거나 풀 리퀘스트의 비디오 개요를 만드는 일까지, 우리는 소프트웨어 구축 방법의 새 패턴과 소프트웨어 자체가 무엇인지에 관한 새 패턴을 발견하고 있다. 우리는 아직 이 새로운 현실을 제대로 내면화하지조차 못했다고 생각한다. 문자 그대로 우리의 전체 소프트웨어 엔지니어링 도구 상자는 사람들로 이루어진 팀이 코드를 손으로 작성하고, 디버그하고, 검토한다는 핵심 전제 위에 설계되어 있으며, 그런 세계는 이제 더는 존재하지 않는다. 나는 컴퓨팅 자체가 무엇인지에 관한 혁명의 한가운데에 있다고 믿으며, 이 모델과 시스템이 계속 빠르게 발전함에 따라 컴퓨팅이라는 생각을 근본적으로 다시 생각해야 한다는 것을 깨닫게 될 것이다. 기대에 맞춰 야망의 규모를 키워라. 이제부터는 모든 것이 더 빠르게 움직일 뿐이다!