테마 전환

프롬프트 엔지니어링 심화 실전: 요령에서 방법론으로

Easton editorial illustration: agent framework comparison toolbox

17번째 테스트 결과가 나왔습니다.

같은 프롬프트, 즉 “이 코드의 성능 병목을 분석하고 최적화 방안을 제안해 주세요”라는 요청에 월요일 오전 Claude는 상세하고 전문적으로 답했지만, 금요일 오후에는 두루뭉술한 말만 잔뜩 늘어놓았습니다. 다른 모델을 시험해 보니 ChatGPT는 수정이 필요한지 묻지도, 왜 고쳐야 하는지 설명하지도 않은 채 곧바로 코드를 바꿔 버렸습니다.

프롬프트의 효과는 늘 “그럭저럭 괜찮음”과 “완전히 쓸 수 없음” 사이를 오갔습니다. AI 보조 코딩이나 Agent 애플리케이션을 만들 때 이런 불안정성은 골칫거리입니다. 그러다 한 가지 문제를 깨달았습니다. 그동안 단편적인 기법을 이어 붙여 프롬프트를 만들었을 뿐, 제대로 된 방법론을 세우려 한 적이 없었던 것입니다.

이 글에서는 바로 이 문제를 명확히 짚어 보려 합니다. “몇 가지 요령을 아는 수준”에서 “체계적인 방법론을 익히는 수준”으로 나아가기 위해 3계층 프롬프트 기술 프레임워크, Chain-of-Thought와 ReAct의 원리, 자동 최적화 도구 DSPy, 그리고 Claude와 ChatGPT에 각각 다른 프롬프트를 작성하는 방법을 살펴봅니다. 마지막으로 실무에 적용할 수 있는 평가 방법도 공유합니다. 프롬프트가 좋은지 나쁜지 알 수 없다면 최적화는 방향 없는 시행착오에 불과합니다.

왜 “요령”에서 “방법론”으로 나아가야 할까

AI에게 “단계별로 생각해 달라”고 하거나, 몇 가지 예시를 주어 따라 하게 하거나, “당신은 전문가입니다”라고 역할을 부여하는 등의 “요령”을 들어 봤을 것입니다. 이런 기법은 분명 효과가 있지만, 문제는 결과가 지나치게 불안정하다는 점입니다.

경험 의존 방식의 한계

2023년부터 2024년까지 대부분의 프롬프트 기법은 경험에 의존했습니다. 경험 의존이란 쉽게 말해 “일단 해 보는 것”입니다. 단어 몇 개를 바꾸고 실행한 뒤 결과가 좋으면 쓰고, 나쁘면 다시 고칩니다. 이 방식에는 몇 가지 뚜렷한 문제가 있습니다.

결과를 예측할 수 없습니다. 같은 프롬프트도 모델이 바뀌면 작동하지 않을 수 있습니다. 같은 모델조차 호출 시점에 따라 출력 품질이 크게 달라지기도 합니다. 저를 포함해 많은 사람이 몇 시간 동안 프롬프트를 조정한 뒤, 다음 날 어제 잘되던 버전이 다시 나빠진 일을 겪습니다.

재현하고 전수하기 어렵습니다. 훌륭한 프롬프트를 만들었는데도 동료가 사용하면 결과가 다릅니다. 프롬프트 안에 자신도 미처 의식하지 못한 컨텍스트, 예를 들어 이전에 모델과 나눈 대화나 자신의 글쓰기 습관 등이 숨어 있을 수 있기 때문입니다. 이런 요소는 문서에 담기 어려워 다른 사람이 결과를 재현할 수 없습니다.

평가 기준이 없습니다. 프롬프트가 좋은지 나쁜지는 어떻게 알 수 있을까요? 많은 경우 느낌에 의존합니다. “이번 출력은 괜찮아 보인다”는 판단은 지나치게 주관적입니다. 정량 지표가 없으면 체계적으로 최적화할 수 없습니다.

89%
첫 시도 이해 정확도
Source: 한 핀테크 기업이 3C 공식을 도입한 후의 테스트 데이터

흥미로운 데이터가 하나 있습니다. 한 핀테크 기업은 체계적인 프롬프트 방법, 이른바 “3C 공식”인 Context, Constraint, Content를 도입하기 전 첫 시도 이해 정확도가 61%에 불과했습니다. 체계적인 프레임워크를 도입한 뒤에는 89%까지 올랐습니다. 작은 개선이 아니라 질적인 도약입니다.

2025~2026년의 전환

2025년부터 프롬프트 엔지니어링은 “수동 매개변수 조정”에서 “체계적인 엔지니어링”으로 전환하고 있습니다. 이 변화에는 세 가지 핵심 진전이 있습니다.

모듈식 설계. 프롬프트를 재사용 가능한 구성 요소로 나누고, 코드를 작성하듯 조립합니다. 매번 긴 프롬프트를 처음부터 작성하는 대신 표준 모듈 몇 개를 조합합니다. 각 구성 요소를 따로 테스트하고 최적화할 수 있어 전체 안정성이 크게 높아집니다.

자동 최적화. 사람이 직접 프롬프트를 조정하는 대신 프레임워크가 최적화합니다. DSPy는 이를 대표하는 프레임워크입니다. 작업과 평가 기준을 정의하면 자동으로 반복하면서 최적의 프롬프트 구성을 찾습니다. 핵심 철학은 “Programming, not prompting”입니다.

표준화된 평가. 정량 지표와 테스트 프레임워크를 활용하면 프롬프트의 효과를 객관적으로 측정할 수 있습니다. DeepEval, Promptfoo 같은 도구는 정확성, 일관성, 안전성, 비용 효율성 등의 평가 차원을 제공합니다. 이제 평가는 감이 아니라 데이터에 근거합니다.

솔직히 말해 이 세 가지는 제 업무 방식을 완전히 바꿨습니다. 예전의 프롬프트 조정은 “운에 맡기는 일”에 가까웠지만, 이제는 설계, 테스트, 반복 개선, 데이터 근거를 갖춘 엔지니어링에 더 가깝습니다. 이것이 “요령”에서 “방법론”으로 넘어가는 핵심 변화입니다.

3계층 프롬프트 기술 프레임워크

프롬프트 기술을 세 계층으로 나누어 이해하면 훨씬 명확해집니다. 기본 계층, 추론 계층, 시스템 계층은 각각 서로 다른 유형의 문제를 해결합니다.

기본 계층: 모델이 요청을 이해하게 하기

이 계층은 가장 기본적인 문제, 즉 모델이 원하는 내용을 출력하도록 만드는 방법을 다룹니다.

Zero-shot, 즉 제로샷 프롬프팅은 예시를 전혀 주지 않고 모델에 바로 작업을 요청하는 방식입니다. 예를 들면 다음과 같습니다.

마이크로서비스 아키텍처가 무엇인지 설명해 주세요.

간단하고 직접적이어서 쉬운 작업이나 일반 상식 질문에 적합합니다. 그러나 복잡한 작업이나 특정 형식의 출력이 필요한 경우 Zero-shot의 결과는 불안정할 때가 많습니다.

Few-shot, 즉 퓨샷 프롬프팅은 모델이 학습할 수 있도록 2~5개의 예시를 제공합니다. 제품 설명을 조금 활기찬 문체로 작성하게 하고 싶다면 다음처럼 쓸 수 있습니다.

다음 예시의 문체를 참고해 새 제품 설명을 작성해 주세요.

예시 1:
제품: 무선 블루투스 이어폰
설명: 귀에 착용하는 작은 우주. 콘서트 현장에서 듣는 듯 선명한 음질과 장거리 비행 내내 함께할 만큼 든든한 배터리를 갖췄습니다.

