No messages table! The data model behind my own Claude-based chatbot

개요

Claude 기반 챗봇 'Claudius'의 데이터 모델은 관계형 데이터베이스의 정규화 방식이 아닌, 애플리케이션의 읽기/쓰기 패턴에 맞춰 문서 모델링을 중심으로 설계되었습니다.

주요 내용

  • 메시지 테이블 부재: 챗봇 대화 기록에서 메시지는 별도의 'messages' 컬렉션에 저장되지 않고, LangGraph checkpointer의 에이전트 상태와 함께 관리됩니다. 이는 애플리케이션이 대화 메시지를 항상 에이전트 상태와 함께 읽기 때문에 별도의 메시지 테이블을 조인하는 비효율성을 제거하기 위한 설계입니다.
  • 문서 모델링 접근 방식: 관계형 데이터베이스와 달리 문서 데이터베이스는 애플리케이션의 데이터 접근 패턴을 중심으로 문서를 설계합니다. 데이터가 함께 사용될 때 함께 저장되는 것이 원칙입니다.
  • 스키마 유연성과 검증: 문서 데이터베이스는 스키마가 없다는 것이 아니라, 유연하고 사용 사례 기반의 데이터 모델을 의미합니다. Zod 스키마를 사용하여 코드 내에서 스키마를 관리하고, 런타임 검증과 TypeScript 타입을 통합합니다.
  • 주요 컬렉션 및 특징:
  • settings: _id 문자열로 식별되는 여러 형태의 전역 싱글톤(allowlist, model catalog 등)을 하나의 컬렉션에 저장하며, _id 기반의 판별적 연합(discriminated union) Zod 스키마를 사용합니다.
  • 사용자(users): dailyMessageCount와 같이 함께 읽고 쓰는 데이터는 임베딩 객체로 저장하여 데이터 모델링 기법으로 활용합니다.
  • 데이터베이스 엔진에 의한 정책 강제:
  • 보존 기간 (Retention): 게스트 사용자의 대화 및 메모리에 expiresAt 필드를 추가하고 TTL(time-to-live) 인덱스를 사용하여 MongoDB 엔진이 자동으로 문서를 삭제하도록 설정합니다.
  • 원격 측정 (Telemetry): 모든 토큰 사용량 데이터는 usage_events 컬렉션에 기록되며, MongoDB의 time-series 컬렉션 기능을 활용하여 효율적인 시간 기반 쿼리를 지원합니다.
  • 사용자 ID 기반 필터링 (Tenant Isolation): 벡터 검색 시 userId를 기준으로 사전 필터링하는 기능을 인덱스의 속성으로 설정하여 다른 사용자의 데이터를 반환하지 않도록 합니다. chunks 컬렉션은 검색 인덱스 강화를 위해 userId를 중복 저장합니다.
  • 인덱스 생성 시 고려사항:
  • 검색 인덱스는 컬렉션이 이미 존재해야 생성 가능합니다.
  • Atlas는 검색 인덱스 빌드를 비동기적으로 수행하므로, 빌드가 완료되기 전에 쿼리가 실행될 수 있습니다. createSearchIndex 함수는 빌드가 큐에 들어간 시점에 반환됩니다.
  • 코드 무결성 유지: 모든 데이터 접근은 타입이 지정된 accessor 함수(conversationsCol(), memoriesCol() 등)를 통해 이루어지며, userId는 ObjectId로 통일하여 필터링 및 조회가 일관되도록 합니다.

시사점

챗봇의 데이터 모델링을 애플리케이션의 접근 패턴에 맞춰 설계함으로써, 보존 기간, 원격 측정, 사용자 격리와 같은 핵심 정책들이 코드 관리가 아닌 데이터베이스 엔진과 인덱스의 속성으로 구현되어 유지보수성과 견고성이 향상됩니다.

원문 읽기 →
원문을 불러오는 중...

댓글

GitHub Discussions