NVIDIA ACE는 게임용 AI 에이전트 구축을 위한 기술 제품군입니다. 이 솔루션은 음성 인식부터 지능형 상호작용, 애니메이션에 이르기까지 게임 속 캐릭터의 모든 요소를 구현할 수 있도록 통합 준비가 완료된 클라우드 및 온디바이스 AI 모델을 제공합니다.
이러한 모델을 게임 엔진과 함께 효율적으로 구동하기 위해, NVIDIA In-Game Inferencing (NVIGI) SDK는 개발자가 C++ 기반 게임 및 애플리케이션에 통합할 수 있는 고성능 라이브러리 세트를 포함하고 있습니다.
NVIDIA In-Game Inferencing SDK 1.5는 AI 에이전트가 플레이어와 협력하여 2D 던전의 몬스터를 격퇴하는 새로운 코딩 에이전트 샘플을 도입했습니다. 일반적으로 로컬 소형 언어 모델(SLM)에 의해 구동되는 AI 에이전트는 GPU에 과도한 호출을 생성하여 그래픽 렌더링과 자원 경합을 벌이기도 합니다. 이번 포스팅은 추론 호출 횟수를 최소화하고 각 호출의 효율을 극대화하여, 그래픽과 연산 사이의 GPU 점유 갈등을 줄이는 방법을 심도 있게 분석합니다.
코딩 에이전트: 유령을 길들이는 방법
OpenAI의 창립 멤버인 Andrej Karpathy는 거대 언어 모델(LLM)과 협업하는 과정을 유령을 소환하는 것에 비유했습니다. 이는 LLM 에이전트, 특히 코드를 직접 작성하는 에이전트에게 매우 적절한 은유로 다가옵니다. 그간 많은 커스텀 에이전트들은 특정 함수가 정의되면 모델이 호출 시점을 결정하고 결과를 반환받는 도구 호출 수준에 머물러 왔습니다. 하지만 우리는 더욱 야심 찬 가능성에 주목해야 합니다. AI 에이전트가 단순히 기존 함수를 호출하는 단계를 넘어, 함수 자체와 이를 뒷받침하는 코드 전체를 직접 생성하게 만드는 방식입니다. 이러한 접근은 적은 연산 처리량으로도 기계의 성능을 비약적으로 강화합니다.
물론 여기에는 명확한 트레이드오프가 존재합니다. 코드 실행 권한을 가진 제약 없는 LLM은 보안 측면에서 심각한 위협이 될 수 있기 때문입니다. 실제로 메모리를 고갈시키거나 게임 프로세스를 중단시킬 위험이 있으며, 어느 불운한 사용자가 경험했듯 “캐시를 정리하려다” 하드 드라이브 전체를 포맷해버리는 불상사가 발생할 가능성도 배제할 수 없습니다.
그럼에도 코딩 에이전트는 복잡한 다단계 추론, 동적 적응성, 그리고 소형 언어 모델(SLM) 사용량 절감이라는 확실한 이점을 선사합니다. 이어서 저희는 잠재적인 위협이었던 코딩 에이전트라는 유령을 어떻게 게임 플레이를 돕는 친절한 조력자로 탈바꿈시켰는지 구체적으로 살펴보겠습니다.
코딩 에이전트가 도구 호출보다 뛰어난 이유
AI 에이전트를 논할 때 가장 보편적으로 활용되는 방식은 도구 호출입니다. 모델이 구조화된 JSON 데이터를 출력하면 게임이나 애플리케이션이 이를 분석해 해당 함수를 실행하는 구조를 취합니다. 함수 호출 능력 자체는 강력하지만, 이는 모델이 충분히 ‘생각’할 시간을 가진 뒤에야 발휘됩니다. 특히 사용자의 GPU 자원을 두고 그래픽과 경합해야 하는 환경에서 이러한 추론 과정은 상당한 비용을 발생시킵니다.
모델이 JSON을 전송한 뒤 응답을 기다리고, 다시 생각하여 답변을 내놓는 과정이 반복될수록 귀중한 시간이 소모됩니다. 이는 결과적으로 게임 렌더링에 투입되어야 할 찰나의 순간들을 잠식하는 결과를 초래합니다.
또한, 함수 호출 과정에 복잡한 로직이 개입될 경우 시스템은 상대적으로 취약한 모델의 능력에 의존할 수밖에 없습니다. 언어 모델은 본질적으로 루프를 처리하지 못하며, 단순히 토큰을 생성할 뿐입니다. 상태 변수를 추적하려 시도할 수는 있겠지만, 그 과정에 엄격한 논리는 결여되어 있습니다. 처리해야 할 항목이 여러 개라면 모델은 누락, 중복, 혹은 환각 없이 각 항목을 기억해야 하며, 처리하는 모든 항목마다 개별적인 추론 비용을 지불해야 합니다.
수치 분석 역시 또 다른 도전 과제입니다. 도구 호출 방식에서 정확도는 모델 자체의 수학적 능력이나, 정확성을 보장하기 위해 별도로 작성된 또 다른 함수에 전적으로 의존합니다. 결국 도구 호출은 확장성 측면에서 한계를 드러냅니다. 모든 함수 호출은 GPU 자원을 점유하는 추가적인 추론 부하를 일으키며, 개발자는 이를 완화하기 위한 고심을 거듭해야 합니다.
반면, 코딩 에이전트는 컴퓨터가 이미 가장 잘하는 영역인 ‘코드 실행’을 활용합니다. 프로그래밍은 언어 모델이 새롭게 갖게 된 강력한 능력 중 하나로 손꼽힙니다. 한 번에 하나의 함수를 호출하는 대신, 단 한 번의 추론으로 필요한 모든 함수 호출 코드를 동시에 생성할 수 있습니다. 초기 생성 이후에는 성능 저하 없이 과업을 완료할 때까지 표준 코드가 실행될 뿐입니다.
유연성 또한 코딩 에이전트의 강점입니다. 언어 모델 스스로 루프를 돌기는 어렵지만, 코딩 에이전트는 루프와 카운터, 필터가 포함된 코드를 손쉽게 작성합니다.
다음은 적을 조준하기 위해 도구 호출 방식이 사용되는 가상의 사례를 보여주는 스키마입니다.
[
{
"name": "get_enemies_list",
"parameters": {
"properties": {
"position": {"type": "string", "description": "Position to search from"},
"radius": {"type": "number", "description": "Search radius"}
}
}
},
{
"name": "target_enemy",
"parameters": {
"properties": {
"enemy_name": {"type": "string", "description": "Name of the enemy to target"}
},
"required": ["enemy_name"]
}
}
]
플레이어가 “가장 가까운 적을 조준해”라고 명령했을 때, 기존의 도구 호출 방식이 작동하는 과정을 살펴보겠습니다.
- 추론 호출 1: SLM이
get_enemies_list함수를 호출하기로 결정합니다. - 도구 응답:
["goblin_01", "skeleton_archer_01", "orc_chief"]와 같은 리스트를 반환합니다. 이때 리스트는 단순한 문자열 형태여야 하는데, 개체의 전체 스키마를 포함할 경우 컨텍스트 윈도우(Context Window) 용량을 초과해버리기 때문입니다. - 추론 호출 2: 모델이 리스트를 확인하고 대상을 선택한 뒤,
target_enemy("goblin_01")를 호출합니다. - 도구 응답: 성공 메시지를 수신합니다.
- 추론 호출 3: 함수 호출 결과와 현재 상태를 플레이어에게 피드백으로 전달합니다.
단 하나의 의사결정을 내리기 위해 무려 세 번의 추론 호출이 발생했습니다. 이제 동일한 “적 조준” 동작을 코딩 에이전트로 처리했을 때 어떤 변화가 일어나는지 대조해 보겠습니다.
get_enemies(position, radius)
--[[
Find enemies near a position.
Parameters:
position (table): Center point as {row, col}
radius (number): Search radius
Returns:
table: Array of enemy entities (with .name, .position, .health, etc.)
Example:
local nearby = get_enemies(ally.position, 10)
]]
set_target(ally, enemy)
--[[
Set an ally's attack target.
Parameters:
ally (entity): The ally to command
enemy (entity): The enemy to target
Example:
set_target(warrior, nearby[1])
]]
“가장 가까운 적을 조준해”라는 명령에 대해 소형 언어 모델(SLM)이 생성한 코드는 다음과 같습니다
local enemies = get_enemies(ally.position, 10)
local closest = nil
local min_dist = math.huge
for _, enemy in ipairs(enemies) do
local dx = enemy.position[1] - ally.position[1]
local dy = enemy.position[2] - ally.position[2]
local dist = math.abs(dx) + math.abs(dy)
if dist < min_dist then
min_dist = dist
closest = enemy
end
end
if closest then
set_target(ally, closest)
end
단 한 번의 추론 호출만으로 소형 언어 모델(SLM)은 적들을 순회하고, 각 위치에 접근하며, 거리를 계산해 가장 가까운 대상을 선택하는 모든 과정을 수행합니다. 코딩 에이전트는 단순한 문자열이 아닌 풍부한 속성을 가진 엔티티 객체를 직접 다루며, 도구 설계자가 전혀 예상하지 못한 정교한 논리를 구성해 냅니다.
여기서 주목할 점은 탁월한 유연성입니다. 동일한 get_enemies 함수라도 플레이어 주변, 아군 근처, 혹은 특정 지점 근처의 적을 찾는 용도로 자유롭게 활용될 수 있습니다. 일단 적 목록을 확보하면 SLM은 화살에 취약한 적을 노리거나, 가장 가까운 적을 조준하고, 체력이 가장 낮은 대상을 선택하는 등 어떠한 선택 로직도 즉석에서 작성합니다. 반면 도구 호출 방식에서 새로운 요구사항에 대응하려면 더 많은 도구와 추론 호출이 필요하며, 이는 곧 복잡성의 증가로 이어집니다. 코딩 에이전트는 동일한 기초 요소를 조합해 런타임에 새로운 전략을 스스로 구축합니다.
코딩 에이전트 샘플 던전
‘유령’이라는 테마에 맞춰, IGI SDK는 코딩 에이전트를 시연하기 위한 ASCII 던전 크롤러를 포함하고 있습니다. 이 던전은 대규모 게임의 모든 구성 요소를 갖추면서도, 게임의 가장 단순한 형태 중 하나인 텍스트 기반으로 구현되었습니다. 플레이어는 이곳에서 이동하고, 아이템을 수집하며, 몬스터와 전투를 벌입니다. 또한 모험 과정에서 강력한 아군인 AI 에이전트와 함께합니다. 이 지능체는 플레이어의 요청에 따라 실체화되어 전투를 돕고, 위험한 임무를 수행하며, 앞으로 닥쳐올 위협에 대한 정보를 제공하는 든든한 조력자 역할을 수행합니다.

