AI 이것저것

[번역] 검증 루프 닫기: 에이전트로 소프트웨어를 만들기 위한 관측가능성 기반 하네스

mindol 2026. 6. 5. 10:40
검증 루프 닫기: 에이전트 기반 개발을 위한 관측가능성 하네스
Datadog 블로그 · AI

검증 루프 닫기: 에이전트로 소프트웨어를 만들기 위한 관측가능성 기반 하네스

저자: Alp Keles, Jai Menon, Sesh Nalla, Vyom Shah 게시일: 2026년 3월 9일 분량: 약 12분 원문 보기 ↗
이 문서는 원문을 문장 단위로 그대로 옮긴 완역이 아니라, 모든 섹션의 핵심 내용을 한국어로 정리한 해설본입니다. 원문의 그림 8개와 검증 피라미드 표는 Datadog 서버의 원본을 그대로 참조합니다(인터넷 연결 시 표시). 정확한 표현·전체 맥락은 위의 원문 링크를 함께 참고하시기 바랍니다.
대표 이미지
원문 대표 이미지

AI 에이전트는 이제 어떤 팀이 검증할 수 있는 속도보다 빠르게 소프트웨어를 만들어 냅니다. 병목은 "코드를 작성하는 일"에서 "작성된 코드를 신뢰하는 일"로 옮겨갔습니다.

저자들은 이 변화가 새로운 일은 아니라고 봅니다. 과거 프로그래머들이 컴파일러를 거부했던 시기가 있었고, 손으로 짠 어셈블리가 더 나은 경우도 실제로 있었습니다. 컴파일러가 신뢰를 얻은 이유는 번역 대상 언어의 의미가 정밀하게 정의돼 있었기 때문입니다. 즉 프로그래머가 "무엇을" 할지 정의하면, "어떻게" 구현할지는 컴파일러에 맡길 수 있었습니다. 자동화는 언제나 검증과 짝을 이룰 때에만 신뢰를 얻었다는 것이 핵심 관찰입니다.

AI 에이전트는 컴파일러보다 신뢰를 쌓기가 더 어렵습니다. 에이전트는 제약 없는 자연어를(때로는 신뢰할 수 없는 출처에서) 입력받아 실행 가능한 코드로 변환하기 때문입니다. 따라서 이 새로운 "프로그램 합성 엔진"의 출력을 검증할 새로운 방법이 필요합니다.

하네스 우선 엔지니어링(harness-first engineering)

Datadog은 이 지점을 기회로 봅니다. "바이브 코딩(vibe-coding)"이 "묻지마 배포(yolo-deploy)"로 번지지 않게 막는 것입니다. 접근법은 하네스 우선 엔지니어링입니다. 에이전트가 생성한 코드를 한 줄씩 읽는 대신, 코드가 올바른지 수 초 내에 높은 신뢰도로 알려주는 자동 검사 체계에 투자하는 방식입니다.

흐름은 다음과 같습니다. 에이전트가 코드를 생성하고, 하네스가 검증하며, 프로덕션 텔레메트리가 실제 동작을 확인합니다. 무언가 잘못되면 그 피드백이 하네스를 갱신하고, 에이전트는 다시 시도합니다. 하네스를 만드는 구체적 방법은 결정론적 시뮬레이션 테스트, 형식 명세, 섀도 평가, 관측가능성 기반 피드백 루프 등으로 엄밀성이 제각각이지만, 원칙은 같습니다. 검증을 빠르고 자동적으로 만들어, 사람의 리뷰로는 감당할 수 없는 일을 하네스가 대신하게 한다는 것입니다.

이 방향의 토대는 지난 1년간 쌓아온 BitsEvolve입니다. LLM이 이끄는 진화형 최적화 도구로, 프로덕션 기반 피드백 루프로 진화된 코드의 정확성을 유지합니다. 라이브 트래픽으로 검증한 성과로는 핵심 데이터 수집 함수에서 10배, 민감정보 스캐닝용 DeBERTa 인코더에서 1.53배, 시계열 예측 모델 Toto에서 1.57배의 속도 향상이 있었습니다. 여기서 얻은 교훈은 하네스가 충분히 견고하면 LLM이 자유롭게 탐색해도 결과가 유지된다는 점입니다. 좋은 하네스는 반복을 값싸게 만들고, 약한 하네스는 더 좋은 모델이나 더 많은 사람 리뷰로도 보완할 수 없습니다.

