주요 컨텐츠로 이동
제품

Lakebase Postgres로 AI 에이전트 오케스트레이션 간소화하기

CLA가 장시간 실행되는 태스크, 관측 가능성 및 비용 귀속을 위해 Databricks 네이티브 솔루션을 구축한 방법

작성자: Li Yu, Michelle JanneyCoyle, Jon Cormack, Yarri Bryn, Alec Sorensen , Darshana Nair

  • Postgres 기반의 확장 가능한 태스크 큐: 두 개의 Lakebase 테이블을 브로커, 캐시 또는 스케줄러 없이도 장시간 실행되는 에이전트 태스크를 위한 내구성이 뛰어나고 동시성이 보장되며 장애 복구 능력을 갖춘 큐로 전환하는 패턴에 대해 심층 분석합니다.
  • 완전한 Databricks 네이티브 아키텍처: Lakebase, Databricks Apps, Lakeflow Jobs, MLflow 및 Unity Catalog Volumes를 외부 인프라 운영 없이 에이전트 기반 문서 파싱을 위한 엔드투엔드 파이프라인으로 결합하는 참조 설계입니다.
  • 실시간 관측 가능성 및 불변성: Postgres LISTEN/NOTIFY 트리거와 SSE(Server-Sent Events)를 결합하여 오버헤드 없이 비용과 태스크를 자동으로 추적하는 저지연 운영자 대시보드를 구축하는 방법을 심층 분석합니다.

소개

전통적으로 감사는 상세한 문서 검토와 정보 추출이 필요한 지루하고 까다로운 프로세스입니다. 이 프로세스를 가속화하기 위해, 글로벌 입지를 넓혀가고 있는 선도적인 전문 서비스 기업인 CLA(CliftonLarsonAllen LLP)는 Databricks Forward Deployed Engineering 팀과 협력하여 에이전트 기반(agentic) 감사 솔루션을 구축하고 프로덕션에 도입했습니다. 양사는 공동으로 품질 저하 없이 추출 시간을 몇 시간에서 몇 분으로 단축하는 문서 처리 애플리케이션을 개발했습니다. 이 애플리케이션은 Lakebase Postgres, Databricks Apps, Lakeflow Jobs, MLflowUnity Catalog Volumes를 사용하여 전적으로 Databricks 상에 구축되었습니다. 이 블로그에서는 해당 시스템의 핵심 구성 요소 중 하나인 Lakebase 기반 오케스트레이션 레이어에 초점을 맞춥니다.

오케스트레이션 레이어는 장시간 실행되는 작업 조정, 재시도 관리, 비용 귀속, 실시간 가시성 제공을 담당합니다. Lakebase와 Databricks Apps를 통해 큐잉, 오케스트레이션 및 관찰 가능성(observability)을 위한 별도의 인프라를 구축할 필요가 없어졌습니다.

또한 Lakebase는 스토리지와 컴퓨팅을 분리함으로써 이 아키텍처를 대규모 환경에서도 실용적으로 만들어 줍니다. 기존의 Postgres 배포와 달리, 스토리지는 내구성과 독립성을 유지하면서 컴퓨팅은 수요에 따라 확장할 수 있습니다. 이러한 기능들이 결합되어 Lakebase는 Databricks에서 장시간 실행되는 에이전트 기반 워크로드를 위한 더 간단하고 확장 가능한 오케스트레이션 패턴의 실용적인 기반이 됩니다.

에이전트 기반 워크로드의 오케스트레이션 과제

