
GPT-4 API를 실무에 연결한 첫 달, 예상의 세 배에 가까운 청구서를 받았습니다. 원인은 단 하나였습니다. 매 요청마다 길게 늘어뜨린 역할 지정 문장이었고, 두 달 만에 비용을 41% 줄인 건 프롬프트 길이를 다듬은 것 외에 아무것도 하지 않아서였습니다.
토큰 비용을 낭비하는 프롬프트의 구조
토큰(token)이란 LLM이 텍스트를 처리하는 최소 단위입니다. 한국어 한 글자가 하나의 토큰이 되기도 하고, 영어 단어 하나가 여러 토큰으로 쪼개지기도 합니다. API 비용은 이 토큰 수에 비례해서 청구됩니다. 처음에는 이 구조를 제대로 몰랐습니다.
제가 쓰던 프롬프트는 이런 식이었습니다. "당신은 10년 경력의 시니어 개발자입니다. 항상 친절하고 정확하게 답변하며, 한국어로 응답하고, 코드는 실행 가능하게 작성하며, 설명은 간결하게 해주십시오." 이게 매 요청마다 앞에 붙었습니다. OpenAI Tokenizer(출처: OpenAI)에 직접 붙여넣어 보니 예상의 두 배가 넘는 토큰을 쓰고 있었습니다. 여기서 Tokenizer란 내가 작성한 프롬프트가 실제로 몇 개의 토큰으로 분해되는지 시각적으로 확인할 수 있는 OpenAI 공식 도구입니다.
문제는 그 문장들이 결과에 거의 기여하지 않는다는 점이었습니다. "10년 경력 시니어 개발자처럼 답변하라"를 "시니어 개발자 관점으로"로 줄였더니 토큰이 줄었고, 응답 품질은 달라지지 않았습니다. 문어체도 마찬가지였습니다. "이 코드를 최적화하여 실행 속도를 향상시켜 주시기 바랍니다"를 "이 코드 최적화해줘"로 바꿔도 결과는 같았습니다. AI한테 공손하게 말할 필요가 없다는 걸 그때 처음 실감했습니다.
더 큰 문제는 불필요한 컨텍스트(context)였습니다. 컨텍스트란 모델이 응답을 생성할 때 참고하는 배경 정보 전체를 뜻합니다. "우리 팀은 이런저런 상황이고 이 프로젝트는 어쩌다 시작됐으며..."로 시작하는 배경 설명이 항상 앞에 붙어 있었습니다. 잘라내고 나서야 알았습니다. 모델이 필요한 건 상황 설명이 아니라 입력 조건과 출력 형식이라는 걸. 두 달 후 비용이 41% 줄었고, 작업량은 동일했습니다.
프롬프트를 최적화할 때 실질적으로 줄일 수 있는 요소를 정리하면 다음과 같습니다.
- 매 요청마다 반복되는 역할 지정 문장 → 시스템 프롬프트로 분리하거나 핵심만 남기기
- 존댓말·겸양 표현 → 간결한 명령형으로 교체
- 무관한 배경 스토리 → 입력값과 원하는 출력 형식만 명시
- 중복 조건 나열 → 같은 말을 다른 표현으로 반복하는 구조 제거
컨텍스트 압축과 품질 사이의 균형
프롬프트를 무조건 짧게 써야 좋다는 생각은 위험합니다. 제가 직접 실험해봤는데, 지나치게 줄이면 모델이 맥락을 파악하지 못하고 엉뚱한 방향으로 응답을 생성합니다. 다이어트처럼 적정 수준이 있고, 굶는 건 안 됩니다.
여기서 핵심은 로스트 인 더 미들(Lost in the Middle) 현상입니다. 이는 모델이 긴 프롬프트를 처리할 때 중간에 위치한 정보를 상대적으로 덜 반영하는 경향을 뜻합니다. 프롬프트 앞뒤는 잘 읽히지만 중간은 흐릿해지는 구조입니다. Lilian Weng의 프롬프트 엔지니어링 정리(출처: Lilian Weng Blog)에서도 이 현상을 학술적 근거와 함께 다루고 있는데, 실무에서 제가 경험한 것과 정확히 일치했습니다. 중요한 조건을 프롬프트 중간에 넣었더니 무시되는 경우가 실제로 있었습니다.
이 문제를 해결하는 방식은 두 가지입니다. 첫째는 핵심 조건을 프롬프트 앞이나 뒤에 배치하는 것이고, 둘째는 시스템 프롬프트(system prompt)와 사용자 메시지(user message)를 구조적으로 분리하는 것입니다. 시스템 프롬프트란 모델의 역할과 행동 방식을 사전에 정의하는 영역으로, 매 요청마다 반복되는 고정 지시사항을 여기에 몰아넣으면 토큰 낭비 없이 일관된 응답을 받을 수 있습니다. 이 구조는 Anthropic의 Claude 프롬프트 엔지니어링 공식 문서에서도 권장하는 방식입니다.
일반적으로 프롬프트가 길수록 결과가 좋다는 인식도 있는데, 저는 이게 반쪽만 맞는 말이라고 봅니다. 블로그나 커뮤니티에서 유행하는 "슈퍼 프롬프트"류 수백 줄짜리 구성은 실제로 써보면 비용만 높이고 결과는 비슷하거나 오히려 나쁠 때가 많습니다. 맥락을 풍부하게 주는 것과 군더더기를 쌓는 것은 다릅니다. 전자는 필요하고, 후자는 낭비입니다.
퓨샷 프롬프팅(few-shot prompting)은 이 균형을 잘 보여주는 기법입니다. 퓨샷 프롬프팅이란 모델에게 원하는 입출력 형식의 예시를 몇 가지 보여줌으로써 응답 패턴을 유도하는 방식입니다. 배경 설명 두 문단보다 예시 두 개가 훨씬 효과적인 경우가 많았습니다. 같은 결과를 더 적은 토큰으로 얻을 수 있는 전형적인 방법입니다.
프롬프트 최적화에서 놓치기 쉬운 포인트를 정리하면 이렇습니다.
- 중요한 조건은 프롬프트 앞 또는 끝에 배치할 것
- 역할 지정은 시스템 프롬프트에 한 번만 고정
- 배경 설명 대신 예시(few-shot)로 형식을 전달
- Tokenizer로 실제 토큰 수를 직접 확인한 뒤 줄이기
결국 프롬프트 최적화는 절약이 목적이 아닙니다. 최소한의 토큰으로 원하는 결과를 안정적으로 얻는 것이 목적입니다. 토큰을 아끼려다 맥락을 너무 줄이면 결과가 무너집니다. 반대로 군더더기를 방치하면 비용이 쌓이고 중요한 조건이 묻힙니다. 직접 써보고, Tokenizer로 확인하고, 결과를 비교하는 반복이 제일 확실합니다. 프롬프트는 한 번 잘 짜두면 이후에 계속 이득을 봅니다.
참고:
OpenAI 프롬프트 엔지니어링 공식 가이드 https://platform.openai.com/docs/guides/prompt-engineering
OpenAI Tokenizer 도구 https://platform.openai.com/tokenizer
Anthropic 프롬프트 엔지니어링 문서 https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview
Lilian Weng - Prompt Engineering 논문 정리 https://lilianweng.github.io/posts/2023-03-15-prompt-engineering/
OpenAI API 비용 계산 문서 https://openai.com/api/pricing