플레이어가 지시를 내리면 즉시 코드가 작성되며, 새로운 명령이 떨어지기 전까지 프로그램은 소형 언어 모델(SLM)에 다시 접근하지 않습니다. 도구 호출 체인으로도 동일한 결과를 얻을 수는 있겠지만, 반복적인 추론 호출이 할당된 프레임 타임 슬라이스를 잠식하는 비용을 치러야만 합니다.
코딩 에이전트의 보안 위협 모델
호스트 시스템에서 실행되는 코드를 생성하기 위해 SLM을 사용하는 방식은 다음과 같은 명백한 보안 및 안전 리스크를 동반합니다.
- 위험한 함수 접근: SLM이
os.execute("rm -rf /")나require("socket")같은 명령을 생성하면, 코딩 에이전트는 순식간에 파일을 삭제하거나 네트워크 연결을 시도하는 위협으로 돌변합니다. - 무단 파일 접근: 모델이 중요 파일이나 API 키의 위치를 찾아내 외부로 유출하거나 삭제할 가능성이 존재합니다.
- 자원 고갈: SLM이 메모리를 끊임없이 할당하는 루프를 작성하여 시스템 자원을 고갈시킬 수 있습니다.
- 스택 오버플로: 적절한 종료 조건이 없는 재귀 함수를 작성하여 시스템 오류를 유발합니다.
- 무한 루프: 모델이
while true do end와 같은 코드를 작성할 경우 제어권이 반환되지 않는 문제가 발생합니다. - 샌드박스 탈출: SLM이 내부 구조를 조작하여 격리된 실행 환경을 무력화하고 탈출을 시도할 수 있습니다.
- 상태 손상: 생성된 코드가 게임이나 애플리케이션의 핵심 데이터 상태를 오염시킬 위험이 있습니다.
대상 언어 선정 시 고려사항
대상 언어를 선택할 때는 실행까지 걸리는 시간, 전반적인 성능, 통합 및 디버깅의 복잡성, 그리고 생성된 코드의 품질과 안전성을 반드시 따져봐야 합니다.
게임을 구동하는 동안 추론 호출은 전체 프레임 타임의 아주 작은 부분만을 점유해야 합니다. 렌더링 파이프라인을 멈추게 만드는 거대한 부하는 결코 허용될 수 없기 때문입니다. 매 프레임마다 몇 개의 토큰을 나누어 생성하며 추론 부하를 분산하는 것은 가능할지 몰라도, 컴파일 과정은 그만큼 유연하게 대처하기 어렵습니다. 따라서 이러한 특성은 C++나 C#과 같은 컴파일 언어를 선택지에서 제외시키며, 그 대안으로 인터프리터 언어의 도입을 요구합니다.
이러한 맥락에서 Python과 Lua라는 두 가지 언어가 대표적인 후보로 떠오릅니다.
파이썬은 가장 먼저 고려하게 되는 당연한 선택지입니다. SLM은 Python 코드를 매우 능숙하게 생성하며, 관련 생태계 또한 방대합니다. 그러나 Python은 본래 임베딩이나 샌드박싱을 목적으로 설계되지 않았습니다. 전역 인터프리터 락(GIL)은 멀티스레드 호스트 환경을 복잡하게 만들며, 실행 환경을 격리하려면 하위 프로세스나 하위 인터프리터를 별도로 운용해야 하는 번거로움이 뒤따릅니다. 더욱이 메모리 사용량이나 실행 시간을 제한하는 내장 기능조차 갖추고 있지 않습니다. Python을 샌드박스 내에서 구동할 수는 있겠지만, 이는 언어 본연의 성질과 끊임없이 사투를 벌여야 함을 의미합니다.
반면, Lua는 처음부터 적대적인 환경에 임베딩될 것을 상정하여 설계되었습니다. 전체 런타임 크기는 약 200KB에 불과하며, 1밀리초(ms) 미만의 찰나에 실행을 시작합니다. 무엇보다 앞서 언급한 모든 보안 위협에 대해 이미 문서화된 대응책을 갖추고 있다는 점이 돋보입니다.
- 위험한 함수 차단: 선택적 라이브러리 로딩 방식을 채택합니다.
io나os라이브러리를 아예 로드하지 않으면, 해당 기능들은 존재조차 하지 않는 상태가 됩니다. - 메모리 고갈 방지: 커스텀 할당자 후크(Custom allocator hook)를 활용하세요. 모든 할당 과정을 추적하고 엄격한 상한선을 강제할 수 있습니다.
- 스택 오버플로 대응: 함수 호출 시 디버그 후크를 설정하여 호출 깊이를 계산하고, 임계치를 넘어서면 즉시 오류를 발생시킵니다.
- 무한 루프 제어: 명령어 실행 횟수에 디버그 후크를 걸어 둡니다. 일정 수(N) 이상의 명령어가 실행되면 작동을 중단시킵니다.
- 메타테이블 조작 방지: 전역 객체에서
getmetatable과setmetatable을 제거하여 접근을 원천 봉쇄합니다. - 상태 손상 방지: 커스텀
__newindex메타메서드를 적용해 보호된 필드에 대한 쓰기 시도를 거부합니다.
결과적으로 Lua는 이번 IGI 샘플의 모든 요구사항을 충족했으나, 여전히 세심한 강화 작업이 필요했습니다. 본 샘플에서는 위험하거나 불필요한 함수를 nil로 설정하는 패턴(lua_pushnil(L); lua_setglobal(L, "funcname"))을 적용했습니다. 메모리 팽창은 기본 할당자를 래핑하여 추론 과정을 추적함으로써 억제했습니다. 또한 개발자는 lua_sethook을 설정해 프로그램이 콜 스택을 터뜨리거나 무한정 대기하는 상황을 방지할 수 있습니다. 마찬가지로, 게임 상태를 보호하기 위해 잠금 처리된 커스텀 메타메서드로 메타테이블 접근을 제한하는 방식도 유효합니다.
여기에 나열된 조치들은 샘플을 안전하게 고정하기 위해 취해진 단계 중 일부에 불과합니다. 개별 게임이나 사용 사례에 따라 추가적인 보안이 필요할 수 있지만, 이 팁들은 코드를 분석하는 독자들에게 훌륭한 이정표가 되어줄 것입니다.
보안을 한층 강화하려면 WebAssembly(Wasm) 런타임 내에 Lua를 임베딩하는 방법도 고려해 보시기 바랍니다. 에이전틱 동작의 보안을 유지하는 더 자세한 방법은 ‘WebAssembly를 활용한 에이전틱 AI 워크플로우 샌드박싱‘ 및 ‘에이전틱 워크플로우 샌드박싱과 실행 리스크 관리를 위한 실무 보안 가이드‘ 블로그 포스팅에서 확인하실 수 있습니다.
보안은 나중에 덧붙이는 부연 설명이 아니라 핵심 고려사항이어야 합니다. 언어의 선택은 편의가 아닌 보안의 관점에서 내려야 하는 결정입니다. 이러한 전제에서 시작해 다양한 공격 벡터를 이해하고 방어한다면, 시스템 속의 유령은 언제나 당신의 든든한 친구로 남을 것입니다.
NVIDIA In-Game Inferencing SDK 시작하기
지금 바로 NVIDIA In-Game Inferencing SDK를 통해 샘플을 직접 경험해 보세요. 빌드하고 실험하며 여러분의 게임, 앱, 프로젝트에 이 기술을 적용할 창의적인 방법을 구상해 보시기 바랍니다.
GDC에서 만나요
NVIDIA RTX 뉴럴 렌더링과 AI가 차세대 게임 산업을 어떻게 재편하고 있는지 확인하세요. NVIDIA의 개발자 및 성능 기술 부문 부사장인 John Spitzer가 패스 트레이싱과 생성형 AI 워크플로우의 최신 혁신을 공개하며 게임 개발의 미래를 제시합니다.
또한, NVIDIA 응용 딥러닝 연구 부문 부사장인 Bryan Catanzaro와 함께 AI 최신 트렌드를 다루는 인터랙티브 ‘Ask Me Anything’ 세션에도 참여해 보시기 바랍니다.