StateGraph 상태 그래프

1. 개념

  • 상태(State)를 기반으로 구축하는 가장 기본적인 그래프
  • 작업자인 노드(Node)는 상태(State)에 데이터를 읽고 쓰면서 다른 노드와 통신한다.
  • 다음 포스팅부터 살펴볼 상태(State), 노드(Node), 엣지(Edge)로 구성된다.

상태(State), 노드(Node), 엣지(Edge) 포스팅들을 모두 둘러본 후 이 글을 다시 읽어보는 것을 권장한다.

2. StateGraph 클래스 살펴보기

(1) 생성자

  • langgraph.graphStateGraph 클래스를 사용한다.
  • StateGraph 는 빌더 클래스이므로, 직접 실행할 수 없고 compile() 메서드로 실행 가능한 그래프를 만들어야 한다.
  • 필수 파라미터는 state_schema 즉, “상태 스키마” 이다.
  • 그 외로 context_schema, input_schema, output_schema 등의 선택적 파라미터가 있다.
1
2
3
4
5
6
7
8
9
StateGraph(
  self,
  state_schema: type[StateT],
  context_schema: type[ContextT] | None = None,
  *,
  input_schema: type[InputT] | None = None,
  output_schema: type[OutputT] | None = None,
  **kwargs: Unpack[DeprecatedKwargs] = {}
)

(2) 생성자 파라미터

파라미터 타입 설명 필수
state_schema type[StateT] 상태(State)의 스키마를 정의한 클래스 필수
context_schema type[ContextT] 런타임 컨텍스트를 정의하는 스키마 클래스
user_id, db_conn 과 같이 실행 내내 고정으로 참조하는 공통 정보
 
input_schema type[InputT] 그래프의 가장 앞단 입력 스키마 클래스  
output_schema type[OutputT] 그래프의 최종 출력 스키마 클래스  

2. 사용 방법

(1) StateGraph 인스턴스 생성과 상태(State) 할당

  • langgraph.graphStateGraph 클래스를 사용해 인스턴스를 생성한다.
  • 생성할 때 필수적으로 상태(State)에 대한 스키마 클래스를 파라미터로 넣어줘야 한다.
  • 상태(State) 외의 파라미터는 추후 심화 포스팅에서 살펴보기로 한다.
1
2
3
4
5
6
7
8
9
10
11
from typing import TypedDict, Annotated
from operator import add
from langgraph.graph import StateGraph
from collections import Counter

class MyState(TypedDict):
    count: Annotated[int, add]
    win_logs: Annotated[list[str], add]
    winner: str

graph = StateGraph(state_schema = MyState)

(2) 노드(Node) 추가

  • add_node("노드별칭", 노드함수) 메서드를 이용해 그래프에 노드를 추가한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def first_round_node(state: State) -> State:
    return {
        "count": 1,
        "win_logs": ["철수"]
    }

def second_round_node(state: State) -> State:
    return {
        "count": 1,
        "win_logs": ["민수"]
    }

def judge_node(state: State) -> State:
    c = Counter(state["win_logs"])
    return {
        "winner": c.most_common()[0][0]
    }

graph.add_node("first", first_round_node)
graph.add_node("second", second_round_node)
graph.add_node("judge", judge_node)

(3) 시작노드 및 종료노드 지정

  • set_entry_point 메서드로 시작 노드를 지정하며
  • set_finish_point 메서드로 종료 노드를 지정한다.
1
2
graph.set_entry_point("first")
graph.set_finish_point("judge")

(4) 엣지(Edge)로 경로 추가

  • add_edge 메서드로 노드와 노드간의 연결 경로를 추가한다.
1
2
graph.add_edge("first", "second")
graph.add_edge("second", "judge")

(5) 컴파일(Compile)로 실행 가능한 그래프 만들기

  • compile 메서드를 이용해 실행 가능한 그래프 인스턴스를 생성한다.
1
compiled = graph.compile()

(6) 실행

  • invoke 메서드를 이용해 그래프를 실행할 수 있다.
  • 이 외로도 실행하는 메서드가 존재하며, 이는 추후 심화 포스팅에서 살펴보도록 한다.
1
result = compiled.invoke({"count":0})

3. 전체 예시 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from typing import TypedDict, Annotated
from operator import add
from langgraph.graph import StateGraph
from collections import Counter

class MyState(TypedDict):
    count: Annotated[int, add]
    win_logs: Annotated[list[str], add]
    winner: str

graph = StateGraph(state_schema = MyState)

def first_round_node(state: State) -> State:
    return {
        "count": 1,
        "win_logs": ["철수"]
    }

def second_round_node(state: State) -> State:
    return {
        "count": 1,
        "win_logs": ["민수"]
    }

def judge_node(state: State) -> State:
    c = Counter(state["win_logs"])
    return {
        "winner": c.most_common()[0][0]
    }

graph.add_node("first", first_round_node)
graph.add_node("second", second_round_node)
graph.add_node("judge", judge_node)

graph.set_entry_point("first")
graph.set_finish_point("judge")

graph.add_edge("first", "second")
graph.add_edge("second", "judge")

compiled = graph.compile()
result = compiled.invoke({"count":0})
1
2
# 출력
{'count': 2, 'win_logs': ['철수', '민수'], 'winner': '철수'}

Reference

https://reference.langchain.com/python/langgraph/graph/state/StateGraph

Comments