예시 2:
제품: 휴대용 커피 머신
설명: 카페를 배낭에 넣어 보세요. 언제 어디서나 핸드드립 스페셜티 커피를 즐기고 커피 찌꺼기까지 정교하게 제어할 수 있습니다.

이제 "스마트 보온 텀블러"의 제품 설명을 작성해 주세요.

모델은 예시의 문체를 따라 작성합니다. Few-shot의 핵심은 예시가 기대하는 출력 스타일과 일치해야 한다는 점입니다. 개수는 많을 필요가 없지만(2~5개면 충분합니다) 품질이 높아야 합니다.

Role Prompting, 즉 역할 프롬프팅은 모델에 특정 정체성을 부여합니다. 출력의 문체와 전문성을 제한하는 데 도움이 됩니다.

당신은 성능 최적화와 시스템 설계에 능숙한 10년 경력의 백엔드 아키텍트입니다.
다음 코드의 성능 문제를 분석하고 구체적인 병목과 최적화 방안을 제시해 주세요.
코드: [코드 붙여넣기]

역할을 설정하면 모델은 전문적인 관점에서 생각하고 더 구조화된 결과를 내는 경향이 있습니다. 다만 역할은 구체적이어야 합니다. “당신은 전문가입니다”보다 어떤 분야의 전문가이며 어떤 경험이 있는지를 명확히 설명하는 편이 낫습니다.

구조화된 출력은 모델이 JSON, Markdown, 표 등 특정 형식으로 답하게 하는 방법입니다. 데이터를 추출하거나 후속 시스템과 연동할 때 특히 유용합니다.

다음 텍스트에서 제품 정보를 추출해 JSON 형식으로 출력해 주세요.
{
  "product_name": "제품명",
  "price": "가격",
  "features": ["특징 목록"]
}

텍스트: [텍스트 붙여넣기]

구조화 제약을 사용하면 출력의 활용도가 크게 높아지고 후처리 작업이 줄어듭니다.

추론 계층: 모델이 “생각”하게 하기

이 계층의 기술은 모델이 요청을 이해하는 데 그치지 않고 복잡한 추론까지 수행하도록 만듭니다.

Chain-of-Thought(CoT), 즉 사고 연쇄는 모델이 추론 과정을 보여 주도록 합니다. 핵심은 모델에 곧바로 답을 내게 하지 말고 어떻게 생각했는지 먼저 설명하게 하는 것입니다.

2022년 Wei 등의 논문은 CoT가 복잡한 추론 작업의 정확도를 크게 높일 수 있음을 보여 주었습니다. 원리는 간단합니다. 복잡한 문제에는 다단계 추론이 필요하므로, 모델이 그 단계를 적도록 하면 일종의 “사고 완충 공간”이 생겨 오류가 줄어듭니다.

가장 간단한 CoT 사용법은 프롬프트 끝에 다음 문장을 덧붙이는 것입니다.

이 문제를 단계별로 생각한 다음 답을 제시해 주세요.

또는 추론 과정이 포함된 예시를 보여 주는 Few-shot CoT를 사용할 수 있습니다.

문제: 민수에게 사과 5개가 있었습니다. 지영에게 2개를 주고 나무에서 3개를 더 땄습니다. 이제 민수에게 사과가 몇 개 있나요?
추론 과정: 민수는 처음에 사과 5개를 가지고 있었습니다. 지영에게 2개를 주고 나면 5-2=3개가 남습니다. 나무에서 3개를 더 땄으므로 3+3=6개입니다.
답: 사과 6개입니다.

이제 같은 방식으로 다음 문제를 해결해 주세요. 바구니에 딸기 12개가 있습니다. 민수가 4개를 먹었고 지영이 바구니에 6개를 더 넣었습니다. 지금 바구니에는 딸기가 몇 개 있나요?

ReAct는 추론과 행동을 반복하며 모델이 생각하면서 작업을 수행하게 합니다. 흐름은 Thought(다음 단계 생각) → Action(행동 실행) → Observation(결과 관찰) → 다시 다음 단계를 생각하는 구조입니다. 외부 도구를 호출하거나 정보를 검색해야 하는 상황에 특히 적합합니다.

당신은 정보를 검색할 수 있는 도우미입니다. 다음 형식으로 질문에 답해 주세요.

Thought: [현재 해야 할 일]
Action: search("[검색 내용]")
Observation: [검색 결과]
... (답을 찾을 때까지 반복)
Final Answer: [최종 답변]

질문: 2024년 아카데미 작품상 수상작은 무엇인가요?

ReAct는 Agent 개발에서 특히 중요합니다. Agent의 핵심이 “사고-행동-피드백”의 순환이며, ReAct는 그 표준 템플릿을 제공하기 때문입니다.

Self-Consistency, 즉 자기 일관성은 모델이 같은 문제를 여러 번 추론하게 한 뒤 투표로 가장 신뢰할 만한 답을 선택합니다. 높은 정확도가 필요한 상황에 유용하지만 모델을 여러 번 호출해야 하므로 비용이 많이 듭니다.

Tree of Thoughts(ToT), 즉 사고 트리는 모델이 여러 추론 경로를 탐색한 뒤 최적의 경로를 선택하게 합니다. 창의적인 아이디어 생성이나 전략 수립처럼 복잡한 의사결정 문제에 적합합니다.

시스템 계층: 프롬프트 관리의 엔지니어링

이 계층은 단일 기술이 아니라 프롬프트 관리를 하나의 엔지니어링 체계로 바꾸는 접근입니다.

모듈식 프롬프트. 복잡한 프롬프트를 재사용 가능한 여러 모듈로 분해합니다. 예를 들어 Agent 프롬프트는 역할 설정 모듈, 작업 정의 모듈, 출력 제약 모듈, 도구 호출 모듈로 나눌 수 있습니다. 각 모듈을 독립적으로 관리하고 조합할 때 유연하게 구성합니다.

자동 최적화. DSPy 같은 프레임워크를 사용하면 프롬프트 매개변수를 직접 조정할 필요가 없습니다. 작업 시그니처와 평가 지표를 정의하면 프레임워크가 반복적으로 자동 최적화합니다. 뒤에서 자세히 살펴보겠습니다.

표준화된 평가. 테스트 세트를 준비하고 평가 지표를 정의한 뒤 일괄 테스트를 실행해 반복 단계별 점수 변화를 기록하는 평가 체계를 구축합니다. 그러면 프롬프트 최적화가 느낌이 아니라 데이터에 근거하게 됩니다.

3계층 프레임워크는 현재 문제가 어느 계층에 속하며 어떤 기술로 해결해야 하는지 판단하도록 돕습니다. 간단한 작업에는 기본 계층을, 복잡한 추론에는 추론 계층을, 시스템 구축에는 시스템 계층을 사용합니다.

Chain-of-Thought 사고 연쇄 심층 분석

사고 연쇄는 따로 자세히 다룰 가치가 있습니다. 현재 가장 성숙한 추론 강화 기술이며 사용 진입 장벽도 낮습니다. 복잡한 프레임워크 코드를 작성할 필요 없이 프롬프트에 몇 문장만 추가하면 됩니다.

Zero-shot CoT vs Few-shot CoT

두 방식은 각각 적합한 상황이 다릅니다.

Zero-shot CoT는 예시 없이 유도 문장 하나만 추가합니다. 가장 대표적인 문장은 다음과 같습니다.

Let's think step by step.

한국어로는 다음과 같이 쓸 수 있습니다.

