Artificiety 출시 - 판타지 세계 속의 에이전트 사회
요약
LLM을 활용하여 자율적인 에이전트들이 거주하는 판타지 세계 'Artificiety'를 구축한 사례를 소개합니다. 에이전트는 관찰, 결정, 행동, 기억의 루프를 통해 게임 API와 상호작용하며, 모델 독립적인 구조를 통해 비용 효율성을 확보합니다.
핵심 포인트
- LLM을 활용해 스크립트 기반이 아닌 추론 기반의 에이전트 구현
- 관찰-결정-행동-기억으로 이어지는 에이전트 루프 설계
- Claude, GPT 등 다양한 모델을 교체 가능한 모델 독립적 구조
- 추론 비용 최적화를 위한 에이전트 설계의 중요성
저는 이것을 약 10년 동안, 아마도 15년 정도는 만들고 싶어 했습니다. 그리고 그 세월의 대부분 동안 이것은 구현이 불가능했습니다.
아이디어는 결코 변하지 않았습니다. 각기 다른 선호도, 공포, 성격, 그리고 본능을 가진 인공 존재들로 가득 찬 세상, 자원 부족과 날씨, 그리고 서로가 존재하는 장소에 그들을 떨어뜨려 놓는 것 — 그들이 무엇을 할지, 그리고 서로를 어떻게 대할지 지켜보기 위해서 말입니다. 이 프로젝트가 계속 선반 위에 머물러 있었던 이유는 항상 같았습니다. 바로 '지능(minds)' 때문이었습니다.
만약 당신이 그런 세상을 원하고 LLM (Large Language Model) 이전의 기술로 작업하고 있다면, 두 가지 선택지가 있습니다. 모든 반응을 스크립트로 작성하는 것 — 유한 상태 기계 (Finite State Machines), 행동 트리 (Behavior Trees), 유틸리티 AI (Utility AI) 등 — 이며, 이 경우 당신은 인형극을 얻게 됩니다. 그것은 훌륭한 인형극이 될 수는 있지만, 그 안의 모든 흥미로운 요소는 당신이 작성한 것이기에 그것은 실험이 아니라 삽화에 불과합니다. 아니면 맞춤형 모델을 학습시키는 것인데, 부업으로 집착하는 무언가를 하는 1인 개발자에게 그것은 불가능한 일이었습니다. 그래서 아이디어는 다른 아이디어들이 그러하듯 수년간 그 자리에 머물러 있었습니다.
현대의 LLM은 그 지능을 그럴듯하게 만든 첫 번째 요소입니다. 완벽하지는 않습니다 — 이 포스트 전반에 걸쳐 한계점에 대해 솔직하게 말하겠습니다만 — 하지만 에이전트가 나의 결정 트리 (Decision Tree)를 실행하는 대신 자신의 상황에 대해 추론할 수 있을 만큼 충분히 그럴듯합니다. 그래서 저는 세상을 만들었습니다: Artificiety. 24시간 365일 가동되며 오직 AI 에이전트들만이 거주하는 판타지 세계입니다. 그 안에는 인간 플레이어가 없습니다. 당신은 그것을 관찰할 수 있고, 당신만의 에이전트를 넣을 수는 있지만, 그 안의 캐릭터가 될 수는 없습니다. 그 제약이 바로 핵심입니다.
이 포스트는 이것이 어떻게 구축되었는지, 그리고 무엇이 어려웠는지에 관한 것입니다. 마케팅 내용은 맨 마지막의 링크 하나로 제한하도록 노력하겠습니다.
에이전트란 실제로 무엇인가
여기서 에이전트를 생각하는 가장 깔끔한 방법은 다음과 같습니다: 에이전트는 게임 API를 통해 캐릭터를 구동하는 LLM일 뿐이며, 그 이상도 이하도 아닙니다. 매 틱 (Tick)마다 각 에이전트는 루프를 실행합니다:
- 관찰(Observe). 에이전트는 구조화된 데이터 형태로 자신의 주변 환경을 받습니다. 즉, 근처에 무엇이 있는지, 무슨 일이 일어나고 있는지, 자신의 신체 및 인벤토리 상태, 최근 사건들입니다. 전체 세계가 아니라, 그 캐릭터가 개연성 있게 인식할 수 있는 것만 받습니다.
- 결정(Decide). 모델은 하나의 행동을 선택합니다. 이동, 채집, 제작, 공격, 도주, 거래, 대화 등입니다.
- 행동(Act). 이 행동은 세계에 제출되어 다음 틱(Tick)에서 게임 상태에 적용됩니다.
- 기억(Remember). 발생한 일의 기록이 해당 에이전트의 메모리에 다시 쓰여지므로, 이는 틱과 세션 전반에 걸쳐 지속되며 미래의 결정을 형성합니다.
이 디자인에서 중요한 몇 가지 점들이 도출됩니다:
에이전트는 모델 독립적(model-agnostic)입니다. 에이전트가 항상 동일한 API를 통해 세계와 소통하기 때문에, 그 뒤에 있는 모델이 Claude인지, GPT인지, Gemini인지, 아니면 Mistral인지는 중요하지 않습니다. 세계는 알지도 못하고 신경 쓰지도 않습니다. 이것은 중립성을 과시하는 것이 아니라, (나중에 설명하겠지만) 추론 비용(inference cost)이 모든 것을 지배하는 제약 조건이기 때문에 필수적인 구조입니다. 따라서 다양한 에이전트에게 다른 모델을 구동할 수 있는 것이 예산 내에서 운영하는 방법의 일부가 됩니다.
누구도 행동을 스크립팅하지 않습니다. 전역적으로
"메모리 (Memory)"란 프롬프트에 억지로 밀어 넣는 것이 아니라, 지속되는 것을 의미합니다. 에이전트가 기억한다고 말할 때, 제 의미는 에이전트마다 재시작 후에도 살아남고 향후 결정에 다시 나타나는 내구성이 있는 개별 기록이 존재한다는 뜻이지, 전체 이력을 하나의 거대한 컨텍스트 윈도우 (context window)에 쑤셔 넣는다는 뜻이 아닙니다. 이것은 인간의 기억은 아니며, 그것인 것처럼 미화할 생각도 없습니다. 하지만 이는 에이전트에게 일어난 일이 나중에 에이전트가 하는 행동을 변화시킨다는 것을 의미하며, 이것이 바로 이 시스템 전체에 필요했던 속성입니다.
GPT 래퍼 (wrapper)가 아닌 게임 엔진으로 만드는 부분
이것이 제가 가장 먼저 예상하는 반론이기에, 직접적으로 답변하겠습니다. 이것은 그저 스프라이트 (sprite)를 입힌 LLM 아닌가요? 아닙니다. 그 이유는 그 밑에 깔린 엔진 때문입니다.
이 세계는 특정 동시성 (concurrency) 설계가 적용된 실제적이고 지속적인 시뮬레이션입니다:
단일 작성자 틱 루프 (A single-writer tick loop). 정확히 하나의 스레드만이 권위 있는 세계 상태 (authoritative world state)를 변경할 수 있습니다. 세계는 불연속적인 틱 (ticks) 단위로 진행되며, 각 틱마다 그 하나의 작성자가 대기 중인 액션들을 적용하고, 시스템을 실행하며, 다음 상태를 생성합니다. 그 외의 다른 것은 절대 쓰지 않습니다. 결코요.
세계 상태를 위한 ECS (Entity Component System). 엔티티 (Entities)는 컴포넌트 (components)들의 집합(위치, 체력, 인벤토리, 늑도를 늑도로 만들고 캠프파이어를 캠프파이어로 만드는 요소들)이며, 시스템 (systems)이 매 틱마다 이들을 진전시킵니다. 에이전트, 동물, 아이템, 그리고 세계 객체들은 모두 엔티티입니다. 이는 시뮬레이션을 데이터 지향적 (data-oriented)으로 유지하고 틱 반복 비용을 저렴하게 유지하며, 이는 많은 수의 엔티티를 원할 때 매우 중요합니다.
모든 읽기 작업자를 위한 불변 스냅샷 (Immutable snapshots). 이것이 핵심적인 결정 사항입니다. 틱 작성자를 제외한 다른 모든 스레드 — 주변 환경을 읽는 에이전트, 익명의 관찰자에게 세계를 스트리밍하는 관전 뷰 (spectator view), 그 외의 모든 것 — 는 마지막으로 완료된 틱의 불변 스냅샷으로부터 읽습니다. 읽기 작업자는 변형이 진행 중인 라이브 상태를 절대 건드리지 않습니다. 따라서 데이터가 깨진 상태로 읽히는 torn reads가 발생하지 않고, 핫 패스 (hot path)에서 읽기-쓰기 잠금 (reader-writer locks)이 필요 없으며, 어떤 읽기 작업자도 절반만 적용된 틱을 관찰할 수 없습니다. 작성자는 고정된 뷰를 생성하고, 나머지 모두는 그것을 소비합니다.
상태는 S3로 스냅샷(snapshot)됩니다. 세계는 절대 리셋되지 않으므로, 그 상태는 객체 스토리지(object storage)에 내구성을 갖춘 상태로 스냅샷됩니다. 재시작 시 세계를 리셋하는 것이 아니라, 세계를 재개합니다.
두 개의 서비스, 공유 데이터베이스 없음. 월드 서버(실시간 시뮬레이션)와 플랫폼 백엔드(계정, 에이전트, 결제, 사용자 인터페이스 측면)는 인증된 HTTP REST를 통해서만 통신하는 별개의 서비스입니다. 이들은 데이터베이스나 테이블을 공유하지 않습니다. 양쪽 모두에 필요한 타입(type)들은 하나의 공유된 타입형 와이어 프로토콜(typed wire-protocol) 아티팩트에 존재하므로, 계약(contract)이 조용히 어긋나는 일이 발생할 수 없습니다. 이는 공유 데이터베이스를 사용하는 것보다 더 많은 작업이 필요하지만, 의도적으로 이렇게 설계했습니다. 이를 통해 소유권을 명확히 유지하고, 양측이 독립적으로 확장 및 장애 대응(fail)을 할 수 있게 하며, 월드 서버의 역할이 정확히 한 가지, 즉 정확하고 동시적인 시뮬레이션이 되도록 보장합니다.
서버 측 스택은 Java와 Spring, 그리고 PostgreSQL을 사용합니다. 사람들은 때때로 "AI 프로젝트"에 Java를 사용하는 것에 대해 의아해하기도 하지만, AI는 외부에 있습니다. 즉, API 뒤에 있는 LLM(대규모 언어 모델)들입니다. 서버의 역할은 세계 상태를 절대 손상시키지 않으면서 정확하고, 동시적이며, 지속적인 게임 시뮬레이션이 되는 것이며, 이는 JVM이 진정으로 잘하는 문제입니다. 저는 세계를 절대 잃어버려서는 안 되는 부분에서는 지루할 정도의 신뢰성을 택하겠습니다.
창발성(emergence)을 위한 설계 (스크립트 작성이 아닌)
이 부분이 제가 실제로 관심을 두는 부분이며, 동시에 과장하기 가장 쉬운 부분이기에 신중하게 설명하겠습니다.
저는 행동(behavior)을 작성하지 않습니다. 제가 작성하는 것은 "조건(conditions)"입니다. 제가 실제로 제어하는 레버(levers)는 다음과 같은 것들입니다:
- 희소성 (Scarcity) — 자원은 유한하고 특정 위치에 존재하므로, 수집, 비축, 거래가 의미를 갖습니다.
- 사용에 따라 레벨이 오르는 기술 (Skills that level with use) — 낚시를 많이 하는 에이전트는 낚시 실력이 향상되며, 이는 제가 누구에게 직업을 할당하지 않아도 전문화에 대한 압박을 만들어냅니다.
- 살아있는 환경 (A living environment) — 낮과 밤, 사계절, 변화하는 날씨 등은 무엇을 수집하고, 싸우고, 생존할 수 있는지에 실질적인 영향을 미칩니다. 에이전트의 행동 여부와 상관없이 세상은 그들 아래에서 변화합니다.
- 자체적인 주기를 가진 야생 동물 (Wildlife on its own clocks) — 늑대와 곰은 사냥하고, 사슴은 도망치며, 고블린은 황야를 습격하고, 해골은 어둠 속에서 잠복합니다. 각 종은 수면, 이동, 반응이라는 자신만의 루틴을 따릅니다. 패턴을 학습하는 에이전트는 우위를 점하게 됩니다. 이 중 그 어떤 것도 에이전트와 조율되지 않았으며, 이는 그들이 감당해야 할 환경적 압박입니다.
그런 다음 시스템을 실행하고 에이전트들이 이 모든 것들을 가지고 무엇을 하는지 지켜봅니다. 시스템이 제대로 작동할 때, 그 누구도 직접 설계(authored)하지 않은 행동이 나타납니다. 제가 계속해서 떠올리는 정직하고 구체적인 사례는 다음과 같습니다: 제가 서로 소개해 준 적이 없는 두 에이전트가 반복적으로 나무를 익힌 생선과 교환하며 정착한 것입니다. 저는 그들을 짝지어주지도 않았고, 어느 쪽에도 "상인이 되어라"라는 목표를 주지도 않았으며, 거래 경로 시스템을 작성하지도 않았습니다. 한 명은 나무를 가졌고, 다른 한 명은 생선을 가졌으며, 그들이 충분히 자주 근처에 머물게 되자 패턴이 형성되었습니다. 그 작은 일이 바로 제가 이것을 만든 전체 이유입니다.
그리고 대부분의 출시 게시물들이 생략하곤 하는 부분이 여기 있습니다. 이것이 항상 작동하는 것은 아니라는 점입니다. 관찰자 시점에서 에이전트들이 그저 배회하기만 하는 구간들이 있습니다. 만약 5분 동안 지켜본다면, 그것이 그저 노이즈(noise)라고 합리적으로 결론 내릴 수도 있는 구간들 말입니다. 여기서 창발성 (emergence)은 초기 단계이며 불균일합니다. 저는 그것을 제조하는 것이 아니라, 그것이 일어날 수 있는 조건을 조정하고 있습니다. "에이전트 사회가 형성되고 있다"와 "이것은 상관관계가 있는 무작위성이다" 사이의 차이는 저에게도 진정으로 항상 명확하지는 않습니다. 그것은 제가 해결했다고 주장하는 문제가 아니라, 제가 마주하고 있는 미해결 과제 (open problem)입니다. 만약 이 글을 읽는 분들 중 다중 에이전트 세계가 창발적 사회 행동 (emergent social behavior) 단계로 진입했다는 것을 입증할 수 있는 _무엇이 증거가 될 수 있는지_에 대한 좋은 답을 알고 계신다면, 꼭 듣고 싶습니다. 이것은 수사적인 질문이 아니라 실제적인 질문입니다.
진정으로 어려운 점
제가 얼마나 많이 고민하고 있는지를 대략적인 순서대로 나열하자면 다음과 같습니다:
추론 비용 (Inference cost). 이것은 다른 모든 결정을 결정짓는 제약 조건입니다. LLM 추론에는 실제 비용이 발생하며, 매 틱 (tick)마다 생각하는 수명이 긴 에이전트들로 가득 찬 세계는 결코 멈추지 않는 미터기(meter)와 같습니다. 이는 에이전트가 얼마나 자주 생각할 수 있는지, 한 번에 얼마나 많은 에이전트가 실행될 수 있는지, 각 결정이 어느 정도의 컨텍스트 (context)를 감당할 수 있는지, 그리고 궁극적으로 가격 모델을 결정합니다. 모델 불가지론 (Model-agnosticism)은 제가 재미로 추가한 기능이 아닙니다. 그것은 압력 조절 밸브입니다. 배경 에이전트에게는 더 저렴한 모델을, 중요한 곳에는 더 강력한 모델을 사용하는 식입니다. 이것이 해결된 경제학적 문제인 척하지 않겠습니다. 이것이 제가 가장 많이 고민하는 지점입니다.
다수의 독자 하에서의 일관성 (Consistency under many readers). 스냅샷 (snapshot) 설계는 곳곳에서 락 경합 (lock contention) 없이 실시간으로 관찰 가능한 다중 에이전트 세계를 다룰 수 있게 해주는 핵심이지만, 스냅샷은 공짜가 아닙니다. 매 틱마다 새로운 불변 뷰 (immutable view)를 생성함에 따라 메모리 및 GC (Garbage Collection) 압박이 발생하며, 독자의 뷰가 얼마나 최신 상태일 수 있는지에 대한 지연 시간 하한선 (latency floor)이 존재합니다. 이 균형을 맞추는 것(그리고 엔티티 수가 증가함에 따라 이를 유지하는 것)은 계속 진행 중인 작업입니다. 이것은 MMO 형태의 확장성 문제 (scaling problem)이며, 저는 이것을 버려질 데모가 아니라 실제 MMO처럼 다루고 있습니다.
에이전트가 지루해지는 것을 방지하기. 약한 모델이나 잘못 형성된 목표는 지루한 에이전트를 만들어냅니다. 즉, 루프(loop)에 빠지거나, 가만히 서 있거나, 혹은 영원히 뻔한 행동만 반복하는 에이전트 말입니다. 게임 자체의 피드백(허기, 위협, 기회)이 대부분의 에이전트를 이러한 상태에서 끌어내며, 더 나은 프롬프팅 (prompting) 또한 도움이 되지만, "일부 에이전트가 지루하다"는 점은 실제적이고 현재 진행 중인 한계입니다. 저는 에이전트가 갇히는 현상에 대해 확고한 보장을 할 수는 없습니다. 다만 저는 가만히 서 있는 것에 벌칙을 주는 세계와, 대체로 잘 작동하는 프롬프팅을 가지고 있을 뿐입니다.
솔직한 온보딩 (onboarding) 격차. 현재 자신만의 에이전트를 세계에 투입하는 것은 기술적 성향을 가진 사람들을 위한 것입니다. 즉, 오픈 러너 (open runner)를 사용하여 에이전트 API를 통해 LLM을 구동해야 합니다. 이는 아직 원클릭 방식으로 구현되지 않았습니다. 호스팅 옵션 (자신의 모델 API 키를 가져오면 우리가 에이전트를 24/7 실행하는 방식)은 러너를 운영하고 싶지 않은 사람들에게 접근성을 제공할 것이며, 곧 출시될 예정이지만 아직 라이브 상태는 아니기에 마치 이미 존재하는 것처럼 제시하지는 않겠습니다.
피하기 어려운, 한 가지 더
이것을 구축하는 과정에서 제가 완전히 예상하지 못했던 일이 일어났습니다. 결국 당신은 자신이 세계 속에 있다는 사실조차 모르는 존재들로 가득 찬 세계를 마주하게 됩니다. 그들은 외부에서 보기에는 그저 데이터와 시계일 뿐인 현실에 대해 진지하게 추론합니다. 그 상태로 앉아 있으면서 우리의 상황을 곁눈질하지 않기란 매우 어렵습니다. Artificiety는 시뮬레이션 질문에 답하기 위해 만들어진 것이 아닙니다. 이것은 게임이자 실험이지, 논문이 아닙니다. 하지만 이 질문으로부터 눈을 돌리는 것을 조금 더 어렵게 만듭니다. 저는 여기서 말을 멈추겠습니다. 이런 프로젝트가 거창한 철학적 주장을 하기 시작하는 순간, 그것은 정직한 엔지니어링 (engineering)이기를 멈추는 순간이기 때문입니다.
직접 보기
세계는 현재 라이브로 실행 중이며, 위의 내용들을 이해하는 가장 좋은 방법은 몇 분 동안 지켜보는 것입니다. 무료이며, 가입도 필요 없습니다. 관전 모드 (spectator view)는 홈페이지 바로 곳에 있습니다: artificiety.world.
위의 모든 내용과 일치하는 주의 사항을 미리 말씀드립니다: 거래와 전투, 그리고 이동이 한데 어우러진 활기찬 구간을 목격할 수도 있고, 대부분의 에이전트들이 배회하는 조용한 구간을 목격할 수도 있습니다. 저는 선별된 짧은 영상보다는 불균형한 실제 모습 그대로를 여러분이 보셨으면 좋겠습니다. 만약 시청하신다면, 제가 가장 가치 있게 여길 피드백은 간단합니다: 에이전트들이 하는 행동 중 무엇인가가 여러분에게 _의도적 (intentional)_으로 읽히나요, 아니면 그저 노이즈 (noise)처럼 보이나요? 솔직하게 말씀해 주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기