Blog
data-governancepiihitlobservabilityai-agent

AI가 카탈로그를 거버넌스한다 — 제안 워크플로·PII 안전장치·셀프-텔레메트리

Argus Catalog 에이전트가 메타데이터를 자동 생성하되 사람이 승인하게 만드는 거버넌스 설계를 해부합니다. suggest/apply 모드, PII 사람 승인 강제, 폴링 데몬 자동 생성, 그리고 에이전트가 자기 자신을 카탈로그에 등록·계측하는 셀프-텔레메트리까지 정리합니다.

Data Dynamics2026년 6월 14일13 min read

AI가 메타데이터를 자동으로 만들어 주는 건 편리하지만, 그 결과를 검토 없이 카탈로그에 그대로 박아 넣으면 위험합니다. 잘못된 설명, 빗나간 PII 판정이 "공식 메타데이터"로 둔갑할 수 있기 때문입니다. Argus Catalog AgentAI가 생성하되 사람이 승인하는 거버넌스를 기본값으로 두고, 나아가 에이전트가 자기 자신을 카탈로그에 등록·계측하게 만듭니다.

이 글은 5부작 시리즈의 마지막 편으로, 메타데이터 생성 작업(tasks.py)과 셀프-텔레메트리(telemetry.py)를 다룹니다. (1편 아키텍처부터 읽으면 전체 그림이 잡힙니다.)

1. 메타데이터 생성 작업 5종

배치/워커 모드가 만드는 메타데이터는 다섯 가지입니다. 모두 컨텍스트 수집(스키마·샘플·용어집) → LLM 생성 → 결과 처리라는 같은 흐름을 공유합니다.

작업생성물결과 처리
describe데이터셋 상세 설명 (markdown)제안 또는 직접 적용
summarize한 줄 요약
columns컬럼별 설명 일괄
tags분류 태그 추천항상 제안
piiPII 컬럼 감지 + 근거항상 제안 (민감 — 사람 승인 강제)

2. suggest vs apply — 거버넌스의 갈림길

결과를 카탈로그에 어떻게 반영할지는 --mode가 결정합니다.

  • suggest(기본) — 카탈로그의 AI 제안 워크플로에 반입합니다. UI의 제안 목록에 쌓이고, 사람이 하나씩 승인/거절합니다. 거버넌스가 유지되는 권장 모드입니다.
  • apply — 데이터셋에 직접 적용(PUT)합니다. 신뢰 환경 전용입니다.
def _submit(catalog, cfg, dataset, items, apply_fields=None) -> str:
    """결과 처리 — suggest 면 반입, apply 면 직접 수정 (PII 제외)."""
    if cfg.mode == "apply" and apply_fields:
        catalog.update_dataset(dataset["id"], apply_fields)
        items = [i for i in items if i.get("_apply_field") is None]
    if items:
        catalog.import_suggestions(dataset["id"], items, provider="agent", model=cfg.model)
    ...

제안으로 반입할 때 provider="agent"model(예: qwen2.5:7b)을 함께 기록합니다. 승인자는 "이 설명을 누가, 어떤 모델로 만들었는가"를 보고 판단할 수 있습니다. 출처가 남는다는 건 거버넌스의 출발점입니다.

3. PII는 예외 없이 사람 승인

가장 민감한 건 PII(개인정보) 감지입니다. 어떤 컬럼이 이메일·전화번호·주민번호인지 판정하는 일은 잘못되면 컴플라이언스 사고로 직결됩니다. 그래서 PII는 apply 모드여도 직접 적용하지 않고 항상 제안으로만 남깁니다.

def run_pii(catalog, llm, cfg, dataset) -> str:
    """PII 컬럼 감지 — 민감 정보라 모드와 무관하게 항상 제안만 (사람 승인 강제)."""
    parsed, _ = llm.generate_json(build_pii_prompt(dataset, sample), SYSTEM_PROMPT)
    # 실제 존재하는 컬럼만 통과 (모델 환각 방어)
    known = {f["field_path"].lower() for f in dataset.get("schema_fields", [])}
    findings = [p for p in parsed
                if isinstance(p, dict) and str(p.get("name", "")).lower() in known]
    ...
    # suggest 강제 — apply 모드여도 직접 적용하지 않는다
    catalog.import_suggestions(dataset["id"], [item], provider="agent", model=cfg.model)
    return f"PII 제안 {len(findings)}건 (사람 승인 필요)"