이 문제를 단계별로 생각해 주세요.

간단하고 비용이 적게 들어 대부분의 상황에 적합합니다. 연구에 따르면 이 한 문장만 추가해도 복잡한 추론 작업의 정확도가 20~40% 향상될 수 있습니다.

Few-shot CoT는 추론 과정이 포함된 예시를 추가합니다. 예시는 “문제 → 추론 과정 → 답” 형식을 온전히 보여 줘야 합니다.

문제: 한 상점에서 상품 100개를 개당 20위안에 들여왔습니다. 첫날에는 30개를 개당 35위안에, 둘째 날에는 50개를 개당 30위안에 판매했습니다. 셋째 날에는 남은 상품을 개당 15위안으로 할인해 모두 판매했습니다. 총이익은 얼마인가요?

추론 과정:
1. 총비용 계산: 100개 × 20위안 = 2,000위안
2. 첫날 매출: 30개 × 35위안 = 1,050위안
3. 둘째 날 매출: 50개 × 30위안 = 1,500위안
4. 셋째 날 잔여 수량: 100-30-50=20개, 매출: 20개 × 15위안 = 300위안
5. 총매출: 1,050+1,500+300 = 2,850위안
6. 총이익: 2,850-2,000 = 850위안

답: 850위안

이제 같은 방식으로 해결해 주세요.
문제: 한 회사에 직원 200명이 있고 평균 월급은 8,000위안입니다. 연초에 직원 30명을 감원하고 1인당 2개월 치 급여를 보상금으로 지급했습니다. 감원 후 신입 직원 50명을 채용했으며 수습 기간 3개월 동안 월급은 6,000위안입니다. 올해 회사의 급여 지출은 어떻게 변했나요?

Few-shot CoT는 모델을 특정 추론 형식과 사고방식으로 유도할 수 있습니다. 다만 고품질 예시를 작성하는 데 시간이 필요합니다. 예시가 좋지 않으면 오히려 모델을 잘못된 방향으로 이끌 수 있습니다.

어떤 방식을 언제 사용해야 할까요?

  • 작업이 간단하고 추론 경로가 명확한 경우: Zero-shot CoT를 사용하고 유도 문장 하나만 추가하면 충분합니다.
  • 작업이 복잡하고 특정 추론 형식이 필요한 경우: Few-shot CoT를 사용하고 좋은 예시를 몇 개 제공합니다.
  • 모델의 역량이 강한 경우(예: Claude 4): 대체로 Zero-shot CoT만으로 충분합니다.
  • 모델의 역량이 평범하고 정확도가 중요한 경우: Few-shot CoT가 더 안정적입니다.

CoT에 적합한 상황

모든 작업에 CoT가 필요한 것은 아닙니다. 다음과 같은 상황에 가장 적합합니다.

수학적 추론과 논리 분석. 이런 작업은 여러 단계의 계산이나 논리 전개가 필요합니다. CoT는 모델이 단계를 건너뛰거나 빠뜨리지 않도록 합니다.

# CoT를 사용하지 않은 출력 예시:
"답은 850위안입니다."(중간 과정을 건너뛰어 계산이 틀릴 수 있음)

# CoT를 사용한 출력:
"단계별로 계산해 보겠습니다..."
이어서 각 단계를 자세히 보여 줍니다.

다단계 작업 계획. 모델에 프로젝트 계획을 세우거나 시스템 아키텍처를 설계하게 할 때 CoT를 사용하면 먼저 작업을 분해한 뒤 단계별로 전개할 수 있습니다.

코드 생성 과정의 문제 분석. 곧바로 코드를 출력하게 하지 말고 요구사항을 분석하고, 방안을 설계하고, 코드를 작성하도록 합니다.

다음 단계에 따라 사용자 인증 시스템을 구현해 주세요.

1단계: 요구사항을 분석하고 핵심 기능을 나열합니다.
2단계: 데이터 모델과 인터페이스를 설계합니다.
3단계: 구체적인 구현 코드를 제시합니다.
4단계: 테스트 방안을 설명합니다.

요구사항: [요구사항 설명]

CoT의 여러 변형

Auto-CoT는 추론 연쇄를 자동으로 생성합니다. 모델이 예시의 추론 과정을 직접 만든 뒤 Few-shot 예시로 사용하는 방식입니다. 사람이 예시를 작성하는 수고를 줄일 수 있지만, 첫 추론 과정의 품질에 좌우됩니다. 첫 생성이 틀리면 이후 추론도 함께 틀릴 수 있습니다.

CoD(Chain of Debate), 즉 토론 연쇄는 두 모델 역할이 같은 문제를 두고 토론하며 서로의 추론을 반박한 뒤 최종 답을 종합하게 합니다. 복잡하거나 개방적인 문제에서 좋은 결과를 낼 수 있지만 비용이 많이 들고 오래 걸립니다.

CoT 사용 시 주의점

제가 직접 겪은 몇 가지 실수를 짚어 보겠습니다.

추론을 지나치게 강제하지 마세요. 간단한 문제에는 CoT가 필요하지 않습니다. 예를 들어 “베이징의 인구는 얼마인가요?”라는 질문에 CoT를 추가하면 출력만 장황해지고 추론 과정에서 오류가 생길 수도 있습니다. 작업에 다단계 추론이 필요한지를 기준으로 판단하세요.

예시가 작업과 맞아야 합니다. Few-shot 예시로 수학 문제를 줬는데 실제 작업이 논리 추론이라면, 모델이 논리 문제를 수학 문제처럼 풀려 할 수 있습니다. 예시 유형은 실제 작업과 일치해야 합니다.

추론 단계를 너무 길게 만들지 마세요. CoT는 정확도를 높일 수 있지만 추론 과정이 십여 단계처럼 지나치게 길면 중간에 오류가 날 수 있습니다. 매우 복잡한 문제는 먼저 모델이 문제를 나눈 뒤 각 하위 문제를 따로 처리하도록 하는 편이 좋습니다.

CoT는 전반적으로 가장 실용적인 추론 강화 기술입니다. Zero-shot과 Few-shot 두 방식을 익히고 언제 사용하고 언제 사용하지 않을지를 판단하면 프롬프트의 효과가 눈에 띄게 좋아집니다.

ReAct 프레임워크: 추론과 행동의 결합

ReAct라는 이름은 Reasoning + Acting의 줄임말입니다. 사고와 행동을 결합해 모델이 동적으로 도구를 호출하고 정보를 얻어 의사결정을 내리게 합니다. CoT가 모델에 “명확히 생각하게 하는 것”이라면 ReAct는 “생각하면서 행동하게 하는 것”입니다.

Thought → Action → Observation 순환

ReAct의 핵심은 다음과 같은 순환 구조입니다.

Thought(생각) → Action(행동) → Observation(관찰) → Thought → ...

각 순환은 문제 해결을 한 단계씩 진전시킵니다. 검색 강화 질의응답을 예로 들어 보겠습니다.

작업: 2024년 노벨 물리학상 수상자의 연구 분야를 조사합니다.

모델 실행 과정:

Thought: 먼저 2024년 노벨 물리학상 수상자가 누구인지 알아봐야 합니다.
Action: search("2024 Nobel Prize in Physics winners")
Observation: [검색 결과] 2024년 노벨 물리학상은 인공 신경망 분야에 기여한 John Hopfield와 Geoffrey Hinton에게 수여됐습니다.

Thought: 이제 수상자가 누구인지 알았으니 연구 분야를 더 조사해야 합니다.
Action: search("John Hopfield research field")
Observation: [검색 결과] John Hopfield는 Hopfield 네트워크 모델을 제안한 물리학자입니다...

