왜 LangGraph 도입 후 코드가 더 복잡해졌나 — 실패에서 배운 기록
요약
LangGraph 도입 후 오히려 코드 복잡도가 증가했던 실패 사례를 분석하고 해결 과정을 기록했습니다. 프레임워크의 핵심 기능을 제대로 활용하지 못한 설계 오류와 상태 관리 문제를 짚어봅니다.
핵심 포인트
- 프레임워크의 책임 경계를 이해하지 못한 채 도입 시 복잡도 증가
- 이중 체크포인팅 및 상태 관리 불일치 문제 발생
- 부분 최적화에 치중한 '바이브 코딩'의 위험성 경고
- 독립 토폴로지 및 thread_id 격리를 통한 구조 개선
"상태 관리와 흐름 제어가 깔끔해지겠지"라는 기대로 LangGraph를 도입했는데, 오히려 코드가 복잡해졌습니다.
프레임워크를 도입하고도 구조가 나빠질 수 있다는 걸 직접 겪고 정리한 경험에 대한 기록과 공유입니다.
진단해보니 상태는 이러했는데
- 그래프에 노드가 하나뿐. current_step → END 구조라 조건부 엣지도 분기도 없었고, graph.invoke()가 함수를 직접 호출하는 것과 똑같음. Step 전환은 그래프 밖 서비스 코드가 판단하는 형태.
- 같은 상태를 두 곳에 저장. LangGraph MemorySaver(인메모리)와 자체 PostgreSQL Checkpointer가 동일 세션을 이중으로 저장·복원하면서 불일치 발생.
- 8,700여 줄 정도의 3개 LangGraph 실행 코드 (Executor)에 중복. 실질 핵심 로직은 "LLM 호출 + 프롬프트 조립" 정도였고, 나머지 대부분은 상태 관리·조건 분기·에지케이스 패치.
표면적으로는 프레임워크의 실제 기능(조건부 엣지, 내장 체크포인터, Human-in-the-Loop)을 쓰지 않고 껍데기로만 도입한 게 문제였는데, 더 파고들었더니 원인은 따로 있었습니다.
- 대부분 바이브 코딩으로 만들어졌지만, 제작 과정중에 내부 코드나 설계 원칙을 깊이 들여다보지 않고, 매번 요구사항과 의도만 정리해 구현을 이어간 방식.
- 문제는 바이브 코딩 자체가 아니라 검증 없는 진행이었음. 눈앞의 기능을 최적화할 뿐 전체 구조의 책임 경계는 지켜주지 않음. 이중 체크포인팅도, 흩어진 상태도, 중복된 로직도 전부 부분 최적화의 누적.
- 설계자가 없었던 게 아니라, 프레임워크가 무엇을 책임지도록 설계됐는지 충분히 이해하지 못한 채 그 위에서 지시만 내린 상태가 진짜 원인.
그래서 반성하고, 이렇게 되돌렸습니다.
- 독립 토폴로지 + thread_id 격리로 세션 분리
- State에는 메타데이터만 두고 본문은 Store로 이동
- regex 파싱 대신 네이티브 tool_use 사용
- 테스트 가능하도록 노드 분리
- 프레임웍크에 대한 정확한 이해와 활용 구조가 필요했던 나 자신
"어떻게 쓰는가"가 아니라 "어떻게 잘못 썼는가"에 대한 기록/공유 입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 RSS: GeekNews (한국어)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기