왜 길이 제어가 어려운가
LLM은 토큰을 순차 생성하며 "정확히 500자"를 세면서 멈추지 않는다. 학습 데이터의 분포와 문장 종결 확률에 따라 길이가 결정되기 때문에, 프롬프트에 "500자로"라고 적어도 실제 출력은 300~900자로 넓게 흔들린다. 게다가 토큰과 글자 수는 1:1이 아니다. 한국어는 대략 1토큰이 1~2글자, 영어는 1토큰이 3~4글자에 해당해 max_tokens만으로 목표 길이를 맞추면 문장이 중간에 잘린다.
세 가지 제어 축
길이 제어는 성격이 다른 세 축을 구분해야 한다. 각각 실패 양상이 다르다.
| 방식 | 동작 | 한계 |
|---|---|---|
| max_tokens | 하드 컷 | 문장 중간 절단 |
| 프롬프트 지시 | 확률적 유도 | 편차 큼 |
| stop 시퀀스 | 구조 경계에서 종료 | 경계 설계 필요 |
실무에서는 세 축을 조합한다. 프롬프트로 목표를 유도하고, max_tokens로 상한을 걸어 비용을 방어하며, 구조화 출력에서는 stop으로 깔끔하게 끊는다.
프롬프트로 목표 길이 유도하기
모델은 추상적 글자 수보다 구체적 형식 제약을 잘 따른다. "간결하게"보다 "3개 항목, 각 1문장"이 편차가 작다. 목표를 구조로 환산해 지시하는 편이 안정적이다.
SYSTEM = """다음 제약을 반드시 지켜라.
- 정확히 3개의 불릿, 각 불릿은 한 문장.
- 각 문장은 40자 이내.
- 서론/맺음말 없이 불릿만 출력."""
글자 수를 직접 지정할 때는 범위로 주고 여유를 둔다. "약 400~500자"가 "500자"보다 실제 분포를 좁힌다. 하한을 명시하면 지나치게 짧아지는 문제도 함께 억제된다.
토큰 예산 계산과 max_tokens
목표 글자 수를 토큰으로 환산해 상한을 설정한다. 한국어 기준 안전 계수를 넉넉히 잡아야 종결부가 잘리지 않는다. 목표보다 20~30% 여유를 두고, 실제 컷은 프롬프트 지시가 담당하게 한다.
def token_budget(target_chars, lang="ko", margin=1.3):
# 경험적 글자/토큰 비율
ratio = 1.6 if lang == "ko" else 4.0
tokens = int(target_chars / ratio * margin)
return max(64, tokens)
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=token_budget(500, "ko"), # 상한 방어용
system=SYSTEM,
messages=[{"role": "user", "content": user_input}],
)
max_tokens는 품질 제어가 아니라 비용·지연 상한이라는 점을 기억한다. 이 값에 의존해 길이를 맞추면 반드시 문장이 잘린다.
후처리로 목표에 수렴시키기
단발 호출로 안 맞으면 검증 후 재요청하는 루프가 확실하다. 초과분은 요약, 부족분은 확장으로 유도하되 재시도 횟수를 제한해 비용 폭주를 막는다.
def fit_length(gen, text, lo=400, hi=500, tries=2):
for _ in range(tries):
n = len(text)
if lo <= n <= hi:
return text
hint = ("더 압축, 핵심만." if n > hi
else "구체 예시 1개 추가.")
text = gen(text, hint)
return text[:hi] # 최종 안전장치
문장 경계를 지키며 자르려면 단순 슬라이싱 대신 마지막 종결 부호까지만 남기는 방식을 쓴다. 절단은 최후 수단이다.
스트리밍 환경의 주의점
스트리밍에서는 응답이 완결되기 전에 사용자에게 노출되므로 후처리 재요청이 부자연스럽다. 이때는 프롬프트 유도와 토큰 예산에 더 무게를 두고, 재요청 대신 첫 시도의 성공률을 높이는 데 집중한다. 실측 길이 분포를 로깅해 계수를 주기적으로 보정하면 재시도율이 눈에 띄게 줄어든다.
정리
길이 제어는 단일 파라미터로 해결되지 않는다. 프롬프트로 목표를 구조화해 유도하고, max_tokens로 상한을 방어하며, 검증-재요청 루프로 수렴시키는 3단 구성이 실무의 기본형이다. 글자와 토큰의 비율은 언어·도메인마다 다르므로, 실제 출력 분포를 측정해 계수를 보정하는 과정을 운영에 포함시켜야 안정적으로 목표 길이에 도달한다.