한 문장으로 말하면: 잘 물어 확률을 당기는 기술
프롬프트 엔지니어링(prompt engineering)은 대규모 언어모델(LLM, Large Language Model)에게 원하는 결과를 얻기 위해 입력 문장, 즉 프롬프트(prompt)를 설계하고 다듬는 기술이다. 모델 자체를 다시 학습시키지 않고, 오직 건네는 말과 그 말에 곁들이는 맥락만으로 출력을 원하는 방향으로 끌고 간다.
이 정의의 핵심은 '확률'에 있다. 언어모델은 매 순간 다음에 올 후보 토큰들의 확률 막대그래프를 세우고 그중 하나를 골라 문장을 이어 붙인다. 그 확률이 어떻게 정해지느냐를 보면, 절반은 모델이 학습으로 갖춘 성질이고 나머지 절반은 우리가 방금 건넨 말이다. 같은 질문이라도 어떻게 묻느냐에 따라 막대그래프의 모양이 달라진다.
그래서 프롬프트 엔지니어링을 한 문장으로 다시 옮기면 이렇다. 애초에 잘 물어, 원하는 답이 나올 확률을 우리 쪽으로 당기는 일이다. 마법 주문을 외우는 게 아니라, 모델이 이미 가진 능력을 정확히 겨냥해 꺼내는 작업에 가깝다.

설계된 게 아니라 발견된 것 — 요리에 가까운 기술
프롬프트 기법을 이해할 때 가장 먼저 못 박아야 할 관점이 하나 있다. 이 기법들은 누군가 책상에서 이론으로 설계한 게 아니라, 실제로 써 보며 발견한 것이라는 사실이다. 보통의 공학은 원리를 먼저 세우고 그에 맞춰 도구를 만든다. 물리학에 가깝다.
프롬프트 기법의 역사는 정반대로 흘렀다. 거대한 예측 기계가 먼저 세상에 나왔고, 수많은 사람이 그 기계를 이리저리 써 보며 '이렇게 물으니 더 잘하더라'를 하나씩 캐냈다. 요리나 원예에 가깝다. 해 보고, 되는 걸 남긴다.
이 관점을 잡으면 뒤에 나올 모든 기법이 한 줄기로 꿰인다. zero-shot에서 few-shot으로, 다시 생각의 사슬(CoT)과 ReAct로 넘어가는 흐름은 각 기법이 앞선 기법의 한계에서 자라난 결과다. 그리고 그 방향은 모두 하나를 가리킨다. 모델이 스스로 더 많이 생각하고, 더 많이 행동하게 만드는 쪽이다.
실무자에게 이 프레임이 중요한 이유가 있다. 프롬프트에 정답 공식은 없다. 도메인과 모델, 과제가 바뀌면 잘 통하던 프롬프트도 흔들린다. 그러니 '한 번 만든 마법 문장'을 붙잡기보다, 계속 실험하고 개선하는 태도가 본질에 맞다.
그냥 시키기, zero-shot의 힘과 한계
가장 단순한 방식은 그냥 시키는 것이다. 예시도 요령도 없이 원하는 일을 말로 지시한다. 이것을 제로샷(zero-shot)이라 부른다. 여기서 '샷(shot)'은 모델에게 미리 보여 주는 예시의 개수를 뜻한다. 예시를 하나도 안 주니 제로샷이다.
놀랍게도 제로샷은 상당히 잘 통한다. '이 문단을 세 줄로 요약해줘', '이 문장을 영어로 옮겨줘', '회의록에서 할 일만 뽑아줘' 같은 지시는 예시 없이도 대체로 원하는 답을 준다. 사실 챗봇에 던지는 질문 대부분이 제로샷이다. 우리가 평소 쓰는 그 방식이다.
그런데 일이 까다로워지면 결과가 들쭉날쭉해진다. 특히 흔들리는 건 형식이다. '긍정인지 부정인지만 답해'라고 했는데 장황한 설명을 늘어놓거나, 표로 달라고 했는데 문장으로 답한다. 지시만으로는 우리가 머릿속에 그린 결과 모습을 모델이 정확히 맞추지 못한다.
제로샷의 이 한계가 다음 방법을 불렀다. 말로 아무리 설명해도 안 통할 때, 차라리 원하는 모습을 직접 보여 주면 어떨까. 여기서 예시를 곁들이는 기법이 등장한다.
예시가 패턴을 세운다 — few-shot과 문맥 속 학습