Thought: 답변에 필요한 정보를 충분히 얻었습니다.
Final Answer: 2024년 노벨 물리학상 수상자 John Hopfield와 Geoffrey Hinton의 연구 분야는 인공 신경망입니다...

이 순환 구조를 통해 모델은 추론 중에 “정보를 보충”할 수 있습니다. 모르는 내용을 추측하는 대신 직접 검색합니다. CoT와의 차이는 분명합니다. CoT는 모델 내부 지식만 사용하지만 ReAct는 외부 도구를 호출해 새로운 정보를 얻을 수 있습니다.

ReAct vs CoT: 핵심 차이

구분CoTReAct
정보 출처모델 내부 지식내부 지식 + 외부 도구
추론 방식순수한 사고사고와 행동을 번갈아 수행
적합한 상황정보가 이미 충분함검색 또는 도구 호출이 필요함
구현 복잡도간단함(프롬프트 수정)복잡함(도구 통합 필요)
비용한 번 호출여러 번 호출할 수 있음

CoT는 모델에 이미 충분한 지식이 있는 수학 추론이나 논리 분석 등에 적합합니다. ReAct는 현재 정보, 데이터베이스 조회, API 호출이 필요한 상황에 더 적합합니다.

ReAct의 프롬프트 구조

표준 ReAct 프롬프트에는 다음 요소가 포함됩니다.

당신은 도구를 사용할 수 있는 지능형 도우미입니다. 다음 형식으로 작업을 완료해 주세요.

사용 가능한 도구:
- search(query): 인터넷에서 정보를 검색합니다.
- database_query(sql): 데이터베이스를 조회합니다.
- calculate(expression): 수학 계산을 수행합니다.

형식:
Thought: [현재 해야 할 일을 분석하는 사고 과정]
Action: [도구 이름과 매개변수, 예: search("검색 내용")]
Observation: [도구 실행 결과, 자동으로 입력됨]
... (Thought-Action-Observation을 여러 번 반복할 수 있음)
Final Answer: [최종 답변]

시작합니다!

작업: [구체적인 작업]

핵심 포인트는 다음과 같습니다.

사용 가능한 도구를 정의합니다. 모델이 어떤 도구를 어떻게 호출할 수 있는지 알려 줍니다. 도구 정의에는 이름, 매개변수 형식, 반환 유형을 구체적으로 적어야 합니다.

출력 형식을 규정합니다. Thought, Action, Observation의 형식을 명확히 해야 시스템이 모델의 출력을 파싱하고 도구를 실행한 뒤 결과를 다시 모델에 전달할 수 있습니다.

종료 조건을 정합니다. 충분한 정보를 얻었을 때 Final Answer를 출력하도록 해 무한 반복을 방지합니다.

Agent 개발에서 ReAct 활용하기

ReAct는 현대 Agent 아키텍처의 기본 패턴 중 하나입니다. 고객 서비스 봇, 데이터 분석 도우미, 자동 운영 시스템 등 어떤 AI Agent를 만들든 ReAct의 사고방식을 사용할 가능성이 큽니다.

실제 프로젝트에서 ReAct 구현은 위의 간단한 프롬프트보다 복잡합니다. 다음 요소가 필요합니다.

  1. 도구 등록 시스템: 도구 인터페이스, 매개변수 검증, 권한 제어를 정의합니다.
  2. 실행 엔진: 모델의 Action 출력을 파싱하고 해당 도구를 호출한 뒤 결과를 형식화해 모델에 다시 전달합니다.
  3. 순환 제어: 최대 반복 횟수와 타임아웃을 설정해 무한 루프를 방지합니다.
  4. 오류 처리: 도구 호출이 실패하면 모델에 상황을 알리고 전략을 조정하게 합니다.

ReAct 사용 시 주의점

모델의 역량이 충분해야 합니다. ReAct는 모델이 여러 대화 차례에 걸쳐 컨텍스트를 유지하고 합리적인 행동을 선택해야 합니다. 역량이 부족한 모델은 도구를 엉뚱하게 호출하거나 작업 목표에서 벗어나기 쉽습니다. Claude와 GPT-4 계열 모델은 ReAct에서 비교적 좋은 성능을 보입니다.

도구 정의가 명확해야 합니다. 어떤 도구가 무엇을 할 수 있는지 모델이 모르면 호출하지 않거나 잘못된 방법으로 호출할 수 있습니다. 각 도구의 설명을 API 문서처럼 자세히 작성해야 합니다.

도구에 지나치게 의존하지 마세요. 모델 내부 지식만으로 답할 수 있는 정보까지 매번 도구를 호출할 필요는 없습니다. 프롬프트에 “내부 지식만으로 충분히 답할 수 있다면 도구를 호출하지 말고 바로 Final Answer를 출력하세요” 같은 판단 로직을 추가할 수 있습니다.

비용을 관리하세요. ReAct는 여러 차례 도구 호출을 일으켜 API 비용이 높아질 수 있습니다. 복잡한 작업에는 ReAct를 사용하고, 간단한 작업에는 일반 프롬프트를 쓰는 편이 경제적입니다.

ReAct는 프롬프트를 “정적 스크립트”에서 “동적 프로그램”으로 바꿔 AI가 실제로 문제 해결 행동을 수행하게 합니다. 이는 “대화형 AI”에서 “행동형 AI”로 나아가는 핵심 단계입니다.

DSPy: 프롬프트 자동 최적화

앞에서 살펴본 CoT와 ReAct는 모두 프롬프트를 직접 작성해야 합니다. 그러나 DSPy는 다릅니다. 핵심 철학은 “Programming, not prompting”입니다. 프로그래밍 방식으로 작업을 정의하면 프레임워크가 프롬프트를 자동으로 생성하고 최적화합니다.

DSPy란 무엇인가

DSPy는 Stanford NLP 그룹이 개발한 프레임워크입니다. 프롬프트 엔지니어링을 프로그래밍 패러다임으로 바꿉니다. 작업의 입력·출력 구조인 Signature를 정의하고, 적절한 Module을 선택하고, Optimizer를 구성하면 프레임워크가 반복적으로 최적의 프롬프트 구성을 찾습니다.

이 접근의 장점은 다음과 같습니다.

더 높은 신뢰성. 직접 작성한 프롬프트에는 누락, 잘못된 형식, 불충분한 제약이 생기기 쉽습니다. DSPy의 선언적 정의는 더 엄밀합니다.

더 나은 유지보수성. 프롬프트가 코드가 되므로 버전 관리, 단위 테스트, 지속적인 반복 개선이 가능합니다.

더 높은 이식성. 모델을 바꿀 때 프롬프트를 다시 조정할 필요가 없습니다. 프레임워크가 새 모델의 특성에 맞춰 자동으로 적응합니다.

DSPy의 핵심 구성 요소

**Signature(작업 시그니처)**는 작업의 입력과 출력 구조를 정의합니다.

import dspy

class QuestionAnswer(dspy.Signature):
    """질문에 답하고 자세히 설명합니다."""
    question = dspy.InputField(desc="사용자의 질문")
    answer = dspy.OutputField(desc="추론 과정이 포함된 자세한 답변")

Signature는 함수의 인터페이스 정의와 같습니다. 입력과 출력이 무엇이며 각 필드에 어떤 요구사항이 있는지 설명합니다. 구체적인 프롬프트 텍스트를 작성하지 않고 구조만 정의하면 됩니다.

**Module(모듈)**은 특정 프롬프트 기술을 재사용 가능한 구성 요소로 캡슐화합니다.

