dspy를 사용하여 LLM 프롬프트 엔지니어링을 자동화하는 개념도. 한 개발자가 태블릿을 들고 프롬프트 컴파일러와 인공지능 최적화 과정을 바라보고 있으며, 기존의 복잡한 수동 튜닝에서 벗어나 빛나는 자동화된 핵심을 통해 AI 프로그램을 설계하는 패러다임 전환을 시각적으로 표현합니다.
|

DSPy, 프롬프트 엔지니어링의 종말? ‘컴파일’ 시대의 시작

DSPy, 프롬프트 엔지니어링의 종말? ‘컴파일’ 시대의 시작

프롬프트 엔지니어링의 종말? DSPy가 ‘하드코딩 프롬프트’를 대체하는 법

혹시 LLM에 사용할 ‘최적의 프롬프트’를 찾으려고 수백 줄짜리 템플릿을 밤새워 수정해 본 경험, 없으신가요? 그렇게 공들여 만든 프롬프트가 언어 모델(LM) 버전만 바뀌어도(예: GPT-3.5 → GPT-4) 성능이 널뛰는 것도 지켜보셨을 겁니다.

우리는 이 과정을 ‘프롬프트 엔지니어링’이라고 부르지만, 솔직히 ‘수동 최적화’나 ‘감에 의존한 노동’에 가까웠습니다.

하지만 만약 이 지루한 프롬프트 튜닝 과정을 ‘자동화’할 수 있다면 어떨까요? 프롬프트를 ‘작성(Writing)’하는 게 아니라 ‘컴파일(Compiling)’하는 겁니다.

오늘 소개할 DSPy는 바로 이 질문에 대한 스탠포드 AI 랩의 답변입니다. DSPy는 “선언형 언어 모델 호출을 자기 개선 파이프라인으로 컴파일한다”는, 조금 어렵지만 강력한 개념을 제시합니다.

이 말을 한마디로 요약하면, DSPy는 언어 모델을 위한 PyTorch라고 할 수 있습니다.

PyTorch가 등장하기 전, 사람들은 신경망 가중치를 손으로 직접 조정하려 했습니다. PyTorch는 이 과정을 ‘옵티마이저(Optimizer)’로 자동화했죠. 이와 똑같습니다. DSPy는 우리가 손으로 조정하던 ‘프롬프트’를 ‘컴파일러’를 통해 자동 최적화하는 새로운 프로그래밍 모델입니다.

이 글에서는 DSPy가 정확히 무엇인지, 왜 기존 방식의 문제를 해결할 수 있는지 명쾌하게 분석해 드립니다.

😩 문제: 기존 방식의 명확한 한계

LangChain, Semantic Kernel 같은 기존 프레임워크도 훌륭합니다. LM을 외부 도구와 연결하는 ‘접착제’ 역할을 잘 수행했죠. 하지만 이들은 결정적인 한계를 가집니다. 바로 ‘하드코딩된 프롬프트 템플릿’에 의존한다는 점입니다.

이 방식의 문제점은 명확합니다.

취약합니다 (Brittle)

프롬프트가 특정 모델(예: GPT-3.5)이나 특정 작업에 과도하게 최적화됩니다. 모델을 Llama2로 바꾸거나 데이터 도메인이 조금만 달라져도 성능이 급락합니다.

비효율적입니다 (Inefficient)

최적의 프롬프트를 찾는 과정이 과학이 아닌 ‘감’과 ‘시행착오’의 영역에 머무릅니다.

확장성이 낮습니다 (Unscalable)

복잡한 작업을 위해 여러 프롬프트를 연결(Chain)하면, 각 단계의 상호작용을 예측하거나 디버깅하기가 지옥처럼 변합니다.

DSPy는 이런 접근법이 “분류기의 가중치를 손으로 직접 튜닝하는 것”과 다를 바 없다고 비판합니다.

💡 해결책: DSPy의 “컴파일” 접근법

DSPy는 이 문제를 정반대로 접근합니다. 개발자에게 “어떻게(How)” 작동할지(예: ‘당신은 친절한 AI 어시스턴트입니다…’)를 지시하는 긴 프롬프트를 쓰라고 요구하는 대신, “무엇을(What)” 할지만 선언하라고 말합니다.