제로샷의 한계를 메운 발견은 단순하다. 말로 설명하지 말고, 예시를 몇 개 보여 주는 것이다. 예시를 몇 개 주면 퓨샷(few-shot), 딱 하나면 원샷(one-shot)이다. 고객 리뷰를 긍정·부정으로 나누는 과제로 차이를 보면 분명하다.
제로샷으로 '다음 리뷰가 긍정인지 부정인지 판단해줘'라고만 하면 어떤 때는 '긍정', 어떤 때는 '긍정입니다, 왜냐하면…' 하고 형식이 흔들린다. 반면 few-shot은 앞에 본보기를 깔아 준다. '리뷰: "포장이 꼼꼼했다." → 긍정 / 리뷰: "두 번이나 환불받았다." → 부정' 같은 예시 몇 줄을 먼저 놓고, 마지막에 판단할 리뷰만 남겨 두면 모델은 앞 예시들이 세운 틀을 이어받아 '긍정' 한 단어만 내놓는다.
여기서 핵심은 예시가 답의 내용만이 아니라 형식까지 지정했다는 점이다. 원하는 모습 자체를 몇 번 보여 주니 모델이 그 모습을 따라 그린다. 특히 애매한 경계 사례(예: '배송은 느렸지만 물건은 마음에 든다')를 판단할 때, 앞선 예시들이 판단 기준까지 함께 세워 준다.
왜 예시 몇 개가 이토록 힘이 셀까. 이 기계의 본업이 '이런 흐름 다음엔 이런 것이 온다'를 잇는 일이기 때문이다. 예시는 '이런 흐름'을 눈앞에 직접 깔아 주는 작업이다. 그러면 모델은 자기가 가장 잘하는 일, 곧 깔린 패턴을 이어 가기만 하면 된다. 이렇게 주어진 문맥 안의 예시만으로 그 자리에서 요령을 잡는 능력을 문맥 속 학습(in-context learning)이라 부른다. GPT-3를 소개한 논문 제목이 그대로 'Language Models are Few-Shot Learners'였다.
한 가지 오해를 여기서 바로잡아야 한다. few-shot은 모델을 영구히 똑똑하게 만드는 게 아니다. 건넨 예시는 오직 이번 대화에서만 힘을 발휘한다. 모델 내부를 다시 학습시키는 파인튜닝(fine-tuning)과는 전혀 다르다. 이미 가진 패턴 잇기 능력에 정확한 본보기를 깔아 주는 것뿐이다. 그래서 예시의 질이 곧 답의 질을 좌우한다.
생각을 소리 내게 하기 — 생각의 사슬(CoT)과 그 확장
분류나 요약을 넘어 여러 단계의 추론이 필요한 문제로 넘어가면 예시만으로도 부족해진다. 수학 문장제나 논리 퍼즐에서 모델이 곧장 답만 뱉으면 자주 틀린다. 여기서 나온 발견이 생각의 사슬(Chain-of-Thought, CoT) 프롬프팅이다. 모델에게 답을 바로 내지 말고 풀이 과정을 단계별로 적으라고 시키는 것이다.
방법은 의외로 단순하다. '단계별로 생각해 보자(Let's think step by step)'라는 한 문장을 붙이거나, 풀이 과정이 적힌 예시를 몇 개 보여 주면 된다. 그러면 모델은 중간 계산과 근거를 문장으로 풀어 놓고, 그 위에서 최종 답을 낸다. 왜 통할까. 언어모델은 자기회귀(autoregressive) 방식으로 한 토큰씩 이어 쓴다. 앞서 써 둔 추론 과정이 그다음 토큰의 확률을 좋은 쪽으로 밀어 준다. 스스로 만든 문장이 다음 단계의 발판이 되는 셈이다.
CoT에서 갈라져 나온 확장들도 같은 방향을 가리킨다. 자기 일관성(self-consistency)은 추론 경로를 여러 번 뽑아 가장 많이 나온 답을 채택해 정확도를 높인다. 생각의 나무(Tree of Thoughts, ToT)는 한 줄기 사슬 대신 여러 갈래로 생각을 뻗고 유망한 가지를 골라 탐색한다. 어려운 문제를 여러 방향으로 두드려 보고 되는 길을 남기는 방식이다.
다시 강조하면 이 모든 기법의 방향은 하나다. 모델이 스스로 더 생각하게 만드는 것. zero-shot에서 few-shot으로, CoT에서 ToT로 이어지는 진화는 그 축 위에 놓여 있다.