# 가장 기본적인 모듈: 직접 예측
qa_basic = dspy.Predict(QuestionAnswer)

# 사고 연쇄 모듈
qa_cot = dspy.ChainOfThought(QuestionAnswer)

# ReAct 모듈(도구 구성 필요)
qa_react = dspy.ReAct(QuestionAnswer, tools=[search_tool, calculator_tool])

모듈에는 프롬프트 기술이 이미 캡슐화되어 있습니다. CoT를 사용하려면 “단계별로 생각해 주세요” 같은 유도 문구를 직접 작성하지 않고 ChainOfThought 모듈을 선택하면 됩니다. 프레임워크가 모듈 유형에 맞춰 프롬프트를 자동으로 생성합니다.

**Optimizer(최적화 도구)**는 프롬프트 구성을 자동으로 최적화합니다.

from dspy.teleprompt import BootstrapFewShot

# 학습 데이터 준비
trainset = [
    dspy.Example(question="재귀란 무엇인가요?", answer="재귀는 함수가 자기 자신을 호출하는 방식입니다..."),
    dspy.Example(question="버블 정렬을 설명해 주세요.", answer="버블 정렬은 인접한 원소를 비교해 정렬합니다..."),
]

# 최적화 도구 구성
optimizer = BootstrapFewShot(max_bootstrapped_demos=3)

# 모듈 최적화
qa_optimized = optimizer.compile(qa_cot, trainset=trainset)

Optimizer는 Few-shot 예시를 자동으로 만들고 프롬프트 구조를 조정하며 반복을 통해 최적 구성을 찾습니다. 학습 데이터와 평가 기준을 제공하면 매개변수를 대신 조정해 줍니다. 모델 가중치가 아니라 프롬프트를 조정한다는 점을 제외하면 머신러닝의 학습 과정과 비슷합니다.

완전한 DSPy 예시

프로그래밍 질문에 답하는 QA 시스템을 만들어 보겠습니다.

import dspy

# 1. Signature 정의
class CodeQA(dspy.Signature):
    """프로그래밍 관련 질문에 명확한 설명과 예시로 답합니다."""
    question = dspy.InputField(desc="프로그래밍 관련 질문")
    answer = dspy.OutputField(desc="개념 설명과 코드 예시가 포함된 자세한 답변")

# 2. 언어 모델 구성
lm = dspy.LM("claude-3-5-sonnet-20241022", api_key="your_key")
dspy.settings.configure(lm=lm)

# 3. 모듈 생성(ChainOfThought로 추론 능력 추가)
qa = dspy.ChainOfThought(CodeQA)

# 4. 직접 호출
result = qa(question="Python에서 데코레이터를 어떻게 구현하나요?")
print(result.answer)

이 예시에서는 프롬프트 텍스트를 전혀 작성하지 않았습니다. ChainOfThought 모듈이 사고 연쇄 유도가 포함된 프롬프트를 자동으로 생성합니다. answer 출력에는 추론 과정과 자세한 설명이 포함됩니다.

효과를 최적화하려면 학습 데이터와 Optimizer를 추가할 수 있습니다.

# 5. 학습 데이터 준비
train_examples = [
    dspy.Example(
        question="REST API란 무엇인가요?",
        answer="REST API는 네트워크 애플리케이션 인터페이스의 설계 스타일입니다..."
    ),
    dspy.Example(
        question="Git의 브랜치 개념을 설명해 주세요.",
        answer="Git 브랜치를 사용하면 주 개발선과 분리된 독립적인 작업 흐름을 만들 수 있습니다..."
    ),
]

# 6. 평가 함수 정의
def evaluate_answer(example, pred):
    """답변에 키워드가 포함되었는지, 길이가 적절한지 확인합니다."""
    keywords = example.question.lower().split()
    has_keywords = sum(1 for k in keywords if k in pred.answer.lower()) >= 2
    length_ok = len(pred.answer) > 100
    return has_keywords and length_ok

# 7. 최적화
optimizer = BootstrapFewShot(metric=evaluate_answer, max_bootstrapped_demos=4)
qa_optimized = optimizer.compile(qa, trainset=train_examples)

# 8. 최적화된 모듈 사용
result = qa_optimized(question="Python에서 데코레이터를 어떻게 구현하나요?")

Optimizer는 학습 데이터를 바탕으로 Few-shot 예시를 자동 생성하고 프롬프트 형식을 조정해 출력 품질을 높입니다. 전체 과정에서 프롬프트를 직접 조정할 필요가 없습니다.

DSPy와 수동 프롬프트는 각각 언제 사용할까

DSPy가 만능은 아닙니다. 프레임워크가 적합한 상황이 있고 직접 작성하는 편이 나은 상황도 있습니다.

DSPy에 적합한 상황:

  • AI 애플리케이션 시스템 구축(같은 유형의 프롬프트를 여러 번 재사용해야 함)
  • 작업 구조가 명확함(입출력을 표준화해 정의할 수 있음)
  • 학습 데이터가 있음(최적화에 활용 가능)
  • 여러 모델로 이전해야 함(모델마다 성능이 다를 때 프레임워크가 자동으로 적응)
  • 프로젝트 복잡도가 높음(프롬프트가 많아 직접 관리하기 어려움)

수동 프롬프트에 적합한 상황:

  • 일회성 사용(한 번 작성하고 한 번만 사용하며 재사용할 필요가 없음)
  • 작업 구조가 모호함(입출력을 표준화하기 어려움)
  • 학습 데이터가 없음(최적화할 수 없음)
  • 빠른 프로토타입 검증(프레임워크 구성에 시간을 쓰지 않고 빠르게 시행착오를 거쳐야 함)
  • 간단한 작업(Zero-shot으로 충분하므로 프레임워크가 필요하지 않음)

제 경험상 프로젝트 단위 애플리케이션이나 장기 유지보수가 필요한 시스템에는 DSPy의 투자 대비 효과가 높습니다. 초기 구성에는 시간이 들지만 이후 반복 개선 속도가 크게 빨라집니다. 일회성 작업이나 간단한 질의에는 직접 작성한 프롬프트가 더 간편합니다.

DSPy 사용 시 주의점

평가 지표가 중요합니다. Optimizer는 평가 함수에 의존합니다. 평가 기준이 적절하지 않으면 최적화 방향도 잘못될 수 있으므로 좋은 평가 지표를 설계하는 데 시간을 들여야 합니다.

학습 데이터의 품질. BootstrapFewShot은 학습 데이터를 바탕으로 예시를 생성합니다. 데이터 품질이 낮으면 생성된 예시도 좋지 않아 결과가 오히려 나빠질 수 있습니다.

지나치게 최적화하지 마세요. 반복 횟수가 많다고 항상 좋은 것은 아닙니다. Optimizer가 학습 데이터에 “과적합”되어 새로운 문제에서 오히려 성능이 떨어질 수도 있습니다. 합리적인 최대 반복 횟수를 설정하세요.

DSPy는 프롬프트 엔지니어링의 새로운 방향, 즉 수동 조정에서 자동 최적화로의 전환을 보여 줍니다. AI 애플리케이션을 체계적으로 만들고 싶은 개발자라면 익혀 둘 가치가 있는 도구입니다.

Claude vs ChatGPT: 모델별 모범 사례

Claude와 ChatGPT는 현재 가장 대표적인 두 대규모 언어 모델입니다. 같은 프롬프트인데 왜 두 모델의 출력이 다른지, 각각 어떻게 최적화해야 하는지 묻는 사람이 많습니다. 여기서는 두 모델의 차이와 맞춤형 모범 사례를 살펴봅니다.

모델 특성 비교

