참고자료


1️⃣ Langchain 이해하기

📋 Langchian의 필요성

Langchian

랭체인(LangChain)은 LLM(대형 언어 모델)을 사용하여 애플리케이션 생성을 단순화하도록 설계된 프레임워크이다.(참고: 위키백과)

다양한 AI 모델을 통합하여 관리

from openai import OpenAI
 
client = OpenAI()
 
completion = client.chat.completions.create(
    model = "gpt-3.5-turbo",
    messages = [
        {"role": "system", "content": "당신은 USER의 말에 공감해주는 상담사입니다."},
        {"role": "user", "content": "우울해서 빵을 샀어"}
    ]
)
 
response = completion.choices[0].message
print(response)
 
# Output
# ChatCompletionMessage(content='저도 그런 날이 있어요. 때때로 작은 것이라도 기분을 나아지게 해줄 때가 있죠. 빵을 사서 즐거운 시간을 보내셨길 바라요. 혹시 먹을 때 무슨 종류를 샀나요? 함께 얘기 나누면서 더 즐거운 시간이 될지도 모르겠어요.', role='assistant', function_call=None, tool_calls=None, refusal=None)

LLM과 상호작용할 때 역할은 3가지로 분류할 수 있다.

역할설명
SYSTEM- 모든 상황에 공통적으로 부여되는 지시사항
- 모델의 행동, 성격, 지식 범위 등을 설정
USER- question. 사용자가 모델에 전달하는 메세지
- Template을 통해 지시사항을 함께 입력하기도 함
ASSISTANT- answer. 프롬프트에 대한 모델의 결과값

📋 LangSmith를 통해 추적

LangSmith는 LLM 애플리케이션을 개발, 협업, 테스트, 배포 및 ==모니터링==하기 위한 통합 DevOps 플랫폼이다.

프로젝트별로 구분하여 비용, 사용량, 결과 과정 등을 확인할 수 있어 편리하다.

LangSmith페이지에서 [⚙ Settings] 에 들어가면 LANGCHAIN_API_KEY를 발급받을 수 있다.

# .env
OPENAI_API_KEY = "sk-XXX..."
LANGCHAIN_API_KEY = "XXX..."
LANGCHAIN_TRACING_V2 = "true"
LANGCHAIN_ENDPOINT = "https://api.smith.langchain.com"

나는 파일마다 관리하는 프로젝트가 달라 LANGCHAIN_PROJECT는 코드에서 관리했다.

import os 
from dotenv import load_dotenv
 
load.dotenv()
os.environ["LANGCHAIN_PROJECT"] = "[프로젝트 이름]"

📋 Langchain 없는 OpenAI

📋 Langchain 이용

기본 사용 (1) 단순 질의 응답

# Langchain 이용하기 - 단순 질문
from langchain_openai import ChatOpenAI 
 
model = ChatOpenAI(model_name = "gpt-3.5-turbo") 
response = model.invoke("오늘 너무 우울해서 빵을 샀어")
print(response)
 
# Output
# AIMessage(content='저도 가끔 그럴 때가 있어요. 빵을 사서 조금이라도 기분을 나누고 싶은 마음이 이해돼요. 하지만 무엇보다 중요한 건 그 우울함을 해소하기 위해 노력하는 것이에요. 빵을 먹으면서 마음이 편안해지길 바라고, 우울함을 이겨내기 위해 노력해보세요. 함께 극복할 수 있을 거예요. 함께해요! :)', response_metadata={'token_usage': {'completion_tokens': 156, 'prompt_tokens': 27, 'total_tokens': 183, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-0b598102-ea70-4c9d-ad0f-170bf9253471-0', usage_metadata={'input_tokens': 27, 'output_tokens': 156, 'total_tokens': 183})

기본 사용 (2) Chat 기반 역할 구분

from langchain_openai import ChatOpenAI 
from langchain.schema import AIMessage, HumanMessage, SystemMessage 
 
model = ChatOpenAI(model_name="gpt-3.5-turbo")
messages = [
    SystemMessage(
        content = "당신은 매우 이성적인 사람입니다."
    ),
    HumanMessage(
        content = "오늘 너무 우울해서 빵을 샀어"
    ),
]
 
response = model.invoke(messages)
print(response.content)
 
# Output
# 우울할 때 당황스럽고 위압감을 느낄 수 있지만, 먹는 것으로 감정을 달래는 것은 일시적인 해결책이 될 수 있습니다. 좀 더 건강한 방법으로 우울함을 극복할 수 있는 방법을 찾아보는 것이 중요합니다. 운동을 하거나 취미 활동을 즐기는 것도 좋은 방법일 수 있습니다. 또한, 친구나 가족과 소통하거나 전문가의 도움을 받는 것도 고려해보세요. 심리적인 안정을 찾는 것이 중요합니다. 함께 이야기를 나누는 것이 도움이 되길 바랍니다.