생각에 행동을 더하다 — ReAct와 도구 사용
생각만으로는 넘을 수 없는 벽이 있다. 모델은 자기가 학습한 시점까지의 지식만 갖고 있고, 최신 정보나 실시간 데이터는 알지 못한다. 여기서 나온 발견이 ReAct(Reasoning + Acting)다. 이름 그대로 추론(Reasoning)과 행동(Acting)을 번갈아 엮는다.
ReAct의 흐름은 이렇다. 모델이 먼저 '무엇을 알아야 하나'를 생각하고(Reason), 검색이나 계산 같은 도구를 호출해 행동하고(Act), 그 결과를 관찰(Observe)한 뒤 다시 생각으로 돌아온다. 이 순환을 답이 나올 때까지 반복한다. 예컨대 '오늘 서울 날씨에 맞춰 옷을 추천해줘'라는 요청이면, 모델은 날씨 조회 도구를 부르고, 돌아온 결과를 근거로 추천을 완성한다.
ReAct는 오늘날 AI 에이전트(agent)의 뼈대에 해당한다. 검색, 코드 실행, 데이터베이스 조회 같은 외부 도구와 언어모델을 연결하는 구조가 여기서 나왔다. 프롬프트가 단순한 '한 줄 주문'을 넘어, 모델이 스스로 행동을 계획하고 실행하는 절차로 확장된 것이다.
정리하면 프롬프트 기법의 무게중심은 점점 옮겨 왔다. '어떻게 한 문장으로 잘 시키나'에서 '무엇을 모델 곁에 놓아 스스로 생각하고 행동하게 하나'로. 이 흐름의 다음 자리에 컨텍스트 엔지니어링이 있다.
디코딩 파라미터로 확률의 결을 조절하기
프롬프트 문장 못지않게 출력을 좌우하는 게 디코딩(decoding) 설정이다. 모델이 세운 확률 막대그래프에서 어떻게 다음 토큰을 고르느냐를 정하는 손잡이들이다. 프롬프트 엔지니어링을 실무에 쓸 때 반드시 함께 다뤄야 한다.
가장 널리 쓰는 손잡이가 온도(temperature)다. 값이 낮으면(예: 0에 가까움) 확률이 높은 토큰에 답이 몰려 결과가 일관되고 안정적이다. 값이 높으면 확률 막대가 평평해져 덜 뻔하고 다양한 답이 나온다. 사실 확인이나 분류처럼 정확성이 중요한 일은 낮게, 창작이나 브레인스토밍은 조금 높게 두는 편이 맞다.
후보를 잘라 내는 방식도 있다. top-k는 확률 상위 k개 토큰만 후보로 남긴다. top-p(누적 확률 샘플링, nucleus sampling)는 확률을 큰 순서로 더해 누적값이 p에 이를 때까지의 토큰만 남긴다. 둘 다 엉뚱하고 확률 낮은 토큰이 튀어나오는 걸 막으면서도 적당한 다양성을 지키는 장치다.
아래 표에 자주 쓰는 설정을 정리했다. 프롬프트를 아무리 잘 짜도 디코딩 설정이 과제와 어긋나면 결과가 어긋난다. 둘을 한 세트로 보는 게 실무 감각이다.
기법과 파라미터 한눈에 비교하기
지금까지 본 프롬프트 기법을 한 표로 견주면 각자의 쓰임이 또렷해진다.
| 기법 | 예시·과정 제공 | 잘 맞는 과제 | 특징 |
|---|---|---|---|
| zero-shot | 없음 | 요약·번역·간단 지시 | 가장 빠르고 간편, 형식이 흔들림 |
| few-shot | 예시 몇 개 | 분류·형식 고정 | 예시가 내용과 형식을 함께 지정 |
| CoT | 풀이 과정 유도 | 수학·논리·다단계 추론 | 중간 과정이 답의 발판 |
| ReAct | 추론+도구 호출 | 검색·계산·실시간 정보 | 에이전트의 기본 골격 |
디코딩 파라미터도 함께 보면 좋다. 프롬프트와 짝을 이뤄 출력의 성격을 정한다.
| 파라미터 | 낮을 때 | 높을 때 | 권장 상황 |
|---|---|---|---|
| temperature | 일관·안정 | 다양·창의 | 정확성엔 낮게, 창작엔 높게 |
| top-p | 후보 좁힘 | 후보 넓힘 | 안정성과 다양성의 균형 |
| top-k | 상위 소수만 | 상위 다수 | 엉뚱한 토큰 억제 |
실무에서 쓰는 법 — 구조화와 메타 프롬프팅
실무에서 프롬프트를 짤 때는 즉흥적으로 쓰기보다 구조를 잡는 게 좋다. 역할(누구로서 답할지), 과제(정확히 무엇을 할지), 맥락(어떤 배경과 자료가 있는지), 형식(어떤 모양으로 답할지), 톤(어떤 어조인지)을 나눠 명확히 지정하면 결과가 눈에 띄게 안정된다. 이런 항목을 체계화한 프레임워크가 여럿 있고, CRAFT처럼 요소별로 프롬프트를 조립하는 방식이 대표적이다.