문서 파싱은 매우 흔하고 대용량으로 처리되는 에이전트 기반 워크로드입니다. 다양한 산업 분야의 기업들은 방대한 양의 계약서, 인보이스, 재무 보고서 및 기타 문서를 구조화된 데이터로 변환해야 합니다. 이를 대규모로 실행하면 다음과 같은 다섯 가지 고유한 분산 시스템 문제가 발생합니다.

  • 작업별 예측 불가능한 지연 시간(latency): 2페이지짜리 인보이스는 몇 초 만에 처리될 수 있는 반면, 200페이지짜리 계약서는 몇 분이 걸릴 수 있어 개별 작업이 실행되는 데 걸리는 시간을 예측하기 어렵습니다.
  • 속도 제한(Rate-limit)을 고려한 스로틀링: LLM 및 비전 모델 엔드포인트는 특정 기간 동안 처리할 수 있는 요청 및 토큰 수를 제한합니다. 한 번에 수백 개의 작업을 보내면 이러한 제한을 초과하여 스로틀링이 발생하고 반복적인 재시도로 이어질 수 있습니다. 오케스트레이터는 사후 재시도에만 의존하기보다 진행 중인 작업(in-flight work)을 선제적으로 제한(동시 작업 수, 토큰 예산 또는 둘 다를 통해)해야 합니다.
  • 워크로드 우선순위 지정: 긴급한 제출 건이 대규모 배치 작업 뒤로 밀려 지연되어서는 안 됩니다. 작업별 우선순위를 지정하면 우선순위가 높은 작업(대화형 제출, 프리미엄 등급 요청, 운영자 시작 재처리)이 먼저 발송되도록 보장할 수 있습니다.
  • 작업별 비용 귀속: 재무 팀은 AI 토큰 사용량과 컴퓨팅 소비량별로 세분화하여 특정 작업, 고객 및 에이전트에 지출을 귀속시켜야 합니다.
  • 실시간 진행 상황 가시성: 수백 개의 문서를 업로드하는 사용자는 실시간 진행 상황 보기가 필요합니다.

많은 조직이 오케스트레이션과 관찰 가능성을 위해 여러 전문 시스템을 결합하여 사용합니다. 각 시스템은 자체 인프라, 인증, 모니터링 및 운영 요구사항과 함께 이를 통합하는 데 필요한 작업을 수반합니다. 장시간 실행되는 독립적인 에이전트 기반 작업의 경우, 이러한 오버헤드는 실제 스케줄링 복잡성에 비해 과도하게 큽니다.

저희가 개발한 Databricks 네이티브 솔루션은 Lakebase를 기반으로 위의 모든 요구사항을 충족합니다.

솔루션 아키텍처

솔루션 아키텍처

전체 애플리케이션 스택은 오직 Databricks 서비스로만 구성됩니다:

  • 웹 애플리케이션(Databricks Apps). 사용자가 PDF(Unity Catalog Volumes에 저장됨)를 업로드하고 파싱 요청을 제출하는 FastAPI 기반 사용자 인터페이스입니다. 요청은 Lakebase 작업 테이블에 직접 기록됩니다.
  • Lakebase. 관련 테이블 전반에서 오케스트레이터의 관계형 상태를 호스팅하는 자동 확장 Postgres 데이터베이스입니다. 테이블에는 tasks(상태, 임대 정보 및 구조화된 결과를 보관하는 파싱할 문서) 및 task_attempts(실행 시도당 하나의 행으로, Databricks Job 실행 ID, MLflow 추적 ID 및 시도별 비용 메타데이터를 캡처함)가 포함됩니다. Lakebase는 오케스트레이터 상태에 대한 단일 진실 공급원(single source of truth) 역할을 합니다.
  • 오케스트레이터(Databricks Apps). 장시간 실행되는 워커 데몬 및 운영자 대시보드입니다. 데몬은 Lakebase에서 작업을 가져와 AI 에이전트 레이어로 발송하고 결과를 다시 기록합니다. 대시보드는 동일한 테이블을 읽어 실시간 상태를 표시합니다.
  • AI 에이전트(Lakeflow Jobs). Lakeflow Jobs가 파싱 작업을 실행합니다. 각 Job은 Unity Catalog Volumes에서 PDF를 읽고, 지능형 문서 처리 및 비전/LLM 호출을 통해 이를 처리한 다음, 파싱된 출력을 Lakebase에 저장하고 웹훅을 통해 오케스트레이터에 수신을 확인합니다. MLflow Tracing은 모델 호출, 토큰 사용량, 지연 시간 및 비용 메타데이터와 같은 실행 세부 정보를 캡처합니다.

