LangChain 실습 1 - Prompt
응답 디버깅을 위해 LangSmith 연동 먼저 할 것
1. Simple Chain(Prompt+LLM+OutputParser)

사용자 입력값을 바탕으로 프롬프트를 생성하고, 생성한 Prompt를 Chain을 통해 LLM에게 전달하고, LLM의 응답결과를 Chain을 통해 Output Parser로 전달하는 과정.
1) PromptTemplate 설정
PromptTemplate ? 사용자의 입력값을 활용하여 문자열 프롬프트를 만드는 데 사용되는 LangChain 기본 API.
from langchain_core.prompts import PromptTemplate
question = "{location}의 맛집을 10개 이상 추천해주세요. \n ### 응답예시 ### \n 번호. 음식점- 설명"
prompt_template = PromptTemplate.from_template(question)
2) LLM 설정
프롬프트를 실행할 LLM 모델 설정
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(api_key=api_key)
3) OutputParser 설정
LLM응답을 간단한 문자열로 변환하는 응답파서
그밖에 JsonParser, PDFParser, ListParser등 변환하고자 하는 데이터에 맞는 다양한 Paraser클래스가 존재한다
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
4) Chain 설정
LCEC사용하여 체인 생성
input = {"location":"강남 역삼"}
chain = prompt_template | llm | output_parser
5) Chain 실행
chain.invoke(input)
2. Chain Invoke Methods
사용자가 정의한 체인을 실행할 수 있는 메서드들
1) invoke / ainvoke(동기/비동기)
체인을 호출하고 결과를 반환하는 함수
chain.invoke(input)
2) stream / astream
체인을 호출하고 결과값을 토큰 형태로 스트리밍 하는 함수
for token in chain.stream(input):
print(token, end="", flush=True)
3) batch / abatch
입력 목록에 대해 체인을 호출하고 목록형태로 값을 반환하는 함수
input1 = input
input2 = {"location" : "선릉 압구정"}
chain.batch([input1 , input2])
3. PromptTemplate 살펴보기
1) PromptTemplate
사용자의 입력값을 활용하여 문자열 프롬프트를 만드는 데 사용되는 LangChain 기본 API.
1. format : 탬플릿에 값을 채워서 문자열을 생성하는 함수
template = "{location}의 맛집을 10개 이상 추천해주세요. \n ### 응답예시 ### \n 번호. 음식점 - 설명"
# PromptTemplate
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate.from_template(template)
prompt = prompt.format(country="강남")
print(prompt)
2. input_variables : 템플릿 문자열의 변수와 비교하여 올바른 변수를 사용 중인지 유효성 검사를 하기 위해 사용하는 설정
prompt = PromptTemplate.from_template(
template=template,
input_variables=["location"] # 템플릿에서 location을 사용하지 않는다면 에러 반환
)
chain = prompt | llm
chain.invoke({"location":"강남"})
template = "{location1}과 {location2}의 맛집을 10개 이상 추천해주세요. \n ### 응답예시 ### \n 번호. 음식점 - 설명"
prompt = PromptTemplate.from_template(
template=template,
#input_variables=["location1","location2"], # 템플릿에서 location을 사용하지 않는다면 에러 반환
partial_variables={
"location1": "강남" # dictionary 형태로 partial_variables를 전달
},
)
chain = prompt | llm
chain.invoke({"location2":"김포"})
4. prompt 결합
PromptTemplate은 문자열 기반 프롬프트를 생성하기 때문에 +연산자를 활용하여 여러 템플릿을 연결할 수 있다.
템플릿 + 템플릿 (O) , 템플릿 + 문자열 (O)
template1 = "{location}의 맛집을 10개 이상 추천해주세요. \n ### 응답예시 ### \n 번호. 음식점 - 설명"
prompt1 = PromptTemplate.from_template(template1)
template2 = "\n그 후 맛집이 어떤 유형의 음식을 파는지 알려주세요 EX)양식, 중식"
prompt2 = PromptTemplate.from_template(template2)
template3 = "\n그 후 맛집에서 파는 추천메뉴를 알려주세요."
combined_prompt= (
prompt1+prompt2+template3
)
chain = combined_prompt | llm
chain.invoke({"location": '역삼'})
2) ChatPromptTemplate
대화목록(Chat)을 입력하여 응답결과를 생성할 때 사용하는 템플릿
대화형 프롬프트, 챗봇 개발시 선택하는 프롬프트
메세지는 튜플형태로 구성되며 (Role, Message)의 구조로 이루어져 있다.
#ChatPrmoptTemplate
from langchain_core.prompts import ChatPromptTemplate
chat_template = ChatPromptTemplate.from_messages(
[
# role, message
("system", "당신은 헬스 트레이너입니다. 신규회원에 대해 친절히 상담해주세요."),
("human", "반가워요!"),
("ai", "안녕하세요! 운동하러 오셨어요?"),
("human", "{user_input}"),
]
)
#체인 생성
chain = chat_template | llm
chain.invoke({"user_input":"PT 1회 체험 가능한가요?"})
3) MessagePlaceholder
입력값으로 대화목록을 넣어야 하는 경우 사용하는 컴포넌트
# MessagePlaceHolder
from langchain_core.prompts import MessagesPlaceholder
chat_template = ChatPromptTemplate.from_messages(
[
# role, message
("system", "당신은 헬스 트레이너입니다. 신규회원에 대해 친절히 상담해주세요."),
("human", "안녕하세요"),
("ai", "안녕하세요! 운동하러 오셨어요?"),
MessagesPlaceholder(variable_name="conversation"), # 대화내용
("human", "{user_input}"),
]
)
#체인 생성
chain = chat_template | llm
chain.invoke({"user_input":"PT 1회 체험 가능한가요?",
"conversation" : [
("human", "네!"),
("ai", "왜요?"),
("human", "살빼고 건강해지고 싶어서요!"),
("ai", "PT한번 받아 보는게 어때요?"),
]
})
4) FewShotPromptTemplate
FewShot Prompt로 템플릿 설계시 사용하는 컴포넌트
examples = [
{
"question": "세상에서 가장 가난한 왕은?",
"answer": "최저임금!."
},
{
"question": "오리가 얼면?",
"answer": "언덕!"
},
{
"question": "김밥이 죽으면 뭐가 될까?",
"answer": "김밥천국!"
},
{
"question": "고구려가 백제한테 이긴 이유는?",
"answer": "고구려가 백제보다 ‘고’(高)퀄리티니까!"
},
{
"question": "컴퓨터가 싫어하는 바람은?",
"answer": "윈도우 업데이트!"
},
{
"question": "소금이 죽으면 뭐가 될까?",
"answer": "죽염!"
},
{
"question": "일본인이 토끼 주둥이를 보고 하는 말은?",
"answer": "코Y네!"
},
]
from langchain_core.prompts import FewShotPromptTemplate
example_prompt = PromptTemplate.from_template("질문: {question}\n{answer}")
# FewShotPromptTemplate을 생성합니다.
prompt = FewShotPromptTemplate(
examples=examples, # 사용할 예제들
example_prompt=example_prompt, # 예제 포맷팅에 사용할 템플릿
suffix="질문: {input}", # 예제 뒤에 추가될 접미사
input_variables=["input"], # 입력 변수 지정
)
chain = prompt | llm
chain.invoke({"input": "일본인이 토끼 주둥이를 보고 하는 말은?"}) # 🐰코Y네
5) Example Selector
2022
주어진 예제들에서 사용자의 입력과 가장 유사한 예제를 선택하도록 도와주는 컴포넌트
실습에서 사용할 SemanticSimilarityExampleSelector는 의미적 유사성(Semantic Similarity)을 기준으로 예제를 선택한다.
# ExampleSelector
from langchain_chroma import Chroma
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings
# SemanticSimilarityExampleSelector
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples, # 사용할 예제들
OpenAIEmbeddings(), # 임베딩 모델 -> 의미적 유사성을 측정하기 위해 사용하는 클래스
Chroma, # 벡터 저장소 -> 임베딩을 저장할 저장소
k=1, # 생성할 예제 수
)
# 새로운 질문에 대해 가장 유사한 예제를 선택합니다.
question = "섹시한 소금은?" # 요염
selected_examples = example_selector.select_examples({"question": question})
print(f"입력과 가장 유사한 예제: {question}") # 소금이 죽으면? 죽염
for example in selected_examples:
print(f'question:\n{example["question"]}')
print(f'answer:\n{example["answer"]}')
# FewShotPromptTemplate에 ExampleSelector추가
prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
suffix="Question:\n{question}\nAnswer:",
input_variables=["question"],
)
chain = prompt | llm
chain.invoke(
{"question": "섹시한 소금은?"}
)
유사도 분석에 대해서 여기에 설명하기
6) Langchain Hub를 활용한 Prompt 형상관리
Last updated