여기엔 환각 방어 장치도 들어 있습니다. 모델이 존재하지도 않는 컬럼을 PII로 지목할 수 있으므로, 실제 스키마에 있는 컬럼만 통과시킵니다. 또 pii_typeEMAIL·PHONE·NAME·ADDRESS·ID_NUMBER통제된 값만 쓰도록 프롬프트에서 강제해, 서버가 그대로 저장할 수 있는 형태로만 받습니다.

4. 프롬프트 — 근거에 묶고 표준 용어로 유도

생성 품질의 절반은 프롬프트에서 결정됩니다. prompts.py는 스키마·샘플·용어집을 한국어 컨텍스트로 직렬화하고, 소형 모델도 형식을 지키도록 출력 규칙을 명시합니다.

SYSTEM_PROMPT = (
    "당신은 데이터 카탈로그의 메타데이터 작성 전문가입니다. "
    "데이터셋 스키마와 샘플을 근거로 정확하고 간결한 한국어 메타데이터를 작성합니다. "
    "근거 없는 추측을 하지 않으며, 지시된 출력 형식을 엄격히 지킵니다."
)

두 가지 장치가 핵심입니다.

  • 근거 고정 — "스키마에 근거한 사실만 작성하고, 추측한 내용에는 '추정'을 명시"하도록 지시해, 모델이 지어내지 않게 합니다.
  • 표준 용어 유도 — 조직 용어집을 컨텍스트로 함께 넣어("가능하면 이 용어를 사용") 설명 전반에 사내 표준 용어가 일관되게 쓰이도록 유도합니다.

JSON을 받아야 하는 작업(columns·tags·pii)은 형식 예시를 함께 줘서 파싱 안정성을 높입니다. (2편의 generate_json 코드펜스 방어와 짝을 이룹니다.)

5. worker — 설명 없는 데이터셋을 알아서 채운다

대량 카탈로그에서 메타데이터를 사람이 일일이 트리거하긴 어렵습니다. worker 모드는 설명이 비어 있는 데이터셋을 주기적으로 찾아 generate-all을 돌리는 폴링 데몬입니다.

def _worker_loop(catalog, llm, cfg, args) -> None:
    processed: set[int] = set()
    while True:
        summaries = catalog.list_datasets_by_datasource(args.datasource_id)
        targets = [s for s in summaries
                   if not (s.get("description") or "").strip()   # 설명 없음
                   and s["id"] not in processed]                  # 미처리
        for s in targets:
            ds = catalog.get_dataset(s["id"])
            run_for_dataset(catalog, llm, cfg, ds, list(TASK_NAMES))
            processed.add(s["id"])
        if args.once:
            return
        time.sleep(cfg.poll_interval)

한 번 처리한 데이터셋 id는 프로세스 생존 동안 processed에 기록해, 같은 제안이 중복 반입되는 걸 막습니다. --once 플래그로 1회만 돌리면 cron이나 CI 검증에도 쓸 수 있습니다. 작업 단위로 예외를 격리하므로, 한 데이터셋이 실패해도 나머지는 계속됩니다.

6. 셀프-텔레메트리 — 카탈로그가 자기 AI를 거버넌스한다

마지막 퍼즐 조각이 가장 흥미롭습니다. serve 모드 어시스턴트는 자기 자신을 카탈로그의 AI Agent 레지스트리에 등록하고, 채팅마다 호출 지표(지연·토큰·성공 여부)를 push합니다. "카탈로그가 자기 AI 어시스턴트마저 거버넌스 대상으로 삼는다"는 발상입니다.

