LangChain
- 언어 모델에 기반한 AI 애플리케이션을 쉽게 개발할 수 있도록 도와주는 Framework
- 기존 언어 모델 API를 사용하는 방식은 원하는 기능을 구현하기 위해 모든 코드를 작성했어야 함
- 랭체인을 사용하면 작업들을 간소화 할 수 있고, 다른 언어 모델을 쉽게 교체가 가능하다
pip install langchain
pip install langchain-openai
langchain-openai의 같은 경우 오픈AI 의 GPT API를 사용하기 위해 다운로드 받는다
그래서 기존에 라이브러리와 다르게 import 한다
#기존
from openai import OpenAI
#Langchain
from langchain_openai import ChatOpenAI
불러 올때는 dotenv를 이용하여 다음과 같이 model을 불러와 주면 된다 (본인의 경우 /model애 gemma 들어있음)
from langchain_openai import ChatOpenAI
import os
from dotenv import load_dotenv
load_dotenv()
base_url = os.getenv('base_url')
api_key = os.getenv('api_key')
model = ChatOpenAI(
openai_api_base = base_url,
openai_api_key = api_key,
model="/model",
temperature=0.2
)
다음과 같이 모델을 불러왔다면
role : "user" 와 같이 사용 되는 HumanMessage를 작성해 주자 (사용자 메세지)
message 형태는 list에 담아주면 된다
from langchain_core.messages import HumanMessage
model.invoke([HumanMessage(content="안녕")])
#openai의 경우
{"role":"user","content","안녕"}
invoke = 호출하다
그러면 response가 content에 담겨서 나오게 된다
HumanMessage 외에도 다음과 같이 다양한 Message Type이 있다
AIMessage : 인공지능이 답변해주는 역할 (assistant)
HumanMessage :사용자의 Message (user)
SystemMessage : System
멀티턴
마찬가지로 그냥 출력만 한다면 AI가 대화 내용을 기억하지 못하기 때문에
대화내용을 List에 담아줘야 한다
from langchain_core.messages import HumanMessage,SystemMessage,AIMessage
messages =[
SystemMessage(content="너는 사용자를 도와주는 상담사야")
]
while True:
user_input = input("사용자: ")
if user_input == "exit":
break
messages.append(
HumanMessage(user_input)
)
ai_response = llm.invoke(messages)
messages.append(ai_response)
print("AI : " + ai_response.content)
break
여기서 특이한 점은 message에 추가할 때 reponse 그대로 추가하는 것이다 (content 추출 필요 x)
그 이유는 위에 결과와 같이 return값 자체가 AIMessage 여서 편리하게 가능하다
근데 이렇게 하나하나 list에 넣는 것은 개선 되어야한다
그래서 나온 것이 메세지 히스토리이다
from langchain_core.chat_history import InMemoryChatMessageHistory # 메모리에 대화 기록을 저장하는 클래스
from langchain_core.runnables.history import RunnableWithMessageHistory # 메시지 기록을 활용해 실행 가능한 래퍼wrapper 클래스
이걸한다고 계속 저장되는 것은 당연히 아니고 단순히 메모리 내에서 메세지를 리스트 형태로 보관하는 것이다
(어플리케이션 종료 시 휘발) => 이를 막기 위해서는 파일이나 DB에 저장해야 한다
또한 기존에는 llm.invoke 와 같이 AI를 실행하였다면
RunnableWithMessageHistory를 이용하여 실행해 준다
from langchain_core.chat_history import InMemoryChatMessageHistory # 메모리에 대화 기록을 저장하는 클래스
from langchain_core.runnables.history import RunnableWithMessageHistory # 메시지 기록을 활용해 실행 가능한 래퍼wrapper 클래스
from langchain_openai import ChatOpenAI # 오픈AI 모델을 사용하는 랭체인 챗봇 클래스
from langchain_core.messages import HumanMessage
# 세션별 대화 기록을 저장할 딕셔너리
store = {}
# 세션 ID에 따라 대화 기록을 가져오는 함수
def get_session_history(session_id: str):
# 만약 해당 세션 ID가 store에 없으면, 새로 생성해 추가함
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory() # 메모리에 대화 기록을 저장하는 객체 생성
return store[session_id] # 해당 세션의 대화 기록을 반환
# 모델 실행 시 대화 기록을 함께 전달하는 래퍼 객체 생성
with_message_history = RunnableWithMessageHistory(llm, get_session_history)
config = {"configurable": {"session_id": "user_id"}} # 세션 ID를 설정하는 config 객체 생성
response = with_message_history.invoke(
[HumanMessage(content="안녕? 난 홍길동이야.")],
config=config,
)
print(response.content)
config는 왜 굳이 저렇게 정해줬냐면
langchain은 프레임 워크이기 때문에 사용하기 위해 규약을 확인해 줘야 한다
여기에 저렇게 id 관리하라고 써 있음
즉 RunnableWithMessageHistory는 config (과거이력)을 참고하여 AI 답변을 만들어 주는 것이고
애플리케이션이 종료되기 전까지 AI가 읽었던 config는 계속 가지고 간다
response = with_message_history.invoke(
[HumanMessage(content="안녕? 난 홍길동이야.")],
config={"configurable": {"session_id": "my_user_id"}}, # 세션 ID를 설정하는 config 객체 생성
)
print(response.content)
print(config)
response = with_message_history.invoke(
[HumanMessage(content="내 이름이 뭐야.")],
config=config,
)
print(response.content)
즉 다음과 같이 config 다르게 하면 기록에 없다고 나온다
근데 성질 급한 한국인들 한글자 한글자 생성될 때마다 보고 싶어 한다
그럴 때는 invoke 되신 stream을 써주면 된다
당연히 반복문은 들어가야 한다
for resp in with_message_history.stream(
[HumanMessage(content="사과의 색깔이 뭐야.")],
config={"configurable": {"session_id": "my_user_id"}}, # 세션 ID를 설정하는 config 객체 생성
):
print(resp.content,end="|")
근데 슬슬 느끼는 것이 AIMessage에서 맨날 content 뽑아내는 것도 귀찮다( 너무 많은 정보가 담겨 있음)
그럴 때는 output parser를 만들어서 이용해주면 된다 (ex STROutputParser) -> 즉 그냥 parser를 통과 시켜 주면된다
from langchain_core.output_parsers import StrOutputParser
sparser = StrOutputParser()
result = llm.invoke([HumanMessage(content="사과의 색깔이 뭐야.")])
sparser.invoke(result)
이렇게 두번하기 위찮으면 | 연산자로 이어주면 된다
from langchain_core.output_parsers import StrOutputParser
sparser = StrOutputParser()
chain = llm | sparser
result = chain.invoke([HumanMessage(content="사과의 색깔이 뭐야.")])
result
Prompt Template
근데 매번 프롬포트 작성하는 것도 귀찮기 때문에 프롬포트 템플릿을 만들어주면 좋다
from langchain_core.prompts import ChatPromptTemplate
system_template = "너는 {story}에 나오는 {character_a} 역할이다. 그 캐릭터에 맞게 사용자와 대화하라."
human_template = "안녕? 저는 {character_b}입니다. 오늘 시간 괜찮으시면 {activity} 같이 할까요?"
prompt_template = ChatPromptTemplate([
("system", system_template),
("user", human_template),
])
result = prompt_template.invoke({
"story": "미녀와 야수",
"character_a": "미녀",
"character_b": "야수",
"activity": "저녁"
})
print(result)
langchain의 이름 답게 이를 또 | 연산자로 이어서 만들 수 있다
chain = prompt_template | model | sparser
chain.invoke({
"story": "미녀와 야수",
"character_a": "미녀",
"character_b": "야수",
"activity": "저녁"
})
'AI Study > AI Agent' 카테고리의 다른 글
[AI Agent] ollama 모델 Open Web ui 연동(Docker) (0) | 2025.10.29 |
---|---|
Ollama를 이용한 환경 세팅 (0) | 2025.10.27 |
[AI Agent] OPEN AI의 세가지 API (0) | 2025.10.23 |
[AI Agent] OpenAI API 사용 방법 및 기초 코드 (0) | 2025.09.25 |
RAG의 등장 배경 및 기초 설명 (0) | 2025.09.17 |