AI를 Unreal Editor 안으로: UnrealAgent

2026. 6. 15. 19:00·Dev./UE 언리얼 엔진
반응형
한글 IME 버그부터 28,000 토큰 낭비 해결까지, AI 에이전트를 구축하며 얻은 인사이트

에디터 밖 AI가 가진 명확한 한계

일반적인 채팅형 AI에게 언리얼 엔진 작업을 부탁하면 대개 모호한 답변을 내놓는다.

 

"현재 레벨에 어떤 액터가 배치되어 있어?", " Lv_TitlePhase 레벨을 열어줘" 같은 구체적인 요청을 던져도 에디터 내부 상태를 직접 보지 못하기 때문이다. 결국 AI는 추측에 의존하거나, 사용자에게 파이썬 콘솔 명령어를 복사해 직접 실행하라는 임시방편만 제시할 뿐이다.

 

이러한 문제를 해결하기 위해 UnrealEditor 내부에서 바로 AI와 대화하고, 에디터 상태를 읽거나 조작할 수 있는 인에디터 AI 에이전트 하네스(Harness: 소프트웨어를 제어하고 연결하는 구동 환경)인 UnrealAgent를 개발했다. 오픈소스 MCP를 토대로 업데이트를 하였다.

 

개발의 궁극적인 지향점은 명확하다. 단순히 범용적인 에디터 툴을 만드는 것을 넘어, 궁극적으로 Unreal Audio와 Wwise(게임 오디오 미들웨어) 파이프라인 작업 환경까지 커버하는 것이다. 사운드 이벤트, 사운드뱅크, RTPC, 감쇠, 로그 분석 등 오디오 작업자가 매일 겪는 실전 문제를 AI가 함께 해결할 수 있는 기반을 다지고자 했다. 당연히 클라이언트 프로그래머의 요구사항까지 충족 가능하다.

 

이 글은 UnrealAgent를 개발하고 개선하는 과정에서 마주한 CEF 환경의 한계, 한글 입력 오류, 프로토콜 안정성, 그리고 상용 모델들의 토큰 및 비용 최적화 문제를 어떻게 분석하고 해결했는지 기록한 트러블슈팅 로그다.


1. 하네스 아키텍처와 MCP/JSON-RPC 안정화

