인공지능 개발자 수다(유튜브 바로가기) 자세히보기

자연어처리/LangGraph

[LangGraph] State

Suda_777 2025. 8. 9. 21:00

목차

    반응형

     

    langgraph 버전: 0.6.4

    내용 출처 : LangGrapn Docs

     

    LangGraph

    LangGraph Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents. Get started Install LangGr

    langchain-ai.github.io

     


    1. State 개념

    • 그래프의 전체 상태를 나타내는 데이터 구조
    • 그래프를 만들 때 가장 먼저 정의
    • 그래프에서 사용될 데이터 구조(schema) + state를 업데이트할 때 적용할 방식(reducer 함수) 를 포함함
    • 모든 노드(Node)와 엣지(Edge)는 State를 기반으로 데이터를 읽고 씀

     


    2. State 만들기

    • State의 Schema란 state가 어떤 필드를 포함하고 어떤 타입을 가지는지 정의한 것
    • 아래 두가지 방식으로 생성 가능
      • TypedDict (권장, 문서에서도 주로 사용)
      • Pydantic BaseModel
    • 또한 다중 스키마(Multiple Schmas) 형식으로 구성 가능

     

    2.1. TypedDict 으로 만들기

    • LangGraph 문서에서 주로 사용하는 방식
    • 클래스 정의 시 TypeDict를 상속받음
    • 콜론(:)을 이용해 타입 정의
    • 그래프 안에서 오가는 값, 노드 간 합치는 값은 가볍게 하기 위해 TypeDict가 적합함
    from typing import TypedDict
    
    # 상태 스키마 정의
    class MyState(TypedDict):
        name: str
        greeting: str

     


    2.2. Pydantic BaseModel 으로 만들기

    • 기본값 설정, 유효성 검사, nested 구조 지원 등 풍부한 기능 제공
    • API 입출력, 외부 리소스 I/O, 노드의 입력/출력 계약은 Pydantic으로 감싸서 검증.
    from pydantic import BaseModel
    
    # 상태 스키마 정의
    class MyState(BaseModel):
        name: str
        greeting: str = "Hello!"  # 기본값 설정

     


    2.3. Multiple Schemas

    기본적으로 LangGraph는 하나의 State Schema를 모든 노드가 공유

    하지만 아래와 같은 경우가 있을 수 있다.

    • 입력은 단순한데, 내부 처리에는 다양한 키가 필요할 때
    • 출력에는 특정 결과만 포함하고 나머지는 숨기고 싶을 때
    • 노드 간 비공개 데이터를 주고받고 싶을 때 (예: 캐시, 중간 계산 값)

     

    Input Schema / Output Schema / Internal Schema / Private Schema 등 으로 나눠서 사용

    Schema 타입 설명
    InputState 그래프에 입력으로 들어올 데이터 구조
    OutputState 최종 결과로 반환될 데이터 구조
    OverallState 그래프 전체에서 사용하는 모든 키를 포함하는 내부 스키마
    PrivateState 노드 간 내부 통신에만 사용되는 숨겨진 스키마 (사용자에겐 보이지 않음)

     

    예시 코드

    # 📌 입력 스키마
    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

     


    3. Reducer

    개념

    • 각 state의 key마다 따로 정의되는 함수
    • 해당 key가 어떻게 업데이트될지를 정함

     

    예시 1

    • Reducer가 지정되지 않은 예시
    • 값을 덮어쓰기로 동작함
    from typing_extensions import TypedDict
    
    class State(TypedDict):
        foo: int
        bar: list[str]

     

    예시 2

    • bar 속성에 add reducer가 사용됨
    • Annotated[] 함수의 두번째 인자는 업데이트할 함수가 들어옴
    • 초기: {"foo": 1, "bar": ["hi"]}
    • 노드1: {"foo": 2} → 결과: {"foo": 2, "bar": ["hi"]}  # foo에는 reducer가 없으므로 덮어쓰기
    • 노드2: {"bar": ["bye"]} → 결과: {"foo": 2, "bar": ["hi", "bye"]} # bar는 add 연산이 들어감
    from typing import Annotated
    from typing_extensions import TypedDict
    from operator import add
    
    class State(TypedDict):
        foo: int
        bar: Annotated[list[str], add]

     


    4. Message in Graph State

    • 대부분의 LLM은 “메시지 목록” (list of messages) 형식으로 입력을 받음
    • 예: LangChain의 ChatModel은 HumanMessage, AIMessage 같은 메시지 객체 리스트를 받음
    • 그래프에서도 이런 메시지들을 state에 저장해두면 유용
    • state에 messages라는 key를 추가하고, 여기에 Message 객체 리스트를 저장
    • 이 리스트는 대화 히스토리처럼 누적돼야 하니까, reducer가 필요
    • 사람이 직접 message를 업데이트하거나 고칠 때 (human-in-the-loop 상황)는 add_messages라는 LangGraph 제공 함수 사용

     

    add_messages를 reducer로 설정하면 다음 두 가지 입력 형태를 자동 인식

    # this is supported
    {"messages": [HumanMessage(content="message")]}
    
    # and this is also supported
    {"messages": [{"type": "human", "content": "message"}]}

     

    구현 예시

    from langchain_core.messages import AnyMessage
    from langgraph.graph.message import add_messages
    from typing import Annotated
    from typing_extensions import TypedDict
    
    class GraphState(TypedDict):
        messages: Annotated[list[AnyMessage], add_messages]

     

    LangGraph에서는 위 내용을 이미 구현해 놓음

    즉, 아래와 같이 사용하면 됨

    • messages는 MessagesState에서 자동 제공
    • documents는 내가 추가한 새로운 필드
    from langgraph.graph import MessagesState
    
    class State(MessagesState):
        documents: list[str]
    반응형