구성 요소 간의 데이터 흐름은 다음과 같습니다. 웹 앱은 Unity Catalog Volumes에 PDF를 쓰고 Lakebase에 파싱 요청을 기록합니다. 오케스트레이터는 Lakebase에서 작업을 가져와 Databricks Jobs를 AI 에이전트 레이어로 발송합니다. AI 에이전트는 문서를 처리하고 결과를 Lakebase에 다시 기록하며 상태 업데이트와 함께 오케스트레이터로 콜백합니다.

Databricks의 이러한 내장 기능 덕분에 외부 메시지 브로커(Kafka, Redis), 별도의 스케줄러(Airflow, Temporal) 또는 전용 캐싱 레이어에 의존할 필요가 없었습니다.

작업 대기열 구현

작업 대기열은 Lakebase의 두 Postgres 테이블을 기반으로 합니다. tasks 테이블은 논리적 작업 단위당 하나의 행을 보관하며 작업의 현재 상태, 임대 정보, 에이전트 할당, 상위 추출 및 최종 결과를 기록합니다. task_attempts 테이블은 실행 시도당 하나의 행을 보관하며 Databricks Job 실행 ID, MLflow 추적 ID 및 시도별 비용 메타데이터를 캡처합니다. 부모-자식 관계는 재시도를 지원하며(단일 작업에 여러 번의 시도가 있을 수 있음), 비용 귀속 및 디버깅을 위해 시도 수준의 관찰 가능성을 보존합니다.

두 개의 Postgres 테이블 자체만으로는 아직 작업 대기열이 아닙니다. 네 가지 Postgres 네이티브 패턴을 통해 이를 장시간 실행되는 에이전트 기반 워크로드에 적합하고 강력하며 동시성이 높고 충돌 복원력이 있으며 속도 제한을 고려하는 대기열로 변환합니다.

동시성 및 우선순위를 고려한 대기열 해제(Dequeuing)

기본적인 대기열 해제(dequeue) 쿼리는 WHERE status = 'enqueued' and LIMIT batch_size를 사용하여 다음 사용 가능한 작업을 선택할 수 있습니다. 이 쿼리는 대기열에 추가된 작업을 올바르게 식별하지만, 여러 워커가 동시에 대기열에서 작업을 가져올 때는 충분하지 않습니다. 행 잠금(row locking)이 없으면 상태가 업데이트되기 전에 여러 워커가 동일한 작업을 선택할 수 있습니다.

FOR UPDATE SKIP LOCKED을 추가하면 디큐(dequeue) 작업을 동시성에 안전하게 만들 수 있습니다. 각 워커는 자신이 선택한 행을 잠그고, 다른 워커는 해당 행을 건너뛰고 다음 사용 가능한 작업으로 진행합니다. 또한, ORDER BY priority DESC, created_at 절을 사용하면 각 우선순위 수준 내에서 FIFO 순서를 유지하면서 우선순위가 더 높은 작업이 먼저 선택되도록 보장합니다.

동시성에 안전하고 우선순위가 안정적으로 유지되는 전체 문은 다음과 같습니다.

임대 기반 잠금을 통한 크래시 복구

워커는 VM 회수, 메모리 부족(OOM) 상황 또는 배포 이벤트로 인해 작업 중간에 종료될 수 있습니다. 종료된 작업이 계속 처리 중으로 표시되어 있으면 무기한 보류될 수 있습니다. 해결책은 디큐 시점에 만료 예정인 임대(lease)를 기록하는 것입니다.

주기적인 스위퍼(sweeper)가 lease_expires_at이 지난 모든 작업을 다시 큐에 넣습니다. 종료된 워커가 보유하고 있던 작업은 외부 조정 서비스 없이 몇 분 안에 자동으로 복구됩니다.

속도 제한을 고려한 스로틀링