2025년 후반, 모델 역량이 급격히 도약하는 것이 관측됐습니다. 그 전까지 BitsEvolve는 파일·함수 단위에서 동작했지만, 이제 하네스 우선 접근을 시스템 전체 규모로 밀어붙이면 어떻게 될지 묻기 시작했습니다. 이 글은 그 시리즈의 첫 편으로, 두 프로젝트를 다룹니다. 방법론을 시행착오로 배운 redis-rust와, 그것을 정교화한 Kafka 호환 스트리밍 엔진 Helix입니다.

두 사례 모두에서 하네스는 정확성의 1차 원천으로서 코드 리뷰를 대체할 만큼 강력했습니다. redis-rust는 에이전트 주도 반복 끝에 프로덕션에 준하는 스테이징에서 비슷한 레이턴시와 메모리 87% 절감에 도달했고, Helix는 수백만 회의 결정론적 시뮬레이션을 견디며 Kafka 의미 보장을 해치지 않은 채 디스크 최대 처리량의 약 93%를 달성했습니다. 패턴은 일관됐습니다. 불변식(invariant)이 명시적으로 정의되고 지속적으로 검사되는 순간, 에이전트는 사람이 리뷰할 수 있는 속도보다 안전하게 더 빨리 움직일 수 있었습니다.


redis-rust: 방법론을 배우다

redis-rust는 코딩 에이전트로 완전한 시스템을 만들어본 첫 시도였습니다. 단일 에이전트(Claude Code + Opus 4.5)로 진행했고, 코드베이스가 커지는 과정에서 문제를 발견하며 배우는 방식이었습니다.

아키텍처(샤드별 액터 설계, CRDT 등)를 두고 몇 시간 주고받자 에이전트는 동작하는 Redis 호환 서버를 만들어 냈습니다. 컴파일되고 테스트도 통과했지만, 처음에는 잡아낼 인프라가 없어 놓친 미묘한 오류가 많았습니다. 오류 메시지가 Redis 호환성에서 벗어나 그럴듯하지만 틀린 방향으로 흘렀고, 에이전트는 추상화를 과하게 설계하는 경향도 보였습니다(이후 단순화).

그래서 검증 단계를 한 겹씩 쌓아 올렸습니다. 각 계층은 그 아래 계층이 놓친 무언가에서 출발했습니다.

  • 섀도 상태 오라클(shadow-state oracle): 실제 실행기 옆에서 단순 HashMap을 함께 돌려, 매 연산 후 응답을 비교했습니다. 기본적인 의미 버그는 잡았지만 타이밍 의존 경로는 다루지 못했습니다.
  • 결정론적 시뮬레이션 테스트(DST) + 결함 주입(fault injection)을 추가했습니다.
  • DST에는 검사할 불변식이 필요했고, 이를 위해 복제·가십 프로토콜에 대한 TLA+ 명세를 작성했습니다.
  • CRDT 병합 속성에는 수학적 보장이 필요해, Rust 검증 도구 Kani로 유계 증명(bounded proof)을 추가했습니다.
  • 시스템 수준 정확성을 위해 분산 시스템 테스트 프레임워크 Maelstrom과 선형화 가능성 검사기 Knossos를 1·3·5 노드에서 실행했고, 구현된 명령에 대해 공식 Redis Tcl 호환성 스위트도 돌렸습니다.

다음 단계는 실제 트래픽을 이용한 경험적 검증이었습니다. Redis 샤드 클러스터를 데이터/컨트롤 플레인 API 뒤에서 운영하는 내부 캐싱 시스템 Ephemera를 활용해, redis-rust 섀도 클러스터가 Redis 8.4 대조군과 동일한 워크로드를 받도록 구성했습니다.

