첫 DSPy 프로그램 작성하기
첫 DSPy 프로그램 작성하기
프레임워크가 실제로 어떻게 동작하는지는 작은 프로그램으로 직접 부딪혀 보는 게 가장 빨라요. 여기서는 하이쿠(시)를 생성하는 프로그램을 네 줄로 작성하고, 그 뒤 DSPy가 무대 뒤에서 뭘 하는지 하나씩 설명할게요.
출처: 공식문서
가장 단순한 버전부터
가장 간단한 버전을 작성해서 실행해 봅시다.
haiku_signature = "subject -> haiku"
haiku_generator = dspy.Predict(haiku_signature)
result = haiku_generator(subject="computer science")
print(result.haiku)
첫 줄은 우리의 시그니처(Signature) 를 지정해요. 시그니처는 DSPy의 핵심 개념으로, 프로그래밍에서 함수 시그니처가 입력과 출력을 기술하듯이 작업의 입력과 출력을 정의하는 방법입니다.
DSPy 시그니처를 정의하는 가장 간단한 방법은 "inputs -> outputs" 형식의 문자열이에요. 여기서는 subject를 받아 haiku를 돌려주도록 한 거죠.
언어 모델로 프로그래밍할 때는 변수 이름이 중요해요. 이름은 프로그램의 인터페이스를 정의할 뿐 아니라 모델에 의도를 알려주는 힌트가 됩니다. haiku를 limerick으로 바꾸면 모델은 그 신호를 알아차리고 대신 리머릭을 만들어요. 그리고 프로그램의 출력도 result.haiku가 아니라 result.limerick으로 접근하게 됩니다.
시그니처를 호출 가능한 함수로: dspy.Predict
시그니처를 호출 가능한 함수로 만드는 데는 dspy.Predict를 써요. Predict는 일종의 DSPy Module입니다. 시그니처가 무엇을 원하는지를 정한다면, 모듈은 어떻게 달성할지, 즉 호출 시점의 전략, 제어 흐름, 도구 등을 관리해요.
Predict는 기반이 되는 모듈입니다. dspy.Predict(haiku_signature)를 호출하면 무슨 일이 일어나는지 볼까요.
"subject -> haiku"문자열이 입력·출력 필드가 모두str타입인 Signature 클래스로 파싱돼요.- 이
Signature인스턴스에 기본 지시 문자열이 생성돼요. 이 경우엔 "Given the fieldssubject, produce the fieldshaiku."입니다. - 이
Signature로Predict모듈이 인스턴스화됩니다.
이제 haiku_generator는 호출 가능해졌어요. haiku_generator(subject="computer science")를 호출하면 다음 과정이 시작됩니다.
- DSPy 설정을 확인해서
LM이 설정돼 있는지 검사해요. Adapter가Signature와 입력을LM이 소비할 수 있는 메시지로 렌더링해요. 기본값은ChatAdapter인데, 메시지 형식에 따라 JSON, XML 등 다른 변형도 있어요.ChatAdapter가 프롬프트를 구성해요. 여기엔 시그니처 지시, 입력·출력을 설명하는 필드 스키마, 형식 지시, 그리고 실제 입력("computer science")이 포함됩니다.- 메시지가
LM으로 전송돼요. 캐싱이 기본으로 켜져 있어서 동일한 호출은 캐시된 응답을 돌려줘요. - 응답이 돌아오고
ChatAdapter가 파싱해 출력 필드를 추출해요. Predict모듈이 출력 필드를 담은Prediction객체를 반환해요.result.haiku를 호출하면 생성된 하이쿠가 나옵니다.- 이 호출은
LM히스토리에 기록돼 나중에dspy.inspect_history()로 확인할 수 있어요.
print(result.haiku)를 실행하면 이런 결과가 나옵니다.
Silent code unfolds
Logic threads through hidden paths
Bugs bloom, then resolve
네 줄로, 소프트웨어처럼 읽히고 함수처럼 동작하는 AI 프로그램을 만든 거예요.
프롬프트가 어떻게 만들어졌는지 들여다보기
DSPy가 프롬프팅과 템플릿을 전부 관리해요. dspy.inspect_history(n=1)를 호출하면 우리 프로그램이 만든 실제 프롬프트와 lm이 돌려준 문자열을 볼 수 있습니다.
먼저 DSPy가 시스템 지시를 생성했어요.
Your input fields are:
1. `subject` (str):
Your output fields are:
1. `haiku` (str):
All interactions will be structured in the following way, with the appropriate values filled in.
[[ ## subject ## ]]
{subject}
[[ ## haiku ## ]]
{haiku}
[[ ## completed ## ]]
In adhering to this structure, your objective is:
Given the fields `subject`, produce the fields `haiku`.
대괄호와 해시 표기([[ ## ... ## ]])는 기본 ChatAdapter가 프롬프트를 구조화하는 방식이에요. 입력과 섹션을 구분해 주지요.
다음으로 adapter가 우리 입력을 사용자 메시지로 템플릿화했어요.
[[ ## subject ## ]]
computer science
Respond with the corresponding output fields, starting with the field `[[ ## haiku ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
DSPy는 이 두 개를 lm으로 보냈고, 모델은 이렇게 응답했어요.
[[ ## haiku ## ]]
Silent code unfolds
Logic threads through hidden paths
Bugs bloom, then resolve
[[ ## completed ## ]]
DSPy에서는 시그니처 하나를 조합하면 메시지는 알아서 작성됩니다.
더 알아보기 (Learn more)
- 시그니처 확장하기 — 입력·출력을 더 추가하고 타입을 붙여 봐요.
- Adapters: 시그니처가 프롬프트가 되는 법 — 프롬프트 구성의 원리.