관련 시리즈
관련 시리즈 목록
- 2024.11.11 - [A.I.(인공지능) & M.L.(머신러닝)/LLM] - [LangGrpah] 1. LangGrpah(랭그래프)를 이용한 AI Workflow 관리하기 (현재글)
- 2024.11.13 - [A.I.(인공지능) & M.L.(머신러닝)/LLM] - [LangGrpah] 2. LangGrpah(랭그래프)의 핵심 요소의 개념적 이해
- 2024.11.14 - [A.I.(인공지능) & M.L.(머신러닝)/LLM] - [LangGrpah] 3. Chain과 Agent를 이용한 Workflow 구현 - 쿼리 추출 모델
- 2024.11.20 - [A.I.(인공지능) & M.L.(머신러닝)/LLM] - [LangGrpah] 4. LangGraph를 이용한 RAG 및 검색 Agent 개발
1. LangChain 생태계의 출현
거대 언어 모델(Large Language Model)의 성능이 나날히 발전하며
이를 Application의 형태로 활용하기 위한 다양한 Workflow가 개발되고 있다.
LangChain(랭체인)은 해당 분야에서 가장 먼저 등장한 언어 모델 프레임워크로
Chain, Retrieval, Agent 등 다양한 기능을 구현하는 효과적인 관리 도구로 자리잡았다.
그러나 LLM을 활용한 프로젝트의 규모가 증가하기 시작하며
기존에는 필요하지 않았던 복잡한 요구사항들이 나타나고 있다.
(Multi-Agents를 관리할 수 있는 Workflow, 데이터베이스의 통합적 관리 등)
LangGraph(랭그래프)는 이러한 요구 사항을 효과적으로 해결하기 위한 Workflow 설계 도구로
Graph의 Node, Edge를 기반으로 하여 개별 Node의 State를 효과적으로 관리할 수 있도록 한다.
이를 통해 LangChain에서는 구현하기 어려웠던, 복잡한 Workflow 설계를 가능하게 한다.
2. Chains vs Agents
LangChain 및 LangGraph를 사용하기 이전 먼저 살펴볼 개념으로 Chain과 Agent가 존재한다.
Chain과 Agent는 쉽게 LLM Applicaion의 작업 단위로 이해할 수 있으며, 작동 방식에 따라서 둘로 나눠 구분하게 된다.
LangChainAI Webinar에서는 이 둘을 아래와 같이 표현하고 있다.
- Chain: "미리 정해진 일련의 작업 문자열(Predetermined string of actions)"
- Agent: "LLM을 이용한 작업의 결정(Using the LLM to decide *which* actions to take)"
즉 Chain의 경우 정해진 프레임워크를 순차적으로 수행하는 규칙-기반(Rule-Based)의 작업 단위이며
Agent의 경우 정해진 작업을 수행하는 LLM 기반의 작업 단위로 이해할 수 있다.
이러한 두 가지 작업 단위에 우열은 없으며, 실제 작업에 맞는 적절한 사용이 중요하다.
이를 적절하게 사용하기 위해 등장한 것이 LangGraph라고 볼 수 있는데 ...
사실 LangChain만으로도 Chains 및 Agents를 효과적으로 설계하는 데 큰 문제가 발생하지는 않는다.
그러나 이러한 LLM 모듈의 갯수가 늘어나며, 전체 State에 대한 관리가 상당히 복잡해지기 시작했고
이러한 문제를 해결하기 위해 LangGraph라는 Workflow가 등장하게 되었다고 볼 수 있다.
3. Why LangGraph?
이쯤왔으면 LangGraph를 사용하는 목적은 뚜렷하게 이해될 것이다.
"아 Chain과 Agent를 이용한 '복잡한' Application의 관리를 위한 도구!" 라고 생각할 수 있다.
실제로 LangGraph의 핵심적인 기술은, Graph형태의 연결을 통한 통합적 관리가 맞지만
LLM이 결합된(정확하게 Agent와 Chain이 존재하는) 상황에서 하나의 장점이 더 존재한다.
바로 State 기반 관리를 통해 Agent의 자율성(Contral)을 증대시키면서도,
LLM Module의 신뢰성(Reliability)을 확보하는 것이다.
예를 들어 살펴보자.
몇 가지 단계를 거치는 작업이 존재하고, LLM이 어떤 작업을 수행할지 선택해야 한다고 가정한다.
이를 달성하기 위한 방법은 아래와 같이 존재할 수 있다.
- LLM을 이용하여 가능한 경로 둘 중 하나를 선택하도록 함(Router 형태의 방식)
- LLM을 이용하여 어떤 도구를 호출할지 결정함(Fully Autonomous 형태의 방식)
여기서 Router 형식은 일종의 Chain 방식으로, LLM 을 통해 미리 정해진 경로를 선택하도록 한다.
이는 매우 견고하고 안정적이지만, LLM이 유기적인 결정을 내리는 것이 아닌, 기계적 작업을 수행하도록 한다.
반면 Agent형태의 자발적 수행 방식은, 이는 매우 유기적인 대처능력을 보유하게 되지만
안정성이 절대적으로 감소하기 때문에 실제 서비스의 안정성을 심각하게 훼손한다.
이는 LangGraph가 해결하고자 하는 핵심 도전과제이며
Graph를 통한 연결과, State를 통한 상태관리를 통해 이를 해결하고자 제시하고 있다.
4. LangGraph의 핵심
때문에 LangGraph의 핵심 용어(Glossary)는 다음의 세 가지라고 볼 수 있다.
- State: 전체 어플리케이션의 현재 상태를 공유하는 데이터 구조.
- Nodes: Agnet의 논리를 인코딩하는 함수로, State를 Input으로 받아 작업을 수행한 뒤, 업데이트 된 State를 반환함.
- Edges: 현재 상태에 따라 다음 Nodes를 결정하는 함수로, 고정적인 연결(Fixed Transition)이거나, 조건화된 분기(Conditional Branches)임.
가장 간단한 예시를 통해 살펴보자.
# State의 예시
class InputState(TypedDict):
user_input: str
class OutputState(TypedDict):
graph_output: str
class OverallState(TypedDict):
foo: str
user_input: str
graph_output: str
class PrivateState(TypedDict):
bar: str
먼저 State는 LangGraph의 핵심 요소로, 그래프의 Schema를 결정하는 요소라고 볼 수 있다.
모든 State는 자신이 활용할 수 있는 요소가 무엇인지 명확하게 정의하게 된다.
# 위에서 정의된 State를 통해 Node를 정의
def node_1(state: InputState) -> OverallState:
# Write to OverallState
return {"foo": state["user_input"] + " name"}
def node_2(state: OverallState) -> PrivateState:
# Read from OverallState, write to PrivateState
return {"bar": state["foo"] + " is"}
def node_3(state: PrivateState) -> OutputState:
# Read from PrivateState, write to OutputState
return {"graph_output": state["bar"] + " Lance"}
# Builder 생성
builder = StateGraph(OverallState,input=InputState,output=OutputState)
# Builder에 Node를 추가
builder.add_node("node_1", node_1)
builder.add_node("node_2", node_2)
builder.add_node("node_3", node_3)
State가 정의되면, 다음으로는 이를 활용하는 Node가 정의된다.
Node는 앞서 이야기 했듯 State를 Input으로 받아, 다른 State를 Output으로 반환한다.
이 과정에서 개별 Node는 특정한 Function을 수행하게되지만, 위의 예시에서는 가장 간단한 단어의 결합을 수행하고 있다.
# Edge를 추가
builder.add_edge(START, "node_1")
builder.add_edge("node_1", "node_2")
builder.add_edge("node_2", "node_3")
builder.add_edge("node_3", END)
# Builder를 통해 Graph 컴파일
graph = builder.compile()
graph.invoke({"user_input":"My"})
{'graph_output': 'My name is Lance'}
마지막으로 Graph 속에 Node를 추가하고
이러한 Node를 연결하는 Edge가 추가되게 된다.
Edge는 간단하게 출발노드와, 도착노드를 명시함으로써 연결되게 되며
Graph의 시작과 끝은 START class와 END class를 통해 표현된다.
본 포스팅에서는 매우 기본적인 LangChain 및 LangGraph의 개념과 이를 통한 가장 간단한 Workflow를 살펴보았다.
다음 포스팅에서는 LangGraph 및 LangChain을 통한 실제 Task를 통해 더욱 자세하게 살펴보고자 한다.
'A.I.(인공지능) & M.L.(머신러닝) > LLM' 카테고리의 다른 글
[LangGrpah] 3. Chain과 Agent를 이용한 Workflow 구현 - 쿼리 추출 모델 (0) | 2024.11.14 |
---|---|
[LangGrpah] 2. LangGrpah(랭그래프)의 핵심 요소의 개념적 이해 (0) | 2024.11.13 |
Adapting While Learning (2) | 2024.11.10 |
Magentic-One : 새로운 Agent 프레임워크 (2) | 2024.11.10 |
Mergoo: 다양한 LLM 전문가를 신뢰성 있게 통합하는 방법 (1) | 2024.09.05 |