레이블이 Agent인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Agent인 게시물을 표시합니다. 모든 게시물 표시

20250916

LangGraph 0.2 상태 머신 패턴

LangGraph 0.2 브랜치가 안정화되면서 상태 관리가 꽤 좋아졌다. 특히 체크포인팅과 interrupt.

체크포인트

from langgraph.checkpoint.postgres import PostgresSaver

saver = PostgresSaver.from_conn_string(DSN)
app = graph.compile(checkpointer=saver)

cfg = {"configurable": {"thread_id": "user-42"}}
state = app.invoke({"input": "..."}, config=cfg)
# 다음 호출에서 같은 thread_id면 중간 상태부터 이어감

이게 되면 대화 resume, 실패 복구, human-in-the-loop가 자연스럽게 풀린다. 이전에는 redis에 직접 state pickling했는데 이제 프레임워크 레벨.

interrupt 패턴

특정 노드 앞에서 실행을 일시 정지하고 사람 승인 대기 가능.

g.add_node("confirm_write", confirm_node)
g.add_edge("plan", "confirm_write")
app = g.compile(checkpointer=saver, interrupt_before=["confirm_write"])

# 실행 후 중단된 지점
# 사람이 검토 -> state.update({"approved": True}) -> app.invoke(None, config=cfg)

이것으로 내부 agent의 위험 동작(외부 API 호출, DB write)을 승인 체크포인트로 묶음. 사람 승인 후에만 execute 단계 진입.

Subgraph

서브 그래프가 정식으로 지원됨. "retrieval 체인", "reasoning 체인" 같은 블록을 재사용 가능하게 캡슐화. 큰 플로우는 잘 쪼개야 읽힌다.

단점

  • 여전히 debug는 어렵다. LangSmith 없이는 노드 간 flow 추적이 힘듦.
  • checkpoint DB 스키마가 버전 간 변경 있음. upgrade 시 migration 조심.
  • TypedDict state는 IDE 자동완성 지원이 약해서 큰 state에선 Pydantic v2 모델로 대체하고 싶어지지만, 여전히 일부 엣지 케이스가 있음.

결론

에이전트는 "모델 + 그래프 + 상태"다. LangGraph는 "그래프 + 상태" 축에서 가장 실용적. 모델 선택과 분리되어 있어서, Claude/GPT/오픈소스 어떤 걸 꽂든 그대로 돌아간다. 이게 장기적 베팅 이유.

20240420

LangGraph 초기 도입 실험

LangChain의 자매 라이브러리 LangGraph가 올해 초 나왔다. 이름은 거창한데 결국 상태 머신 위에 LLM 노드를 배치하는 프레임워크.

기존 LangChain agent가 AgentExecutor로 루프 도는 방식이었는데 분기/조건/재시도 다루기가 지저분했다. LangGraph는 명시적 그래프라 디버깅이 훨씬 낫다.

기본 구조

from langgraph.graph import StateGraph, END

class State(TypedDict):
    question: str
    docs: list
    answer: str
    attempts: int

def retrieve(state): ...
def grade(state): ...   # retrieval 품질 판정
def generate(state): ...
def rewrite(state): ... # 질의 재작성

g = StateGraph(State)
g.add_node("retrieve", retrieve)
g.add_node("grade", grade)
g.add_node("generate", generate)
g.add_node("rewrite", rewrite)

g.set_entry_point("retrieve")
g.add_edge("retrieve", "grade")
g.add_conditional_edges("grade",
    lambda s: "generate" if s["docs"] else "rewrite",
    {"generate":"generate", "rewrite":"rewrite"})
g.add_edge("rewrite", "retrieve")
g.add_edge("generate", END)
app = g.compile()

써본 소감

좋은 점: 노드별 로그가 자연스럽게 쌓임. LangSmith에 꽂으면 각 노드 입출력이 전부 trace. 디버깅 훨씬 쉬움.

애매한 점: TypedDict로 state가 정의되는데 중첩 구조 관리가 살짝 피곤. Pydantic 쓰려다가 호환 이슈로 도로 Typeddict.

주의할 점: 조건부 엣지에서 무한 루프 쉽게 남. 우리 첫 버전은 rewrite → retrieve → grade → rewrite ... 이 순환에 20턴 돌다가 terminate됨. 그래서 state에 attempts를 두고 3회 초과 시 END로 강제.

CrewAI는?

같은 시기에 나온 CrewAI도 살짝 봤는데, "역할 기반 agent들의 협업"에 더 초점. 우리 케이스는 분기/상태가 명확한 파이프라인이라 LangGraph가 맞았다.

1년 뒤쯤엔 agent framework 시장이 또 갈릴 것 같다. 지금은 일단 LangGraph로 베팅.