“어떻게”는 DSPy의 컴파일러가 알아서 최적의 방법을 찾도록 맡기는 거죠.

이 마법 같은 자동화는 시그니처(Signatures), 모듈(Modules), 텔레프롬프터(Teleprompters)라는 세 가지 핵심 요소로 작동합니다. 하나씩 살펴보시죠.

1. 시그니처 (Signatures): 작업의 ‘설계도’

시그니처는 LM에 맡길 작업의 ‘설계도’ 또는 ‘명세서’입니다. ‘어떻게’ 하라는 긴 지시문이 아니라, ‘입력’과 ‘출력’이 무엇인지 명확하게 정의하는 선언입니다.

기존 프롬프트: “당신은 질문에 답하는 AI입니다. 주어진 맥락을… (중략)… 단계별로 생각해서 답하세요.”

DSPy 시그니처:

  • 단순한 QA: “question → answer”
  • RAG (검색 증강 생성): “context, question → answer”

이게 전부입니다. “Context와 Question을 줄 테니 Answer를 다오.”라는 작업의 의도만 명확히 전달하는 겁니다. 이 시그니처를 실제 LM이 알아들을 효과적인 프롬프트로 바꾸는 일은 ‘컴파일러(텔레프롬프터)’가 알아서 합니다.

2. 모듈 (Modules): 조립 가능한 ‘부품’

모듈은 PyTorch의 ‘레이어(Layer)’처럼 우리가 조립할 수 있는 ‘부품’입니다. 각 모듈은 위에서 정의한 시그니처를 구현하도록 설계되어 있습니다.

여기서 재미있는 점은 모듈이 가진 ‘파라미터’입니다. 신경망의 파라미터가 ‘가중치(Weight)’라면, DSPy 모듈의 파라미터는 바로 ‘데모(Demonstrations)’, 즉 퓨샷(few-shot) 예시들입니다.

DSPy는 자주 쓰는 기법들을 모듈로 제공합니다.

  • dspy.Predict: 가장 기본 모듈 (시그니처 구현)
  • dspy.ChainOfThought: 알아서 중간 추론(Reasoning) 단계를 추가합니다.
  • dspy.ReAct: 도구 사용을 위한 에이전트 모듈입니다.
  • dspy.Retrieve: 외부 검색 시스템(예: ColBERTv2)을 호출합니다.

이 모듈들을 파이썬 코드(if문, for 루프 등)로 자유롭게 조합하여 RAG나 Multi-hop QA 같은 복잡한 파이프라인을 구축할 수 있습니다.

예시 코드 (RAG):

class RAG(dspy.Module):
    def __init__(self, num_passages=3):
        super().__init__()
        # 1. 검색 모듈 선언
        self.retrieve = dspy.Retrieve(k=num_passages)
        # 2. CoT 기반 답변 생성 모듈 선언
        self.generate_answer = dspy.ChainOfThought("context, question -> answer")
 
    def forward(self, question):
        # 1. 질문으로 문맥 검색
        context = self.retrieve(question).passages
        # 2. 검색된 문맥과 질문으로 답변 생성
        prediction = self.generate_answer(context=context, question=question)
        return prediction

여기서 주목할 점은, 이 코드 어디에도 ‘You are a helpful assistant…’로 시작하는 긴 프롬프트 템플릿이 없다는 사실입니다.

3. 텔레프롬프터 (Teleprompters): 똑똑한 ‘자동 최적화 컴파일러’

텔레프롬프터는 DSPy의 핵심이자, PyTorch의 ‘옵티마이저’에 해당하는 컴파일러입니다.

우리가 할 일은 ‘몇 개의 학습 예제’와 ‘평가 지표(Metric)'(예: 정답과 일치해야 함)를 텔레프롬프터에게 알려주는 것뿐입니다.

