# AI가 한 일을 셀 수 있게 만들기 — 커밋 시그니처부터 LLM 판정까지

"우리 팀 AI 도입했어요."

요즘 어느 개발 조직을 만나도 듣는 말이다. 그런데 바로 다음 질문에 숫자로 답하는 조직은 거의 없다.

**"그래서, 효과가 있었나요?"**

체감은 다들 말한다. "리뷰가 빨라진 것 같아요", "반복 업무가 줄었어요". 하지만 데이터 조직의 리더로서 나는 이 대답이 불편했다. 우리는 서비스 지표는 소수점까지 재면서, 정작 개발 조직 자신의 가장 큰 변화는 감(感)으로 이야기하고 있었다.

그래서 팀에 LLM 에이전트를 도입하면서 한 가지 원칙을 같이 세웠다. **측정할 수 없으면 도입했다고 말하지 않는다.** 이 글은 그 원칙을 지키기 위해 만든 측정 인프라의 설계와, 반년 운영에서 배운 것들의 기록이다.

## 문제: "AI가 한 일"은 기본적으로 셀 수 없다

측정을 시작하려고 보면 곧바로 벽에 부딪힌다. AI가 만든 커밋과 사람이 만든 커밋은 git 히스토리에서 구분되지 않는다. AI가 초안을 잡고 사람이 다듬은 PR은 누구의 것인가? 사람이 시켰지만 AI가 알아서 처리한 이슈는?

설문으로 풀 수는 없다. 설문은 한 번뿐이고, 기억은 부정확하며, 무엇보다 지속 가능하지 않다. 우리가 원한 건 대시보드에 매일 쌓이는 숫자였다.

정리하면 요구사항은 세 가지였다.

1. **결정적(deterministic)일 것** — 사람의 기억이나 성실함에 의존하면 반드시 누락된다
2. **수준을 구분할 것** — "AI를 썼다/안 썼다"의 이진 구분은 정보량이 없다
3. **기존 워크플로우를 바꾸지 않을 것** — 측정 때문에 개발이 느려지면 본말전도다

## 설계: 결정적 신호 + 확률적 판정의 2층 구조

우리의 답은 두 층으로 나누는 것이었다. **아래층은 기계가 자동으로 남기는 결정적 신호, 위층은 그 신호를 해석하는 판정 파이프라인.**

### 1층 — 모든 산출물에 지워지지 않는 시그니처를 남긴다

AI가 관여한 모든 산출물에는 생성 시점에 추적 신호가 박힌다.

**커밋**에는 trailer를 남긴다:

```
Co-Authored-By: Claude <model> <noreply@anthropic.com>
AI-Run-ID: <세션 추적값>
AI-Skill: <어떤 자동화 스킬이 만들었는지>
```

핵심은 **이걸 사람이 쓰지 않는다**는 점이다. git의 `prepare-commit-msg` 훅이 AI 도구의 환경변수를 감지해 자동으로 붙인다. 사람은 아무것도 기억할 필요가 없고, 일반 터미널에서의 커밋에는 아무 영향이 없다. "기억"을 시스템으로 대체하는 것 — 이 원칙은 이후 모든 설계에서 반복된다.

**PR**에는 CI가 라벨을 붙인다. PR이 열리면 재사용 워크플로우가 커밋 메시지를 grep해서 AI 시그니처가 있으면 `ai-authored` 라벨을 자동 부착한다. 신규 저장소도 얇은 caller 워크플로우 하나만 추가하면 측정망에 편입된다.

**문서(위키)**에도 같은 신호를 남긴다. AI가 생성·개편한 페이지에는 라벨과 기계 조회용 property, 그리고 하단에 요청자·모델·세션 ID가 담긴 시그니처 박스가 들어간다.

여기서 운영하며 얻은 교훈 하나. 처음에는 PR 본문에만 신호를 남겼는데, **squash merge가 되면 신호가 유실**됐다. 측정 신호는 반드시 canonical source(git 히스토리 자체)에 박아야 한다. 부가 메타데이터는 언제든 압축·요약 과정에서 사라진다.

### 2층 — 기여 "수준"을 분류한다

신호가 쌓이면 다음 질문이 온다. AI가 얼마나 관여했는가? 우리는 세 단계로 정의했다.

| 수준 | 정의 | 예시 |
|------|------|------|
| **lv1** | AI 초안 + 사람이 검토·완성 | AI가 이슈를 분류·안내하고 사람이 처리 |
| **lv2** | AI가 대부분 실행, 사람은 결정만 | AI가 PR을 만들고 사람이 리뷰·머지 |
| **lv3** | AI 자율 수행, 사람 개입 0 | 자동 분류→자동 답변→자동 종료 |

