랭체인

0201 강의 Part.2 Ch.1 11~13 파일 01-01 partial_variables,ChatPromptTemplate, MessagePlaceholder

유방울 2025. 1. 25. 06:45

방법 1 from-template() 메소드 사용해 PromptTemplate 객체 생성

치환될 변수를 {}로 묶어서 템플릿 정의=

from langchain_core.prompts import PromptTemplate

# template 정의. {country}는 변수로, 이후에 값이 들어갈 자리를 의미
template = "{country}의 수도는 어디인가요?"

# from_template 메소드를 이용하여 PromptTemplate 객체 생성
prompt = PromptTemplate.from_template(template)
prompt

PromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, template='{country}의 수도는 어디인가요?')

 

변수 대한민국으로 넣어보기

prompt.format

# format으로 변수 입력하고 prompt 출력시 제대로 나옴
prompt = prompt.format(country="대한민국")
prompt

'대한민국의 수도는 어디인가요?'

 

다시 보면!##

template 만들고

prompt 만들고

chain 만들어서 invoke (딕셔너리형태가 정석인데 변수가 1개면 key값만 입력 가능)

# template 정의
template = "{country}의 수도는 어디인가요?"

# from_template 메소드를 이용하여 PromptTemplate 객체 생성
prompt = PromptTemplate.from_template(template)

# chain 생성
chain = prompt | llm

# country 변수에 입력된 값이 자동으로 치환되어 수행됨
# 아래처럼 딕셔너리 형식이 정석임
# chain.invoke({"country":"대한민국"}).content

chain.invoke("대한민국").content

'대한민국의 수도는 서울입니다.'

 

방법 2 PromptTemplate 객체 생성과 prompt 동시에 생성

유효성 검사를 위해 input_variables를 명시적으로 지정

# template 정의
template = "{country}의 수도는 어디인가요?"

# PromptTemplate 객체를 활용하여 prompt_template 생성
# 여태까지랑 다른 방식
# 직관적인 스타일
prompt = PromptTemplate(
    template=template,
    input_variables=["country"],
)

prompt
PromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, template='{country}의 수도는 어디인가요?')
# prompt 생성
prompt.format(country="대한민국")

'대한민국의 수도는 어디인가요?'

partial_variables

변수 2개 이상

country2 미국임

# template 정의
# partial_variables 입력받아야 할 변수가 2개 이상일 때 중간과정에서 변수가 확정될 때

template = "{country1}과 {country2}의 수도는 각각 어디인가요?"

# PromptTemplate 객체를 활용하여 prompt_template 생성
prompt = PromptTemplate(
    template=template,
    input_variables=["country1"],
    partial_variables={
        "country2": "미국"  # dictionary 형태로 partial_variables를 전달
    },
)

prompt
PromptTemplate(input_variables=['country1'], input_types={}, partial_variables={'country2': '미국'}, template='{country1}과 {country2}의 수도는 각각 어디인가요?')

country1에 대한민국 넣어서 

prompt 확인하면 대한민국, 미국 뜸

prompt.format(country1="대한민국")

'대한민국과 미국의 수도는 각각 어디인가요?'

 

partial_variables

partial : 함수를 부분적으로 사용

아래 예시는 항상 공통된 방식으로 가져오고 싶은 변수가 있음

ex)  날짜, 시간

 

결괏값이 function -> 아직 호출되지 않은 것임

get today 함수가 있고 오늘 날짜 알아서 받아올 것이고

n도 아직 안 들어가서 호출 안됨

# 매개변수 받을 필요 없음
# strtime 아니고 strftime임!
def get_today():
    return datetime.now().strftime("%B %d")
    
prompt = PromptTemplate(
    template="오늘의 날짜는 {today}입니다. 오늘이 생일인 유명인 {n}명을을 나열해 주세요. 생년월일을 표기해주세요.",
    input_variables=["n"],
    partial_variables={
        "today": get_today
    },
)
prompt

PromptTemplate(input_variables=['n'], input_types={}, partial_variables={'today': <function get_today at 0x000001E6FD260040>}, template='오늘의 날짜는 {today}입니다. 오늘이 생일인 유명인 {n}명을을 나열해 주세요. 생년월일을 표기해주세요.')

prompt 3으로 format

prompt.format(n=3)

'오늘의 날짜는 January 26입니다. 오늘이 생일인 유명인 3명을을 나열해 주세요. 생년월일을 표기해주세요.'

chain 생성 후 invoke 실행

# chain 을 생성합니다.
chain = prompt | ChatOpenAI(model_name="gpt-4o", temperature=0)

# chain 을 실행 후 결과를 확인합니다.
# 
print(chain.invoke(3).content)

 

파일로 template 읽어오기

파일이 길어지면? 파일로 불러올 수 있음

파일형식 : yaml

인코딩 설정 해야지 오류 안 뜸

예시 1

# 프롬프트가 길어진다면? 파일로 불러오기
from langchain_core.prompts import load_prompt

prompt = load_prompt("prompts/fruit_color.yaml", encoding="utf-8")
prompt

PromptTemplate(input_variables=['fruit'], input_types={}, partial_variables={}, template='{fruit}의 색깔이 뭐야?')

예시 2

# 조금 더 긴 prompt
# encoding="utf-8" 이거 넣어줘야 함
prompt2 = load_prompt("prompts/capital.yaml", encoding="utf-8")
print(prompt2.format(country="대한민국"))

대한민국의 수도에 대해서 알려주세요.
수도의 특징을 다음의 양식에 맞게 정리해 주세요.
300자 내외로 작성해 주세요.
한글로 작성해 주세요.
----
[양식]
1. 면적
2. 인구
3. 역사적 장소
4. 특산품