LLM 및 비전 모델 엔드포인트는 일반적으로 초당 요청 수 제한과 분당 토큰 수(TPM) 제한이라는 두 가지 고유한 할당량을 적용합니다. 단일 스로틀링 전략으로 이 두 가지를 모두 해결하기는 어렵습니다. 오케스트레이터는 구성을 통해 에이전트별로 선택할 수 있는 세 가지 모드를 지원합니다.

동시성 제한. MAX_CONCURRENT_TASKS 매개변수는 오케스트레이터가 동시에 디스패치하는 작업 수를 제한합니다. 이 제한은 디큐 시점에 tasks 테이블에서 현재 PROCESSING 상태인 행의 수를 세어 적용됩니다.

카운트가 제한 이상이면 새로운 작업이 디큐되지 않습니다. 로컬 실행기(executor)의 큐 크기가 아닌 데이터베이스 행 수에 기준을 두고 확인하므로, 워커 재시작, 임대 복구, 다중 레플리카 배포 전반에서 제한을 정확하게 유지할 수 있습니다. 이 모드는 각 작업의 토큰 사용량이 거의 균일하고 초당 요청 수 제한이 있는 엔드포인트에 적합합니다.

토큰 예산. MAX_TPM 매개변수는 진행 중인(in-flight) 작업 전반의 예상 토큰 속도를 제한합니다. 오케스트레이터는 작업의 토큰 수를 추정하고, 모든 PROCESSING 상태 작업의 예상 토큰 속도를 합산합니다. 이 합계에 새 작업의 예상 토큰을 더한 값이 예산 범위 내에 있는 경우에만 새 작업이 디큐됩니다.

결합 제한. MAX_CONCURRENT_TASKSMAX_TPM이 모두 구성된 경우, 오케스트레이터는 더 엄격한 제약 조건을 적용합니다. 이 모드는 특정 상황에서는 동시성 제한을 받고(짧고 비용이 적게 드는 많은 작업), 다른 상황에서는 토큰 제한을 받는(분당 할당량을 초과하는 단일 초장문 문서) 워크로드를 처리합니다.

세 가지 모드 모두에서 스로틀링 결정은 FOR UPDATE SKIP LOCKED와 동일한 트랜잭션 내의 디큐 시점에 이루어집니다. 현재 할당량에 맞지 않는 작업은 큐에 그대로 유지되며 다음 디큐 주기에서 다시 고려됩니다. 별도의 스케줄링 상태나 인메모리 대기 큐, 워커 레플리카 간의 조정 레이어가 필요하지 않습니다.

멱등성 웹훅 콜백

AI 에이전트 레이어가 작업을 완료하면 결과와 함께 오케스트레이터에 콜백을 게시합니다. 콜백 전송은 정확히 한 번(exactly-once) 보장되지 않습니다. Databricks가 재시도할 수 있고, 네트워크가 중단될 수 있으며, 프록시가 다시 전송할 수도 있습니다. 콜백 처리기는 멱등성을 갖도록 설계되었습니다. PROCESSING 및 ENQUEUED 상태를 모두 수락하고, 이미 완료된 작업은 아무 작업도 수행하지 않는 것(no-op)으로 처리합니다. 동일한 페이로드는 동일한 결과를 생성하므로 이중 청구 또는 중복 처리의 위험이 제거됩니다.

이 네 가지 패턴이 결합되어 동시성 상황에서도 정확하고, 크래시에도 안전하며, 부하 상황에서 속도 제한을 고려하고, 재시도 시 멱등성을 유지하는 작업 큐가 생성됩니다. 실행 중인 시스템에 대한 실시간 가시성은 다음 섹션에서 설명하는 별도의 메커니즘을 통해 제공됩니다.

실시간 운영자 대시보드

많은 문서가 처리 중일 때, 운영자는 에이전트 성능, 작업 상태 및 워크로드 비용을 명확하게 볼 수 있어야 합니다. 오케스트레이터를 지속적으로 폴링하거나 별도의 메트릭 플랫폼에 의존할 필요가 없어야 합니다. 오케스트레이터는 워커 데몬을 실행하는 동일한 Databricks App에서 제공하는 단일 대시보드에 이 기능을 직접 통합합니다.