분류 자체도 최대한 자동화했다. 이슈를 AI 봇이 분류하는 순간 lv1이 붙고, 그 이슈에 AI 시그니처가 있는 PR이 연결되는 순간 **lv2로 자동 승격**된다. 해결된 이슈는 주기적으로 LLM 판정 파이프라인이 다시 읽어 lv3(완전 자율) 여부를 판정한다.

이 분류 체계에서 중요했던 설계 결정 두 가지:

**첫째, 라벨은 exclusive하게 — 정확히 하나만.** lv1과 lv2가 동시에 붙어 있으면 집계가 오염된다. 승격 시 기존 라벨을 원자적으로 제거한다.

**둘째, 수준은 상승 방향으로만 움직인다.** LLM 판정이 "이건 사실 AI 기여가 아니었다"고 판단해도 강등하지 않는다. 판정 자체가 확률적이기 때문에 양방향으로 움직이게 하면 측정값이 진동하며 노이즈가 된다. 대신 확신이 낮은 케이스는 `unknown` 라벨을 붙여 **사람의 분기 결산 검증 큐**로 보낸다. 확률적 판정은 반드시 사람 검증의 안전망과 짝을 이뤄야 한다.

## 운영에서 배운 것들

반년을 돌리면서 시스템은 예상 못 한 방식으로 우리를 가르쳤다.

**1. 자동화의 부작용은 자동화로 잡는다.** 초기에 PR 본문에 언급된 이슈 키를 자동으로 "해결됨" 처리하는 로직이 있었는데, *참조*로만 적은 이슈가 잘못 닫히는 사고가 났다. 참조와 산출물을 구분하도록 파서를 고치고, 회귀 테스트를 박았다. 측정 인프라도 프로덕션이다 — 같은 엄격함으로 다뤄야 한다.

**2. 예외 케이스가 지표를 왜곡한다.** 봇이 만드는 릴리스 PR, 이슈가 구조적으로 없는 브랜치들이 검증 게이트에 걸려 자동화 전체를 막았다. 예외 규칙을 명시적으로 정의해 통과시키되, 어떤 예외가 얼마나 발생하는지도 같이 집계했다. 침묵하는 예외가 가장 위험하다.

**3. 측정이 문화를 바꾼다 — 이게 진짜 수확이다.** "전후를 실측한다"가 기본값이 되자, 팀의 다른 업무에도 번졌다. 자동 분류 봇의 효과를 주장할 때 도입 전후 리드타임을 실측해 비교했고, 데이터 이관 때는 이론 처리량과 실측 처리량을 대조했다. 측정 인프라의 최종 산출물은 숫자가 아니라 **"측정 없이는 주장하지 않는" 팀**이었다.

## 반년의 숫자

그래서, 효과가 있었나? 이제 우리는 숫자로 답한다. 도입 반년 기준:

- **AI 작성 머지 PR 수백 건** — 사람이 리뷰하고 머지한, 프로덕션에 들어간 코드
- **AI가 실행을 주도한 업무 1,000건 이상** (lv2 이상)
- **외부 데이터 요청 처리 리드타임 약 5분의 1로 단축** — 자동 분류·안내 도입 전후 실측
- 리더인 나 자신도 반년에 수백 건의 PR — 18년차 조직장이 다시 코드베이스 한가운데서 일하게 됐다

이 숫자들의 가치는 크기가 아니라 **출처**에 있다. 전부 시스템이 자동으로 남긴 신호에서 집계됐고, 언제든 같은 쿼리로 재현된다.

## 시작하려는 팀에게: 최소 구성 3가지

거창한 플랫폼이 필요한 게 아니다. 오늘 시작한다면 이 세 가지면 된다.

1. **커밋 trailer 자동화** — `prepare-commit-msg` 훅 하나. AI 도구 환경변수를 감지해 `Co-Authored-By` trailer를 붙인다. 30분이면 만든다.
2. **PR 라벨 CI** — 커밋에서 시그니처를 grep해 라벨을 붙이는 워크플로우. 조직의 reusable workflow로 만들면 저장소마다 3줄짜리 caller만 추가하면 된다.
3. **수준 정의 문서** — lv1/lv2/lv3가 무엇인지 팀이 합의한 한 페이지. 자동화는 그다음이다.

측정은 감시가 아니다. 우리 팀에서 이 숫자는 한 번도 개인 평가에 쓰인 적이 없다. 이 숫자가 답하는 질문은 하나다 — **"우리가 도입한 이 변화는, 정말로 효과가 있는가?"** 그 질문에 데이터로 답할 수 있게 되는 순간, AI 도입은 유행이 아니라 엔지니어링이 된다.
