LangGraph와 PostgreSaver를 활용한 체크포인트 저장 및 비동기 처리 설정 방법

환경 구성

사용된 라이브러리 버전:

  • Python: 3.12.9
  • langgraph: 0.5.4
  • langgraph-checkpoint-postgres: 2.0.23
  • psycopg: 3.2.10

체크포인트 초기화 방식

방법 1: 직접 연결 객체로 초기화

PostgresSaver 클래스를 직접 사용하여 데이터베이스 연결을 설정할 수 있습니다.

from psycopg import Connection
from langgraph.checkpoint.postgres import PostgresSaver

db_uri = "postgres://<user>:<password>@<host>:<port>/<database>"
conn = Connection.connect(db_uri)
conn.autocommit = True  # 필수: 트랜잭션 내에서 CREATE INDEX CONCURRENTLY 실행 불가 → 자동 커밋 필요

checkpointer = PostgresSaver(conn)
checkpointer.setup()

방법 2: 연결 문자열로 간편 초기화

from_conn_string 메서드를 사용하면 자동으로 컨텍스트 관리를 지원합니다.

from langgraph.checkpoint.postgres import PostgresSaver

db_uri = "postgres://<user>:<password>@<host>:<port>/<database>"
with PostgresSaver.from_conn_string(db_uri) as checkpointer:
    checkpointer.setup()

스키마 지정 옵션

기본적으로 테이블은 public 스키마에 생성됩니다. 특정 스키마에 저장하려면 연결 문자열에 options 파라미터를 추가하세요.

db_uri = "postgres://<user>:<password>@<host>:<port>/<database>?options=-csearch_path%3D<your_schema>,public"

이 경우, your_schema에 테이블이 생성되며, public도 검색 경로에 포함됩니다.

비동기 처리 설정

작업 흐름의 비동기 출력을 사용하려면 AsyncPostgresSaver를 사용해야 합니다. 동기 호출로 접근하면 오류가 발생합니다.

from langgraph.graph import StateGraph

workflow = StateGraph(MainState)
workflow.add_node("node1", execute_node_func)

# ... 노드 및 상태 정의 생략 ...

async def generate_async_response(*args, **kwargs):
    async with AsyncPostgresSaver.from_conn_string(db_uri) as async_checkpointer:
        graph = workflow.compile(checkpointer=async_checkpointer)

        inputs = {
            # 입력 데이터
        }
        config = {
            "configurable": {
                "thread_id": "123456",
            }
        }

        async for output in graph.astream(inputs, config, subgraphs=True, stream_mode="updates"):
            # 결과 처리 로직
            pass

비동기 모드에서의 상태 조회 변경

비동기 체크포인트 사용 시 동기 메서드(get_state)는 사용 불가능합니다. 대신 aget_state를 사용해야 합니다.

# 기존 동기 방식 (비동기 체크포인트에서는 작동하지 않음)
def is_thread_interrupted(graph, thread_id: str):
    state = graph.get_state({"configurable": {"thread_id": thread_id}})
    return state.next not in [(), ("__end__",)]

# 수정된 비동기 방식
async def is_thread_interrupted(graph, thread_id: str):
    state = await graph.aget_state({"configurable": {"thread_id": thread_id}})
    return state.next not in [(), ("__end__",)]

비동기 함수 내에서 상태를 확인하고 조건부 재개 로직을 적용할 수 있습니다.

async def generate_async_response(*args, **kwargs):
    async with AsyncPostgresSaver.from_conn_string(db_uri) as async_checkpointer:
        graph = workflow.compile(checkpointer=async_checkpointer)

        inputs = { ... }
        config = { "configurable": { "thread_id": "123456" } }

        if await is_thread_interrupted(graph, thread_id="123456"):
            inputs = Command(resume=inputs)

        async for output in graph.astream(inputs, config, subgraphs=True, stream_mode="updates"):
            # 스트림 출력 처리
            pass

태그: LangGraph postgres Checkpoint Asynchronous async

7월 9일 04:25에 게시됨