대시보드 기능

운영자용 대시보드는 실행 중인 시스템의 특징을 보여주는 일련의 운영 메트릭을 표시합니다. 모든 메트릭은 날짜 범위, 작업 상태 및 에이전트별 필터링을 지원합니다.

  • 상태별 총 작업 수. 상태 전환이 발생할 때 실시간으로 업데이트되는 각 상태(대기 중, 처리 중, 완료됨, 실패함, 취소됨)의 작업 수입니다.
  • 입력 및 출력 토큰. MLflow Traces에서 가져온 작업별 및 집계된 토큰 수입니다.
  • LLM 비용. MLflow Traces에서 모델이 내보낸 추정치(각 모델 호출 후 몇 초 이내에 사용 가능)입니다.
  • 컴퓨팅 비용. system.billing.usage에서 가져온 오케스트레이터의 작업 실행에 따른 Serverless Jobs 컴퓨팅 비용입니다.
  • 응답 시간 중앙값. 완료된 작업을 대상으로 계산됩니다. 재시도 백오프(retry-backoff) 이상치 및 포화 상태에서의 대기열 꼬리 지연(queueing-tail latency)으로 인한 왜곡을 방지하기 위해 평균 대신 중앙값을 사용합니다.
  • 신뢰도. AI 에이전트 레이어에서 반환되어 작업 결과와 함께 표시되는 문서별 신뢰도 점수입니다.

구현

tasks 테이블의 상태 변경은 Postgres LISTEN/NOTIFY 이벤트를 트리거합니다. 백엔드는 단일 LISTEN 연결을 유지하고 연결된 대시보드 클라이언트에 **Server-Sent Events (SSE)**를 통해 이벤트를 배포(fan out)합니다. 브라우저는 EventSource 연결을 열고 유의미한 상태 변경이 발생할 때마다 약 1초 이내에 실시간 업데이트를 받습니다. 이 구현에는 Redis, WebSocket 서버, 메시지 버스가 필요하지 않습니다.

폴링은 기본 10초 간격의 영구적인 폴백으로 유지됩니다. 클라우드 수신(ingress) 프록시를 통한 스트리밍 연결은 클라이언트 측 오류 이벤트를 발생시키지 않고 바이트를 누락할 수 있습니다. 영구적인 폴링은 이러한 경우에도 대시보드가 최신 상태를 유지하도록 보장합니다. UI 표시기를 통해 live(SSE 활성화됨) 채널과 polling(SSE 사용 불가) 채널을 구분할 수 있습니다.

대시보드의 데이터는 지연 시간 특성이 서로 다른 세 가지 소스에 걸쳐 있습니다. 즉, Postgres(즉시), MLflow의 trace API(1초 미만), 시스템 청구 테이블에 대한 웨어하우스 쿼리(가끔 수십 초 소요)입니다. 빠른 쿼리는 매 새로고침 주기마다 데이터를 공급하며, 느린 쿼리는 사용자 작업 시에만 실행되고 결과를 사용할 수 있을 때까지 로딩 상태와 함께 낙관적으로 반환됩니다.

애플리케이션별 비용 귀속

Databricks 시스템 청구 테이블은 계정 범위로 지정됩니다. 모든 작업(job), 모든 모델 호출 및 기타 모든 애플리케이션이 동일한 system.billing.usage 행에 기여합니다. 범위를 지정하지 않으면 애플리케이션 수준의 "OCR 비용" 타일이 워크스페이스의 모든 모델 호출에 대한 사용량을 집계하게 됩니다.

해결책은 오케스트레이터가 제출한 Databricks Job 실행을 기록하고(tasks.locked_bytask_attempts.run_id에서 추적됨), 청구 쿼리를 해당 세트로 필터링하는 것입니다. 단일 SQL 웨어하우스가 여러 애플리케이션을 지원할 수 있으며, 각 대시보드에는 자체 지출만 표시됩니다.

