Skip to content

LLM 답변 길이 제어 — 글자가 아닌 토큰과 max_tokens

LLM 답변 길이 제어 — 글자가 아닌 토큰과 max_tokens




TL;DR

  • 증상: AI 답변 길이를 프롬프트로 제한(“N자 이내로”)해도 무시당하거나, 반대로 문장이 중간에 뚝 잘림
  • 원인: 모델은 글자가 아니라 토큰으로 생성한다. 한글은 1글자가 평균 약 1.7토큰. max_tokens 한도에 먼저 걸려서 잘리는 거였음
  • 해결: 프롬프트 강제를 포기하고, 토큰↔글자 비율을 실측해서 max_tokens 파라미터 자체를 맞춤
  • 효과: 문장이 중간에 잘리는 문제가 사라짐. retry 단계도 줄어듦
  • 한계: 토큰 비율은 언어·내용마다 다르다. 추정하지 말고 실측해야 함

환경

이 글은 제가 혼자 만들어 쓰는 AI 집사 Jarvis 기준입니다.

  • 모델: Anthropic Claude (Discord 봇에서 CLI로 호출)
  • 문제 났던 기능 A: max_tokens ≈ 1300
  • 문제 났던 기능 B: max_tokens = 340 (주석에 ”≈ 한글 330~400자”라고 추정값을 박아둠)
  • 콘텐츠: 한글 위주 (코드·숫자 일부 섞임)

“300자 이내로 써”가 안 먹혔습니다

어느 순간 Jarvis 답변이 너무 길어졌습니다. 디스코드에서 보기 답답할 정도였습니다. 그래서 시스템 프롬프트에 적었습니다. “답변은 300자 이내로.”

안 줄었습니다. 톤만 살짝 바뀌고 길이는 그대로였습니다. 더 강하게 적었습니다. ”반드시 300자 이내. 초과 금지.” 이번엔 가끔 줄긴 했는데, 이상하게 문장이 중간에서 뚝 끊겼습니다. “…그래서 팀장” 하고 끝나버리는 식입니다.

처음엔 모델이 지시를 무시한다고 생각했습니다. “얘가 글자 수를 못 세나?” 싶어서 retry 로직을 붙였습니다. 1차 답변이 길면 “더 줄여” 하고 다시 부르고, 그래도 길면 또 부르고. 비용은 늘고, 응답은 느려지고, 그런데도 길이는 들쭉날쭉했습니다.

프롬프트로 안 되는 걸 프롬프트로 더 세게 미는 짓을 한참 했습니다. 백엔드 9년을 하고도 “지시를 더 강하게 쓰면 되겠지”라고 생각한 겁니다.


모델은 글자를 안 봅니다, 토큰을 봅니다

막혀서 한 발 물러나 모델이 텍스트를 어떻게 만드는지부터 다시 봤습니다. 여기에 답이 있었습니다.

모델은 글자(character)를 하나씩 쓰는 게 아니라 토큰(token) 단위로 생성합니다. 토큰은 단어보다 작고 글자보다 큰, 모델이 텍스트를 쪼개는 조각입니다. 영어는 보통 한 단어가 1~2토큰인데, 한글은 사정이 다릅니다. 받침과 조사 때문에 한 글자가 여러 토큰으로 쪼개지는 경우가 많습니다.

그리고 결정적으로, API에는 max_tokens라는 파라미터가 있습니다. “이번 응답은 최대 몇 토큰까지 생성해라”는 하드 리밋입니다. 이 한도에 도달하면 모델은 문장이 끝났든 말든 그 자리에서 생성을 멈춥니다. “…그래서 팀장”에서 끊긴 게 바로 이거였습니다. 글자 수 지시를 무시한 게 아니라, 토큰 한도에 먼저 부딪힌 겁니다.

정리하면 이렇습니다.

  • 프롬프트의 “300자 이내”는 소프트한 권유입니다. 모델이 참고는 하지만 보장은 안 합니다.
  • max_tokens물리적 천장입니다. 여기 걸리면 무조건 잘립니다.

저는 소프트한 권유로 물리적 천장을 통제하려 했던 거였습니다. 만지는 데가 처음부터 틀렸습니다.


종이에 계산해보니 답이 나왔습니다

그래서 직접 계산해봤습니다. 제 설정은 max_tokens가 약 1300이었습니다. 그리고 제 콘텐츠 기준으로 한글은 대략 1글자당 1.5토큰 정도였습니다.

최대 글자 수 = max_tokens ÷ (글자당 토큰)
             = 1300 ÷ 1.45
             ≈ 896자

