들어가며: 왜 '상태 유지' 에이전트인가?

소파 청소 견적을 받기 위해 업체에 연락해 본 적 있으신가요? 사이즈, 재질, 사진, 주소까지 주고받고, 견적 확인 후 다시 일정 조율까지… 꼬박 15분이 걸립니다. 이 과정을 AI에게 맡기면 어떨까요?

단순한 챗봇과 진짜 AI 에이전트의 차이는 **'상태(State)'**에 있습니다. 고객이 "투룸이고 냉장고 내부 청소도 해주세요, 화/수요일 가능해요"라고 한 번에 말하면, 에이전트는 부족한 정보를 파악하고, 가격을 계산하며, 예약까지 원스톱으로 처리해야 합니다.

이 글에서는 Python과 LangGraph를 사용해 멀티스텝 예약 워크플로우를 처리하는 상태 기반 에이전트를 직접 만들어 봅니다. 여기에 Langfuse를 붙여 관측 가능성(Observability)까지 확보하는 실무적인 접근을 다룹니다. (참고로, 이 에이전트의 전체 소스 코드는 GitHub에서 확인할 수 있습니다.)

AI chat interface for customer service booking agent with LangGraph Technical Structure Concept

핵심 구현: LangGraph로 상태 머신 만들기

LangGraph의 핵심은 **공유 상태(Shared State)**입니다. 여러 고객 메시지에 걸쳐 대화가 이어져야 하므로, TypedDict로 상태 스키마를 정의합니다.

from typing import TypedDict, Optional

class BookingDetails(TypedDict):
    service_type: Optional[str]
    size: Optional[str]
    address: Optional[str]
    preferred_dates: Optional[list[str]]
    price: Optional[float]

class AgentState(TypedDict):
    messages: list
    booking_details: BookingDetails
    next_step: str

이제 그래프 빌더를 생성하고 노드를 추가합니다. 예를 들어 가격 계산 노드는 다음과 같이 상태를 읽고 부분 업데이트를 반환합니다.

from langgraph.graph import StateGraph, END

def calculate_price_node(state: AgentState):
    details = state["booking_details"]
    # 실제 가격 계산 로직 (예: 서비스 종류, 사이즈 기반)
    price = calc_price(details)
    return {"booking_details": {**details, "price": price}, "next_step": "confirm"}

graph = StateGraph(AgentState)
graph.add_node("gather_info", gather_info_node)
graph.add_node("calculate_price", calculate_price_node)
graph.add_node("book_appointment", book_node)

정보 수집 후, 조건부 라우팅 함수가 충분한 정보가 있는지 판단합니다.

def route_after_gather(state: AgentState):
    if is_complete(state["booking_details"]):
        return "calculate_price"
    return END  # 추가 고객 메시지 대기

graph.add_conditional_edges("gather_info", route_after_gather)
graph.add_edge("calculate_price", "book_appointment")
graph.add_edge("book_appointment", END)

마지막으로 체크포인터와 함께 그래프를 컴파일하면 상태가 자동으로 저장되어, 대화가 끊겨도 이어서 진행할 수 있습니다.

from langgraph.checkpoint.memory import MemorySaver
app = graph.compile(checkpointer=MemorySaver())

이 구조의 장점은 명확합니다. LLM의 유연한 대화 능력과 결정론적 비즈니스 규칙(가격 계산, 예약 로직)을 분리하여, 예측 가능하면서도 자연스러운 사용자 경험을 제공합니다.

Python code editor showing LangGraph state schema and node definitions Coding Session Visual

주의사항 및 심화 팁: 관측 가능성(Observability) 확보하기

프로덕션 환경에서 AI 에이전트를 운영할 때 가장 중요한 것은 **'무슨 일이 일어나고 있는지 아는 것'**입니다. Langfuse는 오픈소스 LLM 관측 플랫폼으로, 프롬프트, 입출력, 토큰 사용량, 비용을 추적할 수 있습니다.

from langfuse.callback import CallbackHandler

langfuse_handler = CallbackHandler(
    public_key="pk-lf-...",
    secret_key="sk-lf-...",
    host="https://cloud.langfuse.com"
)

# 그래프 실행 시 콜백 전달
app.invoke(inputs, config={"callbacks": [langfuse_handler]})

주의할 점:

  • LLM 호출 비용은 예상보다 빠르게 누적될 수 있습니다. Langfuse 대시보드에서 토큰 사용량을 주기적으로 모니터링하세요.
  • 상태 스키마가 복잡해질수록 디버깅이 어려워집니다. 각 노드의 입출력을 로깅하는 습관을 들이세요.
  • 체크포인터를 메모리 대신 PostgreSQL 등 영속 저장소로 교체하면 서버 재시작에도 상태가 유지됩니다.

이 기술의 한계는 LLM의 비결정성입니다. 동일한 입력에도 다른 응답이 나올 수 있으므로, 중요 비즈니스 로직(가격, 예약 확정)은 반드시 코드로 검증하는 방어 로직이 필요합니다.

Langfuse observability dashboard monitoring LLM token usage and traces Programming Illustration

결론: 다음 단계는?

지금까지 LangGraph와 Langfuse를 활용해 상태 기반 예약 에이전트를 구축하는 방법을 살펴봤습니다. 이 프로젝트는 v0 수준이지만, 모듈화된 설계 덕분에 확장이 용이합니다.

실무 적용을 위한 조언:

  • 국내 SI 환경에서는 레거시 시스템과의 연동이 관건입니다. 예약 데이터를 기존 ERP나 CRM에 동기화하는 어댑터 레이어를 반드시 고려하세요.
  • 프론트엔드는 Streamlit으로 빠르게 프로토타이핑한 뒤, 실제 서비스에서는 React나 Vue로 교체하는 것을 권장합니다.
  • WhatsApp, 카카오톡 등 메신저 연동을 추가하면 고객 접점을 크게 확장할 수 있습니다.

다음 학습 방향:

  • LangGraph의 interrupt 기능을 활용한 human-in-the-loop 워크플로우
  • Langfuse의 평가(Evaluation) 기능으로 에이전트 응답 품질 자동 측정
  • 멀티 에이전트 구조로 확장 (예: 예약 에이전트 + 알림 에이전트)

AI 에이전트는 단순한 유행이 아니라, 반복적인 비즈니스 프로세스를 자동화하는 실질적인 도구입니다. 작은 워크플로우부터 시작해 보세요.


함께 보면 좋은 글:

근거자료: I Replaced a 15-Minute Booking Process with a LangGraph AI Agent

본 콘텐츠는 신뢰할 수 있는 출처를 바탕으로 AI 도구를 활용하여 초안이 작성되었으며, 편집자의 검토를 거쳐 발행되었습니다. 전문가의 조언을 대체하지 않습니다.