또 하나 실전에서 유용한 기법이 메타 프롬프팅(meta prompting)이다. 프롬프트로 프롬프트를 개선하는 방법이다. 모델에게 '이 프롬프트의 약점을 지적하고 더 나은 버전으로 고쳐줘'라고 시키면, 모델이 스스로 지시를 다듬어 준다. 좋은 프롬프트를 처음부터 완벽하게 쓰려 애쓰기보다, 초안을 만들고 모델과 주고받으며 다듬는 흐름이 훨씬 효율적이다.

무게중심이 컨텍스트로 옮겨 간다는 말은 실무에서 특히 실감 난다. 지시 한 줄보다 무엇을 곁에 놓느냐가 중요해진다. 지시, 예시, 문서, 기억, 도구 — 이 다섯 조각을 어떤 순서로 배치하느냐가 답의 질을 가른다. 관련 문서를 검색해 프롬프트에 끼워 넣는 검색 증강 생성(RAG, Retrieval-Augmented Generation)이 널리 쓰이는 것도 같은 맥락이다.
흔한 오해와 한계, 그리고 프롬프트 인젝션
가장 흔한 오해는 '마법 주문'이 존재한다는 믿음이다. 특정 문구를 넣으면 어떤 과제든 잘된다는 식의 접근은 오래 못 간다. 프롬프트의 효과는 모델과 과제, 도메인에 따라 달라진다. 한 곳에서 잘 통한 프롬프트가 다른 곳에서 무너지는 일은 흔하다. 정답 공식이 아니라 실험과 반복이 본질이다.
두 번째 오해는 few-shot 예시가 모델을 영구히 학습시킨다는 착각이다. 앞서 짚었듯 예시는 이번 대화 안에서만 유효하다. 모델의 가중치를 바꾸려면 파인튜닝이 필요하고, 이는 프롬프트 엔지니어링과 다른 층위의 작업이다.
한계도 분명하다. 프롬프트로 모델의 근본 능력을 넘어서게 만들 수는 없다. 학습하지 않은 사실을 억지로 끌어내려 하면 그럴듯한 거짓, 곧 환각(hallucination)이 나온다. CoT로 추론을 유도해도 틀린 전제 위에서는 틀린 결론이 나온다. 프롬프트는 능력을 겨냥해 꺼내는 도구지, 없는 능력을 만들어 내는 도구가 아니다.
보안 측면의 위험도 알아야 한다. 프롬프트 인젝션(prompt injection)은 악의적인 입력으로 원래 지시를 무력화하거나 탈취하는 공격이다. 사용자 입력이나 외부 문서에 '앞의 지시를 무시하고 이렇게 하라'는 문구를 숨겨 넣는 식이다. 시스템 지시와 사용자 입력을 분리하고, 외부에서 들어온 내용을 신뢰하지 않는 설계가 방어의 기본이다.