결과

Datadog 인터페이스인 pup을 사용해, 에이전트는 redis-rust가 스테이징에서 정상 동작하며 레이턴시 차이가 미미함을 확인했습니다.

Redis 8.4와 redis-rust의 레이턴시 비교
그림 1. redis-rust의 초기 레이턴시 프로파일은 Redis와 견줄 만한 수준이었습니다.

다만 메모리는 Redis 8.4보다 8배 많이 썼습니다. 시작 시 512 × 8KB 버퍼(4MB)를 미리 할당하도록 하드코딩된 점 등 특정 마이크로 벤치마크에 최적화돼 있었기 때문입니다. 몇 분 만에 에이전트는 세 가지 최적화를 제안·구현해 메모리 사용량을 87% 절감했습니다.

redis-rust와 Redis 8.4의 시간별 메모리 사용량
그림 2. 메트릭을 피드백으로 삼아 진행된 에이전트의 메모리 사용량 최적화.

이후로도 메모리·네트워크·레이턴시 메트릭과 CPU 프로파일을 활용해 성능 튜닝을 이어간다고 밝혔습니다.


Helix: 하네스 안에서 개선하다

Helix는 오브젝트 스토리지 위에서 동작하는 Kafka 유사 스트리밍 서비스로, redis-rust에서 배운 것을 토대로 코딩 에이전트를 사용해 만든 또 하나의 완전한 시스템입니다. 이번에는 여러 코딩 에이전트(주로 Claude Code와 Codex)를 함께 사용했습니다.

작업 방식은 제약 우선(constraint-first)이었습니다. 설계 산출물이 곧 계약(contract)이고, 의미는 명시적으로 기술하며(10년 넘게 Kafka를 운영한 경험 반영), 모든 산출물은 실수를 반증할 수 있는 검증 피라미드의 피드백 메커니즘과 결합됩니다.

검증 피라미드(verification pyramid)

각 계층은 속도와 엄밀성을 맞바꿉니다.

계층도구소요 시간신뢰 수준
상징적(Symbolic)TLA+ 명세2분 읽기이해(Understanding)
주력(Primary)DST약 5초높음(High)
전수(Exhaustive)모델 검사 (Stateright)30–60초증명(Proof)
유계(Bounded)유계 검증 (Kani)약 60초증명(유계)
경험적(Empirical)텔레메트리 + 벤치마크수 초–수 분실측 근거(Ground truth)
검증 피라미드 다이어그램
그림 3. 공유 불변식이 TLA+ 명세에서 Stateright, DST, Kani, 스테이징 텔레메트리로 흘러가며, DST가 주력 검증 계층 역할을 합니다.

코드보다 계약이 먼저(contracts before code)

핵심 불변식(복제 로그 + 오브젝트 스토리지, 파티션 모델, 장애 경계, Kafka 호환성)을 먼저 기술한 뒤, 에이전트가 각 하위 시스템을 독립적으로 설계하게 했습니다. Raft(TLA+로 검증), 쓰기 선행 로그(WAL), 티어링, DST, 서비스 계층, Kafka 와이어 프로토콜 등입니다. 에이전트는 시스템의 의미를 임의로 지어내서는 안 됩니다. 무엇이 "내구성 보장(durable)"이고 무엇이 "확인 응답(acknowledged)"인가, 무엇이 "커밋됨"이고 무엇이 "가시화됨"인가, 각 경계에서 크래시가 나면 어떻게 되는가를 명확히 정의해야 합니다.

AntithesisAWS는 이를 "준형식적 방법(semi-formal methods)"이라 부릅니다. 검사할 수 있을 만큼 명시적이면서, 지속적으로 돌릴 수 있을 만큼 값싼 명세와 불변식을 말합니다. 이 작업의 부담은 코드 작성 자체의 대략 2~3배이지만, 곧바로 본전을 뽑습니다. 명시적 불변식 덕분에 에이전트의 매 반복이 주관적 판단이 아니라 객관적인 통과/실패 판정으로 바뀌기 때문입니다.