즉 제 설정에서 모델이 물리적으로 만들 수 있는 한글은 최대 900자 가까이였습니다. 그 안에서는 프롬프트로 길이를 조절할 수 있지만, 이 천장 자체는 프롬프트로 못 넘습니다. 반대로 답변이 천장에 가까워지면 문장 완결과 무관하게 잘릴 수밖에 없었습니다.

해결은 허무할 만큼 단순했습니다. 길이를 더 짧게 강제하고 싶으면 프롬프트를 고치는 게 아니라 max_tokens를 내리면 되고, 문장이 잘리는 게 싫으면 max_tokens에 여유를 주면 됩니다. 그동안 프롬프트 문구만 며칠을 만지작거렸는데, 정작 손봐야 할 숫자는 코드 한 줄 위에 있었습니다.


진짜 함정은 “추정 환산”이었습니다

그런데 여기서 한 번 더 데였습니다. 다른 기능에서는 max_tokens를 340으로 잡아두고 주석에 “340토큰 ≈ 한글 330~400자”라고 적어놨었습니다. 그 비율을 믿고 설계했는데, 실제로 돌려보니 모델이 574자를 만들고 나서 8번째 문장 중간에 잘렸습니다.

원인은 제가 토큰↔글자 비율을 실측 안 하고 추정했다는 겁니다. 주석엔 1토큰당 1.18자로 적었는데, 실제 제 한글 콘텐츠는 1토큰당 1.7자 가까이 나왔습니다. 추정과 실측이 40% 넘게 차이 났고, 그 오차가 그대로 “문장 중간 절단”으로 나타난 겁니다.

그래서 비율을 한 번 실측해서 박아뒀습니다. 한글은 대략 1토큰 ≈ 1.7자. 이 숫자 하나를 실측으로 고정하니, 그 뒤로는 “이 기능은 600자까지 받고 싶다 → 600 ÷ 1.7 ≈ 353토큰 + 여유”처럼 역산이 깔끔하게 됐습니다.

토큰 비율은 언어마다, 심지어 같은 언어라도 내용에 따라 달라집니다. 코드가 많은 답변이냐 숫자가 많은 답변이냐에 따라 달랐습니다. 그래서 “대충 이 정도겠지”로 환산하면 거의 항상 어긋났습니다. 제 경우엔 그 어긋남이 8번째 문장 한복판에서 답변이 잘리는 걸로 돌아왔습니다.


시스템 점검 체크리스트

LLM 답변 길이가 마음대로 안 된다면 점검해보세요.

  • 길이 제한을 프롬프트로만 하고 있진 않은가? (max_tokens가 진짜 천장이다)
  • 문장이 중간에 잘린다면 → max_tokens 한도에 걸린 건 아닌가?
  • 토큰↔글자 비율을 추정으로 환산하고 있진 않은가? (실측 필수)
  • 다루는 언어의 토큰 비율을 아는가? (한글은 대략 1토큰 ≈ 1.7자)
  • 길이 조절을 프롬프트 강제 + retry로 우회하느라 비용을 낭비하고 있진 않은가?

마무리

“왜 시키는 대로 글자 수를 안 줄이지?”라고 모델을 탓하던 시간이 꽤 길었습니다. 알고 보니 모델은 처음부터 글자 수라는 개념으로 일하지 않았습니다. 토큰으로 세고 있었고, 저만 글자로 말하고 있었습니다.

개인 프로젝트라 이렇게 며칠씩 한 군데서 데일 수 있었던 것 같습니다. 회사 일이었으면 누가 옆에서 “그거 max_tokens 문제 아니야?” 한마디 해줬을 텐데, 혼자 만드니까 프롬프트만 붙들고 있었던 겁니다.

그래도 한 번 실측해서 1토큰 ≈ 1.7자로 박아두니, 그 뒤로 길이 관련해서 다시 데인 적은 없습니다. 추정값 주석을 믿었던 게 제일 크게 물렸던 부분이라, 지금은 새 기능 만들 때 토큰 비율은 무조건 한 번 돌려보고 숫자를 확정합니다.





참고 :

Anthropic Docs - Token counting
Anthropic Docs - Models & max_tokens




읽어주셔서 감사합니다.🖐


Ramsbaby
Written byRamsbaby
이 블로그는 직접 개발/운영하는 블로그이므로 당신을 불쾌하게 만드는 불필요한 광고가 없습니다.

#My Github#소개 페이지#Blog OpenSource Github#Blog OpenSource Demo Site