스크립트가 아닌 프롬프트로 내 아침의 25분을 자동화하기
요약
현대적인 관측성 스택과 API를 지원하지 않는 레거시 도구 사이의 데이터 간극을 LLM 에이전트를 활용해 자동화한 사례를 다룹니다. 작성자는 매일 아침 수동으로 처리하던 이메일, HTML 테이블, Jira 등의 비정형 데이터를 에이전트가 통합 계층 역할을 수행하도록 설계하여 업무를 자동화했습니다.
핵심 포인트
- 현대적 모니터링 스택과 레거시 도구 사이에는 API가 없는 '관측성 이음새(Observability seam)'가 존재함
- 레거시 통합 문제는 기술적 결함보다는 우선순위 밀림으로 인한 아키텍처 설계의 공백 문제임
- LLM 에이전트를 단순 생산성 도구가 아닌, 비정형 데이터를 정형화하는 '통합 계층(Integration Layer)'으로 활용 가능함
- 이메일, HTML 테이블, Confluence 페이지 등 API가 없는 소스도 에이전트를 통해 신호 추출 및 자동화가 가능함
내가 일했던 모든 진지한 엔지니어링 조직은 동일한 이중성을 가지고 있었다. 한쪽에는 현대적인 관측성 스택 (Observability stack)이 있다. AppDynamics, Datadog, 혹은 현재 가장 선호되는 것이 무엇이든 간에 말이다. 실시간 메트릭 (Real-time metrics), 분산 트레이스 (Distributed traces), 아름다운 대시보드, 알림 라우팅 (Alert routing)까지. 수년간의 투자가 이루어졌고, 제대로 작동한다. 다른 한쪽에는 현재 스택보다 10년 앞선 레거시 모니터링 도구 (Legacy monitoring tools)들이 길게 늘어져 있다. OpenTelemetry를 지원하지 않는 도구들, 웹훅 (Webhook)으로 데이터를 보낼 수 없는 도구들, 그리고 출력 형식이 매일 아침 UTC 기준 11:15에 이메일로 발송되는 73행짜리 HTML 테이블로 고정되어 버린 도구들 말이다. 이 두 영역은 서로 소통하지 않는다. 그리고 대부분의 조직에서 누군가는 매일 아침 25~30분 동안 수동으로 그 간극을 메운다. 그 누군가가 바로 나였다.
아무도 아키텍처 다이어그램에 그리지 않는 간극
모든 엔터프라이즈 아키텍처 다이어그램에 존재해야 하지만 결코 그려지지 않는 상자가 있다: "Dave가 25분 동안 이메일을 읽는다" 이것이 내가 관측성 이음새 (Observability seam)라고 부르는 것, 즉 현대적인 모니터링 스택과 그것이 수용할 수 없는 레거시 출력물 사이의 경계다. 이러한 이음새가 존재하는 이유는 다음과 같다:
- 레거시 도구들이 현대적인 관측성 컨벤션 (Observability conventions)이 생기기 전에 구축되었기 때문
- 통합 작업 (Integration work)은 기능 개발 작업 (Feature work)보다 영구적으로 우선순위가 낮기 때문
- 비용이 집중되지 않고 여러 사람의 아침 시간에 분산되어 있어, 결코 "해결해야 할" 우선순위에 도달하지 않기 때문
내가 계속해서 깨닫게 된 통찰은 이것이 기술적인 문제가 아니라는 점이다. 이것은 아무도 그려 넣지 않은 아키텍처의 표면적 (Architectural surface area) 문제다. 일단 그렇게 바라보기 시작하면, 해결책은 다룰 수 있는 수준이 된다.
레거시 꼬리 부분이 실제로 어떻게 생겼었나
나의 구체적인 환경에는 네 가지 데이터 소스가 있었는데, 그 중 어느 것도 관측성 스택으로 유입되지 않았다:
| 소스 | 형식 | 빈도 | 복제 지연 알림 (Replication latency alerts) |
|---|---|---|---|
| 이메일 (본문 텍스트) | 이메일 (본문 텍스트) | 하루에 여러 번 | |
| DB 백업 상태 보고서 | 이메일 (73행 HTML 테이블) | 매일 UTC 11:15 | |
| 인프라/AWS 알림 | 이메일 (제목 패턴) | 하루 20~50건 | |
| 배포 검토 (Deployment Review) | Jira 매크로 기반 Confluence 페이지 | 수동 확인 |
이 중 그 어떤 것도 API를 가지고 있지 않다. 그 어떤 것도 나의 SIEM이나 APM으로 데이터를 공급하지 않는다.
사용 가능한 유일한 통합 접점은 다음과 같았습니다: 이메일로 도착하거나, 알려진 URL에 존재한다는 점입니다. 이러한 제약 사항은 곧 기회이기도 합니다.
아키텍처: 통합 계층으로서의 에이전트 (Agent as Integration Layer)
핵심 결정은 LLM 에이전트를 단순한 생산성 도구가 아니라, 이질적이고 비정형적인 레거시 출력물과 일관되고 실행 가능한 일일 요약이 필요한 인간 사이를 잇는 '틈새를 메우는 통합 계층 (seam-closing integration layer)'으로 취급하는 것이었습니다. 에이전트는 매일 아침 네 가지 작업을 수행합니다:
-
복제 지연 (Replication Latency) — 노이즈로부터 신호 추출 (Signal extraction from noise)
최신 경고를 찾고, 본문을 읽고, 본문에 실제로 내용이 채워져 있는지 보고합니다. 이는 사소해 보일 수 있지만, 그렇지 않습니다. 복제 경고는 때때로 빈 본문과 함께 발생합니다. 즉, 이메일은 도착했지만 내용은 오지 않은 상태입니다. 수동으로 작업할 때는 이메일을 보고 문제가 없다고 가정하기 때문에 이를 놓치기 쉽습니다. 에이전트는 "본문이 비어 있음"을 명시적인 플래그 상태 (flagged state)로 만듭니다. 이는 단순히 경고를 모니터링하는 것이 아니라, 모니터링 실패 자체를 포착하는 것입니다. -
백업 보고서 (Backup Report) — 반정형 HTML로부터의 구조화된 추출 (Structured extraction from semi-structured HTML)
73행의 HTML 테이블을 파싱하고, BACKUP_STATUS 열을 집계하며, 완료되지 않은 행만 노출합니다. 출력 결과: "69 완료, 0 실패, 백업 없음 3건 — db01, db02, db05." 읽는 데 걸리는 시간은 3초입니다. 73행을 눈으로 훑는 인간은 더 느리고 때때로 놓치는 부분이 생깁니다. -
인프라 알림 (Infrastructure Notifications) — 대규모 분류 (Classification at scale)
매일 20개에서 50개의 이메일이 도착하며, 각 이메일은 STATUS - Alert (Server Name : X and DB Name : Y) 패턴을 따릅니다. 에이전트는 모든 제목을 분류하고, 상태별로 집계하며, 각 이메일로 바로 연결되는 링크와 함께 SUCCESS가 아닌 항목만 노출합니다. 출력 결과: "21 SUCCESS, SERVER04U / DB09에서 1 WARNING 발생." 이 한 줄이 50개 이메일 전체에 대한 실행 가능한 출력물입니다. -
배포 검토 (Deployment Review) — 알려진 URL로부터의 실시간 데이터 읽기
Confluence 페이지를 읽고, Jira 매크로 구조를 식별하며, 기반 필터에 직접 쿼리하여 실시간 이슈 수를 보고합니다.
"누군가 Confluence 페이지를 업데이트했습니다"와 "현재 프로덕션 배포의 실제 상태는 이렇습니다" 사이의 간극을 메웁니다.
왜 Python 스크립트 대신 LLM을 사용하는가?
합리적인 엔지니어라면 다음과 같이 질문할 것입니다: "IMAP + 정규표현식 (regex) + cron으로 할 수 없었나요?" 맞습니다. 그리고 많은 경우 그것이 정답입니다. 대기업들은 이미 Airflow, Power Automate, Splunk SOAR, Logic Apps를 운영하고 있습니다. 이것은 진공 상태에서 시작되는 자동화가 아닙니다. 솔직한 비교는 다음과 같습니다:
| 접근 방식 | 강점 | 다음과 같을 때 한계가 있음 |
|---|---|---|
| Python + 정규표현식 (regex) + cron | 결정론적 (Deterministic), 감사 가능, 빠름 | 이메일 형식이 변경되거나 새로운 경고 패턴이 나타날 때 |
| ETL / SOAR 파이프라인 | 확장 가능, 거버넌스 적용, 통합됨 | 상류 (upstream) 단계에서 스키마 합의가 필요할 때 |
| LLM 에이전트 (agent) | 형식의 가변성을 허용, 낮은 설정 비용 | 출력이 비결정론적 (nondeterministic)이며 감사가 더 어려움 |
LLM이 줄여주는 것은 통합의 필요성이 아니라 통합의 마찰 (integration friction)입니다. 백업 보고서의 열 순서가 바뀔 수 있습니다. AWS 알림 제목 패턴이 달라질 수 있습니다. 새로운 데이터 소스가 일주일간의 스키마 작업 대신 영어 한 문장만으로 추가될 수 있습니다. 이러한 유연성에는 비용이 따릅니다. 결정론적 (determinism)인 특성을 적응성 (adaptability)과 맞바꾸는 것입니다. 놓친 예외 케이스가 다음 실행 시 드러나도 괜찮은 아침 분류 요약 (morning triage digest) 용도라면, 이러한 트레이드오프는 수용 가능합니다. 하지만 자동화된 복구 (remediation)를 트리거하는 시스템이라면 그렇지 않습니다.
올바른 사고 모델: LLM 에이전트는 관측 가능성(observability)의 틈새를 메우는 비용을 낮춰줍니다. 정확성 보장이 중요한 결정론적 파이프라인을 대체하는 것이 아닙니다.
유지할 가치가 있는 설계 원칙
독립적인 섹션 격리 (Independent section isolation)
각 소스는 독립적으로 처리됩니다. 한 섹션의 커넥터 장애가 다른 섹션을 중단시키지 않습니다. 에이전트는 "사용 불가" 노트를 생성하고 계속 진행합니다. 부분적인 보고서라도 아무런 반응 없는 실패(silent failure)보다는 훨씬 더 가치가 있습니다.
신호로서의 부재 (Absence as a signal)
각 섹션에는 해당 소스에 대한 이메일이 발견되지 않을 경우 실행되는 무결성 검사 (sanity check)가 포함됩니다. "오늘 수신된 복제 경고 없음"은 조용히 건너뛰어지는 것이 아니라 경고로 굵게 표시됩니다. 이는 메일 라우팅 변경 후 백업 보고서 이메일이 조용히 도착하지 않게 되었던 두 번째 달에 큰 효과를 발휘했습니다.
그 무결성 검사 (sanity check)가 즉시 이를 포착했습니다. 수동 분류 (manual triage)를 했다면 아무 문제 없이 실행되었다고 가정했을 것입니다.
델타 지향성 (Delta orientation)
이 보고서는 "모든 것의 현재 상태가 무엇인가"가 아니라, "어제 이후로 무엇이 변했거나 실패했는가"에 답합니다. 동일함을 확인하는 것은 정보 가치가 없지만, 변화를 확인하는 것과 동일한 주의력을 소모합니다. 델타 지향적 (delta-oriented) 보고서는 오직 주의가 필요한 곳으로만 주의력을 유도합니다.
런타임 날짜 해결 (Runtime date resolution)
프롬프트는 절대 날짜를 하드코딩하지 않습니다. "오늘"은 실행 시점의 로컬 시계에 따라 해결됩니다. 사소한 부분 같지만, 오래된 프롬프트가 어제의 범위로 실행되는 일련의 미묘한 버그들을 방지합니다.
프롬프트 (정제됨)
프롬프트 자체가 보존할 가치가 있는 결과물입니다:
당신은 매일 오전 9시 운영 보고서를 생성합니다. 조용히 실행하십시오 — 이 프롬프트는 자기 완결적 (self-contained)입니다.
필수 커넥터 (REQUIRED CONNECTORS)
- Microsoft 365 / Outlook (이메일 검색 + mail:// URI에 대한 read_resource)
- Atlassian (getConfluencePage; 선택적으로 searchJiraIssuesUsingJql)
만약 어떤 커넥터가 누락되었거나 오류가 발생하면, 해당 섹션에 명확하게 "⚠ 커넥터 사용 불가"라는 노트를 표시하고 계속 진행하십시오. 전체 보고서를 절대 중단하지 마십시오.
"오늘"의 범위 (SCOPE OF "TODAY")
"오늘" = 작업이 실행되는 현지 시간 기준의 달력상의 날짜입니다. 항상 outlook_email_search에 afterDateTime: "today"를 전달하십시오.
==== 섹션 1 — 복제 지연 모니터링 (오늘의 최신 경고) ====
- 오늘의 최신 경고를 검색합니다.
- 전체 본문을 위해 해당 URI에 대해 read_resource를 수행합니다.
- 보고: 오늘의 경고 횟수, receivedDateTime, 발신자, 그리고 본문 텍스트 또는 본문이 공백뿐인 경우 "본문이 비어 있음"을 보고합니다.
==== 섹션 2 — DB 백업 보고서 (실패 확인) ====
- 오늘의 보고서 이메일을 찾습니다.
- 행을 파싱(parse)합니다; BACKUP_STATUS 열의 합계를 계산합니다.
- 명시적으로 상태를 기술합니다: "X 완료, Y 실패, Z 백업 없음." 실패 횟수가 0보다 크면 굵게 표시합니다.
==== 섹션 3 — 오늘의 인프라 알림 ====
- 발신자로부터 알림을 가져오되, 50개로 제한합니다.
- 제목 패턴을 파싱합니다: "STATUS - Alert (Server : X and DB : Y)"
- 상태별로 횟수를 요약합니다. SUCCESS가 아닌 모든 항목은 굵게 표시합니다.
- SUCCESS가 아닌 항목들을 각각의 webLink와 함께 나열합니다.
==== 섹션 4 — 배포 검토 (Confluence) ====
- getConfluencePage, contentFormat="html".
- JIRA 도구를 사용할 수 있는 경우, 각 필터를 실행하고 실시간 이슈(issue) 수를 포함합니다.
==== 출력 형식 ====
- 일반 마크다운 (Plain markdown).
- 오늘 날짜가 포함된 H1 헤더 하나.
- 순서대로 네 개의 H2 섹션.
- 주의가 필요한 모든 항목은 굵게 표시합니다.
- "Sources:"로 끝맺음 — 중복 링크 금지.
- 어조: 사실적. 불필요한 미사여구 금지. 사과 문구 금지.
==== 건전성 검사 (SANITY CHECKS) ====
- 섹션 1 결과가 0인 경우: "오늘 복제 경고(replication alerts)가 없습니다 — 모니터링 시스템이 다운되었을 수 있습니다."
- 섹션 2 결과가 0인 경우: "백업 보고서 이메일이 아직 수신되지 않았습니다."
- 섹션 3 결과가 0인 경우: "오늘 인프라 알림(infra notifications)이 없습니다 — 알림 파이프라인(alerting pipeline)을 확인하십시오."
- 섹션 4 실패 시: 수동 접속을 위한 직접적인 Confluence URL을 포함합니다.
주목할 만한 세 가지 사항:
섹션 간의 독립성이 명확합니다. 각 섹션은 우아하게 실패(fail gracefully)하고 계속 진행하도록 지시되었습니다. 결함 격리(Fault isolation)가 프롬프트에 직접 인코딩되어 있습니다. 건전성 검사(Sanity checks)는 가장 가치 있는 줄(lines)입니다. "오늘 이메일을 받지 못함"을 표시하는 것은 상위 모니터링 시스템이 조용히 고장 난 경우의 실패 모드를 포착합니다. 이는 체크리스트 방식의 인간 검토가 놓치기 쉬운 바로 그 실패 모드입니다.
프롬프트는 버전이 관리되는 산출물(artifact)입니다. 환경이 변화함에 따라 — 새로운 이메일 형식, 새로운 Confluence 페이지, 커넥터 업그레이드 등 — 프롬프트도 진화합니다. 이를 살아있는 문서로 취급하십시오.
솔직한 트레이드오프 (Tradeoffs)
단점을 언급하지 않는다면 유용한 게시물이 되지 않을 것입니다.
LLM 출력은 비결정론적 (nondeterministic)입니다. 동일한 입력이라도 실행할 때마다 약간씩 다른 요약이 생성될 수 있습니다. 저는 일주일에 한 번씩 에이전트의 집계 수치를 원본 이메일 수와 대조하여 점검(spot-check)합니다.
토큰 잘림 (Token truncation)은 실제로 발생합니다. 73행의 HTML 테이블을 컨텍스트 윈도우 (context window)에 밀어 넣으면 조용히 잘려 나갈 수 있습니다. 방어적 프롬프팅 (Defensive prompting)이 이를 완화할 수는 있지만 제거할 수는 없습니다.
데스크톱 의존성. 제 설정에서는 데스크톱 앱이 열려 있을 때 예약된 작업이 실행됩니다. 오전 9시에 노트북이 절전 모드라면 보고서는 노트북을 열 때 실행됩니다. 일일 요약(daily digest) 용도로는 허용 가능하지만, 시간 민감도가 높은 모니터링 용도로는 적합하지 않습니다.
신뢰를 구축하는 데는 교정(calibrate) 시간이 필요합니다.
이 시스템을 처음 실행한 첫 주에는 어쨌든 모든 것을 수동으로 확인했습니다. 4주 차에 접어들 무렵에는 재확인을 멈추었고, 보고서가 신뢰할 수 있다는 것을 알 수 있을 만큼 충분한 장애(incident) 데이터를 확보했습니다. 그 교정(calibration) 기간 또한 배포의 일부입니다.
패턴의 일반화(The Pattern Generalizes) 일단 형태를 파악하고 나면 — 에이전트가 정해진 주기(cadence)에 따라 이질적인 소스(heterogeneous sources)를 읽고, 차이점(deltas)만 필터링하며, 인간의 주의가 필요한 사항만 드러내는 방식 — 이 패턴은 어디에서나 나타납니다:
- 온콜(On-call) 인수인계 요약 (PagerDuty + Slack + Jira + APM을 결합 및 요약)
- 스프린트(Sprint) 상태 보고서 (차단된 티켓, 노후화된 티켓, 담당자 없는 티켓 — 주간 자동화)
- 보안 경고 분류 (SOC 메일러는 종종 중요한 3개를 찾기 위해 200개의 이벤트를 생성함)
- 컴플라이언스(Compliance) 증거 수집 (SOC 2 갱신은 분석의 문제라기보다 주로 수집의 문제임)
도메인은 변하지만, 아키텍처는 변하지 않습니다.
사고 모델의 전환(The Mental Model Shift)
효율성 향상은 실질적입니다 — 대략 하루 25분 × 연간 근무일 250일 ≈ 연간 약 100시간. 하지만 그것이 가장 흥미로운 결과는 아닙니다.
푸시(push)에서 풀(pull)로. 대부분의 모니터링 도구는 모든 것을 당신에게 보내고, 당신이 무엇이 중요한지 결정하게 합니다. 시스템 입장에서 전송 비용은 제로에 가깝지만, 인간에게는 막대한 비용이 듭니다. 에이전트는 이를 뒤집습니다: "매일 아침 차이점(delta)을 물어보겠습니다."
대시보드에서 요약본(digests)으로. 대시보드는 누군가 그것을 볼 때만 가치가 있습니다. 5개의 소스를 합성하여 단 한 페이지로 필터링하는 일일 요약본은 5개의 완벽한 대시보드보다 운영 측면에서 더 유용합니다. 왜냐하면 가상된 제약 조건인 '시각화(visualization)'가 아니라, 실제 제약 조건인 '주의력(attention)'을 해결하기 때문입니다.
체크리스트에서 차이점(deltas)으로. 과거의 아침 상태 점검은 다음과 같았습니다: 이 5곳을 열고, 각각이 녹색(정상)인지 확인한다. 그것은 동일함을 확인하는 데 소비되는 인지 부하(cognitive load)입니다. 올바른 버전은 오직 "무엇이 변했는지 알려달라"는 것입니다.
이것이 무엇이고 무엇이 아닌가
이것은 당신의 관측 가능성(observability) 인프라를 LLM 프롬프트로 대체하자는 주장이 아닙니다. 당신의 APM은 이 에이전트가 결코 할 수 없는 일들을 수행하고 있습니다: 실시간 이상 탐지(real-time anomaly detection), 분산 추적 상관관계(distributed trace correlation), 인프라 토폴로지 매핑(infrastructure topology mapping).
에이전트(agent)는 그것과 경쟁하지 않습니다. 에이전트가 하는 일은 이음새(seam), 즉 현대적인 관측성 스택(observability stack)과 그것이 수용할 수 없는 레거시 출력물(legacy outputs) 사이의 간극을 해결하는 것입니다. 이 이음새를 가시화하는 것이 첫 번째 단계이며, 이를 메우는 것이 두 번째 단계입니다. 에이전트는 그 가교 역할을 합니다. 만약 당신의 아침이 "이메일에서 몇 가지만 확인해 보자"로 시작된다면, 당신에게는 관측성 이음새(observability seam)가 있는 것입니다. 이를 메우기 위한 도구는 현재 사용 가능하며, 구현 비용은 잘 작성된 프롬프트(prompt) 하나면 충분합니다. 당신의 환경에는 어떤 관측성 이음새가 있나요? 사람들이 어떤 데이터 소스(data sources)를 우회하며 작업하고 있는지 궁금합니다. 댓글을 남겨주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기