원문: Simplify AI agent orchestration with Lakebase Postgres 저자: Li Yu, Michelle Janney Coyle, Jon Cormack, Yarri Bryn, Alec Sorensen, Darshana Nair 게시일: 2026년 7월 22일
요약
- Postgres 위의 확장 가능한 태스크 큐(Scale-Ready Task Queue): Lakebase 테이블 한 쌍을 장시간 실행되는 에이전트 태스크를 위한 내구성 있고, 동시성에 안전하며, 크래시에 강인한 큐로 바꾸는 패턴을 깊이 있게 다룹니다 — 브로커, 캐시, 스케줄러 없이.
- 완전한 Databricks 네이티브 아키텍처: Lakebase, Databricks Apps, Lakeflow Jobs, MLflow, Unity Catalog Volumes를 엮어 에이전트 기반 문서 파싱을 위한 엔드투엔드 파이프라인을 만드는 레퍼런스 설계로, 운영해야 할 외부 인프라가 없습니다.
- 실시간 관측 가능성과 불변식(Invariants): Postgres
LISTEN/NOTIFY트리거와 Server-Sent Events(SSE)를 결합해, 비용과 태스크를 자동으로 추적하는 저지연 오퍼레이터 대시보드를 오버헤드 없이 구축하는 방법을 깊이 있게 다룹니다.
서론
전통적으로 감사(auditing)는 상세한 문서 검토와 정보 추출을 요구하는 지루한 과정입니다. 이 과정을 가속하기 위해, 성장하는 글로벌 입지를 가진 선도적 전문 서비스 기업 CLA(CliftonLarsonAllen LLP)는 Databricks Forward Deployed Engineering 팀과 협력하여 에이전트 기반 감사 솔루션을 구축하고 프로덕션화했습니다. 우리는 함께 품질 저하 없이 추출 시간을 몇 시간에서 몇 분으로 줄이는 문서 처리 애플리케이션을 개발했습니다. 이 애플리케이션은 전적으로 Databricks 위에 구축되었으며, Lakebase Postgres, Databricks Apps, Lakeflow Jobs, MLflow, Unity Catalog Volumes를 사용합니다. 이 블로그에서는 그 시스템의 한 핵심 구성 요소인 Lakebase 기반 오케스트레이션 계층에 초점을 맞춥니다. 오케스트레이션 계층은 장시간 실행되는 태스크를 조율하고, 재시도를 관리하며, 비용을 귀속시키고, 실시간 가시성을 제공하는 역할을 합니다. Lakebase와 Databricks Apps를 통해 우리는 큐잉, 오케스트레이션, 관측 가능성을 위한 별도 인프라의 필요성을 없앱니다. Lakebase는 또한 스토리지와 컴퓨트를 분리함으로써 이 아키텍처를 대규모에서도 실용적으로 만듭니다. 전통적인 Postgres 배포와 달리, 컴퓨트는 수요에 따라 확장될 수 있는 반면 스토리지는 내구성 있고 독립적으로 유지됩니다. 이러한 역량이 함께 어우러져 Lakebase는 Databricks 위의 장시간 실행 에이전트 워크로드를 위한, 더 단순하고 확장 가능한 오케스트레이션 패턴의 실용적 토대가 됩니다.에이전트 워크로드의 오케스트레이션 과제
문서 파싱은 매우 흔하고 대용량인 에이전트 워크로드입니다. 여러 산업의 기업들은 대량의 계약서, 인보이스, 재무 신고서 및 기타 문서를 구조화된 데이터로 변환해야 합니다. 이를 대규모로 실행하면 다섯 가지 뚜렷한 분산 시스템 문제가 드러납니다.- 예측 불가능한 태스크별 지연 시간: 두 페이지짜리 인보이스는 몇 초 만에 처리될 수 있지만, 200페이지짜리 계약서는 몇 분이 걸릴 수 있어 개별 태스크가 얼마나 오래 실행될지 예측하기 어렵습니다.
- 레이트 리밋을 고려한 스로틀링: LLM 및 비전 모델 엔드포인트는 주어진 기간 동안 처리할 수 있는 요청 수와 토큰 수를 제한합니다. 한 번에 수백 개의 태스크를 보내면 그 한도를 초과하여 스로틀링을 유발하고 반복적인 재시도로 이어질 수 있습니다. 오케스트레이터는 반응적 재시도에만 의존하는 대신, (동시 태스크 수, 토큰 예산, 또는 둘 다로) 진행 중인 작업량을 선제적으로 제한해야 합니다.
- 워크로드 우선순위 지정: 긴급 제출 건이 대량 배치 뒤에 밀려 지연되어서는 안 됩니다. 태스크별 우선순위는 더 높은 우선순위의 작업(인터랙티브 제출, 프리미엄 등급 요청, 오퍼레이터가 시작한 재처리)이 먼저 디스패치되도록 보장합니다.
- 태스크별 비용 귀속: 재무 팀은 지출을 특정 태스크, 고객, 에이전트에 귀속시키고, AI 토큰 사용량과 컴퓨트 소비로 나누어 파악해야 합니다.
- 실시간 진행 상황 가시성: 수백 개의 문서를 업로드하는 사용자는 실시간 진행 상황 뷰를 필요로 합니다.
솔루션 아키텍처
전체 애플리케이션 스택은 전적으로 Databricks 서비스로 구성됩니다.
- 웹 애플리케이션 (Databricks Apps): 사용자가 PDF를 업로드하고(Unity Catalog Volumes에 저장됨) 파싱 요청을 제출하는 FastAPI 기반 사용자 인터페이스입니다. 요청은 Lakebase의
task테이블에 직접 기록됩니다. - Lakebase: 오케스트레이터의 관계형 상태를 관련 테이블에 걸쳐 호스팅하는 오토스케일링 Postgres 데이터베이스입니다.
tasks(파싱할 문서로, 상태·리스 정보·구조화된 결과를 보관),task_attempts(실행 시도당 한 행으로, Databricks Job 실행 ID·MLflow 트레이스 ID·시도별 비용 메타데이터를 캡처)로 구성됩니다. Lakebase는 오케스트레이터 상태에 대한 단일 진실 공급원(single source of truth) 역할을 합니다. - 오케스트레이터 (Databricks Apps): 장시간 실행되는 워커 데몬이자 오퍼레이터 대시보드입니다. 데몬은 Lakebase에서 태스크를 디큐(dequeue)하여 AI Agents 계층으로 디스패치하고, 결과를 다시 기록합니다. 대시보드는 동일한 테이블을 읽어 실시간 상태를 표시합니다.
- AI Agents (Lakeflow Jobs): Lakeflow Jobs가 파싱 작업을 실행합니다. 각 Job은 Unity Catalog Volumes에서 PDF를 읽고, Intelligent Document Processing 및 비전/LLM 호출을 통해 이를 처리하며, 파싱된 출력을 Lakebase에 저장하고, 웹훅을 통해 오케스트레이터에게 확인을 보냅니다. MLflow Tracing이 모델 호출, 토큰 사용량, 지연 시간, 비용 메타데이터 같은 실행 세부사항을 캡처합니다.
태스크 큐 구현
태스크 큐는 Lakebase 내 두 개의 Postgres 테이블로 뒷받침됩니다.tasks 테이블은 논리적 작업 단위당 한 행을 보관하며, 태스크의 현재 상태, 리스 정보, 에이전트 할당, 상위 추출(parent extraction), 최종 결과를 기록합니다. task_attempts 테이블은 실행 시도당 한 행을 보관하며, Databricks Job 실행 ID, MLflow 트레이스 ID, 시도별 비용 메타데이터를 캡처합니다. 부모-자식 관계는 재시도를 지원하고(하나의 태스크가 여러 시도를 가질 수 있음) 비용 귀속과 디버깅을 위한 시도 수준의 관측 가능성을 보존합니다.
Postgres 테이블 한 쌍 그 자체만으로는 아직 태스크 큐가 아닙니다. 네 가지 Postgres 네이티브 패턴이 이들을 장시간 실행 에이전트 워크로드에 적합한, 견고하고 동시성에 안전하며 크래시에 강인하고 레이트 리밋을 고려하는 큐로 변모시킵니다.
동시성·우선순위를 고려한 디큐잉
기본적인 디큐 쿼리는WHERE status = 'enqueued'와 LIMIT batch_size를 사용해 다음으로 사용 가능한 태스크를 선택할 수 있습니다. 이 쿼리는 인큐된 태스크를 올바르게 식별하지만, 여러 워커가 동시에 디큐할 때는 충분하지 않습니다. 행 잠금(row locking)이 없으면 상태가 갱신되기 전에 여러 워커가 같은 태스크를 선택할 수 있습니다.
FOR UPDATE SKIP LOCKED를 추가하면 디큐가 동시성에 안전해집니다. 각 워커는 자신이 선택한 행을 잠그고, 다른 워커는 그 행을 건너뛰어 다음으로 사용 가능한 태스크로 계속 진행합니다. 여기에 ORDER BY priority DESC, created_at 절을 더하면, 각 우선순위 수준 내에서 FIFO 순서를 보존하면서도 우선순위가 높은 태스크가 먼저 선택되도록 보장합니다.
동시성에 안전하고 우선순위가 안정적인 완전한 구문은 다음과 같습니다.
리스 기반 잠금을 통한 크래시 복구
워커는 VM 축출(eviction), 메모리 부족(out-of-memory) 상황, 배포 이벤트로 인해 태스크 도중에 종료될 수 있습니다. 종료된 태스크가processing으로 표시된 채 남아 있으면 무기한 점유될 수 있습니다. 해결책은 디큐 시점에 만료되는 리스(expiring lease)를 기록하는 것입니다.
lease_expires_at이 지난 모든 태스크를 다시 인큐합니다. 종료된 워커가 점유하던 태스크는 외부 조정 서비스 없이도 몇 분 안에 자동으로 복구됩니다.
레이트 리밋을 고려한 스로틀링
LLM 및 비전 모델 엔드포인트는 일반적으로 두 가지 뚜렷한 쿼터를 적용합니다. 초당 요청 수(request-per-second) 상한과 분당 토큰 수(tokens-per-minute, TPM) 상한입니다. 하나의 스로틀링 전략이 둘 모두에 딱 맞는 경우는 드뭅니다. 오케스트레이터는 에이전트별 구성으로 선택되는 세 가지 모드를 지원합니다. 동시성 상한(Concurrency cap).MAX_CONCURRENT_TASKS 파라미터는 오케스트레이터가 동시에 디스패치하는 태스크 수를 제한합니다. 이 상한은 디큐 시점에 tasks 테이블의 현재 PROCESSING 행 수를 세어 적용됩니다.
MAX_TPM 파라미터는 진행 중인 태스크들에 걸친 예상 토큰 비율(token rate)을 제한합니다. 오케스트레이터는 태스크의 토큰 수를 추정하고, 모든 PROCESSING 태스크에 걸친 예상 토큰 비율을 합산합니다. 그 합계에 새 태스크의 예상 토큰을 더한 값이 예산 안에 들어올 때만 새 태스크가 디큐됩니다.
결합 상한(Combined cap). MAX_CONCURRENT_TASKS와 MAX_TPM이 모두 구성된 경우, 오케스트레이터는 더 빡빡한 제약을 적용합니다. 이 모드는 한 상황에서는 동시성에 묶이고(짧고 저렴한 태스크가 많은 경우) 다른 상황에서는 토큰에 묶이는(하나의 매우 긴 문서가 분당 쿼터를 포화시키는 경우) 워크로드를 처리합니다.
세 모드 모두에서 스로틀링 결정은 FOR UPDATE SKIP LOCKED와 동일한 트랜잭션 안에서, 디큐 시점에 이루어집니다. 현재 쿼터 안에 들어올 수 없는 태스크는 큐에 남아 다음 디큐 주기에 다시 고려됩니다 — 별도의 스케줄링 상태도, 인메모리 대기 큐도, 워커 레플리카 간 조정 계층도 없습니다.
멱등적 웹훅 콜백
AI Agents 계층이 태스크를 완료하면 결과와 함께 오케스트레이터로 콜백을 보냅니다. 콜백 전달은 정확히 한 번(exactly-once)이 아닙니다. Databricks가 재시도할 수 있고, 네트워크가 중단될 수 있으며, 프록시가 재전송할 수 있습니다. 콜백 핸들러는 멱등적(idempotent)으로 설계되어,PROCESSING과 ENQUEUED 상태를 모두 받아들이고 이미 종료 상태(terminal)인 태스크는 무동작(no-op)으로 처리합니다. 동일한 페이로드는 동일한 결과를 만들어내며, 이중 과금이나 중복 처리의 위험을 없앱니다.
이 네 가지 패턴이 결합되어, 동시성 하에서 정확하고, 크래시 하에서 내구성 있으며, 부하 하에서 레이트 리밋을 고려하고, 재시도 하에서 멱등적인 태스크 큐를 만들어냅니다. 실행 중인 시스템에 대한 실시간 가시성은 다음 섹션에서 설명하는 별도의 메커니즘으로 제공됩니다.
실시간 오퍼레이터 대시보드
많은 문서가 진행 중일 때, 오퍼레이터는 에이전트 성능, 태스크 상태, 워크로드 비용에 대한 명확한 뷰를 필요로 합니다. 그들은 오케스트레이터를 계속 폴링하거나 별도의 메트릭 플랫폼에 의존해서는 안 됩니다. 오케스트레이터는 이 기능을 워커 데몬을 실행하는 동일한 Databricks App이 표시하는 단일 대시보드에 직접 통합합니다.대시보드 기능
오퍼레이터를 향한 대시보드는 실행 중인 시스템을 함께 특징짓는 일련의 운영 메트릭을 표시합니다. 모든 메트릭은 날짜 범위, 태스크 상태, 에이전트로 필터링할 수 있습니다.- 상태별 태스크 총계. 각 상태(enqueued, processing, completed, failed, cancelled)의 태스크 수로, 상태 전이가 발생할 때 실시간으로 갱신됩니다.
- 입력 및 출력 토큰. MLflow Traces에서 가져온 태스크별 및 집계 토큰 수입니다.
- LLM 비용. MLflow Traces에서 나온 모델 방출 추정치(model-emitted estimate)로, 각 모델 호출 후 몇 초 내에 사용 가능합니다.
- 컴퓨트 비용.
system.billing.usage에서 가져온, 오케스트레이터의 태스크 실행에 귀속되는 Serverless Jobs 컴퓨트 비용입니다. - 중앙값 응답 시간. 완료된 태스크에 걸쳐 계산됩니다. 재시도-백오프 이상값과 포화 상태의 큐잉-테일 지연에 의한 왜곡을 피하기 위해 평균 대신 중앙값을 사용합니다.
- 신뢰도(Confidence). AI Agents 계층이 반환한 문서별 신뢰도 점수로, 태스크 결과와 함께 표시됩니다.
구현
tasks 테이블의 상태 변경은 Postgres LISTEN/NOTIFY 이벤트를 발생시킵니다. 백엔드는 단일 LISTEN 연결을 유지하고, 이벤트를 Server-Sent Events(SSE)를 통해 연결된 대시보드 클라이언트로 팬아웃(fan out)합니다. 브라우저는 EventSource 연결을 열고, 의미 있는 상태 변경이 있을 때마다 약 1초 이내에 실시간 업데이트를 받습니다. 이 구현에는 Redis도, WebSocket 서버도, 메시지 버스도 필요하지 않습니다.
폴링은 기본 10초 간격으로 영구적인 폴백(fallback)으로 유지됩니다. 클라우드 인그레스 프록시를 통과하는 스트리밍 연결은 클라이언트 측 오류 이벤트를 발생시키지 않고 조용히 바이트를 누락시킬 수 있으므로, 영구 폴링은 그런 경우에도 대시보드가 최신 상태를 유지하도록 보장합니다. UI 표시기는 실시간(SSE 활성) 채널과 폴링(SSE 불가) 채널을 구분합니다.
대시보드의 데이터는 지연 특성이 서로 다른 세 가지 소스에 걸쳐 있습니다. Postgres(즉각적), MLflow의 트레이스 API(1초 미만), 시스템 빌링 테이블에 대한 웨어하우스 쿼리(때로 수십 초)입니다. 빠른 쿼리는 모든 새로고침 주기에 반영되고, 느린 쿼리는 사용자 액션이 있을 때만 실행되며 결과가 준비될 때까지 로딩 상태로 낙관적으로(optimistically) 반환됩니다.
애플리케이션별 비용 귀속
Databricks 시스템 빌링 테이블은 계정 범위(account-scoped)입니다. 모든 잡, 모든 모델 호출, 그리고 다른 모든 애플리케이션이 동일한system.billing.usage 행에 기여합니다. 범위를 지정하지 않으면 애플리케이션 수준의 “OCR 비용” 타일이 워크스페이스 내 모든 모델 호출의 사용량을 합산하게 됩니다.
해결책은 오케스트레이터가 제출한 Databricks Job 실행을 기록하고(tasks.locked_by와 task_attempts.run_id에 추적됨) 빌링 쿼리를 그 집합으로 필터링하는 것입니다. 하나의 SQL 웨어하우스가 여러 애플리케이션을 뒷받침할 수 있으며, 각 대시보드는 자신의 지출만 표시합니다.
동일한 쿼리 아키텍처는 오퍼레이터가 지정하는 필터와 자연스럽게 조합됩니다. 비용 수치는 다른 모든 대시보드 메트릭과 마찬가지로 날짜 범위, 태스크 상태, 에이전트로 더 좁힐 수 있어, 대시보드를 벗어나지 않고도 “지난 7일간 실패한 태스크에 든 비용은 얼마인가?” 또는 “이번 달 에이전트 X의 태스크당 중앙값 지출은 얼마인가?” 같은 질문에 답할 수 있습니다.
이는 비용 수치를 모니터링하고, 배분하고, 보고하기 쉽게 만듭니다.
오케스트레이션의 중추(Backbone)로서의 Lakebase
Postgres를 큐로 활용하는 패턴은 데이터 엔지니어링 커뮤니티에서 잘 확립되어 있습니다. Lakebase는 이 패턴을 Databricks 위의 프로덕션 아키텍처로 실현 가능하게 하는 추가적인 운영 특성을 제공합니다.- 오토스케일링 컴퓨트. Lakebase는 워크로드에 맞춰 Postgres 컴퓨트 유닛을 위아래로 확장하여, 오케스트레이터가 최대 용량을 24시간 내내 지불하지 않고도 데이터베이스에 의존할 수 있게 합니다.
- OAuth 로테이션 인증. Lakebase는 연결 인증에 수명이 짧은 OAuth 토큰을 사용합니다. 커넥션 풀이 토큰을 자동으로 갱신하여, 애플리케이션 구성에서 정적 자격 증명을 없애고 로테이션 런북(runbook)을 제거합니다.
- Unity Catalog 통합. Lakebase는 Databricks의 나머지 부분과 아이덴티티, 권한, 거버넌스를 공유합니다. 오케스트레이터의 서비스 프린시펄(service principal)은
tasks와results테이블에 대한 명시적 권한을 부여받으며, 별도의 IAM 구성이 필요하지 않습니다. - 브랜칭 및 스냅샷. 프로덕션 태스크 테이블을 디버깅을 위해 개발 환경으로 복제하는 것은 표준 Lakebase 작업이며, 네이티브로 지원됩니다.