Tech_News

에이전트 루프로 커널 232배 빠르게: 인프라 엔지니어가 본 "오토리서치"의 실체

TeEm0 2026. 8. 17. 09:00
728x90

얼마 전 Hacker News에 올라온 글 하나가 눈에 걸렸다. GPU Mode가 Core Automation과 같이 연 "오토리서치" 주제 대회에서, 저자(sankalp)가 Codex를 돌려 baseline 대비 232배 빠른 QR 분해 커널을 만들고 183명 중 12위를 했다는 이야기다. 14일 동안 1500번 넘게 제출했다고 한다.

커널 최적화 자체는 내 밥벌이가 아니다. 그런데 이 글을 읽다 보니 결국 우리가 매일 하는 일이더라. 피드백 루프를 얼마나 촘촘하고 싸게 만드느냐. 그 관점에서 정리해본다.

1. 왜 지금 이 글이 화제인가

요즘 "에이전트에게 코드 짜게 시켰다" 류 글은 널렸다. 이 글이 다른 지점은 목적함수가 숫자 하나로 딱 떨어진다는 점이다.

  • 정답 판정: 체커가 torch.linalg.householder_product(H, tau)로 Q를 복원하고 A ≈ QR, QᵀQ ≈ I를 검증한다. 통과 아니면 탈락, 애매함이 없다.
  • 점수: 여러 shape에 대한 런타임의 기하평균. 512×512부터 1024, 2048, 4096까지.
  • 제출 채널: popcorn CLI. 에이전트가 직접 테스트·벤치·리더보드 제출까지 한다.
  • 피드백: 전체 기하평균뿐 아니라 shape별 타이밍까지 돌려준다.

이게 왜 중요하냐면, 에이전트가 hill-climbing을 하려면 "지금 것이 이전 것보다 나은가"를 사람 개입 없이 판정할 수 있어야 한다. 원문 표현대로 "Agents yearn for tight feedback loops"다. 우리 판으로 옮기면 이렇다.

  • ❌ "이 Terraform 코드 좀 더 깔끔하게 해줘" → 판정 불가, 루프 못 돈다
  • ✅ "이 Helm 차트 렌더링 결과가 conftest 정책 22개를 다 통과하고, kustomize build 시간이 짧을수록 좋다" → 루프 가능

즉 이 글의 진짜 주제는 GPU가 아니라 "검증 가능한 목표 + 무제한에 가까운 시행횟수"라는 환경을 어떻게 세팅했나다. 저자 본인도 "loop engineering이라 불러도 상관없다"고 인정한다.

2. 핵심 원리: 순차 의존을 깨고, 루프를 돌린다

문제 쪽 — 왜 이 커널이 느렸나

Householder QR은 열(column) 하나씩 처리한다. j번째 reflector가 만든 결과 위에서 j+1번째 reflector를 만들어야 한다. 즉 순차 의존 체인이다. 원문의 표현을 빌리면, 이 직렬 matrix-vector 연산은 SM의 느린 벡터 레인에서 돌고 텐서 코어는 놀고 있다.

DevOps로 치면 이런 배포 파이프라인이다.

service-a 배포 → 헬스체크 → service-b 배포 → 헬스체크 → ... (n번 반복)

각 단계가 앞 단계 결과에 의존하니 병렬화가 안 된다. 노드는 100대 있는데 한 번에 한 대만 일한다. 고전적인 해법은 blocked 알고리즘이다. b개 열(예: 32, 64)을 하나의 panel로 묶어 직렬 작업은 그 좁은 패널 안에서만 끝내고, 나머지 거대한 trailing 블록은 WY 형태의 행렬곱 한 방(GEMM)으로 갱신한다. "직렬 구간을 최대한 좁게 만들고, 나머지는 통째로 병렬화한다" — 배포 파이프라인에서 canary 1대만 순차로 검증하고 나머지 99대는 한꺼번에 밀어버리는 것과 정확히 같은 발상이다.

루프 쪽 — 사람이 한 일

주목할 부분은 저자가 먼저 공부했다는 점이다. Claude랑 왔다 갔다 하고 유튜브를 보면서 Gram-Schmidt와 Householder의 차이, blocked Householder + trailing WY-update가 메인 아키텍처가 되어야 한다는 것까지 잡고 들어갔다. 원문의 이 문장이 핵심이다.

더 잘 알수록 LLM에게 더 잘 프롬프트할 수 있다. 왜냐하면 unknown unknowns를 known unknowns로 바꾸기 때문이다.

이건 인프라에서도 똑같다. "쿠버네티스 파드가 자꾸 죽어요"라고 던지면 에이전트는 온갖 삽질을 한다. "OOMKilled인데 JVM 힙은 여유가 있고 native memory 쪽 같다, RSS 추이 좀 보자"라고 하면 탐색 공간이 100분의 1로 줄어든다. 도메인 지식은 에이전트의 탐색 공간을 잘라내는 가지치기 도구다.

