LLM 에이전트는 왜 느릴까. 큰 이유 하나는 다음에 할 행동을 매번 글자 하나하나 지어내서 정하기 때문이다. 여기서 토큰은 모델이 글을 다룰 때 쓰는 최소 단위다. 에이전트가 "위로 한 칸"을 결정하는 순간에도, 그 다섯 글자를 처음부터 생성한다. "아래로 한 칸"도, "왼쪽으로 한 칸"도 마찬가지다. JevSpawn은 바로 이 행동을 지어내는 비용을 정조준한다.
생각해 보면 이상한 낭비다. 에이전트가 저울질하는 대안 행동들은 대개 틀이 똑같고 값 몇 개만 다르다. 방향 하나, 숫자 하나. 그런데도 매번 문장 전체를 새로 쓴다. 그렇다면 공유되는 틀은 고정해 두고, 바뀌는 칸만 정해진 후보 중에서 고르면 되지 않을까. 글을 짓는(생성) 대신 선택지 중에서 확률로 고르는(선택) 쪽으로 바꾸는 것이다.
이 발상 자체는 새롭지 않다. 'Jev식 모델'이 먼저 했다. 논문이 비교 대상으로 삼은 TypeSafe Jev는 질문에 문장으로 답하지 않고, 정해진 선택지에 각각 확률을 매겨 바로 돌려준다. 유한한 보기 위에서 고르니 빠르다. 문제는 그 보기 목록을 애플리케이션이 미리 짜서 넣어 줘야 한다는 점이다. 자율 에이전트에게 이건 치명적이다. 무엇을 할 수 있는지는 자연어 지시에서 그때그때 읽어 내야 하고, 새 관찰이 들어올 때마다 달라지기 때문이다.
그래서 진짜 어려운 문제는 이렇게 좁혀진다. 유한 선택의 속도를 유지하면서, 그 행동 목록이 상호작용 도중에 바뀔 수 있게 하는 것. JevSpawn이 푼 게 이 지점이다.
해법을 한 문장으로 줄이면, 행동의 빈칸(필드)을 정책의 일부로 끌어들인 것이다. 정책이란 에이전트가 다음 행동을 고르는 규칙을 말한다. 미리 받아 쓰는 게 아니라, 모델이 과제 설명을 보고 그 빈칸을 스스로 선언하고 피드백을 받아 고친다.
주방에 빗대면 차이가 선명해진다. TypeSafe Jev는 "매운맛/순한맛 중 고르세요"라는 주문서를 손님이 미리 짜 줘야만 일하는 셰프다. 빠르지만 주문서가 없으면 아무것도 못 한다. JevSpawn은 "냉장고를 열어 보고 가능한 보기를 네가 짜라"고 맡긴 셰프다. 과제 지시와 상호작용 규칙을 읽고, 빈칸의 이름과 의미, 그리고 앞선 선택에 따라 허용되는 유한한 값들을 직접 선언한다. 빈칸을 다 채우면 그게 곧 실행 가능한 행동 하나가 된다.
이 셰프를 받치는 장치가 넷이다.
첫째, 병렬 스포닝. 한 상태에서 여러 행동 후보를 한꺼번에 펼친다. 어느 조합부터 볼지는 결합 확률, 즉 여러 선택이 함께 일어날 가능성이 안내한다. 논문 설정에서는 부모 하나를 골라 서로 다른 행동을 최대 네 개까지 편다.
둘째, 피드백 기반 분기 선택. 각 후보를 부모 환경의 독립 복사본에서 한 번 실행해 본다. 거기서 나온 관찰을 보고 분기 점수를 다시 매긴다. 해보고 나서 마음을 바꿀 수 있다는 뜻이다.
셋째, 표현 수정. 쌓인 피드백을 보고 선언 자체를 고쳐 쓴다. 가능한 행동의 목록이 상호작용 중에 변한다 — 미리 박힌 빈칸에 묶인 기존 Jev식 모델과 갈라지는 바로 그 지점이다.
넷째, 보존된 분기로부터의 복구. 막다른 길에 몰렸을 때 처음부터 다시 걷지 않는다. 아까 갈림길에서 고르지 않고 접어 둔 다른 길로 되돌아가, 그 지점부터 다시 이어 간다. 앞선 경로를 재생성하는 비용을 아낀다.
여기서 한 가지는 분명히 해 두자. 추가 학습은 없다. 사전학습된 파라미터는 그대로 둔다. 선언을 새로 짜거나 고치거나 최종 답을 낼 때만 텍스트를 생성하고, 반복 탐색은 유한 정책으로 돈다.
속도의 비결은 두 가지 '공유'다.
하나는 행동 구조 공유다. 완전한 설명을 매번 다시 쓰지 않고 빠진 칸만 채운다. 앞 문단에서 본 그대로다.
다른 하나는 접두사 공유다. 접두사란 여러 후보가 함께 쓰는 앞부분 문맥이다. 여러 동화가 전부 "옛날 옛적에"로 시작한다면, 그 도입부를 한 번만 읽어 두고 뒤에 이어지는 부분만 바꿔 읽는 것과 같다. 후보마다 공통 앞부분을 다시 계산하지 않으니, 처리할 입력 토큰이 '매번 접두사를 포함하는' 비용에서 '접두사를 한 번만 처리하는' 비용으로 떨어진다.
비교는 통제된 조건에서 이뤄졌다. 정책 모델은 Qwen3.8-27B 하나로 고정했다. JevSpawn도, 경쟁한 베이스라인 일곱도 전부 같은 모델을 썼다. 온도 0, 시드 42로 무작위성을 걷어 냈고, 전체 예산은 300초로 묶었다. 그러니 이건 "어느 방법이 절대적으로 빠른가"가 아니라, 같은 조건에서의 상대 비교다.
경쟁 상대들의 접근은 크게 셋으로 나뉜다. 모델을 언제 어디서 부를지 줄이는 쪽(호출 조직화), 스텝 사이에 오가는 정보량을 줄이는 쪽(정보 축소), 출력 생성 속도 자체를 올리는 쪽(디코딩 가속). JevSpawn은 이 셋과 다른 축 — 행동 생성 그 자체 — 을 겨눈다. 다만 '행동을 지어내지 않고 고른다'는 발상이 처음은 아니다. 앞서 본 TypeSafe Jev의 유한 선택이나, 결정적인 생성 경로를 건너뛰는 SGLang 같은 선행기술을 논문도 토대로 짚는다. JevSpawn의 기여는 이 아이디어를 적응형 행동 공간과 분기 탐색에 결합해, 그 목록이 상호작용 도중 바뀌게 만든 데 있다.
결과를 읽을 때 한 가지만 주의하면 된다. 과제마다 재는 단위가 다르다. 길찾기류는 성공률(0~1)을 쓰고, 퍼즐·수치 게임은 벤치마크 보상이나 점수를 쓴다. 0.96과 305.12를 나란히 놓고 비교하면 안 된다.
가장 흥미로운 결과가 여기 있다. 보통은 점수를 올리면 시간이 더 든다. 그런데 내비게이션 두 과제에서는 둘 다 좋아졌다.
| 과제(성공률) | JevSpawn | 최고 베이스라인 | 지연: JevSpawn / 가장 빠른 베이스라인 |
|---|---|---|---|
| Maze | 0.96 | FoldAgent 0.52 | 40.91초 / 47.91초 |
| Grid | 0.95 | FoldAgent 0.73 | 40.58초 / 61.44초 |
지연은 요청부터 최종 응답까지 걸린 전체 시간(E2E)이다. Maze는 0.52에서 0.96으로 거의 두 배, Grid는 0.73에서 0.95로 1.3배가량 올랐다. 점수가 큰 폭으로 뛰는데 시간은 오히려 짧다. 품질과 속도는 보통 맞바꿔야 하는 두 지표다 — 하나를 더 얻으려면 다른 하나를 포기해야 하는 관계이고, 그 최선의 가장자리를 파레토 경계라 부른다. 그런데 이 두 과제에서는 JevSpawn이 그 상충을 깨고 양쪽을 함께 가져갔다. 품질과 속도가 둘 다 더 나은 방법이 사실상 없다는 뜻이다.
반대편 결과도 있다. LightsOut 보상은 0.61로 AgentPrune의 0.34를 앞서고, Nullify는 0.21로 HiAgent·FoldAgent의 0.09를, 2048은 305.12점으로 LLMCompiler의 5.00을 멀찍이 따돌린다. 다만 2048의 지연은 169.94초로, 가장 빠른 33.51초보다 한참 길다. 점수를 얻는 대가로 시간을 치른 영역이다.
그리고 모든 과제를 이긴 건 아니다. AgentPrune은 PPNL·RushHour·Sokoban에서 여전히 가장 강하다. Sokoban에서 JevSpawn의 파레토 경계 소속은 불안정한데, 이건 LLMCompiler보다 1.50초 빠르지만(122.49초 대 123.99초) 점수는 낮은(0.150 대 0.350) 상황, 즉 속도와 품질이 상충하는 처지를 반영한 결과라고 논문이 직접 밝힌다.
구조는 그대로 두고 유한 채점 부분만 외부 TypeSafe Jev API로 갈아 끼운 변형도 돌려 봤다. 결과는 엇갈린다. 외부 API 변형은 일부 과제에서 Qwen 자체 채점을 앞서지만 다른 과제에서는 뒤진다. 게다가 API 통신까지 포함하면 자체 채점의 1.4~2.1배 시간이 든다. 외부 인터페이스가 품질에서 늘 유리하지도 않고, 속도에서는 오히려 손해라는 얘기다.
처리량(prefill을 뺀 순수 생성 속도)에서는 PPNL 544.35, LightsOut 580.05로 표 안 최고치를 찍는다. prefill은 모델이 답을 내기 전에 입력 문맥을 한 번에 읽어 들이는 준비 단계다. 재미있는 건 Maze와 Grid의 텍스트 처리량이 N/A로 찍힌다는 점이다. 느려서가 아니다. 이 두 과제는 처음부터 끝까지 유한 평가로만 돌아 텍스트를 거의 생성하지 않는다. 숫자보다 "어디서 텍스트 생성을 통째로 걷어 냈는가"가 핵심이다. 길찾기에서 속도가 터진 이유도 여기 있다.
이쯤에서 솔직한 그림이 필요하다. JevSpawn에는 켜고 끄기만 하면 되는 보편 스위치가 없다. 좋은 설정값이 과제마다 정반대로 뒤집힌다. 쓸 만한 기술이냐 아니냐는, 이 '뒤집힘'을 내 과제에 맞게 조율할 수 있느냐에 달렸다.
탐색 폭은 양날의 검이다. 폭은 한 번에 몇 갈래를 펼칠지를 말한다. 폭을 1로 좁히면 Maze 성공률은 0.16, Grid는 0.58까지 주저앉는다. 그래서 더 넓히고 싶어진다. 그런데 폭을 10으로 키우면 Maze는 전부 풀리는 대신, Nullify 보상이 절반으로 깎이고 RushHour 지연은 두 배가 된다. 넓은 탐색이 과제에 따라 독이 된다.
같은 예산도 어떻게 쪼개느냐에 따라 결과가 뒤집힌다. 아래는 행동 네 개짜리 예산을 '부모 수 × 부모당 행동 수'로 다르게 나눠 본 것이다.
| 배분 | Maze | Grid |
|---|---|---|
| 1 × 4 | 0.88 | 0.94 |
| 2 × 2 | 1.00 | 1.00 |
| 4 × 1 | 0.12 | 0.75 |
Maze는 2×2에서 완벽히 풀리고 4×1에서 무너진다. 그런데 바로 그 4×1 극단 배분이 2048 점수는 오히려 올린다. 공식이 과제마다 다르다는 걸 이보다 잘 보여주기 어렵다.
선언을 고정할지 고쳐 쓸지, 관찰을 분기 안에 가둘지 분기끼리 공유할지도 전부 과제에 달렸다. 다만 그 혼란 속에 하나 일관된 신호가 있다. 관찰을 분기끼리 공유하면, 점수는 과제별로 갈려도 여덟 과제 전부에서 지연이 낮아졌다. 켜 둘 만한 기본값 하나가 여기 있는 셈이다.
시간 예산과 라운드 수는 정면으로 부딪친다. 탐색 라운드를 36에서 108로 늘리면 2048 점수는 315.16에서 1102.24로 뛴다. 더 생각할수록 잘 푼다. 그런데 300초 마감을 걸면, 108라운드에서 2048 과제의 85퍼센트가 타임아웃이다. 더 깊은 사고가 현실의 지연 예산과 충돌한다.
마지막으로 이 방법의 바닥에 깔린 전제. "행동들이 형태를 공유하고 값이 유한하다"는 것이다. 논문의 과제는 격자 이동·퍼즐·수치 게임이라 이 전제가 잘 맞는다. 행동이 열린 자연어(자유 서술, 코드 작성)거나 인자 공간이 사실상 무한한 과제에서도 같은 이득이 날지는, 이 실험만으로는 단정하기 어렵다. 모든 결과가 Qwen3.8-27B 한 모델에서 나왔다는 점도 일반화의 숙제로 남는다.
이런 조건을 꼼꼼히 따지는 이유는, 이 기술을 우리 서비스에 현실적으로 어떻게 댈지 가늠하기 위해서다. 구체적인 장면 하나를 끝까지 따라가 보자.
고객이 진행 중인 프로젝트에서 납기를 앞당겨 달라고 요청했다. AI PM은 다음 한 수를 정해야 한다. 바뀐 일정에 맞춰 수집 작업을 다시 돌릴지, 영향받는 산출물 목록을 먼저 뽑을지, 고객에게 축소할 범위를 되물을지, 내부 담당에게 재배치를 알릴지. 지금 구조에서는 이 판단을 긴 추론 텍스트로 한 번 길게 뽑아 내린다. 느리고, 한 번 고른 길로 밀고 가다 어긋나면 되돌리는 비용이 크다.
이 장면에 JevSpawn의 틀을 대 보면 바뀌는 지점이 또렷하다. PM의 "다음 한 수"는 사실 형태가 반복되는 유한 행동이다. 대상(어떤 작업·어떤 산출물), 동작(재수집·목록화·질의·통지), 수신자처럼 몇 개의 칸으로 쪼개진다. 매번 자연어로 길게 쓰는 대신 이 칸들의 후보를 선언하고 유한 확률로 고르면, 같은 결정을 더 가볍게 내릴 여지가 생긴다. 온틀이 이미 쓰는 좁은 액션 도구 — 말과 행동이 일치하고 서버가 결정론적으로 실행하는 설계 — 가 "형태를 공유하고 값이 유한한 행동"의 정의에 그대로 들어맞는다.
그렇다고 논문을 그대로 가져올 수는 없다. 걸리는 건 둘째 장치, 분기 시뮬레이션이다. "후보를 독립 복사본에서 실행해 보고 고른다"는 전제는, 그 실행에 부작용이 없고 되돌릴 수 있을 때만 성립한다. 격자 이동은 복사본에서 몇 번이든 공짜로 돌려볼 수 있다. 하지만 PM의 실제 행동 상당수 — 외부 연동 호출, 고객에게 나가는 질의 — 는 부작용이 있어 가볍게 떠볼 수가 없다. 복사본에서 고객에게 메일을 네 번 보내 볼 수는 없는 노릇이다. 그러니 이 구조는 수집 결과 미리보기나 내부 상태 전이처럼 되돌릴 수 있는 행동에만 먼저 대고, 부작용 있는 행동은 여전히 승인 게이트를 거치게 두는 편이 맞다.
여기서 한발 물러서 보면, 이 논문이 가리키는 방향은 업계의 큰 흐름과 맞닿아 있다. 초기에는 추론부터 행동까지 전부 LLM의 자유 생성에 맡겼다. JevSpawn은 그 담론에서 한 걸음 물러나, 되돌릴 수 있는 결정론적 행동은 유한 선택으로, 열린 생성이 필요한 부분은 텍스트 생성으로 분리한다. 온틀식 적용도 같은 하이브리드다. 다음 한 수를 고르는 결정은 유한 정책으로, 고객에게 보낼 문장은 텍스트 생성으로.
다만 한 가지는 선을 그어 둬야 한다. "유한 정책이 더 싸다"는 건 격자·퍼즐 과제에서 나온 결론이지, 우리 과제에서 보장된 사실이 아니다. 그래서 적용의 첫 단계는 확장이 아니라 측정이어야 한다. 제안은 이렇다.
이 작은 비교에서 시간과 성공률이 실제로 좋아질 때에야, 앞선 실험들의 숫자가 우리 실무의 판단으로 넘어온다. 그 전까지 "더 싸다"는 말은 가설이지 결론이 아니다.
그대로 보장되지 않는다. 논문의 숫자는 무작위성을 걷어 내 방법 자체만 비교하려고 통제한 값이다. 운영에서는 온도·모델·입력이 매번 다르므로, 서비스에 올리기 전 자기 환경에서 다시 재는 게 맞다.
맞는 지적이다. 병렬로 갈래를 펼치는 건 더 많은 연산을 벽시계 시간으로 접어 넣는 방식이다. 논문이 H100 4장 고정 조건에서 전체 지연으로 쟀다는 점을 기억해야 한다. 쓸 수 있는 하드웨어가 빠듯하면, 폭을 넓힐 때의 지연 이득이 줄어들 수 있다.
초록에 GitHub 주소(https://github.com/Hoyant-Su/JevSpawn)가 공개돼 있다. 세부 구현과 재현은 해당 저장소와 논문 부록을 참고하면 된다.