GitHub - Olow304/memvid: Video-based AI memory library. Store millions of text chunks in MP4 files with lightning-fast semantic search. No database needed.
GitHub
1. 이번 주 목표
커리큘럼 상의 목표는 챗봇의 형태의 서비스를 구현해보는것
이다.
커리큘럼 자체보다는 LangChain에 관심이 많아 이를 더 잘 이해하기 위한 포석으로 삼는다.
2. 학습 내용
1. LangChain
기본적으로 챗봇
은 다음과 같은 방식으로 동작한다.
유저의 메세지를 LLM에 입력으로 전달
LLM inference를 통해 출력으로 답변을 획득
획득한 답변을 유저에게 반환
그런데 LLM inference는 다음과 같은 문제들을 수반한다.
다양한 LLM inference: 지금도 계속해서 새로운 LLM이 생겨나고 있고, 서로 다른 interface를 제공한다. 예를들어 HuggingFace
에서 LLM들과 API를 통해 사용할 수 있는 GPT-4는 아예 다른 방식으로 구현해야 한다. 따라서 LLM을 교체할 때마다 새로 구현을 해야하는 비용이 발생한다.
Prompt design: LLM inference의 성능은 prompting에 따라 좌우된다. 특정한 template이 주어졌을 때 유저의 메세지를 잘 수정해주는 코드를 구현하는 것은 많은 공수가 들어간다.
높은 외부 data source 사용 난이도: RAG와 같은 방식은 외부 data source를 활용한다. 하지만 이렇게 외부 source를 활용하는 방식은 개인이 처음부터 구현하기에 난이도가 너무 높다.
이런 문제들을 해결하기 위한 도구 중 LangChain이 있다.
LangChain이란?
💡 LangChain은 대규모 언어 모델(LLM)을 사용하여 애플리케이션을 개발하기 위한 오픈 소스 오케스트레이션 프레임워크이다. 챗봇
같은 LLM 기반 애플리케이션을 구축하는 과정을 간소화시킬 수 있다.
LangChain이 제공하는 기능들을 요약하면 다음과 같다.
LLM abstraction: 여러가지 LLM interface를 쉽게 대응할 수 있는 pipeline을 제공한다. HuggingFace, GPT-4, Gemini 등 다양한 LLM들을 최소한의 코드 수정으로 inference할 수 있게 해준다.
Prompt template: 유저의 메세지를 주어진 template에 맞춰 자동으로 수정하는 기능을 제공한다.
Indexes: 외부 data source를 사용한 LLM inference를 쉽게 진행할 수 있게 indexes를 제공한다.
2. LangGraph
커뮤니티에서 LangGraph에 대한 언급을 몇번 목격한 적이 있다. LangChain에 대해 정리하게 된 김에, LangGraph에 대해도 한번 정리해보면 좋을 것 같다는 생각이 들었다.
LangChain으로 pipeline을 구성해서 상태 전달을 하고, 그 과정에서 출력을 만들어 낸다. 이 과정에서 발생할 수 있는 문제는 다음과 같다.
LLM pipeline 내에서 상태 전달을 할 때 특정 단계의 출력이 문제가 되어 전체 파이프라인에 문제가 발생
이런 문제를 해결하기 위해 전후처리나 분기처리등을 추가하곤 하는데 LLM의 특성상 잘 제어되지 않음.
LangGraph는 LangChain 생태계에서 발생하는 위와 같은 상태 전달 문제들을 보완하기 위해 만든 프레임워크이다. 심지어 LangChain 진영에서 직접 만들었다.
2.1 LangGraph의 특징
상태 기반 그래프 구조: 애플리케이션의 로직을 노드와 엣지로 구성된 그래프로 표현한다.
유연한 상태 관리: 복잡한 상태를 쉽게 정의하고 관리할 수 있다.
조건부 라우팅: 동적인 의사결정 프로세스를 구현할 수 있다.
체크포인팅: 그래프 실행 상태를 저장하고 복원할 수 있어 장기 실행 태스크와 오류 복구에 유용하다.
서브그래프 지원: 복잡한 시스템을 모듈화하여 관리할 수 있다.
2.2 LangChain과의 비교
LangChain과 LangGraph는 둘 다 LLM 애플리케이션 개발을 위한 도구지만, 약간의 차이가 있다.
| 특징 | LangGraph | LangChain |
|--------------|------------------------------------------------|-----------------------------------------------|
| 주요 목적 | 복잡한 워크플로우 및 의사결정 프로세스 구현 | LLM 통합 및 체인 구성 |
| 구조 | 그래프 기반 | 체인 및 에이전트 기반 |
| 상태 관리 | 명시적이고 세밀한 제어 | 암시적이고 자동화된 관리 |
| 유연성 | 높음 (커스텀 로직 쉽게 구현) | 중간 (미리 정의된 컴포넌트 중심) |
| 학습 곡선 | 상대적으로 가파름 | 상대적으로 완만함 |
| 용도 | 복잡한 AI 시스템, 다중 에이전트 | 간단한 LLM 애플리케이션, RAG |
현재 LangChain만 사용해본 입장에서 이렇게 장단점을 테이블로 정리해도 크게 와닿지는 않는다. 다만 선택을 한다고 했을 때 프로덕트의 현재 단계나 목적에 따라 선택이 나뉠 수 있을 것 같다.
빠른 프로토타이핑으로 검증하기 위해서라면: LangChain
검증은 이미 되었고 사용성을 더 고도화 하기 위해서라면: LangGraph
프로덕트의 라이프 사이클에서도 자연스럽다고 느껴진다. LangChain으로 빠른 검증을 하고, LangGraph로 이주한다. 혹은 개념상으로 LangGraph상의 단일 노드가 이전 단계에서 LangChain으로 만들어놓은 결과물이 될 수도 있다.
만약 내가 멀티모달 형태의 서비스를 구현해야 한다면 애초에 입력부터 분기가 발생하기 때문에 주저하지 않고 LangGraph를 선택할 것 같다.
3. Streamlit
앞에서 LangChain에 대해서는 충분히 알아봤다. 그럼 Backend는 LangChain으로 구성한다고 치고, 챗봇은 Frontend도 필요하지 않은가? 처음부터 프론트엔드를 붙여서 개발하기에는, LangChain의 장점인 빠른 프로토타입을 통한 검증
이 상쇄되는 느낌이다.
그래서 이럴 때 사용하기 좋은 Streamlit
이라는 오픈소스 웹 프레임워크가 존재하고, 다음과 같은 특징이 있다.
Pure Python: 순수하게 Python으로 구성되어 있다. Python만 사용해서 UI를 구성할 수 있으므로, HuggingFace와 같은 AI Model을 쉽게 활용할 수 있는 장점이 있다.
다양한 Widget: slider, 차트, 챗봇과 같은 직접 구현하기 복잡한데 활용도는 높은 widget들을 제공하고 있다.
3.1 예시 코드
다음은 Streamlit
으로 챗봇을 구성하는 예시 코드이다.
import streamlit as st
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
model = ChatOpenAI(model="gpt-4o-mini")
st.title("GPT Bot")
# Session state 초기화
if "messages" not in st.session_state:
st.session_state.messages = []
# 만약 app이 rerun하면 message들을 다시 UI에 띄우기
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if prompt := st.chat_input("What is up?"):
with st.chat_message("user"):
st.markdown(prompt)
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("assistant"):
messages = []
for m in st.session_state.messages:
if m["role"] == "user":
messages.append(HumanMessage(content=m["content"]))
else:
messages.append(AIMessage(content=m["content"]))
result = model.invoke(messages)
response = result.content
st.markdown(response)
st.session_state.messages.append({
"role": "assistant",
"content": response
})
여기서 Gemma3 같은 오픈소스 LLM으로 변경하는 방법도 존재할 것 같다.
3. 느낀점
이제 드디어 LangChain과 LangGraph의 경계가 분명해졌다.
챗봇을 구현하는건 재밌었다. Gemma3를 파인튜닝한 후 서빙해보면 좋을 것 같다.
다음 내용이 궁금하다면?
이미 회원이신가요?
2025년 5월 4일 오후 1:51
추
... 더 보기