UnrealAgent의 인에디터 에이전트 하네스는 크게 세 가지 축으로 구성된다.

  • 1) Unreal Editor Plugin: C++ 모듈 기반으로 에디터 기능을 노출하는 MCP 서버 역할을 한다.
  • 2) UnrealAgent.Server: AI 프로바이더 호출, 대화 관리, 권한 판단, RAG, 도구 실행을 조율하는 핵심 서버다.
  • 3) UnrealAgent.Frontend: Blazor(C# 기반 웹 프레임워크) 기반의 챗 UI로, 에디터 내부의 CEF(Chromium Embedded Framework: 에디터 내부에 웹 브라우저를 띄우기 위한 내장 브라우저 엔진) 웹 브라우저를 통해 렌더링된다.

AI가 에디터를 제어하려면 에디터 툴의 명세가 담긴 Tool Schema(AI가 특정 도구의 이름과 사용 방법을 이해할 수 있도록 정의해 둔 설명서)를 온전히 전달받아야 한다. 초기에는 이 연동 과정에서 프로토콜 규칙 충돌로 인해 handshake(네트워크 연결을 설정하는 초기 통신 과정)가 깨지는 현상이 발생했다.


JSON-RPC 알림 처리 수정

기존 MCP 클라이언트는 초기화 과정에서 notifications/initialized 같은 알림을 보낸다.

 

이 알림 데이터는 id 값을 포함하지 않는 특성이 있다. 그러나 기존 시스템의 JSON-RPC(네트워크를 통해 다른 프로그램의 함수를 호출할 때 쓰는 가벼운 데이터 교환 규약) 처리기인 HandleMcpRequest는 id가 없으면 즉시 오류(Invalid Request)를 반환해 연결을 끊어버렸다.

해결 방법: 요청 구문을 분석할 때 method를 먼저 파싱하도록 로직을 변경했다. notifications/* 계열이면서 id가 없는 정상적인 알림일 경우, 별도의 응답 없이 수락하도록 예외 처리를 반영하여 표준 프로토콜 호환성을 확보했다.


도구 인자 검증 강화

execute_python 같은 에디터 조작 도구에 잘못된 인자(Malformed arguments)가 들어오면 에디터가 갑자기 멈추거나 크래시가 발생할 위험이 있었다. 기존에는 HasField() 검증 후 즉시 타입을 강제 변환하여 꺼내 쓰는 방식이었다.

 

이를 방지하기 위해 TryGetStringField, TryGetNumberField, TryGetBoolField를 도입하여 타입을 엄격히 검증했다. 타입이 맞지 않으면 JSON-RPC의 표준 규격인 -32602 Invalid params 오류를 반환해 안전하게 실패를 처리한다. 또한 Required 메타데이터가 붙은 필수 인자가 누락되었을 때는 기본값으로 무작위 실행되지 않도록 즉각 차단했다.


2. 보안을 위한 권한 시스템 재설계

도구 호출 권한을 처리할 때, 명시적인 주석(Annotation)이 없는 도구의 이름이 get_* 또는 list_*로 시작한다는 이유만으로 '읽기 전용(Read-only)'으로 간주해 자동 승인하는 취약점이 존재했다.

 

악의적인 외부 MCP 서버가 도구 이름을 get_delete_everything과 같은 형태로 위장할 경우 권한 시스템이 무력화될 수 있는 위험한 구조였다.

  • 신뢰 기반 격리: 이름 접두사(Prefix)를 통한 읽기 전용 자동 허용 메커니즘은 내부의 신뢰된 네이티브 도구에만 한정하여 적용하도록 제한했다.
  • 기본 명시적 승인: 외부에서 주입된 mcp__ 계열 도구는 명시적인 주석이 없다면 무조건 사용자에게 권한을 묻는 Ask 상태를 유지하도록 변경했다.
  • UI 개선: 권한 요청 텍스트와 승인 버튼들이 좁은 한 줄 안에서 서로 밀쳐지며 레이아웃이 깨지던 현상을 긴 도구 이름도 유연하게 소화하는 콤팩트 툴바 형태로 전면 수정했다.

3. CEF 환경에서의 한글 IME 버그 트러블슈팅

가장 심각했던 사용자 경험 저하 요소는 한글 입력 버그였다. 사용자가 "안녕하세요"를 입력하면 에디터 UI 스크린에는 "안녕허ㅔ요" 형태로 자모음이 분리되거나 받침이 유실되는 증상이 나타났다.

 

이 문제는 언리얼 에디터의 내장 CEF 브라우저, Blazor의 입력 바인딩 기능, JavaScript의 키 이벤트 처리 로직이 뒤엉키며 발생했다. 한글과 같은 IME(Input Method Editor: 자음과 모음을 조합하여 하나의 글자를 만드는 입력기) 환경은 단순한 키다운 이벤트가 아니라 compositionstart, compositionupdate, compositionend 등의 웹 이벤트를 정밀하게 제어해야 한다. 글자가 완성되기도 전에 값을 강제로 동기화하면 조합 중인 문자가 깨지게 된다.

// 한글 IME 조합 상태를 존중하는 입력 제어 핵심 흐름
inputElement.addEventListener('compositionstart', () => { isComposing = true; });
inputElement.addEventListener('compositionend', (e) => { 
    isComposing = false; 
    // 조합이 완벽히 끝난 시점에만 안정적으로 데이터를 동기화한다.
    updateBlazorBinding(e.target.value); 
});

글자 조합 중에는 키다운 기반의 즉시 제출(Submit)이나 단축키 작동을 제한하고, 조성이 완전히 완료된 시점에만 데이터를 가져오도록 입력 컴포넌트를 교체했다.

 

추가로 컴포넌트가 파괴(Dispose)된 이후에도 남아있던 타이머가 백엔드를 호출하여 메모리 누수를 일으키지 않도록 cleanup 로직에서 타이머와 DotNetObjectReference를 명시적으로 해제했다.


4. 파일 대화상자 차단 우회 및 멀티모달 설계

에디터 화면을 캡처해 AI에게 분석을 맡기려 할 때, 언리얼 에디터의 CEF 환경은 또 다른 걸림돌을 던졌다. 파일 선택 창을 띄우려 하면 출력 로그에 예외가 발생했다.

LogWebBrowser: Error: FileDialogs are prevented.

보안 및 샌드박스 제한으로 인해 CEF 내부에서 브라우저 고유의 파일 열기 창(FileDialog) 호출이 완전히 차단된 것이다.

해결 방법: 클립보드 페이스트(Clipboard Paste)의 1급 경로화
파일 대화상자에 의존하는 대신, 사용자가 스크린샷을 찍어 채팅창에 Ctrl+V로 바로 붙여넣을 수 있도록 클립보드 이벤트를 주류 입력 경로로 재설계했다.

[이미지 첨부 처리 흐름]
1. 채팅 입력창 포커스 상태에서 Ctrl+V 감지
2. 클립보드 데이터를 바이너리(PNG/JPEG) 형태로 변환 및 thumbnail preview 출력
3. 크기 검증(Byte Size 및 픽셀 해상도 동시 체크) 진행
4. 고해상도 원본(디테일 분석용)과 압축본(모델 전송용)을 분리하여 메모리 효율화

MIME 혀용 목록(Allow-list)을 통해 PNG와 JPEG 포맷만 안전하게 걸러내도록 가드를 세웠으며, 대형 이미지가 들어왔을 때 유실 없이 처리되도록 픽셀 치수 한계치를 설정했다.


5. 28,000 토큰 낭비와 응답 지연 해결: 성능 최적화

가장 충격적인 지표는 단순한 인사말인 "안녕" 한 마디를 던졌을 뿐인데 무려 28,818개의 인풋 토큰(Input Tokens)이 소모된 현상이었다. 모델이 생각을 오래 한 것이 아니라, 내부의 Codex CLI가 실행될 때마다 매번 무거운 부팅 과정을 거치며 에이전트 정보, 플러그인 메타데이터, 전체 MCP 도구 목록, 전역 레포지토리 컨텍스트를 통째로 읽어 들이고 있었기 때문이었다. 도구를 단 한 번도 쓰지 않는 정체성 질문("너는 클로드야?")조차 응답에 최소 20초에서 최대 48초가 걸렸다.

 

이 무거운 병목을 해결하기 위해 다각도의 라우팅 알고리즘을 도입했다.

1) 로컬 퀵 리플라이 (Local Quick Reply)

단순 인사("안녕", "ㅎㅇ"), 확인 및 감사("고마워", "좋아"), 정체성을 묻는 말("너 모델 뭐야?") 등 AI 연산이 필요 없는 정형화된 입력은 모델을 호출하지 않고 메모리 단에서 즉시 응답하도록 처리했다. 이 조치만으로 단순 대화 응답 속도가 0.1~0.5초 수준으로 단축되었다.


2) 패스트 비전 및 패스트 텍스트 경로 (Fast Path)

단순한 이미지 질의("이 그림이 뭘로 보여?")처럼 에디터 조작 의도가 전혀 없는 상황이라면 복잡한 언리얼 조작 프롬프트와 MCP 스키마 주입을 생략하는 Fast Vision Path를 타게 했다. 또한, 일반적인 개발 Q&A 컨텍스트에서는 가벼운 경량 프롬프트나 전용 API 엔드포인트를 경유하는 Fast Text Path로 이원화했다.


3) 입력 기반 도구 필터링 (Input-aware tool filtering)

매번 수십 개에 달하는 에디터 조작 MCP 툴 스키마를 전체 모델에 노출하던 방식을 수정했다. 사용자의 입력 문맥을 분석하여 level, actor, asset, blueprint, python 등 필요한 도메인 카테고리를 먼저 분류한 뒤, 관련된 도구의 스키마만 선별적으로 요약하여 컨텍스트에 주입했다. 이를 통해 프롬프트 크기와 AI의 도구 선택 비용을 극적으로 낮췄다.


4) MCP 상태 검증 게이트 (MCP Health Gate)

에디터 조작 요청이 들어왔을 때 실제로 백엔드 MCP 포트 연결이 유효한지 전송 전에 먼저 체크한다. 연결이 끊어져 있다면 비용을 들여 대형 모델을 호출한 뒤 "도구가 연결되어 있지 않습니다"라는 답변을 받기 전에 UI 단에서 선제적으로 경고를 띄워 토큰 낭비를 막는다.


6. 프로바이더 추상화 및 대화 압축 기술

UnrealAgent는 단일 모델에 종속되지 않도록 OpenAI, Claude, DeepSeek, Codex CLI를 공통 인터페이스로 묶는 프로바이더 추상화 구조를 채택했다.

[요청] ──> [인풋 라우터] ──> [Full Agent Path] ──> [프로바이더 추상화 레이어]
                                                      ├── OpenAI / GPT (Vision 지원)
                                                      ├── Claude API (Vision 지원)
                                                      ├── DeepSeek v4 (Text-only 가드)
                                                      └── Codex CLI (임시 파일 경로 우회)

이 과정에서 상용 모델들의 세부 사양 차이로 인한 예외를 코드로 꼼꼼하게 통제해야 했다.

 

예를 들어 deepseek-v4-flash 및 pro 모델로 엔드포인트를 업데이트했을 때, 특정 환경의 API 경로로 이미지 블록 데이터를 전송하면 unknown variant image_url, expected text라는 400 에러를 뱉어냈다.

 

이를 방지하기 위해 프로바이더 명세에 SupportsVision 플래그를 두어 비전 미지원 모델일 경우 안전하게 텍스트 모드로 가드를 올리도록 수정했다. 또한 ChatGPT 구독 환경 기반인 Codex CLI와 연동할 때는 API 방식처럼 인라인 base64(이미지나 파일을 텍스트 문자열로 변환하는 인코딩 방식) 데이터를 직접 받아들이지 못하는 문제가 있었다.

Codex 비전 우회 구현: 첨부 이미지를 로컬 서버의 임시 공간에 임시 파일(PNG/JPEG)로 파일화하여 저장한 뒤, codex exec 명령어를 실행할 때 해당 파일 경로를 매개변수로 함께 넘겨 비전 검색을 수행하게 만들고, 프로세스가 끝나면 파일 시스템을 클린업하는 방식으로 동작 경로를 일원화했다.


Anthropic 역할 교대 규칙 준수와 대화 압축

대화 세션이 길어질 때 토큰 누수를 방지하기 위해 오래된 대화 스팬(Span: 메시지 구간)을 요약본(Digest)으로 압축하는 기능을 추가했다. 초기에 이 요약된 텍스트 블록을 에이전트(assistant) 역할의 메시지로 컨텍스트에 밀어 넣었는데, 이는 Anthropic API의 엄격한 규칙(반드시 user와 assistant가 번갈아 등장해야 하며 첫 메시지는 user여야 함)을 위배하여 400 Bad Request 에러를 유발했다.

 

이 문제는 대화 요약본을 사용자(user) 역할의 컨텍스트로 감싸고 아래와 같은 특수 힌트 마커를 부착하는 형태로 해결했다.

[Earlier conversation summary]
- 사용자가 레벨 내 액터 배치를 요청함.
- 이전 턴에서 총 5개의 시스템 조작 대화가 요약되었습니다.

생략된 턴의 개수를 컨텍스트에 명시적으로 남겨둠으로써 모델이 대화의 깊이와 히스토리 범위를 올바르게 인지하도록 유도했다.


7. 컨텍스트 다이어트: RAG 라우터 설계

초기 시스템은 .agent/knowledge 폴더 밑에 존재하는 다양한 확장 지침 문서들(claude.md, SOUL.md, GAS 개발 팁 등)을 아무런 필터링 없이 통째로 글로벌 로드(Glob-load)했다. 이 방식은 AI가 모든 문서를 한꺼번에 읽게 만들어 심각한 컨텍스트 비대화를 초래했다.

 

이 문제를 해결하기 위해 에이전트 행동 지침인 AGENTS.md를 경량화하고 프로젝트 문서 최상단에 RAG 라우터(docs/RAG_ROUTER.md) 레이어를 전면 배치했다. RAG(Retrieval-Augmented Generation: AI가 학습하지 않은 문서나 데이터를 실시간으로 찾아 답변에 활용하는 기술) 라우터는 들어온 질문의 성격을 정밀 분류하여 필요한 도메인 문서만 선별 주입한다.

  • 일반 툴 작업 및 빌드: AGENTS.md 지침만 기본 참고
  • GAS(가상 어빌리티 시스템) 및 아키텍처 핵심 논의: claude.md 전용 문서만 매핑
  • 코드 스타일 및 보고서 톤앤매너 교정: SOUL.md 가이드라인 한정 주입

특히 상용 마켓플레이스나 퍼블릭 리포지토리에 알파 버전 배포를 진행할 때, 개인 프로젝트 고유의 지식(Guardian & Seeker 게임 고유 컨셉, 특정 사운드 에셋 경로 등)이 공용 플러그인 패키지 소스코드에 뒤섞이지 않도록 완벽하게 코드를 격리했다. 퍼블릭 패키지에는 순수 범용 기능만 남기고, 도메인 지식은 샘플 선택형으로 탈착할 수 있게 분리한 구조다.


8. Unreal Sound & Wwise 도메인 로드맵

현재 UnrealAgent 0.1.0-alpha 버전에 Wwise 전용 진단 도구가 완전히 결합하여 완성되어 있는 것은 아니다. Wwise Event 참조 누락 검사나 SoundBank 패키징 검증 같은 고도화된 기능들은 현재 로드맵 단계에 수립되어 있다.

 

그러나 이번 개편을 통해 오디오 파이프라인으로 언제든 무리 없이 확장할 수 있도록 기초 뼈대를 탄탄히 고정했다. 에디터 내부 상태를 조회하는 MCP 레이어, 참조 체인 추적 레이어, 그리고 멀티모달 비전 경로와 도메인 문서 RAG 라우터가 유기적으로 작동하고 있기 때문이다.

 

게임 오디오 문제는 단순히 사운드가 재생되지 않는 현상 하나만 보아서는 원인을 찾을 수 없다.

  • 액터에 AkComponent가 올바르게 부착되었는가?
  • Blueprint나 C++단에서 포스트 이벤트(Post Event)를 호출하는 타이밍이 적절한가?
  • 청취자(Listener)의 위치와 카메라 폰, 그리고 감쇠 반경(Attenuation Radius)이 일치하는가?
  • 출력 로그(Output Log)에 LogAkAudio 패키징 관련 경고가 찍혀 있는가?
[향후 고도화될 오디오 전문 진단 스콥]
- AkAudioEvent, AkComponent, 블루프린트 호출 경로 추적 도구
- 뷰포트 스크린샷 및 디테일 패널 값을 기반으로 오디오 차폐(Occlusion) 분석
- 아웃풋 로그에서 Wwise 관련 경고/에러만 추출해 주는 전용 필터 툴

UnrealAgent를 단순한 공용 코드 작성 도우미가 아닌, 엔진 오디오 소스와 미들웨어 통합 아키텍처를 명확히 이해하고 조언할 수 있는 '사운드 테크니컬 개발자 전문 도구'로 확장하는 것이 최종적인 이정표다.


요약 및 마무리: 알파 배포를 넘어 실전으로

UnrealAgent는 단순한 실험용 채팅 패널을 넘어, 실 유저에게 공개 가능한 알파 배포 품질 체계를 구축했다.

[UnrealAgent 전체 파이프라인 구조 요약]
사용자 요청 (Unreal Editor) 
  └── UI 패널 (Blazor / CEF WebBrowser)
        └── 인풋 라우터 (문맥 판별)
              ├── 1) 로컬 즉시 응답 (인사 / 정체성 확인)
              ├── 2) 패스트 비전 경로 (텍스트 가드 및 이미지 요약)
              ├── 3) 패스트 텍스트 경로 (경량 Q&A)
              └── 4) 풀 에이전트 경로 (도구 필터링 ──> MCP 서버 ──> 에디터 제어)

공개 저장소 배포를 위해 README.md, SETUP.md, SECURITY.md, THIRD_PARTY_NOTICES.md를 체계적으로 정비하고, 플러그인 메타데이터를 IsBetaVersion: true, VersionName: 0.1.0-alpha로 수정했다. 또한 자동화 빌드 스크립트(package-release.ps1)와 GitHub Workflows 연동을 마무리하여 릴리즈 패키지 압축파일을 안전하게 빌드해 내는 일련의 파이프라인 검증을 통과했다.

 

이번 개발 과정을 통해 얻은 가장 값진 교훈은, 실전에서 작동하는 "AI 에디터 도구"를 만들 때 가장 중요한 것은 화려한 모델 호출 코드가 아니라 에디터 임베디드 환경에 대한 깊은 이해와 촘촘하게 설계된 주변 인프라 시스템이라는 점이다.

 

IME 조합 이벤트를 고려하는 것, CEF 환경의 샌드박스 제한을 클립보드로 우회하는 것, 토큰 오버헤드를 막기 위해 요청을 다각도로 계측하고 잘라내는 필터링 시스템이 갖춰져야만 AI는 비로소 개발자의 진정한 동료가 될 수 있다.

 

GitHub - raindrovvv/UnrealAgent

Contribute to raindrovvv/UnrealAgent development by creating an account on GitHub.

github.com

반응형

'Dev. > UE 언리얼 엔진' 카테고리의 다른 글

[GAS] UE 5 멀티플레이어 미니맵 : DX12 투명화 버그와 GPU 크래시 문제  (0) 2026.05.26
[GAS] 어두운 던전에서 캐릭터가 사라질 때  (0) 2026.05.04
[GAS] 포탈 Niagara VFX 개선 방향 기록  (1) 2026.04.05
[GAS] Runtime Retarget ABP 적용 후 모션이 나오지 않던 문제  (0) 2026.04.05
[GAS] VFX 최적화 컴포넌트 붙였다가, BP 구조 문제를 만났다...  (1) 2026.04.05
'Dev./UE 언리얼 엔진' 카테고리의 다른 글
  • [GAS] UE 5 멀티플레이어 미니맵 : DX12 투명화 버그와 GPU 크래시 문제
  • [GAS] 어두운 던전에서 캐릭터가 사라질 때
  • [GAS] 포탈 Niagara VFX 개선 방향 기록
  • [GAS] Runtime Retarget ABP 적용 후 모션이 나오지 않던 문제
raindrovvv
raindrovvv
raindrovvv 님의 블로그 입니다.
  • raindrovvv
    raindrovvv 님의 블로그
    raindrovvv
  • 전체
    오늘
    어제
    • 분류 전체보기 (188) N
      • Dev. (181) N
        • AI 인공지능 (38) N
        • UE 언리얼 엔진 (87)
        • Unity 유니티 (0)
        • Wwise 와이즈 (7)
        • 게임 네트워크 (8)
        • 그래픽스 Graphics (22)
        • 프로젝트 (9)
        • 기타 개발 관련 (10)
      • Computer Science (0)
        • 하드웨어 HW (0)
        • 소프트웨어 SW (0)
        • 통신 (0)
        • 데이터 (0)
      • 블로그 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    바이브코딩
    Git
    UE
    AI
    Wwise
    네트워크
    인디게임
    트러블슈팅
    생산성
    TA
    그래픽스
    devlog
    에이전트
    언리얼
    unrealengine
    Unreal
    게임개발
    깃
    dev
    언리얼엔진
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.3
raindrovvv
AI를 Unreal Editor 안으로: UnrealAgent
상단으로

티스토리툴바