동일한 쿼리 아키텍처는 운영자 중심의 필터와 자연스럽게 결합됩니다. 비용 수치는 다른 모든 대시보드 메트릭과 마찬가지로 날짜 범위, 태스크 상태 또는 에이전트별로 세분화할 수 있어, 대시보드를 벗어나지 않고도 "지난 7일 동안 실패한 태스크의 비용은 얼마인가요?" 또는 "이번 달 에이전트 X의 태스크당 지출 중앙값은 얼마인가요?"와 같은 질문에 대한 답을 얻을 수 있습니다.

이를 통해 비용 수치를 쉽게 모니터링하고 할당하며 보고할 수 있습니다.

오케스트레이션의 중추로서의 Lakebase

Postgres-as-queue 패턴은 데이터 엔지니어링 커뮤니티에 잘 정착되어 있습니다. Lakebase는 이 패턴을 Databricks의 프로덕션 아키텍처로 실행 가능하게 만드는 추가적인 운영 특성을 제공합니다.

  • 컴퓨팅 자동 확장(Autoscaling). Lakebase는 워크로드에 따라 Postgres 컴퓨팅 단위를 확장 및 축소하므로, 오케스트레이터가 상시 최고 용량에 대한 비용을 지불하지 않고도 데이터베이스를 활용할 수 있습니다.
  • OAuth 순환 인증. Lakebase는 연결 인증을 위해 수명이 짧은 OAuth 토큰을 사용합니다. 연결 풀은 토큰을 자동으로 새로 고치므로 애플리케이션 구성에서 정적 자격 증명이 필요 없고 순환 런북을 제거할 수 있습니다.
  • Unity Catalog 통합. Lakebase는 Databricks의 나머지 부분과 ID, 권한 및 거버넌스를 공유합니다. 오케스트레이터의 서비스 주체(service principal)는 tasksresults 테이블에 대한 명시적 권한을 부여받으므로 별도의 IAM 구성이 필요하지 않습니다.
  • 브랜칭 및 스냅샷. 디버깅을 위해 프로덕션 태스크 테이블을 개발 환경으로 복제하는 것은 기본적으로 지원되는 표준 Lakebase 작업입니다.

이러한 기능은 팀이 태스크 대기열 관리를 위해 자체 호스팅 Postgres 대신 관리형 메시지 브로커를 도입하도록 만드는 일반적인 운영상의 번거로움을 제거합니다.

영향 및 결론

CLA에서는 여기에 설명된 오케스트레이션 패턴을 통해 문서 처리 프로덕션 워크플로를 지원하여 추출 시간을 몇 시간에서 몇 분으로 단축합니다. 이 아키텍처는 외부 시스템 없이도 대기열 관리, 스케줄링 및 관찰 가능성(observability)을 관리하기 위해 Lakebase Postgres를 중심으로 Databricks 네이티브 서비스를 사용합니다. 이를 통해 통합 오버헤드를 줄이는 동시에 확장 가능하도록 구축된 통합 플랫폼의 장점을 최대한 활용할 수 있습니다.

프로덕션 환경에서 이 패턴은 내구성 있는 태스크 관리, 우선순위 제어, 속도 제한을 고려한 스케줄링, 실시간 가시성 및 태스크별 비용 추적을 제공합니다. 이러한 기능들은 주변 인프라를 단순하게 유지하면서 에이전트 기반(agentic) 워크로드를 오케스트레이션하는 실용적인 방법을 제공합니다.

단일 플랫폼에서 AI 에이전트 오케스트레이션을 간소화할 준비가 되셨나요? Databricks Free Edition을 체험해 보고, 첫 번째 Lakebase Postgres 프로젝트와 Databricks App을 생성한 다음, MLflow Tracing 10분 데모를 따라 에이전트 워크플로에 엔드투엔드 관찰 가능성을 추가해 보세요.

(이 글은 AI의 도움을 받아 번역되었습니다. 원문이 궁금하시다면 여기를 클릭해 주세요)

최신 게시물을 이메일로 받아보세요

블로그를 구독하고 최신 게시물을 이메일로 받아보세요.