자주 묻는 질문
자주 묻는 질문 (FAQs)
DSPy를 써야 할지, 어떻게 쓰는지, 배포·디버깅 시 겪는 흔한 질문들을 모아 둔 페이지예요. 프레임워크 철학부터 구체적인 에러 처리까지 한곳에서 정리했어요.
출처: 문서
본문
경고: 이 페이지는 최신 상태가 아니며 DSPy 2.5와 2.6에서는 완전히 정확하지 않을 수 있어요.
DSPy가 나에게 맞나요? DSPy vs. 다른 프레임워크
DSPy의 철학과 추상화는 다른 라이브러리·프레임워크와 상당히 달라서, DSPy가 자기 작업에 맞는(또는 맞지 않는) 프레임워크인지 판단하기는 보통 명확해요. NLP/AI 연구자(또는 새 파이프라인·새 작업을 탐색하는 실무자)라면 대답은 일반적으로 변함없이 그렇다예요. 다른 일을 하는 실무자라면 계속 읽어주세요.
DSPy vs. 프롬프트용 얇은 래퍼 (OpenAI API, MiniChain, 기본 템플릿) 다시 말해, 프롬프트를 문자열 템플릿으로 바로 쓸 수는 없나? 극도로 단순한 설정에서는 그럴 수도 있어요. (신경망에 익숙하다면, 이건 아주 작은 2층 NN을 Python for-loop로 표현하는 것과 비슷해요. 어느 정도는 동작하죠.) 하지만 더 높은 품질(또는 감당할 만한 비용)이 필요할 때는 다단계 분해, 개선된 프롬프팅, 데이터 부트스트래핑, 세심한 파인튜닝, 검색 증강, 더 작은(또는 더 싼, 로컬) 모델 사용을 반복적으로 탐색해야 해요. 파운데이션 모델로 구축하는 진짜 표현력은 이런 조각들 사이의 상호작용에 있어요. 그런데 조각 하나를 바꿀 때마다 다른 여러 컴포넌트를 깨뜨리거나 약화시킬 가능성이 높아요. DSPy는 실제 시스템 설계 외부에 있는 이러한 상호작용의 부분을 깔끔하게 추상화하고(그리고 강력하게 최적화해)요. 모듈 수준 상호작용 설계에 집중하게 해요. 같은 프로그램 을 10~20줄의 DSPy로 표현하면 다단계 지침(GPT-4용), 상세 프롬프트(Llama2-13b용), 파인튠(T5-base용)으로 쉽게 컴파일될 수 있어요. 그리고 프로젝트 핵심에 길고 깨지기 쉬운 모델별 문자열을 유지할 필요도 없어요.
DSPy vs. LangChain, LlamaIndex 같은 애플리케이션 개발 라이브러리 LangChain과 LlamaIndex는 고수준 애플리케이션 개발을 겨냥해요. batteries-included 느낌의 사전 구축 애플리케이션 모듈을 제공하고, 데이터나 설정에 플러그인해요. PDF 질의응답이나 표준 text-to-SQL에 일반 오프더쉘프 프롬프트를 쓰는 것에 만족한다면 이 라이브러리들에서 풍부한 생태계를 찾을 수 있어요. DSPy는 특정 애플리케이션을 겨냥한 수제 프롬프트를 내부에 담지 않아요. 대신 훨씬 더 강력한 일반 목적의 소형 모듈 집합을 도입하고, 그것들이 사용자 데이터로 사용자 파이프라인 안에서 사용자의 LM을 프롬프팅(또는 파인튜닝)하도록 학습 할 수 있어요. 데이터를 바꾸거나, 프로그램 제어 흐름을 조정하거나, 대상 LM을 바꾸면, DSPy 컴파일러가 프로그램을 이 파이프라인에 맞게 특별히 최적화된 새로운 프롬프트(또는 파인튠) 집합으로 매핑할 수 있어요. 그래서 짧은 프로그램을 직접 구현(또는 확장)할 의향만 있다면, 가장 적은 노력으로 작업에 최고 품질을 얻을 수 있는 경우가 많아요. 요약하면, DSPy는 사전 정의 프롬프트와 통합 라이브러리가 아니라, 가볍지만 자동 최적화되는 프로그래밍 모델이 필요할 때 쓰는 도구예요. 신경망에 익숙하다면, 이건 PyTorch(DSPy에 해당)와 HuggingFace Transformers(고수준 라이브러리에 해당)의 차이와 비슷해요.
DSPy vs. Guidance, LMQL, RELM, Outlines 같은 생성 제어 라이브러리 이들은 모두 LM의 개별 완성을 제어하는 흥미로운 새 라이브러리예요. 예를 들어 JSON 출력 스키마를 강제하거나 특정 정규식에 샘플링을 제한하고 싶을 때요. 많은 설정에서 매우 유용하지만, 일반적으로 단일 LM 호출의 저수준·구조적 제어에 초점을 맞춰요. 받은 JSON(또는 구조화된 출력)이 작업에 맞게 정확하거나 유용하다는 것을 보장하지는 않아요. 반면 DSPy는 프로그램의 프롬프트를 다양한 작업 요구에 맞추도록 자동 최적화하며, 여기에는 유효한 구조화 출력 생성도 포함될 수 있어요. 그렇긴 해도, 우리는 DSPy의 Signatures가 이 라이브러리들이 구현하는 regex 같은 제약을 표현하도록 허용하는 것을 고려하고 있어요.
기본 사용법 (Basic Usage)
작업에 DSPy를 어떻게 사용해야 하나요? 이에 관한 8단계 가이드를 작성했어요. 요컨대 DSPy 사용은 반복 과정이에요. 먼저 작업과 최대화할 지표를 정의하고, 예시 입력 몇 개를 준비해요 — 보통 라벨 없이(또는 지표가 필요하면 최종 출력에만 라벨을 두고)요. 그런 다음 내장 레이어(modules)를 골라 각 레이어에 signature(입출력 명세)를 주고, Python 코드에서 모듈을 자유롭게 호출해 파이프라인을 구축해요. 마지막으로 DSPy optimizer로 코드를 고품질 지침, 자동 few-shot 예시, 또는 LM 가중치 업데이트로 컴파일해요.
복잡한 프롬프트를 DSPy 파이프라인으로 어떻게 바꾸나요? 위와 같은 답변이에요.
DSPy 옵티마이저는 무엇을 튜닝하나요? 다시 말해, 컴파일은 실제로 뭘 하나요? 옵티마이저마다 다르지만, 모두 프롬프트나 LM 가중치를 갱신해 프로그램의 지표를 최대화하려 해요. 현재 DSPy optimizers는 데이터를 검사하고, 프로그램을 통한 trace를 시뮬레이션해 각 단계의 좋은/나쁜 예시를 만들며, 과거 결과에 기반해 각 단계의 지침을 제안·개선하고, 자가 생성 예시로 LM 가중치를 파인튜닝하며, 이 중 여러 개를 결합해 품질을 높이거나 비용을 줄일 수 있어요. 더 풍부한 공간을 탐구하는 새 옵티마이저를 병합하고 싶어요. 현재 프롬프트 엔지니어링, "synthetic data" 생성, 자기 개선을 위해 거치는 대부분의 수동 단계는 임의의 LM 프로그램에 작동하는 DSPy 옵티마이저로 일반화될 수 있을 거예요.
기타 FAQ. 각 항목에 공식 답을 추가한 PR을 환영해요. 아래 답변은 기존 이슈, 튜토리얼, 논문에서 대부분 찾을 수 있어요.
-
여러 출력을 얻으려면? 여러 출력 필드를 지정하면 돼요. 짧은 형태 시그니처에서는 "->" 지시자 뒤에 여러 출력을 쉼표로 나열해요 (예:
"inputs -> output1, output2"). 긴 형태 시그니처에서는 여러dspy.OutputField를 포함할 수 있어요. -
자체 지표를 정의하려면? 지표가 float를 반환할 수 있나요? 지표는 모델 생성물을 처리하고 사용자 정의 요구사항에 따라 평가하는 단순 Python 함수로 정의할 수 있어요. 지표는 기존 데이터(예: gold 라벨)와 모델 예측을 비교하거나, LM의 검증 피드백(예: LLM-as-Judge)으로 출력의 다양한 구성 요소를 평가할 수 있어요. 지표는
bool,int,float타입 점수를 반환할 수 있어요. 커스텀 지표 정의와 AI 피드백/DSPy 프로그램을 사용한 고급 평가는 공식 Metrics 문서를 참고하세요. -
컴파일은 얼마나 비싸거나 느린가요? 컴파일 비용을 반영해 참고 실험을 소개할게요. BootstrapFewShotWithRandomSearch 옵티마이저로
gpt-3.5-turbo-1106모델에서 7개 후보 프로그램·10개 스레드로 프로그램을 컴파일하는 경우예요. 이 컴파일은 약 6분, 3200회 API 호출, 입력 토큰 2.7M, 출력 토큰 156,000에, 총 비용 약 $3 USD가 든다고 보고해요 (현재 OpenAI 모델 가격 기준).
DSPy optimizers 컴파일은 자연스럽게 추가 LM 호출을 만들지만, 성능을 최대화하려는 최소한의 실행으로 이 오버헤드를 보충해요. 이는 더 큰 모델로 DSPy 프로그램을 컴파일해 컴파일 타임에 향상된 행동을 학습하고, 추론 타임에 그 행동을 테스트된 작은 모델로 전파해 작은 모델의 성능을 높이는 길을 열어줘요.
배포 또는 재현성 우려 (Deployment or Reproducibility Concerns)
- 컴파일된 프로그램의 체크포인트를 저장하려면? 컴파일된 모듈 저장/로딩 예시예요.
cot_compiled = teleprompter.compile(CoT(), trainset=trainset, valset=devset)
#Saving
cot_compiled.save('compiled_cot_gsm8k.json')
#Loading:
cot = CoT()
cot.load('compiled_cot_gsm8k.json')
-
배포를 위해 내보내려면? DSPy 프로그램 내보내기는 위처럼 저장하기만 하면 돼요.
-
자체 데이터를 검색하려면? RAGatouille 같은 오픈소스 라이브러리가 ColBERT 같은 고급 검색 모델로 문서를 임베딩·인덱싱하는 도구로 자체 데이터 검색을 가능하게 해요. 이런 라이브러리를 통합해 DSPy 프로그램을 개발하면서 검색 가능한 데이터셋을 만들어보세요.
-
캐시를 끄려면? 캐시를 내보내려면? v2.5부터
dspy.LM의cache파라미터를False로 설정하면 캐시를 끌 수 있어요.
dspy.LM('openai/gpt-4o-mini', cache=False)
로컬 캐시는 전역 환경 디렉터리 os.environ["DSP_CACHEDIR"] 또는 노트북의 os.environ["DSP_NOTEBOOK_CACHEDIR"]에 저장돼요. 보통 cachedir을 os.path.join(repo_path, 'cache')로 설정하고 여기서 캐시를 내보낼 수 있어요.
os.environ["DSP_NOTEBOOK_CACHEDIR"] = os.path.join(os.getcwd(), 'cache')
중요:
DSP_CACHEDIR은 레거시 클라이언트(deprecated된 dspy.OpenAI, dspy.ColBERTv2 등)를 담당하고,DSPY_CACHEDIR은 현재dspy.LM클라이언트를 담당해요. AWS lambda 배포에서는 DSP_와 DSPY_ 둘 다 비활성화해야 해요.
고급 사용법 (Advanced Usage)
-
병렬화하려면? 컴파일과 평가 중 모두 해당 DSPy
optimizers또는dspy.Evaluate유틸리티 함수 안에서 여러 스레드 설정을 지정해 DSPy 프로그램을 병렬화할 수 있어요. -
모듈을 고정(freeze)하려면? 모듈의
._compiled속성을True로 설정해 고정할 수 있어요. 이는 모듈이 옵티마이저 컴파일을 거쳤고 파라미터가 조정되지 않아야 함을 나타내요.dspy.BootstrapFewShot같은 옵티마이저에서는 부트스트래핑 과정에서 teacher가 수집한 few-shot 데모를 전파하기 전에 student 프로그램이 고정되도록 내부적으로 처리돼요. -
DSPy assertions을 사용하려면? a) 프로그램에 Assertion 추가하기:
- 제약 정의:
dspy.Assert및/또는dspy.Suggest로 DSPy 프로그램 안에서 제약을 정의해요. 이는 강제하려는 결과에 대한 boolean 검증 체크를 기반으로 하며, 모델 출력을 검증하는 단순 Python 함수일 수 있어요. - Assertion 통합: Assertion 문을 모델 생성 다음(힌트: 모듈 레이어 다음)에 두세요. b) Assertion 활성화하기:
assert_transform_module사용:assert_transform_module함수와backtrack_handler로 assertion을 가진 DSPy 모듈을 감싸요. 이 함수는 내부 assertion 백트래킹·재시도 로직을 포함하도록 프로그램을 변환하며, 커스터마이즈도 가능해요:program_with_assertions = assert_transform_module(ProgramWithAssertions(), backtrack_handler)
- Assertions 활성화: DSPy 프로그램에서
activate_assertions를 직접 호출해요:program_with_assertions = ProgramWithAssertions().activate_assertions()
참고: Assertions를 제대로 쓰려면 위 두 방법 중 하나로
dspy.Assert또는dspy.Suggest문을 포함한 DSPy 프로그램을 활성화해야 해요. - 제약 정의:
오류 (Errors)
- "context too long" 오류는 어떻게 다루나요? DSPy에서 "context too long" 오류를 겪는다면, DSPy 옵티마이저가 데모를 프롬프트에 포함시켜 현재 컨텍스트 창을 초과하는 경우가 많아요. DSPy는 이를
dspy.LMInvalidRequestError의 하위 클래스인dspy.ContextWindowExceededError로 raise해요.max_bootstrapped_demos와max_labeled_demos같은 파라미터를 줄여보세요. 또한 검색된 passage/doc/embedding 수를 줄여 프롬프트가 모델 컨텍스트 길이 안에 들어가게 할 수도 있어요.
더 일반적인 해결책은 LM 요청에 지정한 max_tokens 수를 단순히 늘리는 거예요 (예: lm = dspy.LM('openai/gpt-4o-mini', max_tokens=...)). 다른 제공자 실패는 dspy.LMError 또는 dspy.LMRateLimitError, dspy.LMAuthError, dspy.LMServerError 같은 구체적 하위 클래스를 잡으세요. 자세한 내용은 Errors API reference를 참고하세요.
상세 로그 레벨 설정 (Set Verbose Level)
DSPy는 logging 라이브러리로 로그를 출력해요. DSPy 코드를 디버그하려면 아래 예시처럼 로그 레벨을 DEBUG로 설정하세요.
import logging
logging.getLogger("dspy").setLevel(logging.DEBUG)
또는 로그 양을 줄이려면 로그 레벨을 WARNING이나 ERROR로 설정하세요.
import logging
logging.getLogger("dspy").setLevel(logging.WARNING)
더 알아보기 (Learn more)
- Cheatsheet — 자주 쓰는 패턴 스니펫
- Errors API — 오류 처리
- Configure — 기본 설정