DST가 주력입니다. FoundationDB와 TigerBeetle이 널리 알린 기법으로, 물리적 시간을 추상화하고 실행을 결정론적으로 만들며 결함을 합성적으로 주입합니다. 한 번 실행에 약 5초가 걸리고, 결함 주입이 포함된 무작위 시나리오를 통해 실제 프로덕션 코드를 검사합니다.

TLA+ 명세는 지도를 제공합니다. 구현 코드에서 추출하려면 몇 시간이 걸릴 상태 변수, 액션, 불변식을 정의합니다. 이를 아키텍처 결정 기록(ADR)에서 생성해 모호함을 일찍 잡아냅니다. 더 강한 보장이 필요할 때 모델 검사와 Kani가 단계적으로 개입하고, 텔레메트리가 모든 것을 경험적으로 뒷받침합니다. 어떤 가설을 반증할 수 있는 가장 가벼운 수단을 먼저 사용한다는 원칙입니다.

ADR에서 TLA+ 명세, 불변식 검사로 이어지는 워크플로우 다이어그램
그림 4. 아키텍처 결정 기록(ADR)이 TLA+ 명세를 생성하고, 이 명세가 정의한 불변식이 Stateright·DST·Kani·스테이징 텔레메트리에서 재사용되어 검증 계층 간 정합성을 유지합니다.

DST 피드백 루프

초기 에이전트 구현은 컴파일되고 단위 테스트도 통과했지만 엄밀성이 부족했습니다. 결정론적 검증을 위해 전수 속성 검사, 명시적 불변식, 네트워크·디스크·노드 수준의 구성 가능한 결함 주입을 추가했습니다. 동시 연산이 서로 간섭할 수 있는 구간을 의도적으로 넓히는 BUGGIFY 기법도 사용했습니다.

여기에 속성 기반 테스트(property-based testing)를 결합했습니다. 변성 속성(metamorphic), 왕복 속성(예: decompress(compress(bytes)) == bytes), 차등 테스트(differential testing) 등으로, 이들은 GCC에서 수백 개의 버그를 찾아냈고 AWS Cedar 검증에도 쓰인 기법입니다.

목표는 컴포넌트당 DST 시드 500개였습니다. 결정론적 시드는 실패를 재현 가능하게 만듭니다. 에이전트는 정확히 같은 시퀀스를 재생해 불변식 위반을 일으킨 코드 줄까지 추적할 수 있습니다.

DST가 잡아낸 버그 사례

WAL에서 디스크 동기화(sync)보다 메모리 내 절단(truncation)이 먼저 일어나는 버그가 있었습니다. 디스크 결함이 주입되면 해당 세그먼트는 재시도되지 않아 데이터 손실이 발생했습니다. 해결책은 카피 온 라이트(copy-on-write)였습니다. 시뮬레이션이 가리키고 나면 명백하지만, 리뷰로는 놓치기 쉬운 버그입니다. 이런 버그는 특정 결함 타이밍에서만 나타나 단위 테스트로는 발견되지 않고, 코드 리뷰로는 운이 좋아야 잡힙니다. DST는 이를 수 초 내에 결정론적으로 잡아냈습니다.

컴포넌트당 500시드를 통과한 뒤에는 모든 컴포넌트에 걸쳐 1,000만 시드로 확장했고, 이어 Kafka 의미 불변식을 적용한 시스템 수준 통합으로 나아갔습니다. 즉 확인 응답된 모든 메시지는 소비 가능해야 하고, 컨슈머 오프셋은 단조 증가해야 하며, 리더십 변경이 쓰기를 잃어선 안 된다는 규칙입니다.

성능: 안전망을 갖춘 언덕 오르기(hill-climbing)

