
AI 시대의 Observability 설계 - PII와 AI의 검색성을 양립시키고 자동 복구하기 (실전편)
요약
AI 시대의 Observability 설계에서 개인정보(PII) 보호와 AI의 검색성을 동시에 확보하는 실전 전략을 다룹니다. MCP를 통해 로그에 접근하는 비엔지니어와 AI 모델로 인한 새로운 보안 위협에 대응하기 위해 6단계의 다층 PII 보호 설계를 제안합니다.
핵심 포인트
- AI 도입으로 로그가 DB 권한 없는 사용자에게 PII를 노출하는 새로운 경로가 됨
- PII 차단과 AI 검색성 사이의 양립을 위한 다층적 보안 설계 필요
- BQ Policy Tag와 ETL DLP 등을 활용한 6단계 PII 보호 메커니즘 적용
- 관측 데이터를 활용한 CI 실패 대응 및 자동 복구(auto-remediation) 구현
여러분 안녕하세요! AirCloset에서 CTO를 맡고 있는 Tsuji입니다.
설계편에서는 애플리케이션 / 인프라 / CI / LLM의 4개 축을 각각의 질문 성격에 맞춰 서로 다른 형태로 Observable하게 만드는 이야기를 썼습니다. 여기까지로 관측 스택(Observability stack)의 **쓰기 측(write side)**은 일단 일단락 지었습니다.
하지만 "Observable하게 만든 것"만으로 이야기가 끝나지는 않습니다. 관측 스택에는 본방 데이터(production data)가 흐르는 이상, 여기에 PII(개인정보)가 혼입되는 경로를 차단해야 합니다 ── 이는 AI와는 무관하게, observability 설계에서 소홀히 하면 유출 사고로 직결되는 고전적인 문제입니다.
기존에는 로그를 읽을 수 있는 사람의 집합이 DB를 읽을 수 있는 사람의 집합과 거의 겹쳤습니다. DB 권한을 가진 엔지니어에게 로그는 개인정보에 대한 "추가적인" 경로가 아니었습니다 ── 즉, 로그 측의 방어는 시스템 전체의 방어선을 실질적으로 움직이기 어려운 위치에 있었다는 것이 많은 현장의 실태였을 것입니다.
AI는 이 전제를 깨뜨립니다. MCP를 통해 로그를 가져오는 비엔지니어는 DB 권한을 가지지 않습니다. 로그는 처음으로 **"DB에 액세스할 수 없는 사람이 개인정보에 도달할 수 있는 경로"**가 되었습니다. 게다가 로그 내용은 AI의 입력에도 포함되기 때문에, 모델로의 전송 및 출력으로의 재표출이라는 새로운 유출 면(attack surface)도 생겨납니다. 로그의 PII 대책은 "해두면 좋은 위생 관리"에서 **"신뢰 경계(trust boundary)의 재설계로서 필수"**로 바뀌었다는 것이 본 기사의 전제입니다.
그리고 그 위에서 AI가 관측 스택을 가져올 수 있는 상태를 유지하지 않으면, 애초에 "AI에게 전달할 수 있는 observability"라는 전편의 목표가 성립되지 않습니다.
실전편에서는 이 두 가지의 양립 ── PII를 보호하면서도, AI가 검색할 수 있도록 하는 것 ── 을 어떻게 실현했는지, 그리고 그 결과로서 **CI 실패로부터 PR 제안까지 연결하는 자동 복구(auto-remediation)**가 어떻게 성립되었는지를 쓰겠습니다.
관측 스택은 PII의 통로가 되기 쉽다
애플리케이션이 로그를 출력한다 → Loki로 흐른다 → AI가 MCP를 통해 가져온다 ── 이 순수한 흐름을 구성하기만 하면, 그곳에 다음과 같은 것들이 혼입됩니다:
- 고객의 email이나 전화번호가 에러 로그에 포함됨
- 주문 정보의 응답(response)이 trace의 payload에 실림
- DB 쿼리 로그에 테이블 전체 행이 나옴
평문 PII가 관측 스택에 쌓이면 그대로 AI로부터 검색 가능해집니다. 이는 AI의 능력 이전에의 문제로, 관측 스택이 PII의 통로가 되고 있다는 사실 자체가 리스크입니다. 그리고 동시에, PII를 완전히 지워버리면 "고객 A의 문의를 조사하고 싶다"는 당연한 서포트 업무를 할 수 없게 됩니다.
cortex(사내 AI 플랫폼)에서는 이 대립을 어떻게 풀었을까요. 중요한 것은 "PII의 통로를 차단하는 것"과 "PII로 검색할 수 있는 것"을 이지선다로 만들지 않는 설계입니다.
다층 PII 설계 ── 6개의 층으로 보호
cortex의 PII 대응은 역할이 다른 6개의 층이 조합되어 있습니다:
| 층 | 목적 | 메커니즘 |
|---|---|---|
| 쓰기: BQ Policy Tag | 열 레벨의 액세스 제어 | pii_high / pii_medium / pii_low의 3층 분류. fine-grained reader를 가지지 않은 권한에서 해당 열을 SELECT 하면 Access Denied로 쿼리 자체가 차단됨 (순수한 CLS (Column-Level Security), 동적 마스킹은 사용하지 않음) |
| 쓰기: ETL DLP | 평문 PII를 파생 테이블에 남기지 않음 | Cloud DLP로 커스터머 서포트 데이터 등을 변환 시 redact. [EMAIL_ADDRESS] / [PHONE_NUMBER]의 placeholder로 구조는 유지 |
| 쓰기: 로그 해싱 | Loki에 평문을 남기지 않음 | 애플리케이션 측에서 hashEmail (HMAC-SHA256으로 12-char prefix, 키는 관측 스택 외부에 있음)을 거친 후 log 출력 |
| 검색: 동일 함수로 대조 | 평문을 거치지 않고 특정 고객의 로그 추출 | 쿼리 측도 동일한 hashEmail을 거친 후 Loki에 던짐 |
| 출력: MCP 마스킹 | AI에게 전달되는 시점에 숨김 | 컬럼명 검출로 로컬 부분을 복호화/마스킹 (예: r***@air-closet.com). @domain은 남겨서 1차 대응 시 도메인 특정성을 유지 |
| Identity 분리 | 사원 email은 고객 PII와는 별도 트랙으로 취급 | HMAC 서명된 인증 email로서 attribution에 사용하며, 마스킹 대상에는 포함하지 않음 |
이 중 **4번째인 「검색: 동일 함수로 대조」**가 보안과 사용 편의성을 모두 잡을 수 있는 가장 이상적인 패턴입니다.
본 기사에서는 email을 대표적인 예로 들어 설명하지만, 이 6개 계층의 프레임워크가 보호하는 대상은 email뿐만이 아닙니다. 성명(가나 포함)·전화번호·주소·우편번호·생년월일·카드/은행 정보·외부 서비스의 ID 등 PII는 매우 다양합니다. PII의 성격에 따라 익명화 (Anonymization) 기법은 달라지며 (email/전화번호처럼 동일 함수 해시로 상관관계를 남기는 것, 성명/주소처럼 부분 마스킹 (Partial Masking) 하는 것, 카드나 토큰처럼 완전히 삭제 (Redact) 하는 것), 이 판단은 항목 단위로 수행합니다. 다만 「6개 계층 중 어디에서, 어떻게 보호할 것인가」라는 구조는 공통적이며, 이 부분이 이 설계의 재사용 가능한 핵심입니다.
나아가, 이 익명화는 관측 로그(Loki)에만 국한된 이야기가 아닙니다. 예를 들어 서비스의 DB를 조회하는 MCP 툴에서도 쿼리 결과에 고객의 성명·주소·전화번호 등이 포함될 수 있으므로, AI에 전달하기 직전에 동일한 PII 익명화 규칙을 적용합니다. 즉, **「AI에 전달되는 모든 데이터 경로에서 PII를 익명화한다」**는 일관된 규칙을 데이터 소스의 종류를 넘어 적용하고 있다는 뜻입니다.
해싱 (Hashing)을 「쓰기」와 「검색」 양단에서 통과시키기
일반적으로 「로그에서 PII를 삭제」하면, 나중에 「고객 A의 로그를 찾고 싶다」는 요구를 충족할 수 없게 됩니다. 하지만 쓰기(Write) 시점에 해싱한 값을 로그에 남겨두면, 검색 쿼리 측에서도 동일한 해시 함수를 통과시킴으로써 해당 로그를 찾아낼 수 있습니다. 평문(Plaintext) email은 양단 어디에도 흐르지 않습니다.