자기등록은 프로세스당 1회, idempotent하게. 첫 채팅에서 사용자 토큰을 확보한 뒤 레지스트리에 자신을 등록합니다. 이미 등록돼 있으면(409) 정상으로 보고 넘어갑니다.

def _registration_payload(self, tool_names: list[str]) -> dict:
    return {
        "name": self.name,
        "display_name": "Argus Catalog 어시스턴트",
        "description": "카탈로그 도구를 호출해 근거 기반으로 답하는 tool-use 채팅 어시스턴트.",
        "base_model": self.model,
        "model_provider": self.provider,       # llm_url 로 추정 (ollama/openai/...)
        "protocol": "sse", "streaming": True,
        "pii_handling": "read-only", "hitl_required": False,
        "capabilities": tool_names,            # 노출한 도구 9종
        "use_cases": ["메타데이터 Q&A", "Text-to-SQL", "품질·리니지 설명", "표준 용어 준수 점검"],
    }

페이로드가 곧 어시스턴트의 자기소개입니다 — 어떤 모델을 쓰고, 어떤 프로토콜로 통신하며, PII를 읽기 전용으로만 다루고, 어떤 도구를 가졌는지를 레지스트리가 그대로 기록합니다.

적재는 채팅 1건마다. 서버 핸들러가 채팅을 끝낼 때 지연·토큰·성공 여부를 /ai-agents/{name}/invocations로 보냅니다.

telemetry.record(
    token, tool_names=tool_names, status=status,
    latency_ms=int((time.monotonic() - started) * 1000),
    tokens_in=tokens_in, tokens_out=tokens_out, session_id=conv_id,
)

이 지표는 레지스트리의 미터링/평판 화면에 반영됩니다. 운영자는 어시스턴트가 얼마나 빠른지, 토큰을 얼마나 쓰는지, 실패율이 어떤지를 다른 등록 Agent와 나란히 봅니다.

7. 베스트에포트 — 텔레메트리가 채팅을 막지 않는다

핵심 설계 원칙은 텔레메트리는 절대 채팅을 방해하지 않는다입니다. 모든 네트워크 작업은 베스트에포트로, 실패하면 경고만 남기고 무시합니다.

def record(self, token, *, status, latency_ms, tokens_in, tokens_out, ...) -> None:
    """채팅 1건의 호출 텔레메트리를 push — 베스트에포트(예외를 던지지 않음)."""
    if not self.enabled or not token:
        return
    try:
        self._ensure_registered(token, tool_names)
        self._post(token, f"/ai-agents/{self.name}/invocations", {...})
    except (urllib.error.URLError, OSError) as e:
        logger.warning("텔레메트리 적재 연결 실패: %s — 무시", e)

레지스트리가 없는 환경에서도 어시스턴트는 정상 동작합니다 — 등록에 한 번 실패하면 이 프로세스에선 텔레메트리를 꺼 버리고, 채팅은 그대로 흘러갑니다. 권한 역시 사용자 토큰을 그대로 쓰므로 별도 관리자 계정이 필요 없습니다. AGENT_TELEMETRY=off로 아예 끌 수도 있습니다.

시리즈를 마치며

다섯 편에 걸쳐 Argus Catalog Agent를 해부했습니다.

  1. 아키텍처 — 의존성 0, 세 가지 실행 모드
  2. LLM 레이어 — OpenAI 호환 하나로 모든 백엔드 통합
  3. 도구 — 읽기 전용 9종, 권한 위임, 자가검증
  4. SSE 통신·표시 — 단일 이벤트 규약, 실시간 tool_call UI
  5. 거버넌스 — 제안 워크플로, PII 안전장치, 셀프-텔레메트리

관통하는 철학은 분명합니다. AI는 생성하되 사람이 승인하고, 모든 것이 표준 위에서 가볍게 동작하며, 에이전트조차 거버넌스 대상이 된다. 데이터 카탈로그에 AI를 붙이려는 팀이라면, 이 다섯 가지 원칙이 좋은 출발점이 되리라 믿습니다.