redis-rust와 Helix 모두에서 정확성이 고정되자, 성능 작업은 통제된 언덕 오르기가 됐습니다. 에이전트가 최적화를 제안하면 전체 DST 스위트를 돌리고, 테스트를 통과하면 처리량을 측정해 변경을 유지하며, 실패하면 되돌립니다. 실제로 redis-rust에서는 에이전트가 프로파일링 데이터를 근거로 CPU 최적화를 찾았으나 단일 노드 선형화 가능성 테스트를 깨뜨린 사례가 있었습니다(되돌림).

Helix에서는 제로카피 핸들러와 경합 제거로 시작해, 이후 Raft 파이프라이닝, 버퍼드 WAL, 종국에는 액터 기반 아키텍처라는 더 큰 변경을 제안했습니다. 액터 기반 설계로의 전환은 사람의 결정이었습니다. 하루 뒤, 전체 DST 체계를 여전히 통과하면서 디스크 최대 처리량의 약 93%(fio로 측정)에 도달했습니다.

사람은 실제로 무엇을 했는가

두 프로젝트 모두에서 사람의 역할은 좁지만 결정적이었습니다. 시스템 아이디어와 불변식을 정의하고, DST 하네스를 검토·강화하며, 측정 가능한 목표를 세우고, 아키텍처 변경을 승인하는 일입니다. 그 외의 모든 것 — 설계 초안 작성, 컴포넌트 구현, DST 실패 수정, 처리량 최적화 — 은 하네스를 상대로 에이전트가 수행했습니다.

결과

Helix를 사내 스트리밍 컨트롤 플레인과 함께 스테이징에 통합했습니다. Helix 배포에 약간의 설정 추가만으로, 스트리밍 플랫폼 클라이언트가 Helix를 상대로 투명하게 produce·consume할 수 있었습니다.

내부 스트리밍 추상화 뒤에서 Kafka 대체로 동작하는 Helix
그림 5. 내부 스트리밍 추상화 뒤에서 Kafka 호환 대체재로 동작하는 Helix.

여기서 더 나아가, 단일 Helix 클러스터(3노드 Raft 그룹)로 초당 약 1만 건의 프로파일링 데이터 스트림을 저장·서빙하여 스테이징의 APM 프로파일링을 구동했습니다.

스테이징 환경에서 APM 프로파일링 스트림을 서빙하는 모습
그림 6. 스테이징 환경에서 APM 프로파일링 데이터 스트림을 서빙하는 단일 Helix 클러스터.

이 프로파일링 워크로드에서 produce 레이턴시가 크게 개선됐습니다. 스트리밍 플랫폼 클라이언트 기준으로 Helix에 produce할 때 평균 22.2ms로, 기준 Kafka 클러스터의 116ms 대비 큰 차이를 보였습니다.

Helix와 Kafka의 APM 프로파일링 스트림 produce 레이턴시(p50) 비교
그림 7. APM 프로파일링 스트림에 대한 produce 레이턴시(p50) 비교 — Helix 대 기준 Kafka 클러스터.

확장성 역전(scalability inversion)

Helix는 코드 리뷰를 1차 검증 수단으로 삼아서는 만들 수 없었을 것입니다. 에이전트가 너무 많은 반복을, 너무 빠르게 만들어 냈기 때문입니다.

확장성과 엄밀성으로 본 검증 방법 순위 다이어그램
그림 8. 확장성과 엄밀성으로 본 검증 방법들. 코딩 에이전트가 형식적 방법과 코드 리뷰 사이의 전통적 트레이드오프를 어떻게 역전시키는지를 보여 줍니다.

에이전트 이전에는 코드 리뷰가 가장 확장성 있는 검증 방법이었습니다. 모든 팀이 이미 하고 있으니까요. 반대로 형식 검증은 가장 확장성이 낮아, 실패의 대가가 큰 안전 필수(safety-critical) 시스템에서만 정당화되곤 했습니다.

그러나 코딩 에이전트가 등장하면서 경제성이 역전됩니다. LLM이 반복 루프의 일부로 TLA+ 명세를 생성하고, DST 하네스를 작성하며, Kani 증명을 돌릴 수 있게 되면서, 과거 수개월짜리 투자였던 것이 자동화된 파이프라인 단계로 바뀝니다.

