LangGraph에 대해 알아보자

용가리·2025년 7월 14일

반갑습니다
이번 글에서는 LangGraph에 대해 작성해볼까 합니다.
LangGraph는 Agent 개발에 사용되는 라이브러리 중 하나입니다.
난이도는 조금 어려울 지 모르지만, 확장성이 높아 자주 사용되곤 하죠.
그럼 시작 ~!

LangGraph란?

LangGraph는 LangChain 생태계에서 파생된 오픈소스 프레임워크로, 상태 기반(stateful) LLM 애플리케이션을 그래프 형태로 구축할 수 있도록 도와주는 도구입니다. LLM 기반 애플리케이션이 점점 더 복잡한 논리와 흐름을 가지게 되면서, 단순한 체인(Chain) 구조로는 한계가 있기에, 보다 유연한 상태 전이 모델을 적용한 것이 LangGraph입니다.

상태 기반 LLM 어플리케이션 이라는 부분이 핵심이 되겠습니다.
LangGraph는 'State' 라는 개념을 통해 LLM간의 연결을 제어합니다.
LangGraph의 구성 요소를 살펴보도록 하겠습니다.

LangGraph의 구성 요소

1. State

그래프 전반에 공유되는 값들의 집합입니다.
Dict 형태로 전달됩니다.
각 노드는 이 State를 입력으로 받아 새 상태로 변환해 반환합니다.

state = {'phase' : 0, 'previous_result' : ''}

라는 State가 있다면
Node A, Node B, Node C를 거칠 때마다

  • Node A

    • (phase = 0, previous_result = '') 가 입력되고
    • (phase = 1, previous_result = Node_A_result) 가 출력됨
  • Node B

    • (phase = 1, previous_result = Node_A_result) 가 입력되고
    • (phase = 2, previous_result = Node_B_result) 가 출력됨
  • Node C

    • (phase = 2, previous_result = Node_B_result) 가 입력되고
    • (phase = 3, previous_result = Node_C_result) 가 출력됨

이해가 되셨나요 ? LangGraph에서는 이런 식으로 flow를 구성하여 어플리케이션을 제작합니다.

2. Node

실제 작업 (LLM 호출, Tool 실행 등)을 수행하는 단위입니다.
Callable 함수 또는 LangChain의 Chain을 사용할 수 있습니다.
입력으로 State를 받아 출력으로 State를 내보냅니다.

예시 노드 하나를 작성해보겠습니다.

def verification_node(state: MyState)
    previous_result = state['previous_result']
    system_prompt = f'''이전 agent의 대답을 자세히 분석해 폭력적인 요소가 있는지 있다면 yes, 없다면 no를 말하세요.
    이전 agent의 대답 : {previous_result}'''
    llm_result = call_llm(system_prompt = system_prompt)
    return {'previous_result' : llm_result, 'phase' : state['phase'] + 1}

다음과 같이 노드를 작성할 수 있습니다.
MyState는 사용자가 지정한 Pydantic 구조입니다.
노드에서는 꼭 llm을 호출할 필요는 없고, 원하는 기능을 자유롭게 구성하시면 됩니다.
함수에서의 작업이 끝났다면, return을 통해 state를 업데이트 해줘야 다음 노드에서 갱신된 state를 사용할 수 있습니다.

3. Edges

노드를 실행 후 다음에 이동할 노드를 지정합니다.
조건 분기로 사용할 수도 있습니다.

def decide_next(state: MyState):
	previous_result = state['previous_result']
    if previous_result == 'yes':
    	return 'violate'
    else:
    	return 'safe'

graph.add_conditional_edges('decision_node', decide_next,
					{"violate" : "handle_unsafe_node",
                    "safe" : "handle_safe_node",
                    "이외 여러 Output Case" : "분기할 노드 이름")
                    

4. START, END

그래프의 시작과 끝을 정의합니다.
LangGraph의 그래프는 START로 시작하여 END로 끝맺어야 합니다.

START 와 END는 LangGraph 라이브러리에 이미 제작된 Node라고 생각하시면 될 것 같습니다.
이 부분은 아래 Graph를 만드는 과정에서 살펴보시면 바로 감이 잡히실 것 같습니다. (별거아님)

LangGraph로 워크플로우 만들기

위에서 설명한 예시를 바탕으로 간단한 LangGraph 워크플로우를 만들어보도록 하겠습니다.
실제로 동작하지 않는 스켈레톤 코드를 작성해 볼건데,
구조 이해에는 이게 더 도움이 된다고 생각합니다.

from langgraph.graph import StateGraph, START, END
from pydantic import BaseModel

class MyState(BaseModel):
	phase : int
    previous_result : str
    question : str
    
graph = StateGraph(MyState)
graph.add_node(generation_node, "generation")
graph.add_node(verification_node, "verification")

graph.add_edge(START, "generation")
graph.add_edge("generation", "verification")
graph.add_conditional_edges("verification", decide_next, 
		{"violate" : "Note_unsafe", "safe" : "Note_safe"})
graph.add_edge("Note_unsafe", END)
graph.add_edge("Note_safe", END)

workflow = graph.compile()
workflow.recursion_limit = 30

question = input('질의를 입력하세요:')
input_state = {'phase' : 0,
			   'previous_result' :'' ,
               'question' : question}
               
result = workflow.invoke(input_state)

이렇게 LLM Output의 안전성을 판단하는 LangGraph 기반 Workflow가 완성되었습니다.
구조가 머리속에 그려지시나요 ?
그림으로 표현해보겠습니다.

위 코드와 비교하며 잘 살펴보면 충분히 이해가 될거라고 믿습니다.

LangGraph를 처음 다룰 때에는 어려울 수 있지만,, 사용하다 보면 정말 편리한 도구라고 생각될 겁니다. 익숙해 지면 LLM 어플리케이션을 개발할 때마다 이러한 구조들이 머리속에 뚱 하고 튀어나오겠죠.

본 게시물에는 Tool Use에 대한 부분은 다루지 않았습니다.
Agentflow를 구성할 때에는 필수적인 부분이니, 직접 Tool Use 기능까지 추가한 본인만의 Graph를 만들어 보시면 도움이 많이 될 것 같습니다.

'
'
'

여기까지 LangGraph에 대한 글을 마칩니다.
감사합니다 !

0개의 댓글