그럼 텔레프롬프터가 알아서 다음 과정을 수행합니다.

  • 시뮬레이션: 우리가 짠 프로그램(예: RAG)을 학습 데이터로 실행해 봅니다.
  • 필터링: 실행 결과 중 평가 지표를 통과한 ‘좋은’ 실행 궤적(Trace)을 수집합니다.
  • 최적화 (부트스트래핑): 이 ‘좋은’ 궤적들을 가장 효과적인 ‘퓨샷 데모’로 삼아 각 모듈의 파라미터(프롬프트)를 자동으로 최적화합니다.

즉, 개발자가 프롬프트를 튜닝하는 게 아니라, 컴파일러가 데이터를 보고 프롬프트를 자동으로 튜닝하는 것입니다.

심지어 BootstrapFinetune 텔레프롬프터를 쓰면, 이렇게 생성된 데모들로 T5 같은 소형 LM을 직접 파인튜닝할 수도 있습니다.

📊 그래서, 효과가 있나요? (케이스 스터디 요약)

이론은 그럴듯한데, 정말 효과가 있을까요? DSPy 논문은 두 가지 흥미로운 결과를 보여줍니다.

케이스 1: 수학 문제 (GSM8K)

복잡한 수학적 추론이 필요한 태스크입니다.

  • 전문가 튜닝: GPT-3.5에서 전문가가 수동으로 튜닝한 퓨샷 프롬프트는 63.0%의 정확도를 보였습니다.
  • DSPy 컴파일: 반면, DSPy로 자동 컴파일한 간단한 프로그램은 80.3%라는 훨씬 높은 성능을 달성했습니다.

케이스 2: 멀티홉 QA (HotPotQA)

여러 단계의 검색과 추론이 필요한 태스크입니다.

  • 전문가 튜닝: GPT-3.5에서 전문가가 작성한 ReAct 프롬프트는 31.0%의 성능을 보였습니다.
  • DSPy 컴파일: DSPy가 자동으로 최적화한 프로그램은 48.7%로 성능이 크게 향상되었습니다.

놀라운 점: Llama2-13b-chat 모델에 DSPy를 적용하자, GPT-3.5와 거의 대등한 성능(48.3%)을 보였습니다.

더 나아가, DSPy는 Llama2가 생성한 예제로 770M(0.77B) 크기의 소형 T5 모델을 파인튜닝하여, GPT-3.5(48.7%)에 근접하는 39.3%의 성능을 달성했습니다. 이는 저렴한 소형 모델(SLM)도 DSPy 컴파일을 통해 고비용 모델의 성능을 따라잡을 수 있다는 가능성을 의미합니다.

🚀 결론: ‘프롬프트 엔지니어’에서 ‘프로그램 설계자’로

DSPy는 LM 파이프라인을 구축하는 방식에 근본적인 ‘패러다임 전환’을 제안합니다.

특징 👎 기존 방식 (프롬프트 엔지니어링) 👍 DSPy 방식 (프로그램 최적화)
핵심 접근 “어떻게(How)”를 하드코딩 (수동 템플릿) “무엇을(What)”을 선언 (자동 컴파일)
최적화 개발자의 ‘감’과 ‘시행착오’ (수동) ‘컴파일러’가 지표 기반으로 자동화 (자동)
파라미터 고정된 문자열 (String) 학습 가능한 ‘데모’ (퓨샷 예시)
비유 “가중치를 손으로 튜닝” “신경망 옵티마이저 (PyTorch)”
개발자 역할 프롬프트 튜너 (Tuner) 프로그램 및 지표 설계자 (Designer)

물론 DSPy가 모든 것을 해결해 주진 않습니다. 여전히 좋은 ‘시그니처’를 설계하고, 파이프라인의 ‘구조'(모듈 조합)를 짜는 것은 개발자의 몫입니다.

하지만 DSPy는 개발자를 지루하고 반복적인 ‘프롬프트 튜닝’의 굴레에서 벗어나, 더 창의적이고 본질적인 ‘프로그램 설계’에 집중할 수 있게 도와줍니다.

이제 프롬프트에 매달리는 대신, 더 나은 ‘프로그램’과 ‘컴파일러’를 고민할 때가 온 것 같습니다.

최신 프롬프트 엔지니어링 기법을 알고 싶다면 ProB AI 연구소의 콘텐츠를 확인해보세요.

더 알아보기

Similar Posts