들어가며: 왜 '상태 유지' 에이전트인가?
소파 청소 견적을 받기 위해 업체에 연락해 본 적 있으신가요? 사이즈, 재질, 사진, 주소까지 주고받고, 견적 확인 후 다시 일정 조율까지… 꼬박 15분이 걸립니다. 이 과정을 AI에게 맡기면 어떨까요?
단순한 챗봇과 진짜 AI 에이전트의 차이는 **'상태(State)'**에 있습니다. 고객이 "투룸이고 냉장고 내부 청소도 해주세요, 화/수요일 가능해요"라고 한 번에 말하면, 에이전트는 부족한 정보를 파악하고, 가격을 계산하며, 예약까지 원스톱으로 처리해야 합니다.
이 글에서는 Python과 LangGraph를 사용해 멀티스텝 예약 워크플로우를 처리하는 상태 기반 에이전트를 직접 만들어 봅니다. 여기에 Langfuse를 붙여 관측 가능성(Observability)까지 확보하는 실무적인 접근을 다룹니다. (참고로, 이 에이전트의 전체 소스 코드는 GitHub에서 확인할 수 있습니다.)

핵심 구현: 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의 유연한 대화 능력과 결정론적 비즈니스 규칙(가격 계산, 예약 로직)을 분리하여, 예측 가능하면서도 자연스러운 사용자 경험을 제공합니다.

주의사항 및 심화 팁: 관측 가능성(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의 비결정성입니다. 동일한 입력에도 다른 응답이 나올 수 있으므로, 중요 비즈니스 로직(가격, 예약 확정)은 반드시 코드로 검증하는 방어 로직이 필요합니다.
![]()
결론: 다음 단계는?
지금까지 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