LangChain을 활용하여 대화형 AI 모델의 프롬프트를 효율적으로 구성하고 관리하는 방법을 알아보자. 특히, PromptTemplate
과 ChatPromptTemplate
을 이용해 다양한 방식으로 프롬프트를 생성하고 사용하는 방법을 예제를 통해 살펴보자.
PromptTemplate
1. from_template을 통해 한번에 prompt 만드는 방법
PromptTemplate
의 from_template
메서드를 사용하면 간단히 프롬프트를 만들 수 있다. 아래 예시는 특정 작업을 지정된 프로그래밍 언어로 수행하는 로직을 요청하는 프롬프트를 생성하는 방법을 보여준다.
from langchain_core.prompts import PromptTemplate
template = "{task}을 수행하는 로직을 {language}으로 작성해 줘~"
prompt_template = PromptTemplate.from_template(template)
prompt = prompt_template.format(task="0부터 10까지 계산", language="파이썬")
if __name__ == "__main__":
print(prompt) # 0부터 10까지 계산을 수행하는 로직을 파이썬으로 작성해 줘~
2. 생성자를 통해 prompt_template을 생성하는 방법
PromptTemplate
은 생성자를 통해서도 만들 수 있다. 이 방법을 사용하면 input_variables
를 명시적으로 지정할 수 있다. 흥미롭게도, input_variables
를 생략해도 프롬프트 생성이 가능하다.
from langchain_core.prompts import PromptTemplate
template = "{task}을 수행하는 로직을 {language}으로 작성해 줘~"
prompt_template = PromptTemplate(
template=template,
input_variables=["task", "language"],
# input_variables=[], # input_variables=[] 으로 해도 실행된다.
)
prompt = prompt_template.format(task="0부터 10까지 계산", language="파이썬")
if __name__ == "__main__":
print(prompt) # 0부터 10까지 계산을 수행하는 로직을 파이썬으로 작성해 줘~
PromptTemplate의 input_variables은 없어도 동일하게 실행이 된다.
prompt_template = PromptTemplate(
template=template,
# input_variables=[], # input_variables=[] 으로 해도 실행된다.
)
3. json 파일을 통해 PromptTemplate 생성하는 방법
프롬프트 템플릿을 JSON 파일로 관리할 수도 있다. 이를 통해 프롬프트 구성을 외부 파일에서 불러와 사용할 수 있다.
from langchain_core.prompts import load_prompt
prompt_template = load_prompt("sample/template.json")
prompt = prompt_template.format(task="0부터 10까지 계산", language="파이썬")
print(prompt) # 0부터 10까지 계산을 수행하는 로직을 파이썬으로 작성해 줘~
template.json 파일 내용
{
"name": null,
"input_variables": [
"task",
"language"
],
"input_types": {},
"output_parser": null,
"partial_variables": {},
"template": "{task}을 수행하는 로직을 {language}으로 작성해 줘~",
"template_format": "f-string",
"validate_template": false,
"_type": "prompt"
}
4. partial_variables으로 함수를 전달하여 prompt_template을 생성하는 방법
partial_variables
는 체인의 일부 변수에 대해 미리 정의된 값을 제공하여 체인 실행에 필요한 모든 변수를 한 번에 지정하지 않고도 체인을 실행할 수 있다. 예를 들어, 체인의 일부 변수는 고정된 값으로 설정하고 나머지 변수만 실행 시점에 제공하도록 할 수 있다.
def get_language():
return "파이썬"
prompt_template = PromptTemplate(
template="{task}을 수행하는 로직을 {language}으로 작성해 줘~",
input_variables=["task"],
partial_variables={"language": get_language}, # partial_variables에 함수를 전달
)
prompt = prompt_template.format(task="0부터 10까지 계산")
print(prompt)
위의 로직은 아래와 같이 RunnablePassthrough
를 사용하여 더 유연하게 적용할 수 있다.
prompt_template = PromptTemplate(
template="{task}을 수행하는 로직을 {language}으로 작성해 줘~",
input_variables=["task"],
partial_variables={"language": get_language},
)
runnable_template = {"task": RunnablePassthrough()} | prompt_template
prompt = runnable_template.invoke("0부터 10까지 계산")
print(prompt.text)
ChatPromptTemplate
대화형 AI 모델에 특화된 프롬프트 템플릿을 만들 때는 ChatPromptTemplate
을 사용할 수 있다. 이는 메시지 기반의 대화 흐름을 구성하는 데 유용하다.
from langchain_core.prompts import ChatPromptTemplate
prompt_template = ChatPromptTemplate.from_messages(
[
("system", "당신은 맛집 전문가이다."),
("ai", "나는 {city}을 방문하려고 한다."),
("human", "{question}"),
]
)
prompt = prompt_template.format_messages(city="서울", question="맛집 추천해줘")
print(prompt)
실행 결과는 메시지 리스트로 반환된다.
실행결과
[
SystemMessage(content='당신은 맛집 전문가이다.'),
AIMessage(content='나는 서울을 방문하려고 한다.'),
HumanMessage(content='맛집 추천해줘')
]
또는 invoke
메서드를 사용하면 동일한 결과를 얻을 수 있다.
prompt = prompt_template.invoke({"city": "서울", "question": "맛집 추천해줘"})
print(prompt) #
실행결과
messages=[SystemMessage(content='당신은 맛집 전문가이다.'), AIMessage(content='나는 서울을 방문하려고 한다.'), HumanMessage(content='맛집 추천해줘')]
MessagePlaceholder
체인의 메시지 흐름에서 특정 위치에 동적으로 삽입될 메시지를 추가
하는데 사용된다. 이는 대화형 AI 모델이나 다른 응답 생성 시스템을 구축할 때 유용하며, 특정 메시지가 실행 시점에 동적으로 생성되거나 제공되어야 하는 경우에 사용된다.
LLM 호출할 때 이전 메시지 내용을 전부 전달할 때 사용되며 우리가 메시지 내용을 일일히 구성할 필요없이 이전 메시지 내용을 conversation 배열에 넣어서 전달하고 위치만 정하면 알아서 메시지 내용을 구성해준다.
template = ChatPromptTemplate(
[
("system", "너는 AI 봇이야"),
("placeholder", "{conversation}"),
("human", "거기에 1을 더하면?"),
]
)
ChatPromptTemplate
에 placeholder
를 키로 conversation
을 추가하면 된다. 또는 아래와 같이 사용해도 된다.
template = ChatPromptTemplate(
[
("system", "너는 AI 봇이야"),
MessagesPlaceholder(variable_name="conversation", optional=True)
("human", "거기에 1을 더하면?"),
]
)
실제 사용을 할 때는 아래와 같이 conversation에 이전 대화 이력을 추가하고 호출하면 된다.
prompt = template.invoke(
{
"conversation": [
("human", "안녕~"),
("ai", "무엇을 도와드릴까요?"),
("human", "1+1은 뭐야?"),
("ai", "2입니다."),
]
}
)
print(prompt)
실행결과
messages=[SystemMessage(content='너는 AI 봇이야'), HumanMessage(content='안녕~'), AIMessage(content='무엇을 도와드릴까요?'), HumanMessage(content='1+1은 뭐야?'), AIMessage(content='2입니다.'), HumanMessage(content='거기에 1을 더하면?')]
실제 LLM을 호출해보자.
langchain.debug = True
load_dotenv()
llm = ChatOpenAI(temperature=0, model_name="gpt-4o")
chain = template | llm | StrOutputParser()
result = chain.invoke(
{
"conversation": [
("human", "안녕~"),
("ai", "무엇을 도와드릴까요?"),
("human", "1+1은 뭐야?"),
("ai", "2입니다."),
]
}
)
print(result)
langchain.debug = True
를 해서 실제 llm 호출내용을 확인해보면 아래와 같다.
[llm/start] [chain:RunnableSequence > llm:ChatOpenAI] Entering LLM run with input:
{
"prompts": [
"System: 너는 AI 봇이야\nHuman: 안녕~\nAI: 무엇을 도와드릴까요?\nHuman: 1+1은 뭐야?\nAI: 2입니다.\nHuman: 거기에 1을 더하면?"
]
}
System, Human, Ai의 메시자가 \n
를 구분으로 입력이 된다.