Java 모놀리스에서 LangGraph 에이전트로: 전이되는 것들
요약
엔터프라이즈 Java 개발 경험을 바탕으로 LangGraph 에이전트 시스템 구축 시 적용되는 분산 시스템 설계 원칙을 다룹니다. 타임아웃, 재시도, 멱등성, 비용 관리 등 기존 백엔드 엔지니어링 개념이 AI 에이전트 환경에서 어떻게 전이되고 확장되는지 설명합니다.
핵심 포인트
- 에이전트 시스템은 분산 시스템의 장애 모드(타임아웃, 재시도)를 공유함
- LLM의 의미론적 실패를 탐지하기 위한 서킷 브레이커 설계가 중요함
- 상태를 변경하는 에이전트 도구에는 반드시 멱등성과 감사 추적이 필요함
- LLM 비용 관리는 기존의 용량 계획(Capacity Planning)과 유사한 메커니즘으로 접근해야 함
나는 10년 동안 엔터프라이즈 Java 시스템을 구축해 왔다. Spring Cloud 마이크로서비스로 분할된 결제 모놀리스(monolith), 뱅킹 애플리케이션, 그리고 현재는 Cisco 보안 플랫폼을 구축하고 있다. 최근에는 LLM 시스템 구축에 본격적으로 뛰어들었다. 놀라웠던 점은 내가 얼마나 많은 것을 배워야 했는가가 아니었다. 얼마나 많은 것들이 그대로 전이(transfer)되는가였다.
에이전트 시스템(Agentic systems)은 분산 시스템(distributed systems)이다. 어휘는 새로울지 몰라도, 장애 모드(failure modes)는 그렇지 않다.
타임아웃(Timeouts)과 재시도(retries) — 같은 문제, 더 나쁜 기본값
타임아웃 없이 불안정한 의존성(dependency)을 호출하는 Java 서비스는 주니어 엔지니어의 실수다. 하지만 타임아웃 없이 LLM을 호출하는 에이전트는 왠지 정상처럼 여겨진다. LLM 호출은 느리고, 때때로 멈추며, 새로운 방식(잘못된 JSON 형식, 거부, 미완성된 도구 호출 등)으로 실패한다. Resilience4j가 내게 가르쳐준 모든 것이 직접적으로 적용된다: 백오프(backoff)를 포함한 제한된 재시도(bounded retries), 값비싼 무언가로 조용히 대체하는 대신 정직한 오류와 함께 빠르게 실패하는 서킷 브레이커(circuit breakers), 그리고 — 이것은 새로운 것인데 — 의미론적(semantic) 실패 탐지다. 왜냐하면 LLM은 내부에 쓰레기 값이 들어있는 채로 HTTP 200을 반환할 수 있기 때문이다.
Atlas에서는 모델 엔드포인트가 다운되면 게이트웨이가 503 + Retry-After로 서킷 브레이크(circuit-break)를 건다. 그것은 의도적으로 지루하게 설계된 것이다. 지루함이 핵심이다.
멱등성(Idempotency) — 이제 LLM이 선택한 부작용(side effects)과 함께
백엔드 규칙: 재시도할 수 있는 모든 핸들러는 멱등성(idempotent)을 가져야 한다. 에이전트 규칙: 마찬가지다. 다만 재시도는 첫 번째 응답이 "적절해 보이지 않아서" 플래너(planner)가 도구(tool)를 다시 호출하기로 결정한 것일 수 있다는 점이 다르다. 만약 에이전트의 도구가 상태를 변경(mutate)한다면, 채팅 UI에 스트리밍(streaming)이 필요한 것보다 멱등성 키(idempotency keys)와 감사 추적(audit trail)이 더 절실히 필요하다.
Atlas는 모든 쓰기 작업을 청중 범위 토큰(audience-scoped tokens, RFC 8707)과 추가 전용 해시 체인 감사 로그(append-only, hash-chained audit log)를 갖춘 MCP 도구 서버를 통해 라우팅하며, 통제된 동작을 위해 인간 참여(human-in-the-loop) 체크포인트를 뒤에 둔다. 그 설계는 AI 혁신이 아니다. 그것은 어떤 은행급 액션 API(bank-grade action API)라도 갖추어야 할 모습이다. 혁신은 단지 호출자가 LLM이라는 이유만으로 표준을 포기하지 않는 것이다.
비용 예산(Cost budgets)은 새로운 용량 계획(capacity planning)이다
백엔드 작업에서는 커넥션 풀 (connection pools), 스레드 풀 (thread pools), 속도 제한 (rate limits)과 같은 용량 계획 (capacity planning)을 세웁니다. LLM 시스템에서 희소한 자원은 바로 비용 (spend)입니다. 동일한 메커니즘이 적용됩니다. 토큰 버킷 (token-bucket) 속도 제한, 사용자별 일일 예산 가드 (Atlas의 경우 Redis 기반이며, UTC 기준 사용자별 키 지정), 비용 상한선에서의 알림 등이 적용되며, 여기에 새로운 레버 하나가 추가됩니다: 바로 **라우팅 (routing)**입니다. Atlas는 단순한 쿼리는 작은 모델로 라우팅하고, 읽기 작업을 복제본 (replica)으로 라우팅하는 것과 같은 방식으로 다단계 추론 (multi-step reasoning)을 위해 더 큰 모델을 예약해 둡니다. 비용 회귀 (cost regression)는 지연 시간 예산 (latency budget)처럼 CI에서 게이트 (gated) 처리됩니다.
상태 머신 (State machines)이 직관 (vibes)보다 낫다
LangGraph가 저에게 딱 들어맞았던 이유는 그것이 마법이 아니기 때문입니다. LangGraph는 체크포인트 (checkpoints)가 있는 명시적인 상태 그래프 (state graph)입니다. 즉, 노드 (nodes), 엣지 (edges), 지속되는 상태 (persisted state), 재개 가능성 (resumability)을 갖추고 있습니다. 만약 여러분이 워크플로우 엔진 (workflow engine)이나 보상 단계 (compensation steps)가 포함된 사가 (saga) 패턴을 설계해 본 적이 있다면, 이미 이런 방식으로 생각하고 있는 것입니다. 내구성이 있는 인간 승인 체크포인트 (human-approval checkpoint)를 포함한 플래너-실행자 (planner–executor) 패턴은 기업 아키텍트가 2010년 BPM 다이어그램에서 보았을 법한 상태 머신입니다. 이는 찬사입니다.
진정으로 새로운 것들
정직하게 말하자면 반대의 목록도 필요합니다. 백엔드에 상응하는 개념이 없어서 실제로 많은 노력이 필요했던 세 가지가 있습니다:
- 평가 (Evaluation)는 이진적 (binary)이지 않고 통계적 (statistical)입니다. 테스트는 통과하거나 실패하지만, 평가 지표 (eval metrics)는 분포 (distributions)를 따라 움직입니다. 하한선 (floors)과 회귀 밴드 (regression bands)를 설정하는 법(그리고 언제 paired bootstrap이나 McNemar 테스트를 사용할지)을 배우는 것은 새로운 근육을 키우는 과정이었습니다.
- 검색 레이어 (retrieval layer)는 랭킹 (ranking) 문제입니다. 하이브리드 검색 (hybrid search), 재순위화 (reranking), 그리고 기권 임계값 (abstention thresholds)은 Spring의 그 어떤 것보다 정보 검색 (information retrieval)에 더 가깝습니다.
- 프롬프트 인젝션 (Prompt injection)은 신뢰 모델을 역전시킵니다. 백엔드 보안은 자체 데이터를 신뢰하지만, RAG 보안은 그럴 수 없습니다. 검색된 문서는 모델에 대한 신뢰할 수 없는 입력값입니다. 스포트라이팅 (spotlighting)과 격리 (quarantine)는 REST 시대에는 유사한 개념이 없었습니다.
요약된 제안
만약 여러분이 AI 엔지니어링을 눈여겨보고 있는 백엔드 엔지니어라면: 타임아웃 (timeouts), 멱등성 (idempotency), 예산 (budgets), 감사 (audit), 그리고 상태 (state)에 대한 여러분의 본능은 구식 유산이 아닙니다. 그것들은 바로 대부분의 LLM 시스템에 결여되어 있는 정확한 규율 (discipline)입니다. 검색 (retrieval)을 배우고, 평가 (evals)를 배우되, 그 규율을 유지하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기