
에이전트 관측 가능성 (Observability)을 위한 데이터 레이어, SmithDB를 구축했습니다
요약
에이전트 트레이스의 폭발적인 데이터 증가와 복잡한 쿼리 패턴을 처리하기 위해 특수 설계된 분산 데이터베이스 SmithDB가 출시되었습니다. SmithDB는 기존 범용 데이터베이스의 한계를 넘어 멀티모달 콘텐츠와 중첩된 스팬을 효율적으로 관리하며, LangSmith의 핵심 워크로드를 최대 15배 빠르게 처리합니다.
핵심 포인트
- 에이전트 트레이스의 대형화 및 멀티모달 콘텐츠 증가로 인한 기존 관측 가능성 저장소의 한계 극복
- 트레이스 트리 로드, 전체 텍스트 검색, 실행 필터링 등 주요 워크로드에서 업계 최고 수준의 성능 제공
- 오브젝트 스토리지를 기반으로 한 상태 없는(Stateless) 아키텍처로 셀프 호스팅 및 멀티 클라우드 확장성 확보
- 무작위 액세스, JSON 필터링, 트리 인식 쿼리 등 에이전트 네이티브 쿼리 패턴 지원
핵심 요약 (Key Takeaways)
에이전트 트레이스 (Agent traces)가 기존의 관측 가능성 (Observability) 저장소의 한계를 넘어섰습니다— 현대적인 에이전트 트레이스는 수백 개의 중첩된 스팬 (Spans), 멀티모달 (Multi-modal) 콘텐츠, 그리고 몇 시간 동안 열려 있는 스팬을 포함하고 있습니다. 이는 범용 데이터베이스가 처리하도록 설계되지 않은 데이터 볼륨과 쿼리 패턴을 생성합니다.
SmithDB는 모든 주요 관측 가능성 워크로드에서 업계 최고 수준의 성능을 제공합니다— 트레이스 트리 (Trace tree) 로드 시 P50 지연 시간(Latency) 92ms, 전체 텍스트 검색 (Full-text search) 400ms, 실행 필터링 (Run filtering) 82ms를 기록하며, 핵심 LangSmith 경험을 이전보다 최대 15배 더 빠르게 만듭니다.
엔터프라이즈 요구 사항을 위해 구축된 휴대 가능하고 확장 가능한 아키텍처— 상태가 없는 수집 (Stateless ingestion) 및 쿼리 서비스와 함께 오브젝트 스토리지 (Object storage)를 기반으로 하는 SmithDB는 로컬 디스크를 관리하는 대신 컴퓨팅 자원을 추가함으로써 확장합니다. 이를 통해 셀프 호스팅 (Self-hosted) 및 멀티 클라우드 (Multi-cloud) 환경에 쉽게 배포할 수 있습니다.
우리는 이제 핵심 LangSmith 워크로드를 지원하는, 에이전트 관측 가능성을 위해 특수 제작된 분산 데이터베이스인 SmithDB를 출시합니다.
SmithDB는 LangSmith에 주요 관측 가능성 워크로드 전반에 걸친 업계 최고 수준의 성능, 고객이 데이터를 보관하고자 하는 어디에서나 실행할 수 있는 휴대성, 그리고 기존 관측 가능성 저장소가 설계되지 않았던 에이전트 네이티브 (Agent-native) 쿼리 패턴을 지원하는 유연성을 제공합니다.
에이전트는 새로운 데이터 문제를 야기합니다
에이전트 관측 가능성에서 트레이스 (Traces)는 에이전트의 핵심 행동 기록 역할을 합니다.
2023년 LangSmith가 처음 출시되었을 때, AI 애플리케이션은 비교적 단순했습니다. 팀들은 RAG 파이프라인 (RAG pipelines), 프롬프트 체인 (Prompt chains), 그리고 초기 단계의 에이전트들을 구축하고 있었습니다.
그 이후로 에이전트는 더욱 보편화되고 실행 시간이 길어졌으며, LLM 컨텍스트 윈도우 (Context window) 크기는 극적으로 증가했고, 워크로드에는 이미지 및 오디오와 같은 멀티모달 (Multi-modal) 콘텐츠가 점점 더 많이 포함되고 있습니다.
그 결과, 현대적인 에이전트와 관련된 트레이스 데이터는 볼륨(트레이스 수)과 크기(개별 페이로드 크기) 모두에서 폭발적으로 증가했습니다. 현대적인 에이전트 트레이스는 수백 개의 깊게 중첩된 스팬 (Spans)을 가질 수 있습니다.
에이전트 트레이스는 크고 중첩되어 있을 뿐만 아니라, 조각 단위로 도착하기도 합니다. 즉, 에이전트 스팬 (Span)의 시작 이벤트가 종료 이벤트보다 몇 분, 혹은 몇 시간 앞서 도착할 수 있습니다.
이 데이터를 분석하는 데 필요한 쿼리 패턴 (Query patterns) 또한 점점 더 복잡해지고 있습니다. 에이전트 관측 가능성 (Observability)은 다음과 같은 기능을 지원해야 합니다.
무작위 액세스 (Random access): 개별 실행 (Run) 또는 트레이스 (Trace)를 즉시 로드
대화형 필터링 (Interactive filtering): 메타데이터, 피드백, 지연 시간 (Latency), 오류, 태그 및 시간을 기준으로 대규모 트레이스 데이터셋을 슬라이싱
전체 텍스트 검색 (Full-text search): 에이전트 실행의 입력 및 출력 내에서 구절과 패턴 검색
JSON 필터링 (JSON filtering): 임의로 정의된 사용자 메타데이터 및 구조화된 도구 출력에 대한 쿼리
트리 인식 쿼리 (Tree-aware queries): 루트 실행 (Root runs), 자식 실행 (Child runs) 또는 트레이스의 모든 노드를 기반으로 필터링
스레드 재구성 (Thread reconstruction): 여러 에이전트 트레이스에 걸친 장기 실행 대화를 즉시 재구성
집계 (Aggregations): 다양한 필터에 대해 비용, 지연 시간, 토큰 사용량, 평가자 점수 (Evaluator scores) 계산
셀프 호스팅 (Self-hosting) 및 멀티 클라우드 (Multi-cloud) 요구 사항을 충족하면서, 대규모 에이전트 트레이스에 대해 낮은 지연 시간으로 이 모든 기능을 지원하려면 근본적으로 새로운 아키텍처가 필요합니다.
이것이 SmithDB를 구축하게 된 동기입니다.
SmithDB 소개
SmithDB는 에이전트 관측 가능성 및 평가 워크로드 (Evaluation workloads)를 위해 특별히 제작된 LangSmith의 데이터 레이어 (Data layer)입니다.
Rust로 구축되었으며, Apache DataFusion 쿼리 엔진과 Vortex 파일 툴킷을 활용하며, LangSmith의 고유한 워크로드에 맞춰 대폭적인 커스텀을 거쳤습니다.
높은 수준에서 SmithDB는 세 가지 구성 요소로 이루어져 있습니다.
객체 스토리지 (Object storage): 영구적인 트레이스 데이터를 위한 저장소
소규모 Postgres 메타스토어 (Metastore): 세그먼트 메타데이터를 위한 저장소
상태가 없는 수집, 쿼리 및 압축 서비스 (Stateless ingestion, query, and compaction services)
성능
관측 가능성에서 성능은 단순히 있으면 좋은 기능이 아닙니다. 인간과 에이전트 모두에게 느린 관측 가능성 도구는 에이전트 개발 루프 (Development loop)의 병목 현상이 됩니다. SmithDB는 에이전트 관측 가능성에 중요한 핵심 워크로드 전반에서 선도적인 성능을 제공하며, 핵심 LangSmith 경험을 이전보다 최대 12배 더 빠르게 만듭니다.
이식성 (Portability)
SmithDB는 오브젝트 스토리지 (Object Storage)를 기반으로 하기 때문에 관리해야 할 로컬 디스크가 없습니다. 쿼리 (Query) 및 인제스션 (Ingestion) 서비스는 상태가 없는 (Stateless) 구조입니다. 시스템은 컴퓨팅 자원을 추가함으로써 확장되며, 영구적인 데이터는 오브젝트 스토리지에 저장됩니다.
이러한 특성 덕분에 SmithDB는 로컬 디스크와 복잡한 샤딩 (Sharding)이 필요한 기존의 데이터베이스 클러스터보다 셀프 호스팅 (Self-hosted) 및 멀티 클라우드 (Multi-cloud) 환경에 배포하기가 훨씬 쉽습니다.
SmithDB가 이제 프로덕션 트래픽을 처리합니다
현재:
**미국 클라우드 인제스션 (US Cloud ingestion)의 100%**가 SmithDB로 전달됩니다.
**트레이싱 UI (Tracing UI) 쿼리 트래픽의 100%**가 스레드 (Threads)를 포함하여 SmithDB로 전달됩니다.
메타데이터 (Metadata), 피드백 (Feedback), 텍스트 검색 (Text search), 트리 필터 (Tree filters), 트레이스 필터 (Trace filters)를 포함한 모든 주요 필터가 SmithDB를 기반으로 작동합니다.
실행 규칙 (Run rules), 대량 내보내기 (Bulk export), 실험 (Experiments)과 같은 제품 통합 기능이 완료 단계에 있습니다.
곧:
- 모든 관련 제품 인터페이스가 SmithDB로 이식될 예정이며, LangSmith의 셀프 호스팅 배포 시 SmithDB를 사용할 수 있게 됩니다.
초기 피드백
지난 몇 달 동안 고객의 워크로드 (Workload)를 SmithDB로 마이그레이션해 왔습니다. Clay와 Vanta의 팀들이 경험하고 있는 내용은 다음과 같습니다:
우리는 매일 수억 개의 에이전트 관측 가능성 (Agent observability) 이벤트를 LangSmith에 기록합니다. SmithDB 덕분에 우리 팀은 프로덕션 환경에서 에이전트를 개선하는 데 필요한 속도로 해당 데이터를 검색, 디버깅 및 분석할 수 있게 되었습니다. 성능 향상은 즉각적으로 체감될 만큼 인상적이며, 특히 트레이스 탐색 (Trace exploration)이 병목 현상이었던 대규모 프로젝트에서 더욱 그러합니다.
— Jeff Barg, Clay의 AI 책임자
SmithDB로 전환한 이후, 성능 향상을 즉시 느낄 수 있었습니다. UX가 훨씬 더 빠릿빠릿해졌으며, 데이터를 파헤치는 과정이 그 어느 때보다 빠르고 직관적이 되었습니다. 정말 훌륭한 경험입니다.
— Andy Almonte, Vanta의 AI 시니어 엔지니어링 매니저
우리는 대규모 도구 호출 (tool calls)이 포함된 수많은 트레이스 (traces)를 보유하고 있는데, SmithDB로 마이그레이션한 이후 여러 프로젝트에 걸친 트레이스를 쿼리하고 읽는 작업이 훨씬 쉬워졌습니다. 이를 통해 엣지 케이스 (edge cases)를 정확히 찾아내고, 평가 데이터셋 (eval datasets)을 구축하며, 이전보다 훨씬 빠르게 트레이스를 반복 개선할 수 있었습니다.
— Kunal Rai, Unify의 AI 소프트웨어 엔지니어
Cogent의 경우, 우리의 백그라운드 에이전트 (background agents)가 한꺼번에 엄청난 양의 트레이스를 생성할 수 있습니다. 우리는 이러한 시스템에 대한 실시간 관측 가능성 (live observability)이 필요하며, SmithDB는 다른 제공업체들을 테스트할 때 경험했던 '분 단위'가 아닌 '초 단위'로 트레이스를 확인할 수 있는 경험을 제공해 주었습니다.
— Larsen Weigle, Cogent Security의 기술 스태프 (Member of Technical Staff)
주요 엔지니어링 과제
에이전트 관측 가능성 (agent observability) 워크로드를 위한 매우 높은 성능의 데이터베이스로 SmithDB를 만들기 위해 엄청난 양의 엔지니어링 노력이 투입되었습니다.
높은 수준에서 살펴보면, SmithDB는 객체 스토리지 (object-storage) 기반의 로그 구조 병합 트리 (LSM, Log-Structured Merge tree)로 구축되었습니다. LSM은 쓰기 작업을 메모리에 버퍼링하고, 이를 불변의 정렬된 배치 (immutable sorted batches) 형태로 영구 저장소에 플러시 (flush)하며, 주기적으로 해당 세그먼트 (segments)들을 함께 압축 (compact)합니다. 쿼리 시점에는 여러 세그먼트가 읽혀 하나의 정렬된 스트림 (ordered stream)으로 병합됩니다.
SmithDB는 다섯 가지 주요 구성 요소로 이루어져 있습니다:
Ingestion service (수집 서비스): 트레이스 (trace) 쓰기를 수락하고, 파티션(partition) 및 시간 버킷(time bucket)별로 배치(batch) 처리하여 불변 파일 (immutable files)로 기록합니다.
Metastore (메타스토어): 위치, 시간 범위, 행 수(row counts), 업데이트/삭제 벡터 (update/delete vectors)를 포함한 세그먼트 (segment) 메타데이터를 기록합니다.
Query service (쿼리 서비스): 쿼리 인터페이스를 제공하며, LangSmith 실행 의미론 (run semantics)과 오브젝트 스토리지 (object storage)를 이해하는 맞춤형 실행 계획 (execution plans)을 사용합니다. SSD 및 메모리 캐싱 (caching)을 적극적으로 활용합니다.
Compaction service (컴팩션 서비스): 삭제 적용, 업그레이드, TTL 만료 및 인덱스 병합 (index merging)을 수행하는 동시에, 쓰기 최적화된 세그먼트를 쿼리 최적화된 세그먼트로 다시 씁니다.
Cluster manager (클러스터 매니저): 라이브 서비스 노드를 키 범위 (key ranges)에 할당합니다. 이는 SmithDB가 단순히 부하를 분산하려는 것뿐만 아니라, 반복되는 쿼리가 적절한 데이터를 캐싱하고 있을 가능성이 높은 노드에 도달하도록 만들기 때문에 중요합니다.
다음은 몇 가지 주요 엔지니어링 과제에 대한 세부 사항이며, 향후 블로그 포스트에서 자세히 다룰 예정입니다:
오브젝트 스토리지 상에서의 점진적 쿼리 (Progressive querying)
많은 LangSmith 쿼리는 특정 테넌트 (tenant) 및 트레이싱 프로젝트 (tracing project)에 대한 최신 실행 (runs)을 요청합니다. 단순한 오브젝트 스토리지 계획은 모든 후보 파일을 찾아 다수를 열고, 데이터를 정렬 병합 (sort-merge) 및 중복 제거 (deduplicate)한 다음, 그제서야 제한 (limit)을 적용할 것입니다.
SmithDB는 시간을 역순으로 거슬러 올라가며 가장 최신 후보 세그먼트들에 대해 제한된 시간 창 (bounded time window)을 구축합니다. 이를 통해 "모든 것을 정렬한 후 제한"하는 방식에서 "가장 최신의 제한된 슬라이스 (slice)를 읽고, 스트리밍, 병합 및 행 중복 제거를 수행하며, 정확도가 허용하는 즉시 중단"하는 방식으로 전환하여, "Top K" 스타일의 쿼리를 수행하기 위해 스캔해야 하는 데이터를 크게 줄입니다.
수집 노드 (Ingestion nodes)로부터 최신 데이터 읽기
오브젝트 스토리지는 영구적인 신뢰할 수 있는 소스 (source of truth)이지만, 가장 최신의 데이터는 종종 이를 기록한 수집 노드에 여전히 존재합니다.
각 파일 세그먼트(segment)는 해당 파일을 생성한 노드의 서버 식별자(identifier)를 기록합니다. 만약 해당 작성자(writer)가 여전히 온라인 상태라면, 쿼리 플래너(query planner)는 객체 스토리지(object storage)에서 즉시 다시 읽어오는 대신, 수집 노드(ingestion node)의 로컬 SSD와 메모리 캐시(memory cache)에서 해당 파일들을 직접 스캔하는 커스텀 플랜(custom plan)을 사용할 수 있습니다. 이를 통해 최신 데이터를 다루는 쿼리(leading-edge queries)를 수행하기 위해 객체 스토리지로부터 수십 개의 작은 파일들을 읽어야 하는 상황을 방지할 수 있습니다.
실행당 다중 이벤트 (Multiple events per run)
에이전트 관측 가능성(Agent observability)은 장시간 실행되는 스팬(span)을 중심으로 구축됩니다.
전통적인 요청/응답(request/response) 애플리케이션에서 스팬은 밀리초(milliseconds) 내에 시작되고 종료될 수 있습니다. 하지만 에이전트 스팬은 훨씬 더 오래 열려 있을 수 있습니다. 단일 실행(run)에는 모델 완성(model completion), 도구 호출(tool calls), 재시도(retries), 백그라운드 작업(background work) 또는 다른 에이전트로의 핸드오프(handoffs)가 포함될 수 있습니다. 스팬이 종료될 때까지 기다렸다가 데이터를 기록하는 것은 이상적이지 않습니다.
SmithDB에서 실행(run)은 단일 불변 행(immutable row)이 아니라 이벤트(event)의 시퀀스(sequence)입니다. 이는 단순해 보이지만 쿼리 엔진(query engine) 전체에 영향을 미칩니다. 특정 이벤트를 타겟팅하기 위해 필터(filter)를 팬아웃(fanout)하고, 쿼리 시점에 이벤트를 효율적인 방식으로 병합(merge)하기 위해 각별한 주의를 기울입니다. 이러한 실행당 다중 이벤트를 처리하는 방식은 우리의 컴팩션(compaction) 전략에도 영향을 미칩니다.
시간 계층형 컴팩션 (Time-tiered compaction)
수집(Ingestion)은 쓰기 지연 시간(write latency)을 최적화하며, 이 과정에서 많은 작은 불변 세그먼트(immutable segments)가 생성됩니다. 이러한 세그먼트들을 영구적으로 쿼리하는 것은 너무 많은 파일 열기 오버헤드(file-open overhead)와 중복 제거(deduplication) 작업을 발생시킵니다.
컴팩션은 쓰기 최적화된 세그먼트를 쿼리 최적화된 세그먼트로 변환합니다. SmithDB는 시간 계층형(time-tiered) 전략을 사용합니다. 시간 계층화(Time-tiering)는 SmithDB가 이 작업을 얼마나 공격적으로 수행할지를 결정합니다. 최근 데이터는 종료 이벤트(end events)를 받을 가능성이 더 높으므로, 이를 너무 일찍 거대한 파일로 컴팩션하면 불필요한 쓰기 증폭(write amplification)이 발생할 수 있습니다. 반면 오래된 데이터는 더 안정적이고 반복적으로 스캔될 가능성이 높으므로, 더 큰 파일로 병합할 가치가 있습니다.
이를 통해 수집 속도를 빠르게 유지하면서도, 오래된 데이터의 쿼리 비용을 점진적으로 낮출 수 있습니다.
삭제, TTL 및 보존 정책 변경 (Deletes, TTL, and Retention changes)
삭제(deletes) 및 업그레이드(upgrades)와 같은 변이(mutations)는 데이터 파일이 불변(immutable)이기 때문에 관측 가능성(observability) 시스템에서 구현하기 어려운 경우가 많습니다. 기본적으로 SmithDB는 모든 삭제 작업에 대해 데이터 파일을 동기적으로 다시 쓰지 않습니다. 대신, 메타스토어(metastore)가 세그먼트 엔트리(segment entries)에 삭제 및 업그레이드 벡터(deletion and upgrade vectors)를 부착합니다. 쿼리(query) 및 컴팩션(compaction) 경로는 이러한 벡터를 사용하여 불변 파일을 올바르게 해석합니다. 파일 재작성은 컴팩션 과정 중에 발생합니다.
이러한 전략은 SmithDB에서 변이(mutations)의 확장성(scalability)을 매우 높여줍니다. 이는 특히 에이전트 관측 가능성(agent observability)에서 중요한데, 보존(retention) 기간이 균일한 경우가 거의 없기 때문입니다. 대부분의 트레이스(traces)는 최근의 디버깅, 모니터링 및 평가에는 유용하지만, 특정 트레이스의 내용에 따라 아주 적은 일부 하위 집합만이 장기간 보존될 필요가 있습니다.
대형 필드의 지연 실체화 (Late materialization of large fields)
에이전트 트레이스(agent traces)에는 종종 크기가 제한되지 않은 대형 페이로드(payloads)가 포함됩니다. SmithDB는 핵심 실행 필드(core run fields)를 대형 필드(large fields)와 분리함으로써 일반적인 리스트 및 필터 쿼리(list and filter queries)를 빠르게 유지합니다. 핵심 행(core rows)은 대형 필드 파일에 대한 포인터(pointers)를 보유하며, 쿼리 엔진(query engine)은 쿼리가 실제로 해당 필드들을 투영(projects)할 때만 해당 대형 페이로드를 가져옵니다.
이는 사용자가 실제로 실행(run)을 열거나 해당 필드를 요청하지 않는 한, 실행 목록(run list)을 로드하거나 필터를 적용할 때 수 메가바이트(MB)의 JSON을 읽을 필요가 없음을 의미합니다.
전체 텍스트 검색 및 JSON 필터링 (Full-Text Search and JSON Filtering)
1MB 이상의 페이로드에 대해 1초 미만의 전체 텍스트 검색(full-text search)과 JSON 키 경로(key-path) 필터링을 지원하는 것은 도전적인 엔지니어링 문제입니다.
SmithDB는 객체 스토리지(object storage)에 최적화된 맞춤형 역색인 레이아웃(inverted index layout)을 통해 이러한 쿼리를 효율적으로 처리합니다. 로컬 디스크(local disk)에서는 인덱스가 저렴한 탐색(seeks)과 많은 작은 읽기(small reads)에 의존할 수 있습니다. 하지만 객체 스토리지에서는 그러한 패턴이 무너집니다. 불필요한 요청이 발생할 때마다 지연 시간(latency)이 추가되며, 너무 일찍 대규모 포스팅(postings) 또는 위치 목록(positions lists)을 가져오는 것이 쿼리 성능을 저하시킬 수 있기 때문입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 LangChain Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기