먼저 핵심 차이를 정리해 보겠습니다.

구분ClaudeChatGPT(GPT-4 계열)
컨텍스트 길이200K tokens128K tokens
구조화된 출력매우 우수하며 XML/JSON을 선호양호하지만 명확한 형식 제약 필요
추론 스타일더 엄밀하고 단계가 명확함더 유연하며 때때로 단계를 건너뜀
코드 생성품질이 높고 설명이 자세함품질이 높고 창의성이 강함
창의성비교적 보수적더 창의적이고 스타일이 다양함
중국어 표현자연스럽고 유창함자연스럽고 유창함
다중 턴 대화컨텍스트 유지 능력이 강함컨텍스트 유지 능력이 강함

이 차이가 절대적인 것은 아닙니다. 버전과 작업에 따라 달라질 수 있습니다. 다만 전반적으로 Claude는 엄밀한 추론과 구조화된 출력에, ChatGPT는 유연한 창의성과 빠른 응답에 더 치우친 편입니다.

Claude 모범 사례

1. XML 태그로 구조화된 제약을 지정합니다

Claude는 XML 태그 형식을 특히 잘 이해합니다. 콘텐츠를 태그로 감싸면 출력 품질을 높일 수 있습니다.

다음 코드의 성능 문제를 분석해 주세요.

<code>
function processData(data) {
  let result = [];
  for (let i = 0; i &lt; data.length; i++) {
    result.push(transform(data[i]));
  }
  return result;
}
</code>

다음 형식으로 분석 결과를 출력해 주세요.

<analysis>
[성능 문제 분석]
</analysis>

<suggestions>
[최적화 방안]
</suggestions>

XML 태그를 사용하면 모델이 입력 내용과 출력 형식을 명확히 구분할 수 있습니다. Claude는 태그 구조를 충실히 따르므로 분석과 제안이 뒤섞이지 않습니다.

2. 역할 + 제약 + 예시 패턴을 사용합니다

Claude는 역할 설정과 제약을 매우 충실히 따릅니다. 완전한 프롬프트 구조는 다음과 같습니다.

역할 설정:
당신은 Java 백엔드 분야에서 8년 경력을 쌓은 시니어 성능 최적화 엔지니어입니다. 성능 병목을 찾아내고 실제로 적용 가능한 최적화 방안을 제시하는 데 능숙합니다.

작업 제약:
- 분석할 때 구체적인 성능 병목을 지적하세요("최적화할 수 있다"처럼 두루뭉술하게 말하지 마세요).
- 제안에는 코드 수정 예시를 포함하세요.
- 최적화에 위험이 있다면 명확히 설명하세요.

출력 예시:
<analysis>
문제: 반복문에서 객체를 자주 생성해 메모리 압력이 생길 수 있습니다.
위치: 3~5행의 for 반복문입니다.
</analysis>
<suggestions>
제안 1: 배열 크기를 미리 할당합니다.
코드: let result = new Array(data.length);
위험: 뚜렷한 위험은 없습니다.
</suggestions>

이제 다음 코드를 분석해 주세요.
[코드 붙여넣기]

이 구조는 Claude에 역할, 작업, 출력 형식을 알려 줍니다. 결과가 기대에 더 잘 맞게 됩니다.

3. 긴 컨텍스트를 활용해 자세히 분석합니다

Claude의 200K 컨텍스트는 긴 문서와 복잡한 코드를 처리하는 데 적합합니다. 파일 전체를 붙여 넣어도 잘릴 걱정을 덜 수 있습니다.

다음 전체 코드 파일을 분석하고 발생할 수 있는 모든 성능 문제를 찾아 주세요.

전체 코드:
<code>
[수백 줄에 이르는 전체 파일 붙여넣기]
</code>

모듈별로 하나씩 분석하고 각 모듈의 성능 문제와 최적화 방안을 제시해 주세요.

ChatGPT의 128K도 대부분의 상황에는 충분하지만 매우 긴 문서에서는 Claude가 더 유리합니다.

ChatGPT 모범 사례

1. 명확한 출력 형식 제약을 지정합니다

ChatGPT는 유연한 편이어서 출력 형식이 달라질 때가 있습니다. 다음과 같이 명확한 제약이 필요합니다.

코드의 성능 문제를 분석하고 반드시 다음 형식으로 출력해 주세요.

## 성능 문제 분석
- 문제 1: [구체적인 설명]
- 문제 2: [구체적인 설명]

## 최적화 방안
| 문제 | 제안 | 코드 예시 |
|-----|-----|---------|
| [문제 1] | [제안] | [코드] |

코드:
[코드 붙여넣기]

Markdown 형식(## 제목, | 표)으로 출력을 제약하면 ChatGPT가 더 충실히 따릅니다.

2. temperature 매개변수를 조정합니다

ChatGPT의 temperature 매개변수는 출력의 창의성에 영향을 줍니다. temperature = 0은 더 결정론적이고 일관성이 높으며, temperature = 0.7-1은 더 창의적이고 다양한 결과를 냅니다.

# 결정론적 출력(코드 생성, 데이터 분석에 적합)
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": prompt}],
    temperature=0
)

# 창의적인 출력(카피라이팅, 창의적 설계에 적합)
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": prompt}],
    temperature=0.8
)

Claude API에도 비슷한 제어 매개변수가 있지만 ChatGPT에서는 temperature의 효과가 더 뚜렷합니다.

3. 단계별로 유도합니다

ChatGPT는 때때로 단계를 건너뛰고 바로 결과를 제시합니다. 복잡한 작업에서는 단계별로 유도할 수 있습니다.

다음 작업을 단계별로 완료해 주세요.

1단계: 코드의 주요 기능 모듈을 나열합니다.
2단계: 각 모듈의 성능 특성을 분석합니다.
3단계: 성능 병목을 찾습니다.
4단계: 최적화 방안을 제시합니다.

먼저 1단계만 완료해 주세요.

모델이 단계별로 출력하도록 하면 단계를 건너뛰어 발생하는 오류를 줄일 수 있습니다.

같은 작업에 서로 다른 프롬프트 작성하기

텍스트에서 제품 정보를 추출하는 작업을 예로 들어 보겠습니다.

Claude 버전:

다음 텍스트에서 제품 정보를 추출해 주세요.

<text>
[제품 소개 텍스트]
</text>

출력 형식:
<product_info>
<name>[제품명]</name>
<price>[가격]</price>
<features>
<feature>[특징 1]</feature>
<feature>[특징 2]</feature>
</features>
</product_info>

ChatGPT 버전:

텍스트에서 제품 정보를 추출해 JSON 형식으로 출력해 주세요.

텍스트:
[제품 소개 텍스트]

출력 형식 예시:
{
  "name": "제품명",
  "price": "가격",
  "features": ["특징 1", "특징 2"]
}

이 JSON 구조를 엄격히 따르고 다른 필드는 추가하지 마세요.

차이는 Claude에는 XML이 더 안정적이고, ChatGPT에는 JSON과 명확한 형식 제약이 더 효과적이라는 점입니다.

선택 가이드

  • 엄밀한 추론과 구조화된 출력이 필요한 경우: Claude 우선
  • 창의적인 출력과 빠른 프로토타입이 필요한 경우: ChatGPT 우선
  • 긴 문서나 전체 코드 파일을 처리하는 경우: Claude 우선(200K 컨텍스트)
  • 코드 생성과 기술 질의응답: 둘 다 우수하지만 스타일이 조금 다름
  • 카피라이팅과 창의적 설계: ChatGPT 우선(temperature를 높게 설정)