리뷰가 무용해진 것은 아닙니다. 다만 사람의 역할이 이동합니다. 다른 공학 분야가 성숙한 방식과 같습니다. 교량 기술자는 하중 시험을 갖추자 리벳 하나하나를 검사하기를 멈췄고, 야금학자는 분광기를 얻자 배치마다 눈으로 확인하기를 멈췄습니다. 전문성은 출력을 검사하는 일에서 검사 자체를 설계하는 일로 옮겨갑니다.

이 방식으로 만든 모든 프로젝트에서, 에이전트가 만든 모든 diff를 검토하는 데 쓸 시간을 차라리 하네스를 강화하는 데(불변식 강화, 시뮬레이션 커버리지 확대, 텔레메트리 피드백 루프 연결) 쓰는 편이 나았습니다.

하네스는 코드 리뷰가 할 수 없는 방식으로 복리처럼 쌓입니다. 추가한 불변식 하나하나가 눈앞의 diff뿐 아니라 앞으로의 모든 반복에서 한 부류의 버그 전체를 잡아냅니다. 하네스가 있으면 코드 리뷰는 블룸 필터처럼, 즉 빠른 관문이지 정확성의 원천은 아니게 됩니다. 리뷰어가 읽는 것은 diff가 아니라 하네스의 출력입니다. 어떤 불변식이 통과했고, 어떤 시드가 검사됐으며, 어떤 텔레메트리가 확인됐는지를 봅니다. 코드를 읽는다기보다 EXPLAIN ANALYZE를 읽는 일에 가깝습니다.

Helix, redis-rust, 그리고 일부는 30만 줄에 이른 더 큰 실험들까지도, 여전히 사람을 루프 안에 두었습니다. 사람이 하네스를 설계하고, 목표를 세우고, 아키텍처를 승인했으며, 에이전트는 그것을 상대로 반복했습니다.


이것이 향하는 곳

속성을 자동으로 검증할 수 있는 곳(테스트·증명·시뮬레이션·측정을 통해)이라면, 더 많은 책임을 에이전트에 위임할 수 있습니다. 그럴 수 없는 곳에서는 사람이 루프에 남습니다. 저자들은 이 경계를 검증 프런티어(verification frontier)라 부릅니다.

당연한 반론은 "하네스 자체가 틀리면 어떻게 되는가"입니다. 불완전한 불변식은 잘못된 동작에 대한 자동화된 확신을 낳을 수 있습니다. 바로 이 지점에서 관측가능성이 루프를 닫습니다. 프로덕션 텔레메트리(메트릭·로그·트레이스·트래젝터리)가 검증 파이프라인으로 되먹임되어, 모델링된 동작과 실제 실행 사이의 불일치를 드러내고 하네스를 점진적으로 개선하게 합니다. 관측가능성이 없으면 루프는 닫히지 않습니다.

형식적 방법의 가치는 도구 자체가 아니라, 정밀하고 기계로 검사 가능하며 모호하지 않은 제약을 표현하는 규율에 있습니다. 에이전트가 생성하는 속성 테스트, 배포 시 섀도 평가, 프로덕션 동작을 검증하는 텔레메트리는 모두 서로 다른 계층에서 이뤄지는 불변식 추론의 표현입니다. 에이전트와 함께 달라지는 점은, 이 모든 메커니즘을 만들고 반복하기가 훨씬 쉬워졌다는 것입니다. 저자들의 조언은 실패의 비용에 비례해 하네스에 투자하라는 것입니다.

하네스가 루프를 닫기 위해 관측가능성에 의존할 때, 관측가능성 플랫폼은 에이전트가 만든 소프트웨어의 제어 계층(control layer)이 됩니다. 모범 사례는 아직 쓰이지 않았고, 진행하면서 발견해 가는 중입니다.

이어지는 2편에서는 정확성 오라클, 성능 벤치마크, 안전 샌드박스가 모두 자동화되어 사람이 루프에서 완전히 빠지는 시스템인 Unicron × BitsEvolve를 다룹니다.