2️⃣ Langchain with Template

LLM을 제대로 활용하기 위해서는 더 많은 지시사항과 변수들이 필요하다.

이를 ==Prompt(프롬프트) 라고 하는데 LLM에 Prompt를 적용하기 위한 도구가 바로 Chain== 이다.

프롬프트에 특정 문자열이 계속 바뀌는 경우에는 {}를 통해 변수로 지정할 수 있는데, 이를 input_variables라고 한다. 따라서 model_invoke()를 할 때에는 input_variables를 딕셔너리 형태로 입력해야 한다.

기본적인 코드는 다음과 같다. 주로 PromptTemplateChatPromptTemplate가 많이 쓰인다.

from langchain_openai import ChatOpenAI 
from langchain_core.prompts import PromptTemplate
from langchain.chains import LLMChain
 
def make_chain(prompt):
    model = ChatOpenAI(model_name = "gpt-3.5-turbo") 
    chain = LLMChain(prompt=prompt, llm=model)
 
	return chain
 
prompt1 = PromptTemplate.from_template("{object} 가 영어로 뭐야?")
prompt2 = ChatPromptTemplate.from_messages(
    [
        ("system", "object를 영어로 번역해주세요"),
        ("human", "{object}"),
    ]
)
 
chain = make_chain(prompt1) # prompt2
chain.invoke()

📋 Prompt 유형

PromptTemplate

from langchain_core.prompts import PromptTemplate
 
prompt = PromptTemplate.from_template("{object}가 영어로 뭐야?")
chain = make_chain(prompt)
response = chain.invoke({"object":"다람쥐"})
print(response)
 
# Output
# {'object': '다람쥐', 'text': '다람쥐는 영어로 squirrel이라고 합니다.'}

여기서 prompt는 다음과 같이 저장된다.

prompt = PromptTemplate.from_template("{object}{language}로 뭐야?")
print(prompt)
 
# Output
# input_variables=['object'] template='{object}가 영어로 뭐야?'

ChatPromptTemplate

챗봇과 같이 역할의 구분이 필요할 때에는 ChatPromptTemplate을 사용한다.

이 구조는 나중에 메모리 저장 기능이 들어갈 때 많이 쓰인다.

from langchain_core.prompts import ChatPromptTemplate
 
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "영어로 번역해주세요"),
        ("human", "{object}"),
    ]
)
chain = make_chain(prompt)
response = chain.invoke({"object":"다람쥐"})
print(response)
 
# Output
# {'object': '다람쥐', 'text': 'Squirrel'}

여기서 prompt는 다음과 같이 저장된다.

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "영어로 번역해주세요"),
        ("human", "{object}"),
    ]
)
print(prompt)
 
# Output
# input_variables=['object'] messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], template='영어로 번역해주세요')), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['object'], template='{object}'))]

📋 반복 작업

만약 동일한 작업을 여러 번 실행해야 하는 경우 apply()generate()를 활용한다.

input_list = [{"object":"선풍기"},{"object":"지하철"},{"object":"화장"}]
 
prompt1 = PromptTemplate.from_template("{object} 가 영어로 뭐야?")
prompt2 = ChatPromptTemplate.from_messages(
    [
        ("system", "영어로 번역해주세요"),
        ("human", "{object}"),
    ]
)

apply

# Prompt 1
chain = make_chain(prompt1)
 
response = chain.apply(input_list)
print(response)
 
# Output
# [{'text': '선풍기는 영어로 "fan" 입니다.'},
#  {'text': 'Subway'},
#  {'text': '번역은 "translation" 입니다.'}]
 
# Prompt 2
chain = make_chain(prompt2)
 
response = chain.apply(input_list)
print(response)
 
# Output
# [{'text': 'fan'}, {'text': 'subway'}, {'text': 'Translation'}]

generator

# Prompt 1
chain = make_chain(prompt1)
 
response = chain.generate(input_list)
print([x[0].text for x in response.generations])
 
# Output
# ['선풍기는 영어로 "fan" 입니다.', 'Subway', '번역은 영어로 translation이라고 합니다.']
 
# Prompt 2
chain = make_chain(prompt2)
 
response = chain.generate(input_list)
print([x[0].text for x in response.generations])
 
# Output
# ['fan', 'Subway', 'Translation']