#Answer:

ChatPromptTemplate

대화형식으로 프롬프트 주입

튜플 형식(role, message) 구성

system

human : 사용자의 입력값

ai : 출력값

# PromptTemplate이 아닌 Chat이 붙어있음
# 메세지에 HumanMessagePromptTemplate로 한 번 감싸져짐
from langchain_core.prompts import ChatPromptTemplate

chat_prompt = ChatPromptTemplate.from_template("{country}의 수도는 어디인가요?")
chat_prompt

ChatPromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['country'], input_types={}, partial_variables={}, template='{country}의 수도는 어디인가요?'), additional_kwargs={})])

Human

# content가 아니라 Human으로 나옴
# role과 메세지가 있음
# human 우리가 입력한 입력값
# 답변 ai의 답변 메세지
chat_prompt.format(country="대한민국")

'Human: 대한민국의 수도는 어디인가요?'

 from_message에서 튜플로 넣는데 한 번 대괄호로 묶어야 함

template은 from_message()

messages 생성은 format_messages()

from langchain_core.prompts import ChatPromptTemplate

# 메세지는 tuple 형식임
# role은 system, human, ai 중 하나 넣어야 함
chat_template = ChatPromptTemplate.from_messages(
    [
        # role, message
        ("system", "당신은 친절한 AI 어시스턴트입니다. 당신의 이름은 {name} 입니다."),
        ("human", "반가워요!"),
        ("ai", "안녕하세요! 무엇을 도와드릴까요?"),
        ("human", "{user_input}"),
    ]
)

# 챗 message 를 생성합니다.
messages = chat_template.format_messages(
    name="테디", user_input="당신의 이름은 무엇입니까?"
)
messages

[SystemMessage(content='당신은 친절한 AI 어시스턴트입니다. 당신의 이름은 테디 입니다.', additional_kwargs={}, response_metadata={}),
 HumanMessage(content='반가워요!', additional_kwargs={}, response_metadata={}),
 AIMessage(content='안녕하세요! 무엇을 도와드릴까요?', additional_kwargs={}, response_metadata={}),
 HumanMessage(content='당신의 이름은 무엇입니까?', additional_kwargs={}, response_metadata={})]
llm.invoke(messages).content

'제 이름은 테디입니다. 어떻게 도와드릴까요?'

따란

# 뒤에 outputparser를 넣으면 text를 받을 수 있음
chain = chat_template | llm

# 이름을 Teddy로 넣음
# 이전에는 하나의 질문인데 
# 대화형 형식의 프롬프트 만들고 human의 role이 있고 변수가 있고 이를 채우면 답변을 해줌
chain.invoke({"name": "Teddy", "user_input": "당신의 이름은 무엇입니까?"}).content

'제 이름은 Teddy입니다. 저를 통해 궁금한 것이 있거나 도움이 필요하신 경우 언제든지 말씀해주세요!'

정리 : PromptTemplate과 달리 ChatPromptTemplate은 대화형 형식이고, system과 role이 있어서

chat에 최적화됨


MessagePlaceholder

:채워지지 않은 것

:나중에 채워질 곳을 일단 잡아두고 있는 것

:ex 대화 내용을 기록할 때 사용함

: 쌓인 대화를 중간에 input으로 넣어야 하는데 대화가 아직 확정이 안 됨 -> history 변수에 넣음

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

chat_prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "당신은 요약 전문 AI 어시스턴트입니다. 당신의 임무는 주요 키워드로 대화를 요약하는 것입니다.",
        ),
        MessagesPlaceholder(variable_name="conversation"),
        ("human", "지금까지의 대화를 {word_count} 단어로 요약합니다."),
    ]
)
chat_prompt

나중에 사용하는 경우

formatted_chate_prompt 확인

# format으로 채운 것은 word count랑 conversation으로 input variable만 채움
# 아래 코드에서 formatted_chat_prompt 변수로 지정하지 않으면 아직 invoke할 수 없는 것이고 걍 format만 한 것임

formatted_chat_prompt = chat_prompt.format(
    word_count=5,
    conversation=[
        ("human", "안녕하세요! 저는 오늘 새로 입사한 테디 입니다. 만나서 반갑습니다."),
        ("ai", "반가워요! 앞으로 잘 부탁 드립니다."),
    ],
)

print(formatted_chat_prompt)

# format으로 채운 것은 word count랑 conversation으로 input variable만 채움
# 아래 코드에서 formatted_chat_prompt 변수로 지정하지 않으면 아직 invoke할 수 없는 것이고 걍 format만 한 것임

formatted_chat_prompt = chat_prompt.format(
    word_count=5,
    conversation=[
        ("human", "안녕하세요! 저는 오늘 새로 입사한 테디 입니다. 만나서 반갑습니다."),
        ("ai", "반가워요! 앞으로 잘 부탁 드립니다."),
    ],
)

print(formatted_chat_prompt)

chain 생성 후 invoke

근데 결과가 잘 안 나옴;

word count 에 맞게 output이 안 나옴.............

# chain 생성
chain = chat_prompt | llm | StrOutputParser()

# chain 실행 및 결과확인
chain.invoke(
    {
        "word_count": 5,
        "conversation": [
            (
                "human",
                "안녕하세요! 저는 오늘 새로 입사한 테디 입니다. 만나서 반갑습니다.",
            ),
            ("ai", "반가워요! 앞으로 잘 부탁 드립니다."),
        ],
    }
)

'새로 입사한 테디, 반가워요!'