들어가며
ChatGPT의 등장 이후 내로라하는 빅테크 기업들은 생성형 AI 시장에 뛰어들었고, 이 중심에는 대규모 언어 모델(Large Language Model, LLM)이 있다. 이후 최근 몇 년간 자연어 처리 분야에서 LLM의 발전은 혁신적인 변화를 가져왔다. GPT-3/4 와 같은 LLM은 자연어의 이해와 생성 능력이 크게 향상되어 대화형 AI, 컨텐츠 생성, 데이터 분석 등 다양한 분야에서 활용될 수 있는 능력을 보여주었다. 자연스럽게 LLM과 서비스, 애플리케이션을 통합하기 위한 니즈가 증가했지만, 이들 언어 모델의 기능을 효과적으로 활용하려면 기술적 도전이 따른다. 이에 LLM을 애플리케이션에 통합하고 최적화하기 위한 방법론과 도구가 필요했으며, 이 배경에서 등장한 것이 바로 LangChain이다.
LangChain은 언어 모델을 활용한 다양한 애플리케이션 개발을 위한 프레임워크로, 데이터 소스와의 통합, 복잡한 작업의 체계화, 그리고 응답 생성을 위한 파이프라인 구축 등 다양한 기능을 지원한다. 이를 통해 AI 애플리케이션의 개발 과정이 크게 간소화 되었고 LLM을 활용한 애플리케이션 개발의 대표 도구로 자리 잡았다. LangChain은 오픈 소스 프로젝트로, 커뮤니티의 기여를 통해 빠르게 발전하고 있으며 계속해서 여러 가지 기능이 추가되며 확장되고 있다. 이 글에서는 빠르게 발전하고 있는 LangChain 산하 프로젝트 중 LangGraph에 대해 소개하겠다.
1. LangGraph 란
LangGraph는 LangChain에서 2024년 1월 새롭게 추가된 라이브러리로, 여러 에이전트 (Agent) 기반으로 복잡한 워크플로우를 처리할 수 있도록 고안되었다.
(에이전트(agent): LangChain에서 에이전트는 LLM이 다양한 도구와 상호작용하며 복잡한 작업을 처리하도록 설계된 시스템이다. LLM을 통해 단순한 질문에 답변할 뿐만 아니라 복잡한 작업을 처리하기 위해 여러 도구나 데이터 소스 등을 활용하는 역할을 한다.)
LangChain은 다양한 LLM을 활용해 복잡한 질의를 처리하거나, 연속적인 작업 흐름을 관리하는 데 매우 유용하지만, LangChain만으로 해결하기 어려운 문제가 존재한다.
예를 들어, 여러 에이전트가 협력하여 복잡한 작업을 처리하거나, 특정 조건에 따라 작업의 흐름을 분기하고 재 처리하는 등의 구현이 어렵다. (아래 [그림1]은 LangChain 또는 Python을 이용한 일반적인 RAG 방식에서 LangGraph를 이용하여 작업의 결과를 평가하고 이에 따라 기존 흐름이 재 처리되는 RAG를 구현하는 예 이다.) LangGraph를 활용하면 LangChain과 Python 만으로는 구현이 어려운 구조를 간편히 작성할 수 있다. LangGraph는 LangChain의 기능을 확장하여 복잡한 에이전트 런타임 개발에 필수적인 순환 그래프를 만들고 관리할 수 있는 기능을 제공하고, 에이전트를 만드는데 필수적인 애플리케이션의 흐름과 상태를 세부적으로 제어할 수 있다. LangGraph는 이름과 같이 작업을 그래프 형태로 모델링 하여 각 작업의 단계를 노드(Node)와 간선(Edge)으로 관리하고 분기, 루프, 상태 관리 등을 통해 복잡한 작업 흐름을 체계적으로 처리할 수 있다.
2. LangGraph 주요 컴포넌트 및 기능
LangGraph를 구성하는 요소들에 대해 알아보겠다.
2-1. 그래프(Graph)
LangGraph의 핵심으로, 아래 3가지(state, node, edge) 구성요소를 통해 에이전트의 동작을 정의한다.
- 상태(State)
애플리케이션의 현재를 나타내는 데이터 구조로, 파이썬 TypeDict 또는 Pydantic 모델이다. 쉽게 말해 작업상태를 기록한다.
- 노드(Node)
파이썬 함수로 정의되며, 상태(state)를 입력으로 LLM의 호출, 도구 실행 등 사용자가 정의한 작업을 실행하고 업데이트된 상태를 반환한다.
- 간선(Edge)
마찬가지로 파이썬 함수로 정의되며, 특정 노드의 다음 실행 노드를 결정한다. 간선에는 조건부 간선과, 일반 간선이 존재한다.
LangGraph는 노드가 작업을 완료하여 상태를 기록하고 연결된 간선을 따라 다른 노드로 다음 작업을 요청한다. 다음 노드는 정의된 작업을 실행하고 다시 그 결과를 상태에 담아 다음 노드로 전달하는 프로세스가 계속된다.
LangGraph는 기본적으로 두 가지 그래프를 제공한다.
- StateGraph
가장 기본적인 그래프 유형으로, 사용자 정의 상태(객체)를 파라미터로 정의한다. 각 노드는 주어진 작업을 통해 상태를 업데이트한다.
- MessageStateGraph
가장 기본적인 그래프 유형으로, 사용자 정의 상태(객체)를 파라미터로 정의한다. 각 노드는 주어진 작업을 통해 상태를 업데이트한다.
2-2. 상태(State)
Graph를 정의하기 위해 제일 먼저 해야 할 일은 상태를 정의하는 것 이다. 상태는 그래프의 스키마(Scheme)와 상태를 업데이트하는 방식을 지정하는 리듀서 함수(Reducer Function)로 구성된다. 스키마는 TypeDict 또는 Pydantic 모델(기본 값과 데이터 검증을 위해 사용)이 될 수 있으며, 그래프를 구성하는 노드들은 정의한 상태를 입력으로 받고, 지정된 리듀서에 따라 상태를 업데이트하여 반환한다. 명시적으로 리듀서를 지정하지 않으면 데이터는 재정의 되며, 리듀서가 지정되면 리듀서에 따라 데이터가 업데이트 되게 된다. 리듀서는 미리 정의된 유형 외에, 사용자가 직접 정의할 수 있다. 이를 통해 더 복잡한 데이터 업데이트 패턴을 적용할 수 있다. 아래는 명시적으로 리듀서가 지정된 상태와 상태가 변경되는 예이다.
2-3. 노드(Node)
LangGraph에서 노드는 파이썬 함수로 정의된다. 첫 번째 인수는 앞서 정의한 상태(State)이다. (두 째 인수는 선택적(설정 값)으로 추가될 수 있다) 노드는 사용자 정의에 따라 여러 가지 기능을 수행할 수 있다. 단순 연산 작업은 물론이고, LLM의 호출, LangChain 에이전트나 기타 여러 도구를 포함할 수 있다. 노드는 주어진 상태를 바탕으로 지정된 작업을 수행하는 독립적인 실행 주체이다. 정의된 노드는 add_node (“노드이름”, “함수 명”) 메소드를 이용해 그래프에 추가한다. 노드 추가 후, 해당 노드는 “노드이름” 으로 참조할 수 있다. 노드를 추가할 때 노드의 이름을 지정하지 않을 경우 정의된 함수 이름이 해당 노드의 이름이 된다.
노드는 사용자 정의 노드 외에 그래프의 시작과 끝을 알리는 START, END 두 종류의 노드가 존재한다. START 노드는 그래프로 데이터가 처음 유입되어 워크플로우가 시작되는 노드이며, 처음으로 호출되어야 하는 노드를 지정하기 위해 사용된다. (아래 예와 같이 START 노드를 이용해 첫 시작 노드를 간선으로 연결하거나, set_entry _point 메소드를 통해 시작 노드를 지정할 수 있다) END 노드는 정의된 워크플로우가 종료됨을 의미한다. 예시는 간선 정의를 통해 START 와 END 노드를 지정하는 예 이다.
2-4. 간선(Edge)
간선은 정의된 노드와 노드 사이를 연결을 의미하며, 작업의 순서를 결정한다. 노드간 연결되는 간선은 순차적일 수도 있고, 조건부에 따라 분기 될 수 있다. 간선은 두 가지로 구분되며 다음과 같다.
- 기본 간선(Normal Edge)
노드간을 연결하는 간선이다. add_edge(“노드이름”, “노드이름”)로 정의하며, 매개변수 첫 번째는 시작(from) 노드이며 두 번째는 도착(to) 노드이다. 각각 add_node 메소드로 정의한 노드 이름을 지정한다.
- 조건부 간선(Conditional Edge)
1개 이상의 간선으로 선택적으로 라우팅하거나 경우에 따라 종료하려는 경우 사용되는 됩니다. add_conditional_edges(“노드이름”, routing_function, 다음 단계 결정 dict) 메소드로 정의되며, 조건에 따라 여러 분기를 수행할 수 있도록 한다.
첫 번째 파라미터(“노드이름” 으로 설정된) 노드의 작업 이후 두 번째 파라미터 ‘조건부 판단 함수’에서는 노드의 작업의 결과를 판단한다.
조건부 판단 함수는 문자열을 반환하도록 구현되며, 세 번째 파라미터는 반환되는 문자열에 따라 이동할 노드를 지정하는 사전을 정의한다.
2-5. 체크포인터(Checkpointer)
LangGraph 에서는 체크포인터는 워크플로우 실행 중에 상태에 지속성을 부여할 수 있다. 그래프의 상태를 저장하고 복원하는데 사용되며, 실행 기간이 길어질 경우 주기적으로 상태를 저장하여 시스템의 오류나 작업 중단 시 복구할 수 있도록 한다.
MemorySaver와 같은 메모리 기반 체크포인터, SqliteSaver, 외부 데이터베이스(Postres, MongoDB, Redis)를 사용할 수 있다. 아래 예시에서는 MemorySaver 를 사용하는 예 이다.
2-6. 시각화(Visualization)
노드와 간선으로 인해 그래프가 더욱 복잡해지면 그래프를 시각화하기 어려울 수 있지만, LangGraph에는 그래프를 시각화하는 여러 가지 방법이 내장되어 있다. 이를 통해 정의된 그래프를 한 눈에 시각화 할 수 있다.
아래는 Mermaid.ink API 를 통해 이미지(png)로 그래프를 랜더링(rendering) 해주는 예시 이다.
2-7. 설정(Configuration)
그래프를 정의할 때 사용할 설정을 추가할 수 있으며, 추가된 설정은 구성되는 모든 노드에 전달됩니다. 설정은 두 가지 형태로 설정할 수 있다.
- config_schema 정의
add_conditional 사용할 설정을 정의하고, 그래프를 정의할 때 설정한다.
- configurable 필드 사용
그래프를 시작(invoke/stream)할 때, configurable 필드를 생성하여 설정한다.
추가된 설정은 정의한 각 노드에서 파라미터를 추가로 정의하여 사용할 수 있다.
사용자가 정의하는 설정 외에, Recursion Limit 을 설정할 수 있다. 이는 실행되는 최대 단계(노드의 처리)를 설정하는 것으로 기본적으로 25 가 설정됩니다. 해당 값을 초과하면 LangGraph 에서는 ‘GraphRecursionError’ 를 발생시킨다.
이 설정을 통해 그래프의 노드가 무한 반복되지 않도록 한다. 이를 통해 특정 조건이 충족되지 않아 무한루프에 빠지는 상황을 방지한다. 이 설정은 configurable 필드 내부에 추가되는 것이 아닌 config 의 별도의 키(“recursion_limit”)로 설정되어야 하며, 그래프의 런타임에 invoke 또는stream 메소드를 통해 설정할 수 있다.
3. LangGraph 구현 예시
LangGraph를 사용하여 간단한 작업 흐름을 구현해보겠다. 소문자 변환 도구를 이용해 소문자로 변환된 문자를 답변하는 챗봇(Chatbot)이며, 구현 순서는 다음과 같다.
- 상태(State) 정의
- 함수(노드와, 조건부간선에 사용될) 정의
- 그래프 정의 및 컴파일
구현에 앞서 전체적인 구조를 살펴보겠다. 시각화에서 예시로 보여주었던 그래프와 동일한 형태로 구현할 예정이다.
3-1. 상태(State) 정의
상태 정의와 함께 추가적으로 도구와 사용자 입력에 답변할 LLM을 정의한다.
3-2. 함수 정의
조건부 간선에 사용될 함수와, LLM, 도구를 사용하는 로직을 정의한다.
3-3. 그래프 정의 및 컴파일
정의된 노드를 일반 간선과 조건부간선을 통해 연결하여 그래프를 생성하고 컴파일한다.
마치며
이번 글에서는 LangChain에서 새롭게 출시한 LangGraph에 대해 알아보았습니다. LangGraph는 LangChain 생태계의 일부이며, 복잡한 워크플로우를 비교적 쉽게 구축할 수 있도록 지원하는 라이브러리 이다. LangGraph의 강력한 기능 중 하나는 조건에 따라 분기되며 순환될 수 있는 데이터 흐름을 지원한다는 점 이다. 이 구조를 이용해 여러 에이전트가 협력하여 작업을 수행하거나, 조건에 따라 작업 흐름이 달라지거나 반복되어야 하는 복잡한 워크플로우를 구축하는데 유용한 도구가 될 수 있다.
에이전트는 LLM 을 통해 작업의 자동화와 복잡한 의사 결정에 이르는 프로세스까지 다양한 기능을 처리할 수 있다. 이는 앞으로도 더 중요한 도구가 될 것 이다. LangGraph는 결과를 도출하기 위해 필요한 데이터의 검증, 추가, LLM 답변의 재 작성과 같은 조건에 따른 분기를 쉽게 설정할 수 있다. 이를 통해 더욱 품질 높은 결과를 생성할 수 있지만, 손쉽게 구현되는 분기처리로 얘기치 못한 사이클에 빠지거나 응답시간이 더 길어지는 등 고려할 부분도 있다.
기존 프레임워크에서 LLM을 애플리케이션과 통합하면서 시행착오를 거듭하고 계신 개발자 분들께 도움이 될 것으로 예상된다.
LangGraph의 그래프구조의 워크플로우는 LLM을 활용하는 여러 애플리케이션에 국한되지 않고, 대부분의 애플리케이션 아키텍트에도 효과적이다. LangGraph는 LangChain에서 개발된 라이브러리이지만 독립적으로 사용할 수 있으므로 AI 애플리케이션 개발 외에도, 복잡한 프로세스를 포함한 애플리케이션 개발에도 사용을 고려할 수 있다. AI 개발뿐만 아니라 일반적인 개발에 관심 있는 분들도 LangGraph를 경험하고 프로젝트에 적용해보기를 권한다.
에스코어는 RAG 솔루션을 통해 생성형 AI의 활용도를 높이고 답변 신뢰도를 높여 서비스의 가치를 높이고 있다. 에스코어는 오픈소스SW 전문가 집단으로써 아키텍처 설계부터 데이터 마이그레이션과 구축 및 기술 지원까지 고민을 같이할 전문가로 구성된 팀을 보유하고 있다. 또한 검색/생성 단계에서 다양한 지표 기반 검증을 실시하여 RAG의 근본적인 원인 분석과 지속적인 품질 개선이 가능하도록 지원하고 있다.
LangChain, LangGraph를 비롯한 오픈소스 기반의 최신 기술 도입 및 생성형 AI 기반 서비스 구축을 고려 중이시라면 전문 지식과 기술역량을 바탕으로 성공을 이끌 수 있는 에스코어와 함께하길 바란다.
# References
- https://github.com/langchain-ai
- https://github.com/langchain-ai/langgraph
- https://langchain-ai.github.io/langgraph/how-tos/
- https://www.datacamp.com/tutorial/langgraph-tutorial
- https://blog.langchain.dev/langgraph/
- https://blog.langchain.dev/langgraph-multi-agent-workflows/
- https://teddylee777.github.io/langgraph/langgraph-multi-agent-collaboration/
- https://www.youtube.com/watch?v=4JdzuB702wI&t=2006s
김지명 프로
소프트웨어사업부 OSS사업팀
KnoxGraph Gen AI 서비스 개발과 Elasticsearch 검색 서비스를 개발하고 있습니다.
-
다음 글
Register for Download Contents
- 이메일 주소를 제출해 주시면 콘텐츠를 다운로드 받을 수 있으며, 자동으로 뉴스레터 신청 서비스에 가입됩니다.
- 뉴스레터 서비스 가입 거부 시 콘텐츠 다운로드 서비스가 제한될 수 있습니다.
- 파일 다운로드가 되지 않을 경우 s-core_mktg@samsung.com으로 문의해주십시오.