Caveduck(캐릭터 AI 채팅)을 프로덕션으로 운영하며 “비용을 어떻게 깎았나"를 정리한다. 핵심은 프론티어 LLM으로 다 하지 말고, 답이 라벨인 일은 인코더로 내려보내는 것이다.

“LLM 한 줄이면 되잖아?”

캐릭터 채팅 서비스를 처음 붙일 땐 보이는 게 한 줄이다.

LLM.chat(persona + history + user_msg)

그런데 이걸 누적 100만 유저, 하루 수백만 건 채팅 규모로 굴리면 그 한 줄 아래에 빙산이 있다. 매 응답마다 페르소나 이탈·모더레이션을 판단해야 하고, 대화 상태를 추출해야 하고, 장면을 분류해야 한다. 그리고 무엇보다:

비용 = 토큰 × 턴 × 유저

성장과 비용이 같은 곡선을 그린다. 유저당 원가가 생존을 가른다. 이 모든 걸 프론티어 LLM 하나로 처리하면 단가가 감당이 안 된다.

일을 나눠라: 답이 라벨인 것과 아닌 것

핵심은 모든 일을 같은 모델로 하지 않는 것이다. 작업을 성격별로 쪼갠다.

작업 유형예시적합한 모델
① 판단 / 분류 (답이 라벨)페르소나 이탈·모더레이션·세그먼트인코더
② 가벼운 생성 (짧고 정형)상태 추출·요약작은 생성 모델(SLM)
③ 무거운 생성 (긴 창작)캐릭터 대사프론티어 LLM

프론티어에서 작은 전용 모델로 옮기는 건 디스틸레이션이다. 특히 문제를 생성이 아니라 분류로 재정의하면(causal에서 bidirectional로) 훨씬 작은 구조로 내려갈 수 있다.

인코더: 생성하지 말고 판단하라

디코더(GPT류)는 다음 토큰을 하나씩 생성한다. 하지만 “이 응답이 캐릭터의 페르소나를 벗어났나?”, “이 토큰이 대사인가 지문인가?” 같은 건 생성이 아니라 판단이다. 이럴 땐 인코더(BERT/ModernBERT류)가 맞다.

  • 인코더는 앞뒤 문맥을 동시에 본다. 그래서 분류·이해에 유리하다
  • 생성을 안 하니 빠르고 싸다: 단순 분류에서 인코더가 비용을 10~100배 낮추면서 정확도는 2~4점 차이로 따라붙는다

