LLM 애플리케이션 개발에서 중요한 과제 중 하나는 모델이 일관된 방식으로 유의미한 출력을 생성하도록 유도하는 것입니다. 이를 위해 LangChain은 FewShotPromptTemplate과 ExampleSelector라는 강력한 도구들을 제공합니다. 이 글에서는 LangChain에서 예시 기반 학습(Few-Shot Learning)을 구현하는 방법과 유사도 기반 예시 선택 기법에 대해 실습 중심으로 정리합니다.
1. FewShotPromptTemplate: 예시 기반 프롬프트 구성
LLM에게 일관된 응답을 유도하기 위해 몇 개의 예시(질문-답변 페어)를 포함한 프롬프트를 생성하는 방식입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from langchain_core.prompts.few_shot import FewShotPromptTemplate
from langchain_core.prompts import PromptTemplate
examples = [
{
"question": "스티브 잡스와 아인슈타인 중 누가 더 오래 살았나요?",
"answer": "... 최종 답변은: 아인슈타인"
},
{
"question": "네이버의 창립자는 언제 태어났나요?",
"answer": "... 최종 답변은: 1967년 6월 22일"
},
# 다른 예시 생략
]
example_prompt = PromptTemplate.from_template(
"Question:\n{question}\nAnswer:\n{answer}"
)
prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
suffix="Question:\n{question}\nAnswer:",
input_variables=["question"],
)
final_prompt = prompt.format(
question="Google이 창립된 연도에 Bill Gates의 나이는 몇 살인가요?"
)
print(final_prompt)
💻 실행 결과 예시
1
2
3
4
5
6
7
8
이 질문에 추가 질문이 필요한가요: 예.
추가 질문: Google은 언제 창립되었나요?
중간 답변: 1998년
추가 질문: Bill Gates는 언제 태어났나요?
중간 답변: 1955년 10월 28일
추가 질문: 1998년 당시 나이는?
중간 답변: 43세
최종 답변은: 43세
2. ExampleSelector: 예시를 자동으로 선택하기
LangChain의 ExampleSelector
는 사용자의 입력과 유사한 예시만 선택하여 프롬프트에 포함시킬 수 있도록 도와주는 모듈입니다. 예시가 많아질수록 모든 예시를 포함하는 것은 비효율적이며, 메모리나 토큰 제한에도 부딪히게 됩니다. 따라서 적절한 예시만 선별하는 것이 중요합니다.
예시가 많아지면 모든 예시를 프롬프트에 포함하는 것은 비효율적입니다. 이때는 입력 질문과 가장 유사한 예시를 자동 선택해주는 ExampleSelector
를 사용할 수 있습니다.
2-1. SemanticSimilarityExampleSelector
SemanticSimilarityExampleSelector
는 질문과 예시 간의 의미적 유사도를 벡터 임베딩 기반으로 계산하여 가장 유사한 예시들을 선택합니다. OpenAI의 임베딩 모델(OpenAIEmbeddings
)을 활용해 각 예시와 입력 질문을 벡터화하고, 코사인 유사도 등을 기준으로 유사한 예시를 골라냅니다.
- 장점: 의미가 비슷한 예시를 잘 골라냄
- 주의: 예시가 많을 경우 초기 벡터 생성 비용이 다소 존재
1
2
3
4
5
6
7
8
9
10
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples=examples,
embedding=OpenAIEmbeddings(),
vectorstore_cls=Chroma,
k=1,
)
2-2. MaxMarginalRelevanceExampleSelector
MaxMarginalRelevanceExampleSelector
는 의미적 유사성과 다양성을 동시에 고려합니다. 입력 질문과 유사하면서도 예시 간 중복도가 낮은(=정보가 겹치지 않는) 예시를 선택합니다. fetch_k
수만큼 후보를 확보한 뒤, 그 중 최대 다양성을 유지하는 k
개의 예시를 선택합니다.
- 장점: 중복 예시 없이 다양한 정보 제공 가능
- 활용 팁: 복잡한 질의나 창의적인 답변이 필요한 경우 적합
1
2
3
4
5
6
7
8
9
from langchain_core.example_selectors import MaxMarginalRelevanceExampleSelector
example_selector = MaxMarginalRelevanceExampleSelector.from_examples(
examples,
OpenAIEmbeddings(),
Chroma,
k=1,
fetch_k=4,
)
2-3. ExampleSelector + FewShotPromptTemplate 통합
1
2
3
4
5
6
7
8
9
10
prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
suffix="Question:\n{question}\nAnswer:",
input_variables=["question"],
)
chain = prompt | llm
response = chain.invoke({"question": "Google이 창립된 연도에 Bill Gates의 나이는 몇 살인가요?"})
print(response)
🖥️ 실행 결과 예시
1
2
3
4
5
6
7
8
이 질문에 추가 질문이 필요한가요: 예.
추가 질문: Google은 언제 창립되었나요?
중간 답변: 1998년
추가 질문: Bill Gates는 언제 태어났나요?
중간 답변: 1955년 10월 28일
추가 질문: 1998년 당시 나이는?
중간 답변: 43세
최종 답변은: 43세
마무리 정리
FewShotPromptTemplate
은 모델에게 예시를 학습시켜 일관된 출력 형식을 유도할 수 있습니다.SemanticSimilarityExampleSelector
는 의미적으로 가까운 예시를 자동으로 선택해줍니다.MaxMarginalRelevanceExampleSelector
는 다양성과 정보성을 고려하여 예시를 선정합니다.
LangChain을 사용하면 프롬프트를 정교하게 설계하고, 자동화된 예시 선택까지 가능하여 질문에 따라 유동적으로 반응하는 LLM 앱을 만들 수 있습니다.