구체적인 흐름은 다음과 같습니다.
쓰기 측:
// 애플리케이션 코드
logger.info("Subscription updated", {
user: hashEmail(user.email), // → '7a3f9c2e0b1d' (HMAC-SHA256 12-char prefix)
...
검색 측 (특정 고객의 로그를 추출하고 싶을 때):
여기서 한 가지 고민되는 지점이 있습니다. 「고객 A의 로그를 가져오고 싶다」고 할 때, 단순히 구현하면 AI에게 생(Raw) email을 전달하여 MCP 툴이 검색하게 됩니다. 하지만 이는 AI(=모델, 그리고 그 너머의 벤더)에게 평문 PII를 전달하는 것이 되므로, Loki 내부를 해시(Hash)로 보호하더라도 그 전 단계인 검색 입력 단계에서 정보가 유출됩니다.
따라서 cortex에서는 검색 툴을 「비 PII(Non-PII) ID를 받아, MCP 서버 내부에서 email로 변환(Resolve)한 뒤, 그 자리에서 해싱하여 해시값만 반환하는」 형태로 구성합니다. email은 MCP 서버 내부에만 존재하며, 모델에는 단 한 번도 전달되지 않습니다:
// MCP 툴 resolve_email_hash (서버 내부에서 실행)
// 입력은 ID (비 PII). email은 호출자=AI에게 절대 반환하지 않음
const email = await resolveEmailById(userId); // 서버 내부에서 DB를 통해 변환
...
AI는 이 hash를 받아, Grafana MCP를 통해 Loki를 {service_name="subscription"} |~ "${hash}"와 같이 검색합니다. 쓰기 측과 검색 측에서 동일한 hashEmail 함수와 동일한 키(Key)를 사용하므로, 동일한 고객으로부터 발생한 로그는 동일한 hash로 검색됩니다. 반면:
- Loki에는
평문 이메일(email)이 단 한 번도 들어가지 않습니다. - 검색 쿼리가 Loki에 전달되는 문자열에도
평문 이메일은 포함되지 않습니다 (해싱된 값만 전달됨). - 그리고
AI(모델)에게도 평문 이메일은 단 한 번도 전달되지 않습니다. AI가 다루는 것은 비PII(non-PII) ID와 이미 Loki에 있는 해시(hash) 값뿐입니다. 평문 이메일은 MCP 서버라는 신뢰 경계(trust boundary)의 안쪽에서 단 한 발짝도 나가지 않습니다. 로그 유출 시 열거 저항성(enumeration resistance)은
HMAC 키를 관측 스택 외부에 두는 것으로 담보합니다. 이메일은 입력 공간이 좁아 열거가 가능하므로, 단순 단방향 해시 (SHA-256 등)를 사용하면 뚫릴 수 있습니다. 해시 함수는 공개되어 있기 때문에, 로그가 유출되면 공격자는 '흔히 쓰이는 이메일 후보'를 자신의 머신에서 하나씩 해싱하여 유출된 값과 대조하는 것만으로 평문을 복원할 수 있습니다 ── 키가 필요하지 않습니다. HMAC은 해시 계산 자체에 비밀 키를 섞기 때문에, 키를 모르는 공격자는 애초에 후보 이메일을 '유출된 해시와 같은 형태'로 변환할 수 없습니다. 무차별 대입 공격(brute-force)의 영역에 들어설 수 없게 됩니다. 키를 쓰기(write) 측과 검색 도구(search tool) 측 두 곳에만 두고 Loki 본체에는 두지 않음으로써, "로그가 유출되어도 키가 유출되지 않는 한 평문은 보호된다" = 공격에 필요한 조건이 하나 더 늘어나는 상태를 만들고 있습니다. 12자 접두사(12-char prefix, 48 bit)로 축소했기 때문에 이론적으로는 충돌(collision)이 발생할 수 있지만, 고객 모수 규모에서는 실용적으로 무시할 수 있습니다. 생일 문제(Birthday Problem)로 보면, 충돌 확률이 50%가 되기 시작하는 규모는 대략 2,000만 건(≈ 2^24.5) 정도이며, 그보다 적은 규모에서는 기대 충돌 수가 매우 작습니다. 더욱 중요한 것은, 설령 충돌이 발생하더라도
평문이 유출되는 것은 아니라는 점입니다 ── 이 해시는 보안 경계가 아니라 고객 식별을 위한 로그 상관관계 키(log correlation key)이므로, 충돌의 영향은 "다른 고객의 로그가 드물게 동일한 해시에 겹침 = 상관관계 정밀도의 저하"에 그칩니다.
이는 해시 함수의 "동일한 입력에는 동일한 해시 값이 반환된다"는 성질을, "양 끝단에서 동일한 로직을 통과시키면 검색이 성립한다"는 형태로 재사용한 것입니다. 보안과 디버깅 편의성 사이의 트레이드오프(trade-off)를 크게 압축할 수 있습니다.
그리고 당연한 이야기지만, 이 메커니즘은 '애플리케이션 로그 계층'만의 이야기가 아니며, BQ 측은 또 다른 Policy Tag를 통한 열 수준 액세스 제어(column-level access control)로 보호되고 있는(위 표의 1~2행) 다층 구조로 되어 있습니다.
이 "ID로 받고 내부에서 해결·해싱한다"는 방식이 효과적인 이유는, 평문 이메일이 MCP 서버라는 신뢰 경계를 단 한 번도 넘지 않는다는 점입니다. 흔히 사용하는 편한 구현(AI에게 생(raw) 이메일을 전달하여 도구로 검색하게 하는 방식)의 경우, Loki 내부를 아무리 잘 보호하더라도 검색 입력 단계에서 모델에 평문이 전달되어 버립니다. "벤더 약관상 외부로 나가지 않으니 괜찮다"라고 말할 수도 있겠지만, 그것은 약관에 의존하는 것이며 감사(audit)의 관점에서는 취약합니다. ID로 받고 내부에서 해싱하면, 약관에 의존하지 않고 구조적으로 평문을 전달하지 않습니다. 서두에서 "PII 대책은 신뢰 경계의 재설계로서 필수적이다"라고 쓴 것은 바로 이러한 설계 판단을 의미합니다.
여담이지만, 이 설계를 다듬을 때 AI에게 상담했더니 "관리 화면을 만들어 사람이 수동으로 해싱하는 기능을 마련하는 것이 안전하지 않겠느냐"라는 제안을 받았습니다. 확실히 PII를 모델에 전달하지 않는 하나의 해법이 될 수는 있지만, 그렇게 되면 자동 운영에 태울 수 없습니다 (사람이 매번 개입해야 조사가 시작됨). cortex는 "인지하기 전에 고쳐지는" 자동 복구(self-healing)까지 포함하여 운영하는 것을 전제로 하기에, 인력을 개입시키는 해법은 채택할 수 없습니다. "ID로 받고 MCP 내부에서 해싱한다"는 결론에 도달한 것은 이러한 제약 때문이었으며, 어떤 해법이 허용될지를 결정하는 것은 결국 설계자인 우리의 판단이었습니다.
통합 측면 ── "인간 = Web, AI = MCP"로 동일한 백엔드를 공유하기
3개의 백엔드(Prometheus / BQ / Loki)에 관측(Observable) 정보를 흘려보내고, PII도 제대로 보호하는 형태로 만들었습니다. 다음 문제는 누가 어떻게 호출하느냐입니다. 여기서 흔히 발생하는 함정은 "인간용 대시보드 집계"와 "AI용 데이터 제공"을 별도로 만들어 버리는 것입니다. 그렇게 되면:
- 동일한 질문에 대해 두 개의 집계 구현을 떠안게 됨
- 숫자가 미세하게 어긋나기 시작함
- 어느 쪽이 정답인지 알 수 없게 됨
- AI용 집계 업데이트와 인간용 집계 업데이트가 비동기화됨
cortex는 이 부분을 **"동일한 Observable 기반을 공유하고, 소비자용 인터페이스만 분리한다"**는 설계로 해결합니다.

인간 측: AI 운영 포털
사내용 AI 운영 포털 (내부 명칭: PI Lab)이 있으며, 이곳에 관측 대상별 대시보드가 집약되어 있습니다:
- Claude Code 이용량 (설계편에서 보여준 cc-usage 화면)
- MCP 도구 이용량 (server별 / tool별 / user별 / team별)
- 인프라 비용 (Gemini / GCP / AWS / GitHub를 한 화면에서) - 알람 상황, 배포 이력 등등
예를 들어 MCP 이용 대시보드는 실제 모습이 다음과 같습니다:

지난 30일 동안 service-product-graph가 37,458 calls (그 중 에러 7,024), gws가 19,339 calls, db-graph가 17,037 calls ── 라는 형태로, 어떤 MCP가 얼마나 사용되고 있는지, 어디서 실패가 발생하는지를 매일 확인할 수 있는 상태입니다. 참고로 에러율이 높게 보이는 server가 있는 이유는, typed error (= 기대되는 거부, 예: 권한 없음)도 에러 카운트에 포함되어 있기 때문이므로 별도의 해석이 필요합니다. 지난 연재(code-graph deep dive 후편)에서 "annotation graph의 MCP가 약 50,000 calls / 73 users에 사용되고 있다"라고 적었던 수치도 여기서 가져온 것입니다.
이러한 React 측 페이지는 내부 API를 통해 BQ / Prometheus / Loki를 호출하여 표시하는 구조입니다. 집계 로직은 API 측에 집중되어 있습니다.
AI 측: MCP
동일한 데이터 소스를 AI 에이전트가 호출할 때는 용도별 MCP를 경유합니다:
- Grafana MCP ── Loki / Mimir / Prometheus / Tempo에 LogQL / PromQL로 쿼리를 던집니다. AI 에이전트 측이 "지난주 서비스 X에서 에러가 가장 많았던 시간대는?"와 같은 자연어 질문을 LogQL / PromQL로 변환하여 MCP를 통해 던지는 방식으로 역할이 분담됩니다.
- BQ MCP (cortex-product-graph 경유) ──
claude_usage.claude_usage/cortex.mcp_tool_calls를 SQL로 호출합니다.
이 설계의 핵심은 인간용 대시보드와 AI용 MCP가 동일한 백엔드(backend)를 공유하고 있다는 점입니다. "AI용 집계 테이블"과 "인간용 집계 테이블"을 나누지 않습니다. Observable 기반은 하나만 구축하고, 그에 대한 소비자별 인터페이스 계층 (Interface Layer) (Web 대시보드 / MCP)을 별도로 제공하는 형태입니다.
DDD(도메인 주도 설계)의 어휘로 말하자면, MCP와 Web 대시보드는 모두 **프레젠테이션 계층 (Presentation Layer)**이며, 동일한 도메인(= Observable 기반)에 대한 서로 다른 입출력 채널에 불과하다는 정리입니다. "MCP는 뭔가 특별한 메커니즘"이라고 파악하기보다, 단순히 프레젠테이션 계층의 한 형태로서 위치시키는 것이 중복 구현을 피하는 판단을 흔들리지 않게 해줍니다.
이러한 구조가 있기에 "관측 스택이 AI에게 보인다"는 것이 성립됩니다. Observable 기반을 만들어도 **AI를 위한 프레젠테이션 계층(= MCP)**이 없다면 AI가 데이터를 가져올 수 없다는 의미에서, MCP는 "AI에게 전달하기"를 성립시키는 필수 요소입니다.
자동 복구의 진정한 동력
지금까지 설계한 관측 스택을 "단순히 보기 위한 화면"으로 끝내지 않는 계층이 자동 복구입니다. 이는 AI Harness 연재 Part 4에서 전체 내용을 다루었으므로 상세 내용은 생략하지만, 관측 스택 측면에서 보면 기점과 종점은 명확합니다.

구체적인 흐름:
- 탐지: 운영 환경 알람 / CI 실패가 Loki LogQL alert로 발생
- 전달: event-relay (사내 webhook 허브)로 POST
- 기동: auto-review bot (= Claude Code를 탑재한 에이전트)이 기동
- 컨텍스트 수집: bot이 Grafana MCP로 전체 로그(full log)를 가져오고, Product Graph MCP로 관련 PR / commit / 코드를 추적
- 수정 제안: 수정 PR을 생성
- 검증: CI를 통과하면 bot 스스로 auto-merge를 수행하고, 통과하지 못하면 다른 bot이 추가 리뷰를 진행
즉, 자동 복구의 기점은 관측 스택(Observability Stack)이 "무엇이 고장 났는가"를 올바른 형태로 전달할 수 있는 상태에 있는지 여부입니다. error로 인식된다 / stacktrace가 남아 있다 / 관련 코드(PR / commit / graph)를 추적할 수 있다 ── 이 중 하나라도 결여되어 있다면 자동 복구는 중단됩니다 (구체적인 고장 방식은 후술할 남은 과제 섹션에서 다룹니다). 다른 말로 하자면,
관측의 질이 AI 자율 운영의 천장이 된다
이것이 실전편에서 가장 전달하고 싶은 주장입니다. 관측 스택을 "모니터링하기 위한 메커니즘"이 아니라, "AI를 구동하기 위한 입력(Input)"이라고 재정의하면 설계 판단의 우선순위가 바뀝니다.
남은 과제 ── "무엇을 error로 취급할 것인가"와 stacktrace 설계가 핵심
마지막으로, 여기까지 구축했음에도 남아 있는 가장 큰 과제를 솔직하게 적겠습니다.
관측 스택을 아무리 Observable하게 만들어도, 애초에 무엇을 error로 취급할 것인지, 그때 stacktrace가 남아 있는지에 대한 설계가 무너져 있다면 전부 무용지물입니다. 이는 AI Harness 연재 Part 2에서도 cortex 내부의 지식 그래프(Knowledge Graph) 문맥에서 다루었던 내용이지만, 동일한 문제가 관측 스택 측에서도 본질적인 문제로 존재합니다.
구체적으로 어떻게 무너지는가:
try ~ catch로 에러를 삼켜버려(swallow) 로그조차 남지 않음 → 관측 스택에 아무것도 남지 않음catch에서 로그를 남기고는 있지만,console.log수준의 info 레벨로 출력하여 error로 인식되지 않음- error로 출력하고는 있지만,
error.message만 작성하고 stacktrace를 출력하지 않음 → 원인 코드를 추적할 수 없음 - 애초에 비동기 에러(asynchronous error)가 unhandled 상태로 떨어짐
이것들은 모두 관측 스택의 문제가 아니라, 관측의 입구를 만드는 코드 측의 문제입니다. 관측 스택이 아무리 완성도 높게 구축되어 있어도, 입구의 수도꼭지가 망가져 있다면 그곳에서 아무것도 흘러나오지 않습니다.
현재의 대책은 3개 층으로 나뉘어 있으며, 어느 것도 완벽하지 않습니다:
- lint (정적 검사) ──
no-silent-catch규칙이 빈 catch 문이나.catch(() => null)계열의 에러 삼키기를 금지합니다. 하지만 "catch 내에서 어떤 함수 호출이라도 있으면 허용"하는 구조이기 때문에, "logger.info(err.message)로 info 레벨로 격하시키는 경우"나 "error.message만 챙기고 stacktrace는 버리는 경우"와 같은 고장 방식은 정적으로 잡아낼 수 없습니다. - 가이드라인 문서 ── "
serializeError(error)를 통해 stacktrace를 구조화된 필드에 저장한다", "logger.error(err.message)로 stack을 버리는 것은 Major 위반이다" 등을 사내 가이드라인(guidelines)에 명시합니다. 다만 정적 검사가 불가능하여 사람 또는 AI 리뷰에 의존해야 합니다. - AI auto-review ── PR 자동 리뷰 bot은 테스트 커버리지 관점에서 "에러 케이스를 테스트하고 있는가"를 확인하지만, observability에 특화된 체크 항목을 가지고 있지 않기 때문에 stacktrace 설계의 질을 체계적(systematic)으로 잡아낼 수 없습니다.
즉, **"가이드라인은 있고, lint로 일부는 잡을 수 있고, AI 리뷰도 일단 확인하지만, 완벽하지는 않다"**가 솔직한 상태입니다. 진짜 격차(gap)는, 신규 코드가 작성되는 시점에 "이곳은 error로 취급한다 / stacktrace를 남긴다"를 AI가 능동적으로 제안하거나 보완해 주는 Harness가 구축되어 있지 않다는 점입니다. 관측 입구의 설계를 AI가 앞장서서 보증해 주는 장치까지는 갖춰지지 않았습니다.
"관측 스택은 갖춰졌다, 하지만 관측 대상의 설계 자체는 인간이 노력하고 있다" ── 이것이 현재의 솔직한 모습입니다. 이곳을 Harness화 하는 것이 다음 단계가 될 것입니다.
맺음말 ── 정적 편 + 동적 편은 갖춰졌다, 다만 합류는 다음 숙제
code-graph 연재에서 다룬 "정적 분석 그래프를 AI가 끌어올 수 있는 형태로 만든다"가 코드의 구조를 사실(fact)로서 전달하는 이야기였다면, 이번 전/후편은 운영 환경(production)에서 지금 일어나고 있는 일을 사실로서 전달하는 이야기였습니다.
| 형태 | 무엇을 전달하는가 | |
|---|---|---|
| 정적 편 (code-graph + db-graph + annotation graph) | 3개 그래프 병렬 연결 + SAME_ENTITY | 코드와 의미 |
| 동적 편 (전편 + 본 기사) | Prometheus / BQ / Loki + MCP | 운영 환경의 동작과 비용 |
하지만 솔직히 말하자면, 이 두 가지는 현재로서는 아직 별개로 존재하고 있을 뿐입니다. cortex가 표방하는 "AI에게 추론하게 하지 않고, 사실로서 전달한다"를 진정한 완성형으로 가져가기 위해서는, 정적 그래프 (Static Graph)에 동적 데이터 (Dynamic Data)를 흘려 넣어 일체화하는 단계가 남아 있습니다. 이는 code-graph 연재 후편에서 남은 과제로 언급했던 "동적 해석 (Dynamic Analysis)의 부재"와 완전히 동일한 문제로, "저 edge가 운영 환경에서 얼마나 사용되고 있는가"를 정적 그래프의 노드 (Node) 위에 얹는 ── 여기까지 도달해야 비로소 『사실로서 전달한다』가 완성형이 됩니다.
그리고 이 정적 편·동적 편 위에 자동 복구 (Self-healing)가 올라감으로써 "AI가 자율적으로 운영한다"까지는 성립하지만, 정적 편과 동적 편의 합류는 다음 연재의 숙제입니다.
마지막으로, 관측 스택 (Observability Stack) 그 자체보다 관측 대상(=무엇을 error로 취급할 것인가, stacktrace를 남길 것인가)의 설계야말로 핵심이라는 이야기. 하네스화 (Harnessing)의 다음 숙제는 이곳이 될 것입니다.
긴 글 읽어주셔서 감사합니다.
제가 CTO를 맡고 있는 주식회사 에어클로젯(AirCloset)에서는, AI와 함께 새로운 개발 경험을 만들어 나갈 엔지니어를 모집하고 있습니다. 관심 있는 분은 꼭 엔지니어 채용 사이트 에어클로퀘스트(AirCloset Quest)를 확인해 주세요!
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기