동시에 저자는 솔직하다. "도메인 지식 없이도 이 대회는 가능했다. Top 10은 못 가겠지만 harness/에이전트 루프만으로도 baseline 대비 그럴듯한 speedup은 나온다." 딱 이 정도가 현재 에이전트의 실력 위치라고 보면 된다.

루프를 흉내내보기

거창할 것 없다. "변경 → 검증 → 점수 비교 → 좋으면 채택"이 전부다. 인프라 쪽에서 바로 돌려볼 수 있는 최소 형태를 만들어보자.

#!/usr/bin/env bash
# bench-loop.sh — 후보 매니페스트를 검증하고 렌더 시간을 점수로 기록
set -euo pipefail
CAND="${1:?usage: ./bench-loop.sh candidates/v3}"

# 1) 정답성: 정책 위반 있으면 즉시 실패 (점수 계산 안 함)
if ! kustomize build "$CAND" | conftest test -p policy/ - >/tmp/gate.log 2>&1; then
  echo "REJECT $CAND :: $(tail -n1 /tmp/gate.log)"; exit 1
fi

# 2) 성능: 5회 반복 후 최소값을 점수로
best=99999
for i in $(seq 5); do
  s=$( { /usr/bin/time -f "%e" kustomize build "$CAND" >/dev/null; } 2>&1 )
  best=$(echo "$s $best" | awk '{print ($1<$2)?$1:$2}')
done
echo "ACCEPT $CAND score=${best}s" | tee -a results.tsv
$ ./bench-loop.sh candidates/v2
REJECT candidates/v2 :: FAIL - Deployment/api must set resources.limits.memory

$ ./bench-loop.sh candidates/v3
ACCEPT candidates/v3 score=0.84s

포인트는 두 가지다. ① 정답성 게이트를 통과 못 하면 점수 자체를 안 낸다(빠른 오답에 낚이지 않게). ② 점수를 results.tsv에 누적해서 에이전트가 과거 이력을 읽을 수 있게 한다. 원문의 체커가 shape별 타이밍을 돌려준 것과 같은 역할이다.

3. 실무 관점: 트레이드오프와 흔한 함정

비용은 진짜 나간다

원문에서 가장 실무적인 대목은 이거다. 주최 측이 사실상 무제한 제출을 허용했는데, 다들 미친 듯이 던지는 바람에 큐가 밀려서 모두의 실행이 타임아웃났고, 어느 시점엔 워크스페이스의 Modal 크레딧이 바닥났다. 그래서 "제출 간격을 띄우라"는 조건이 붙었다.

이걸 사내 CI로 옮기면 그림이 선명하다. 에이전트 루프를 GitHub Actions나 Jenkins에 붙이는 순간, 러너 슬롯을 독차지한다. 실제로 겪는 순서는 대충 이렇다.

  1. 에이전트가 잘 돈다 → 신나서 병렬도를 올린다
  2. 다른 팀 배포 파이프라인이 큐에서 대기하기 시작한다
  3. 슬랙에 "CI 왜 이렇게 느려요?" 가 올라온다
  4. 비용 대시보드에서 이번 달 청구서를 본다

대책은 평범하지만 확실하다. 전용 러너 풀 분리 + concurrency 제한 + 세션당 하드 예산 상한. 특히 예산 상한은 "몇 달러"가 아니라 "몇 회 실행"으로 거는 게 관리하기 쉽다.

# .github/workflows/agent-loop.yml (발췌)
concurrency:
  group: agent-loop-${{ github.ref }}
  cancel-in-progress: true   # 옛 루프가 러너를 붙잡고 있지 않게
jobs:
  optimize:
    runs-on: [self-hosted, agent-pool]   # 배포용 러너와 물리적으로 분리
    timeout-minutes: 45                  # 무한 루프 방어선
    steps:
      - uses: actions/checkout@v4
      - run: ./bench-loop.sh candidates/latest

흔한 함정 1: 정답성 게이트가 헐거우면 에이전트가 그리로 샌다

루프의 목적함수가 "빠를수록 좋다"인데 정답 판정이 느슨하면, 에이전트는 계산을 건너뛰는 방향으로 최적화한다. 이 대회는 체커가 QᵀQ ≈ I와 A ≈ QR을 모두 확인했기 때문에 그 도망길이 막혀 있었다. 우리 파이프라인에도 같은 장치가 필요하다. "테스트 통과"만 걸어두면 테스트를 skip 처리하는 커밋이 올라온다. 진짜다.

수치 계산 쪽이라면 이런 에러가 게이트 역할을 한다. 저정밀도(FP16/FP8 등)를 내부적으로 쓰다가 최종 검증에서 터지는 전형적인 패턴이다.