실제 프로젝트에서는 작업 유형에 따라 모델을 선택하거나 두 모델을 함께 사용해 결과를 비교할 수 있습니다. 두 모델의 프롬프트 작성법은 각 특성에 맞춰 최적화해야 합니다. 모델의 특성과 맞지 않는 방식을 사용하면 결과가 크게 나빠질 수 있습니다.

프롬프트 평가와 반복 개선 방법론

앞에서는 다양한 프롬프트 기술을 살펴봤습니다. 하지만 프롬프트의 효과를 어떻게 판단할 것인가라는 문제가 남아 있습니다. 평가가 없다면 최적화는 방향 없는 시도에 불과합니다. 여기서는 프롬프트 평가 체계와 반복 개선 방법론을 다룹니다.

평가 차원: 네 가지 핵심 지표

좋은 프롬프트는 다음 네 가지 차원에서 기준을 충족해야 합니다.

정확성. 출력 내용이 올바른가요? 가장 중요한 차원이면서 평가하기도 가장 어렵습니다. 수학 계산이나 사실 질의 같은 객관적인 작업은 출력과 정답을 비교하면 비교적 쉽게 평가할 수 있습니다. 창의적 글쓰기나 방안 설계 같은 주관적인 작업에서는 정확성이 “기대에 부합하는가”로 바뀌어 평가가 더 복잡해집니다.

평가 방법 예시:

  • 수학 문제: 계산 결과와 정답 비교
  • 코드 생성: 코드를 실행하고 테스트 통과 여부 확인
  • 질의응답: 답변에 올바른 정보가 포함되었는지 확인
  • 카피라이팅: 사람이 점수를 매기거나 길이, 키워드 커버리지 같은 핵심 지표 비교

일관성. 같은 프롬프트를 여러 번 호출해도 출력 품질이 안정적인가요? 일관성이 낮은 프롬프트는 오늘 잘 작동하다가 내일 실패할 수 있어 프로덕션 환경에 적합하지 않습니다.

평가 방법: 같은 작업을 10회 실행하고 출력 품질의 변동 범위를 집계합니다. 변동이 지나치게 크면 일관성에 문제가 있습니다.

안전성. 출력에 유해 콘텐츠, 개인정보 유출, 편향된 표현이 포함되어 있지 않은가요? 고객 서비스 시스템이나 콘텐츠 검토 같은 특정 상황에서 특히 중요합니다.

평가 방법: 민감어 탐지와 개인정보 탐지 규칙을 설계하거나 전문 안전성 평가 도구를 사용합니다.

비용 효율성. 프롬프트의 Token 사용량이 합리적인가요? 지나치게 긴 프롬프트는 비용이 높고, 너무 짧은 프롬프트는 효과가 떨어집니다. 균형점을 찾아야 합니다.

평가 방법: 호출할 때마다 Token 수를 기록하고 평균 비용을 계산합니다. 서로 다른 프롬프트 버전의 비용 대비 효과를 비교합니다.

평가 도구

대표적인 프롬프트 평가 도구는 다음과 같습니다.

DeepEval. 정확성, 일관성, 관련성 등 다양한 지표를 제공하는 오픈 소스 프롬프트 평가 프레임워크입니다. 일괄 테스트와 자동 평가에 적합합니다.

from deepeval import evaluate
from deepeval.metrics import AnswerRelevancyMetric, FaithfulnessMetric

metrics = [
    AnswerRelevancyMetric(threshold=0.7),
    FaithfulnessMetric(threshold=0.8)
]

evaluate(test_cases, metrics)

Promptfoo. 프롬프트를 일괄 테스트하고 여러 모델의 출력을 비교하며 평가 보고서를 생성하는 CLI 도구입니다. 프롬프트 효과를 빠르게 검증하는 데 적합합니다.

promptfoo eval --prompts my_prompt.txt --providers openai:gpt-4 --tests test_cases.yaml

OpenAI Evals. 주로 모델 역량을 평가하지만 프롬프트 테스트에도 사용할 수 있는 OpenAI 공식 평가 프레임워크입니다.

이 도구들은 테스트 세트 정의 → 일괄 실행 → 자동 채점 → 보고서 생성이라는 공통 흐름을 가집니다. 수동 테스트보다 훨씬 효율적입니다.

A/B 테스트 절차

프롬프트를 개선할 때 A/B 테스트는 과학적인 접근입니다. 대략적인 절차는 다음과 같습니다.

1단계: 테스트 세트를 준비합니다. 다양한 상황을 포괄하는 대표 작업 샘플 20~50개를 수집합니다. 쉬운 작업만 넣지 말고 다양하게 구성해야 합니다.

2단계: 평가 지표를 정의합니다. 작업 유형에 따라 지표를 선택합니다. 예를 들어 질의응답에는 “답변 정확도 + 정보 커버리지”를, 코드 생성에는 “테스트 통과율 + 코드 품질 점수”를 사용할 수 있습니다.

3단계: 기준 테스트를 실행합니다. 현재 프롬프트로 테스트 세트를 실행하고 각 지표 점수를 기록합니다. 이 점수가 최적화의 출발점입니다.

4단계: 개선 버전을 설계합니다. 기준 테스트에서 드러난 문제에 맞춰 프롬프트를 개선합니다. 정확성이 낮으면 CoT를 추가하고, 일관성이 낮으면 더 엄격한 형식 제약을 추가할 수 있습니다.

5단계: 비교 테스트를 실행합니다. 개선 버전으로 같은 테스트 세트를 실행하고 지표 변화를 비교합니다. 개선 버전의 점수가 높으면 새 버전을 채택합니다.

6단계: 반복합니다. 개선 효과가 뚜렷하지 않으면 원인을 분석하고 다음 개선안을 설계합니다. 목표에 도달할 때까지 반복합니다.

간단한 테스트 기록 표는 다음과 같습니다.

버전정확성일관성Token 비용주요 개선점
v165%변동 큼(±20%)850기준 버전
v278%변동 보통(±10%)920CoT 유도 추가
v382%변동 작음(±5%)1050Few-shot 예시 추가
v485%변동 작음(±3%)1050예시 품질 개선

개선할 때마다 데이터를 기록해 최적화 과정을 추적할 수 있어야 합니다.

프롬프트 버전 관리

프롬프트도 코드이므로 버전 관리가 필요합니다. 다음 방식을 권장합니다.

버전 번호. 각 프롬프트에 v1, v2, v3 같은 버전 번호를 부여하고 변경 날짜와 주요 변화를 기록합니다.

변경 기록. 수정할 때마다 무엇을, 왜 바꿨고 테스트 결과가 어땠는지 기록합니다.

## 프롬프트 버전 기록

### v3 (2026-04-15)
변경: Few-shot 예시 3개를 추가하고 출력 형식 제약을 개선했습니다.
이유: v2의 일관성 테스트 변동이 크고 출력 형식이 불안정했습니다.
테스트: 정확도가 78%에서 82%로 올랐고, 일관성 변동은 ±10%에서 ±5%로 줄었습니다.

### v2 (2026-04-10)
변경: CoT 유도 문구 "단계별로 생각해 주세요"를 추가했습니다.
이유: v1의 정확도가 낮고 복잡한 추론 작업에서 오류가 많았습니다.
테스트: 정확도가 65%에서 78%로 올랐습니다.

### v1 (2026-04-05)
특별한 최적화가 없는 초기 버전입니다.
테스트: 정확도 65%, 일관성 변동 ±20%

저장 방식. 추적하기 쉽도록 프롬프트 파일과 테스트 데이터를 함께 보관합니다. Git으로 관리하거나 전용 프롬프트 관리 도구를 사용할 수 있습니다.