이건 감이 아니라 통제된 실험으로 확인된다. mmBERT를 만든 JHU 연구팀은 인코더와 디코더를 같은 데이터·같은 아키텍처·같은 레시피로 짝지어 학습해 정면 비교했다(Ettin, ICLR'261). 결과는 명확했다: 분류·검색에서는 인코더가 자기보다 큰 디코더를 이긴다. 예컨대 400M 인코더가 1B 디코더를 MNLI(분류)에서 앞선다(반대로 긴 생성 태스크에선 디코더가 이긴다). 즉 판단·분류를 인코더로 내리면 더 작은 모델로 더 잘하는 것이고, 이건 파라미터 수가 아니라 구조(양방향 vs 인과)의 문제다. 디코더 LLM조차 양방향 어텐션을 켜면 임베딩·이해 성능이 오른다는 결과(LLM2Vec2)도 같은 방향을 가리킨다.

우리가 실제로 인코더로 내린 일들:

이탈 판정 (이진 분류). 캐릭터가 페르소나를 벗어났는지를 매 응답마다 판정한다. 인코더 이진분류(0=정상, 1=이탈)면 밀리초·저비용으로 상시 돌릴 수 있다. 프론티어에 매번 물어볼 일이 아니다.

대사/지문/화자 분리 (시퀀스 라벨링). 캐릭터 응답을 대사·지문·화자·이모티콘으로 토큰마다 분류한다(+CRF). 다국어를 한 모델로 처리한다. 이건 경계가 중요한 전형적인 토큰 분류 문제다.

함정: 범용 다국어 인코더가 한국어를 갉아먹는다

여기서 실전 함정이 하나 있다. 인코더로 내리기로 했으면 어떤 인코더를 쓸까? 범용 다국어 인코더(XLM-R, mmBERT 등)를 그냥 쓰면 되지 않을까?

그런데 범용 다국어 인코더의 토크나이저는 CJK, 특히 한국어를 비효율적으로 쪼갠다. 같은 한국어 문장을 더 많은 토큰으로 나누면, 같은 작업을 하는데 연산·비용이 그대로 늘어난다. 비용을 깎으려고 인코더로 내렸는데, 토크나이저에서 새는 셈이다.

그래서 우리는 mmBERT를 한·중·일·영에 특화시킨 인코더를 따로 만들었다. 토크나이저를 갈아끼워 한국어 토큰을 27% 줄이고, 경계 태스크(NER·세그멘테이션)에 강하게. 이 과정에서 “토크나이저는 효율보다 베이스와의 유사성이 중요하다"는 것도 30B 학습을 두 번 하며 배웠다. (이 인코더 모델은 별도 글에서 따로 소개할 예정이다.)

분류로 바꾸면: 어디까지 줄여도 되는지 보인다

생성을 분류로 바꾸면 부수 효과가 크다. 분류는 정확도가 명확하다. 그래서 손실을 재면서 공격적으로 압축할 수 있다: 프루닝·양자화로 모델을 깎아도, 정확도가 얼마 떨어졌는지 숫자로 보인다. (생성 모델은 품질이 모호해서 공격적으로 줄이기 어렵다.)

압축의 끝은 모델이 아니라 실리콘이다. 워크로드가 인코더 + 작은 SLM으로 내려오면, 이건 추론 전용·INT8/FP16 연산, NPU가 가장 잘하는 일이다.

👉 그래서 이 워크로드를 국산 NPU(리벨리온)에 올리는 것까지 실험했다: 정부가 나눠주는 그 국산 NPU, 실제로 쓸 수 있나. 국산 NPU 위에 국산 특화 인코더를 올리면 비용 절감과 전략적 자립을 함께 얻는다.

정리

  • 캐릭터 AI를 프로덕션 규모로 굴리면 비용이 곧 생존이다.
  • 답이 라벨인 일(판단·분류)은 인코더로, 가벼운 정형 생성은 작은 모델로 내려라. 같은 일을 10~100배 싸게.
  • 한국어 중심 서비스라면 CJKE 특화 인코더로 토크나이저 낭비까지 막아라.
  • 그 끝엔 국산 NPU가 있다 (리벨리온 포팅기).

작은 모델로 원가를 줄이는 건 단순한 절약이 아니다. 야심 찬 기능을 감당 가능한 단가로 만드는 일이고, 결국 더 많은 걸 시도할 수 있게 해준다.


  1. Weller, Ricci, Marone, Chaffin, Lawrie, Van Durme. Seq vs Seq: An Open Suite of Paired Encoders and Decoders (Ettin). ICLR 2026. arXiv:2507.11412: 인코더·디코더를 동일 데이터·아키텍처·레시피로 짝지어(17M~1B, 최대 2T 토큰) 비교. 분류·검색은 인코더, 생성은 디코더가 우위이며, 한쪽을 다른 목적으로 이어학습해 바꾸는 것은 네이티브 구조보다 성능이 낮다. ↩︎

  2. BehnamGhader, Adlakha, Mosbach, Bahdanau, Chapados, Reddy. LLM2Vec: Large Language Models Are Secretly Powerful Text Encoders. 2024. arXiv:2404.05961: 디코더 LLM에 ① 양방향 어텐션 활성화 ② MNTP ③ 대조학습을 적용하면 강력한 텍스트 인코더가 된다. 첫 단계가 인과(causal) 어텐션의 제약을 푸는 것. ↩︎