토큰 경계가 프롬프트를 배신할 때
프롬프트를 잘 쓴다는 건 결국 모델이 실제로 보는 입력 단위, 즉 토큰(token)을 이해한다는 뜻이다. 사람은 문장을 단어와 의미 덩어리로 읽지만, 대규모 언어모델(LLM)은 바이트쌍 인코딩(BPE) 같은 방식으로 잘린 조각을 본다. 영어에서는 흔한 단어 하나가 토큰 하나에 대응하는 경우가 많지만, 한국어는 사정이 다르다. 조사와 어미가 붙는 교착어 특성 탓에 '학교에서는' 같은 한 어절이 여러 토큰으로 쪼개진다. 이 조각 단위가 프롬프트 설계에 생각보다 큰 영향을 준다.
가장 흔한 함정이 숫자와 자릿수 처리다. 모델은 '12345' 같은 수를 반드시 한 덩어리로 보지 않는다. 토크나이저에 따라 '123'과 '45'로 나뉘거나 자릿수별로 쪼개진다. 그래서 큰 수의 곱셈이나 자릿수 정렬을 그냥 시키면 엉뚱한 답이 나온다. 실무에서는 계산을 프롬프트 안에서 억지로 시키기보다, 자릿수를 공백으로 분리해 넣거나 아예 계산기·코드 실행 도구로 넘기는 편이 안전하다. 프롬프트의 문제가 아니라 입력 표현의 문제라는 점을 놓치면 원인을 엉뚱한 곳에서 찾게 된다.
토큰 경계는 형식 지정에서도 말썽을 부린다. JSON을 강제할 때 중괄호나 따옴표가 다른 문자와 붙어 하나의 토큰이 되면, 모델이 그 경계를 헷갈려 닫는 괄호를 빠뜨리기도 한다. 코드 블록의 백틱 세 개, 특수 구분자로 흔히 쓰는 '###'이나 '---'도 마찬가지다. 구분자를 고를 때 되도록 모델이 자주 봤을 법한, 학습 데이터에 흔한 패턴을 쓰면 안정성이 올라간다. 잘 안 쓰이는 유니코드 기호를 구분자로 넣으면 오히려 토큰이 지저분하게 쪼개져 역효과가 난다.
토큰 수는 비용과 속도에도 직결된다. 같은 뜻을 담아도 장황한 지시문은 입력 토큰을 늘려 요금과 지연을 키운다. 특히 한국어 프롬프트는 같은 내용이라도 영어보다 토큰이 더 많이 나오는 경향이 있어, 반복 호출이 많은 서비스라면 지시문을 영어로 쓰고 사용자 입력만 한국어로 받는 절충안을 고려할 만하다. 다만 이건 도메인과 모델에 따라 결과가 갈리므로, 실제 토큰 수와 품질을 함께 재보고 판단해야 한다.
위치가 곧 가중치다 — 컨텍스트 배치의 기술
긴 프롬프트를 넣는다고 모든 내용이 똑같이 반영되지는 않는다. 여러 연구와 실무 경험이 공통으로 가리키는 현상이 있다. 모델은 컨텍스트의 맨 앞과 맨 뒤에 있는 정보를 잘 활용하지만, 한가운데에 묻힌 정보는 놓치기 쉽다. 흔히 '중간에서 길을 잃는다(lost in the middle)'고 부른다. 검색 증강 생성(RAG)에서 문서를 여러 개 이어 붙일 때 이 문제가 특히 두드러진다. 정답이 담긴 문서를 목록 중간에 두면, 같은 문서를 맨 앞이나 맨 뒤에 뒀을 때보다 정답률이 떨어진다.
이 특성을 알면 프롬프트 배치 전략이 달라진다. 가장 중요한 지시와 제약 조건은 시스템 프롬프트나 사용자 메시지 첫머리에 두고, 반드시 지켜야 할 출력 형식은 맨 끝에 한 번 더 짚어 주는 식으로 앞뒤를 함께 잡는다. RAG라면 관련성 점수가 높은 문서를 앞쪽과 뒤쪽에 배치하고 덜 중요한 것을 가운데 몰아넣는 재정렬(re-ranking) 후처리가 실제로 효과를 낸다. 단순히 검색 순위대로 이어 붙이는 것과 결과 차이가 꽤 크다.
왜 이런 편향이 생기는지는 자기어텐션(self-attention)의 구조와 위치 인코딩(positional encoding), 그리고 학습 데이터의 분포가 복합적으로 얽힌 결과로 본다. 문서 대부분이 앞머리에 주제를 밝히고 끝에서 결론을 맺는 형식이라, 모델도 앞뒤에 더 민감하게 반응하도록 굳어졌다는 해석이 설득력 있다. 원인이 무엇이든 실무자 입장에서는 '컨텍스트 안에서 위치는 중립이 아니다'라는 사실만 기억하면 된다.
컨텍스트 창이 넓어졌다고 이 문제가 저절로 사라지지도 않는다. 수십만 토큰을 넣을 수 있게 됐어도, 정작 필요한 근거가 어디 있느냐에 따라 성능이 출렁인다. 그래서 '많이 넣기'보다 '잘 골라 앞뒤로 배치하기'가 여전히 중요하다. 긴 컨텍스트를 채우면 채울수록 잡음도 함께 늘어난다는 점을 잊지 말아야 한다. 넣을 수 있다는 것과 넣어야 한다는 것은 다르다.
출력을 강제하는 기술 — 제약 디코딩과 스키마 고정
프롬프트로 '반드시 JSON으로만 답하라'고 아무리 강하게 지시해도, 모델은 확률적으로 다음 토큰을 고르는 기계라 가끔 설명 문장을 덧붙이거나 형식을 깨뜨린다. 자연어 지시만으로 형식을 100% 보장할 수는 없다. 그래서 등장한 것이 디코딩 단계에서 아예 규칙에 어긋나는 토큰을 확률 분포에서 제거하는 방식이다. 흔히 제약 디코딩(constrained decoding) 또는 구조화 출력(structured output)이라 부른다.
작동 원리는 직관적이다. 모델이 다음 토큰의 확률 분포를 내놓으면, 미리 정한 문법(예: JSON 스키마)에 맞지 않는 토큰의 확률을 0으로 눌러 버린다. 여는 중괄호 다음에는 문자열 키나 닫는 중괄호만 허용하고, 나머지 후보는 아예 고르지 못하게 막는 식이다. 이렇게 하면 문법적으로 항상 유효한 출력이 나온다. 정규식이나 문맥 자유 문법(CFG)으로 허용 집합을 정의하는 라이브러리들이 이미 널리 쓰인다.
이 방식은 형식 오류를 없애 주지만 공짜는 아니다. 후보 토큰을 걸러 내려면 매 스텝마다 문법 상태를 검사해야 해서 약간의 오버헤드가 붙는다. 더 미묘한 문제는 모델을 지나치게 좁은 틀에 가두면 내용의 질이 떨어질 수 있다는 점이다. 예를 들어 생각의 사슬(CoT)처럼 자유롭게 추론하는 과정을 막아 버리고 곧장 정답 필드만 채우게 강제하면, 추론이 필요한 문제에서 정확도가 오히려 내려간다. 그래서 '추론은 자유 텍스트로 하게 두고, 최종 결과만 구조화'하는 이중 단계 설계가 실무의 정석에 가깝다.
함수 호출(function calling)이나 도구 사용(tool use) 기능도 결국 이 구조화 출력의 응용이다. 모델에게 사용 가능한 함수의 이름과 인자 스키마를 주면, 모델은 자유 문장 대신 정해진 형식의 호출 명세를 뱉는다. 프롬프트 엔지니어링이 자연어 다루기에서 인터페이스 설계로 넘어가는 지점이 바로 여기다. 잘 정의된 스키마와 명확한 필드 설명이 장황한 지시문보다 훨씬 안정적으로 작동한다.
샘플링을 넘어서 — 앙상블·자기일관성·검증 루프
한 번 물어 한 번 답받는 방식은 확률적 출력의 변덕에 그대로 노출된다. 같은 프롬프트라도 온도(temperature)가 0이 아니면 호출마다 답이 달라진다. 이 변덕을 약점이 아니라 자원으로 뒤집는 기법이 자기일관성(self-consistency)이다. 같은 문제를 온도를 조금 높여 여러 번 풀게 한 뒤, 나온 답들 가운데 다수결로 최종 답을 정한다. 추론 경로는 제각각이어도 정답으로 수렴하는 경로가 여럿이면 그쪽이 정답일 확률이 높다는 발상이다.
이 방식은 특히 수학이나 논리 문제처럼 정답이 명확한 과제에서 단일 CoT보다 정확도를 끌어올린다. 대신 호출 횟수만큼 비용과 지연이 곱절로 늘어난다. 다섯 번 샘플링하면 비용도 대략 다섯 배다. 그래서 모든 요청에 무작정 쓰기보다, 오답 비용이 큰 핵심 판단에만 선택적으로 적용하는 게 현실적이다. 정답 검증이 어려운 개방형 생성(예: 글쓰기)에는 다수결이라는 개념 자체가 잘 안 맞는다는 점도 유의해야 한다.
한 걸음 더 나아가면 생성한 답을 다시 모델에게 검토시키는 검증 루프(verification loop)로 넘어간다. 초안을 만들고, 별도 프롬프트로 오류를 찾게 하고, 그 지적을 반영해 고쳐 쓰게 하는 식이다. 생성기와 비평가의 역할을 분리하면 한 번에 완성하라고 시키는 것보다 결과가 안정된다. 다만 모델이 자기 실수를 스스로 못 보는 경우도 흔해, 검증 단계에 다른 모델을 쓰거나 규칙 기반 검사(예: 코드라면 실제 실행, 수치라면 재계산)를 섞는 편이 신뢰도가 높다.
이런 다단계 구성은 사실상 프롬프트 하나가 아니라 프롬프트들의 파이프라인이다. 각 단계마다 역할, 입력, 출력 형식을 분명히 정하고, 실패 시 재시도 정책까지 설계해야 한다. 프롬프트 엔지니어링이 단발 문장 다듬기에서 워크플로 설계로 확장되는 흐름이 여기서 뚜렷하게 보인다. 아래 표는 단일 호출과 이들 다단계 기법의 성격 차이를 정리한 것이다.
다단계 기법 비교와 비용 감각
어떤 기법을 언제 쓸지는 정확도 요구와 비용 여유 사이의 저울질이다. 무조건 정교한 방식이 좋은 게 아니라, 문제 성격에 맞는 선택이 좋은 것이다. 아래 표는 대표적인 접근을 호출 횟수, 적합 과제, 주의점 기준으로 비교한다.
| 기법 | 대략적 호출 수 | 잘 맞는 과제 | 주의점 |
|---|---|---|---|
| 단일 호출 | 1회 | 단순 질의, 요약 | 출력 변덕에 취약 |
| 자기일관성 | N회(예: 3~10) | 수학·논리 등 정답형 | 비용이 N배, 개방형엔 부적합 |
| 검증 루프 | 2~3회 | 코드·사실 검증 | 자기검증 한계, 외부검사 병행 |
| 도구 사용(ReAct 계열) | 가변 | 계산·검색 필요 | 도구 오류 전파, 지연 증가 |
표에서 보듯 비용은 대체로 정확도와 맞바꾸는 관계다. 실무에서 흔한 실수는 프로토타입 단계에서 온갖 기법을 겹겹이 쌓아 놓고, 정작 운영 단계의 요금과 응답 시간을 계산하지 않는 것이다. 사용자가 1초 안에 답을 기대하는 대화형 서비스라면 다섯 번 샘플링 후 다수결은 애초에 후보가 안 된다. 반대로 야간 배치로 문서 수천 건을 정제하는 작업이라면 지연은 문제가 안 되니 정확도를 위해 호출을 늘려도 좋다.
비용 감각을 기르려면 개념 검증 단계부터 토큰 사용량과 호출 횟수를 로그로 남기는 습관이 필요하다. 어떤 프롬프트가 평균 몇 토큰을 먹고 재시도가 몇 번 일어나는지 숫자로 보면 판단이 선명해진다. 프롬프트 하나를 줄여 얻는 절감이 사소해 보여도, 하루 수백만 호출이면 이야기가 달라진다. 프롬프트 엔지니어링은 품질만이 아니라 운영 경제성까지 함께 다루는 공학이다.
재현성이라는 골칫거리 — 프롬프트를 코드처럼 관리하기
잘 만든 프롬프트도 시간이 지나면 흔들린다. 모델 제공사가 뒤에서 모델을 업데이트하면 같은 프롬프트가 어제와 다른 답을 내놓기도 한다. 온도를 0으로 낮춰도 완전한 결정성이 보장되지 않는 경우가 있어, '똑같은 입력에 똑같은 출력'이라는 소프트웨어의 상식이 여기서는 잘 안 통한다. 이 불확실성을 관리하지 못하면 어제 잘 되던 기능이 오늘 조용히 망가진다.
그래서 성숙한 팀은 프롬프트를 소스 코드와 똑같이 다룬다. 버전 관리 시스템에 프롬프트를 넣어 변경 이력을 남기고, 어떤 프롬프트가 어떤 모델 버전과 짝인지 함께 기록한다. 흔히 프롬프트옵스(PromptOps)라 부르는 흐름이다. 프롬프트를 코드에 하드코딩으로 흩뿌리지 않고 별도 파일이나 템플릿으로 분리하면, 검토와 롤백이 쉬워지고 비개발 직군도 개선에 참여할 수 있다.
변경이 개선인지 개악인지 확인하려면 평가 데이터셋이 필수다. 대표적인 입력 수십에서 수백 건과 기대 결과를 정리해 두고, 프롬프트를 바꿀 때마다 이 셋에 돌려 점수 변화를 본다. 정답이 명확한 과제는 정확도로, 개방형 과제는 채점 기준(rubric)을 만들어 다른 모델에게 채점을 맡기는 'LLM 심판(LLM-as-a-judge)' 방식을 쓴다. 감으로 '좋아진 것 같다'고 배포하는 습관은 반드시 회귀 버그를 부른다.
핵심은 프롬프트 개선을 일회성 손질이 아니라 반복 가능한 실험으로 만드는 것이다. 한 번에 한 가지만 바꾸고, 같은 평가 셋에 돌리고, 숫자로 비교하고, 기록을 남긴다. 이렇게 하면 '요리에 가까운 기술'로 시작한 프롬프트 엔지니어링이 점차 측정 가능한 공학으로 자리를 잡는다. 재현성을 포기하지 않는 태도가 프로토타입과 운영 시스템을 가르는 진짜 경계다.
더 깊이 배우려면 — 이어지는 개념들
프롬프트 엔지니어링을 제대로 이해하려면 그 아래의 원리부터 짚는 게 좋다. 토큰화(tokenization)와 임베딩(embedding), 트랜스포머(Transformer)의 자기어텐션(self-attention)이 어떻게 다음 토큰의 확률 분포를 만들어 내는지 알면, 왜 프롬프트가 그 확률을 흔들 수 있는지가 자연스럽게 보인다.
기법의 원전 논문들을 직접 읽어 보는 것도 권한다. GPT-3의 few-shot 학습을 다룬 'Language Models are Few-Shot Learners', 생각의 사슬을 제안한 'Chain-of-Thought Prompting', 추론과 행동을 엮은 'ReAct', 자기 일관성과 생각의 나무를 다룬 논문들이 오늘 흐름의 뼈대다. 실무 지침으로는 OpenAI의 프롬프트 엔지니어링 가이드가 접근하기 쉽다.
그다음 자연스럽게 이어지는 큰 주제가 컨텍스트 엔지니어링과 RAG다. 프롬프트가 '어떻게 묻나'라면, 컨텍스트 엔지니어링은 '무엇을 곁에 놓나'다. 검색으로 근거 문서를 붙이고, 대화 기억을 관리하고, 도구를 연결하는 설계가 여기에 속한다. AI 에이전트로 넘어가면 ReAct의 순환이 실제 시스템으로 구현되는 모습을 볼 수 있다.
마지막으로, 프롬프트만으로 부족할 때의 선택지도 알아 두면 좋다. 도메인 특화 성능이 필요하면 파인튜닝을, 실시간 지식이 필요하면 RAG를 검토한다. 프롬프트 엔지니어링, 컨텍스트 설계, 파인튜닝은 서로 대체하는 관계가 아니라 상황에 맞춰 조합하는 도구들이다.