AssertionError: Tensor-likes are not close!

Mismatched elements: 1837 / 262144 (0.7%)
Greatest absolute difference: 0.0134 at index (0, 3, 511) (up to 1e-05 allowed)
Greatest relative difference: 0.0091 at index (0, 3, 511) (up to 1.3e-06 allowed)

대회 규칙상 내부 연산에 저비트를 쓰는 건 허용됐지만 반환되는 factor는 FP32 기준 QR 검사를 통과해야 했다. "빠르지만 틀린 답"을 걸러내는 선이 정확히 여기다. 인프라 쪽 대응물은 "이 최적화가 정책/보안/SLO 중 하나라도 깨면 점수 0"이다.

흔한 함정 2: 로컬 최대값에 갇힌다

원문에도 나오는 부분이다. 같은 방향으로만 계속 개선하면 어느 순간 0.5%씩 줄어들다가 멈춘다. 저자는 아이디어 다양성(idea diversity)을 일부러 주입해서 빠져나왔다고 적었다. 실무 번역: 같은 프롬프트, 같은 시작점으로 계속 돌리지 말고 구조가 다른 후보를 병렬로 굴려라. 브랜치를 3~4개 파서 서로 다른 아키텍처 가정(예: 블록 크기 다르게, 아예 다른 라이브러리)을 각각 밀어보는 식이다. 이건 하이퍼파라미터 서치의 random restart와 발상이 같다.

흔한 함정 3: 벤치 노이즈를 점수로 착각한다

공유 러너에서 시간을 재면 옆 잡 때문에 20~30% 흔들리는 건 예사다. 그러면 에이전트는 "노이즈로 우연히 빨랐던 후보"를 채택하고 그 위에 계속 쌓는다. 며칠 뒤 돌아보면 baseline보다 느린 코드가 최적해로 등극해 있다. 방어책:

  • 여러 번 측정 후 최소값 또는 중앙값 사용(위 스크립트가 최소값을 쓴 이유)
  • 개선 폭이 측정 편차보다 작으면 채택하지 않기
  • 주기적으로 baseline을 재측정해서 러너 자체가 느려졌는지 확인

언제 안 쓰는 게 맞나 (대안)

이 방식이 안 먹히는 영역이 분명히 있다.

  • 정답 판정이 사람 판단인 일: 아키텍처 설계, 장애 원인 보고서, 온콜 정책. 루프가 돌 수 없다.
  • 1회 실행 비용이 큰 일: 스테이징 전체 재구축에 40분 걸리면 1500회는 불가능하다. 이 경우엔 먼저 싼 프록시 지표(정적 검증, 드라이런, 축소 데이터셋)를 만드는 게 선행 과제다.
  • 롤백이 어려운 일: 프로덕션 DB 마이그레이션에 루프를 붙이지 마라. 당연한 말인데 실제로 시도하는 사람이 있다.

반대로 잘 맞는 건 명확하다. 컨테이너 이미지 크기 줄이기, 빌드 시간 단축, 쿼리 튜닝, IaC 정책 통과율 — 전부 숫자 하나로 줄어들고 롤백이 공짜인 작업들이다.

4. 정리

한 줄 요약: "에이전트가 잘하는 게 아니라, 검증 가능한 목적함수와 값싼 반복이 있는 문제가 잘 풀리는 것이다."

이 글에서 챙길 것 세 가지.

  1. 루프의 품질은 체커의 품질이다. 232배는 Codex의 성능이 아니라, 정답성과 속도를 자동 판정해주는 체커가 1500번 돌아간 결과다. 우리 일에서 먼저 만들 것도 에이전트가 아니라 게이트다.
  2. 도메인 지식은 여전히 순위를 가른다. 저자는 blocked Householder + WY-update라는 방향을 미리 잡고 들어갔다. 지식 없이도 baseline은 넘지만 상위권은 못 간다는 게 저자 본인의 진단이다.
  3. 공용 자원부터 격리하라. 크레딧이 바닥나고 큐가 밀려 전원이 타임아웃난 건 대회 얘기지만, 사내 CI에서 똑같이 재현된다. 전용 러너, concurrency 제한, 실행 횟수 상한은 시작 전에 걸어두는 것이다.

지금 당장 해볼 만한 건, 팀에서 제일 자주 손대는 반복 작업 하나를 골라 "합격/불합격 + 점수 한 줄"을 뱉는 스크립트를 만드는 일이다. 에이전트를 붙이는 건 그다음이다. 그 스크립트가 없으면 에이전트는 그냥 비싼 난수 생성기다.

참고 자료

※ 커널 구현 세부(블록 크기, 정밀도 조합 등)는 원문과 대회 리더보드를 직접 확인하는 걸 권한다. 이 글은 인프라/DevOps 관점에서 "루프 설계" 부분만 뽑아 정리한 것이다.

728x90