반복 최적화의 핵심

한 번에 너무 많은 것을 바꾸지 마세요. 한 번 개선할 때 변수 하나만 조정해야 어떤 변경이 효과가 있었는지 알 수 있습니다. CoT와 Few-shot을 동시에 추가하지 마세요. 먼저 CoT를 추가해 테스트하고, 그다음 Few-shot을 추가해 테스트합니다.

비용 변화를 확인하세요. 정확도가 높아졌지만 Token 비용이 두 배가 되는 경우도 있습니다. 비용 대비 효과를 따져야 하며 정확도가 높을수록 항상 좋은 것은 아닙니다.

실패한 시도를 기록하세요. 모든 변경이 결과를 개선하는 것은 아닙니다. 실패한 시도도 기록해야 나중에 같은 실수를 반복하지 않습니다.

최적화 목표를 설정하세요. 끝없이 최적화하지 마세요. 정확도 80%처럼 목표를 정하고 달성하면 반복을 멈춥니다. 과도한 최적화는 시간을 낭비하며 한계 효용도 점차 줄어듭니다.

평가와 반복 개선은 프롬프트 엔지니어링의 “마무리” 단계입니다. 평가가 없으면 프롬프트가 좋은지 알 수 없고, 반복 개선이 없으면 지속적으로 발전시킬 수 없습니다. 이 두 단계를 포함해야 프롬프트 엔지니어링이 비로소 완전한 엔지니어링 프로세스가 됩니다.

결론

지금까지 이야기한 내용을 한마디로 요약하면 프롬프트 엔지니어링은 “비과학적인 감”에서 “엔지니어링”으로 바뀌고 있습니다.

3계층 기술 프레임워크는 어떤 기술을 사용해야 하는지 판단하도록 돕습니다. 기본 계층은 “모델이 이해하게 하는” 문제를, 추론 계층은 “모델이 생각하게 하는” 문제를, 시스템 계층은 “프롬프트를 관리 가능하게 만드는” 문제를 해결합니다. CoT와 ReAct는 현재 가장 실용적인 추론 강화 기술이며, DSPy는 자동 최적화라는 새로운 방향을 대표합니다. Claude와 ChatGPT에는 각각 맞는 작성법이 필요합니다. Claude는 XML 태그로 제약하고, ChatGPT는 명확한 형식과 temperature 매개변수로 유도합니다. 평가 체계는 방법론의 마지막 퍼즐 조각이며 평가 없이는 과학적인 최적화도 없습니다.

다음과 같은 일부터 시작해 볼 수 있습니다.

현재 사용 중인 프롬프트를 점검하세요. 3계층 프레임워크와 비교해 어느 계층에 있는지, 결과 불안정, 과도한 비용, 뒤죽박죽인 출력 형식 같은 뚜렷한 문제는 없는지 살펴보세요.

DSPy를 한 번 사용해 보세요. 프로젝트에 프레임워크 기반 관리가 적합하다면 간단한 DSPy 모듈을 구성하고 자동 최적화의 효과를 체험해 보세요.

평가 기준을 세우세요. 테스트 세트를 준비하고 핵심 지표 몇 개를 정의한 뒤 프롬프트 기준 테스트를 실행해 보세요. 데이터가 생기면 최적화 방향도 분명해집니다.

프롬프트 엔지니어링은 분명 반복적인 연습이 필요합니다. 하지만 방법론이 있다면 적어도 더 이상 “감에 의존한 무작정 조정”은 아닙니다. 이 글이 체계적인 사고 프레임워크를 세우는 데 도움이 되길 바랍니다. 궁금한 점이 있다면 언제든 이야기해 주세요.


참고 자료

FAQ

Zero-shot CoT와 Few-shot CoT는 무엇이 다르며, 각각 언제 사용해야 하나요?
Zero-shot CoT는 '단계별로 생각해 주세요' 같은 유도 문구 하나만 추가하며, 간단한 작업이나 모델 역량이 충분할 때 적합합니다. Few-shot CoT는 추론 과정이 포함된 예시를 작성해야 하며, 복잡한 작업이나 특정 추론 형식이 필요할 때 적합합니다. 작업에 다단계 추론이 필요한지, 모델 역량이 충분한지, 고품질 예시를 작성할 시간이 있는지를 기준으로 판단하면 됩니다.
DSPy는 프롬프트를 직접 작성하는 방식보다 어떤 장점이 있나요?
DSPy에는 세 가지 주요 장점이 있습니다.

• 더 높은 신뢰성: 선언적 정의는 수동 프롬프트보다 엄밀해 누락과 형식 오류를 줄입니다.
• 더 나은 유지보수성: 프롬프트가 코드가 되어 버전 관리, 단위 테스트, 지속적인 반복 개선이 가능합니다.
• 더 높은 이식성: 모델을 바꿀 때 프레임워크가 자동으로 적응하므로 프롬프트를 다시 조정할 필요가 없습니다.

프로젝트 단위 애플리케이션, 구조가 명확한 작업, 학습 데이터가 있는 경우, 장기 유지보수가 필요한 시스템에 적합합니다.
Claude와 ChatGPT는 프롬프트 작성 방식이 어떻게 다른가요?
Claude는 XML 태그를 활용한 구조화 제약을 선호하고 역할 설정과 제약을 충실히 따르며, 긴 문서 분석(200K 컨텍스트)에 적합합니다. ChatGPT는 Markdown이나 JSON 같은 명확한 출력 형식 제약이 필요하고 temperature 매개변수로 창의성을 조절할 수 있으며, 유연하고 빠르게 응답하는 편입니다. 핵심은 Claude에는 XML을, ChatGPT에는 JSON과 형식 제약을 활용하는 것입니다.
프롬프트의 효과를 어떻게 평가하나요?
네 가지 핵심 차원을 확인합니다.

• 정확성: 출력 내용이 올바른가
• 일관성: 여러 번 호출해도 품질이 안정적인가
• 안전성: 유해 콘텐츠나 개인정보 유출이 없는가
• 비용 효율성: Token 사용량이 합리적인가

권장 도구는 DeepEval(일괄 테스트), Promptfoo(빠른 검증), OpenAI Evals입니다. 느낌만으로 판단하지 말고 정량 지표를 사용해야 합니다.
ReAct 프레임워크와 CoT는 무엇이 다르며, 각각 어떤 상황에 적합한가요?
CoT는 모델 내부 지식만 사용해 순수하게 사고하고 추론하므로 수학이나 논리 분석처럼 이미 정보가 충분한 상황에 적합합니다. ReAct는 사고와 행동을 결합해 외부 도구로 정보를 얻을 수 있으므로 실시간 정보, 데이터베이스 조회, API 호출이 필요한 상황에 적합합니다. 구현 복잡도 측면에서 CoT는 프롬프트만 수정하면 되지만 ReAct는 도구 통합 시스템이 필요합니다.
프롬프트 최적화에서 A/B 테스트는 어떻게 진행하나요?
표준 절차는 다음과 같습니다.

• 1단계: 대표 작업 20~50개로 테스트 세트 준비
• 2단계: 정확도와 커버리지 등 평가 지표 정의
• 3단계: 기준 테스트를 실행하고 점수 기록
• 4단계: 개선 버전 설계
• 5단계: 비교 테스트로 지표 변화 확인
• 6단계: 목표를 달성할 때까지 반복

핵심 원칙은 한 번에 변수 하나만 바꾸고, 실패한 시도를 기록하며, 최적화 목표의 상한을 정하는 것입니다.

3분 읽기 · 게시일: 2026년 4월 17일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog