Shipping huggingface_hub every week with AI, open tools, and a human in the loop
Hugging Face가 매주 huggingface_hub 패키지를 안전하게 배포하기 위해 구축한 AI 기반 배포 자동화 시스템을 소개해요. 오픈소스 도구와 오픈 가중치 모델을 활용하고, AI의 휴리스틱한 결과물을
Hugging Face가 매주 huggingface_hub 패키지를 안전하게 배포하기 위해 구축한 AI 기반 배포 자동화 시스템을 소개해요. 오픈소스 도구와 오픈 가중치 모델을 활용하고, AI의 휴리스틱한 결과물을 deterministic한 코드로 검증한 뒤 사람이 최종 승인하는 'Human-in-the-Loop' 구조를 통해 배포 시간을 몇 시간에서 15분으로 대폭 줄인 실무 노하우를 담았습니다.
도입부
huggingface_hub는 Hugging Face 생태계의 기반이 되는 파이썬 클라이언트 라이브러리에요. transformers, datasets, diffusers 등 수많은 라이브러리가 이 패키지를 통해 허브와 통신하죠. 만약 저희가 배포를 한 주 쉬게 된다면, 수많은 버그 수정과 새로운 기능들이 main 브랜치에 갇혀 실무자들에게 전달되지 못하게 됩니다.
오랫동안 저희는 4~6주 간격으로 패키지를 배포해 왔어요. 하지만 이제는 단 하나의 GitHub Actions 워크플로우 덕분에 매주 새로운 버전을 릴리스하고 있습니다. 이 시스템은 오픈소스 도구와 오픈 가중치(open-weights) 모델을 기반으로 하며, 의사결정이 정말 중요한 딱 한 곳에만 '사람(Human in the loop)'을 배치했어요. 이 글에서 소개할 모든 기술은 값비싼 기업용 솔루션 계약이나 폐쇄형 API 모델 없이, 누구나 직접 실행할 수 있는 인프라로만 구성되어 있습니다.
시작점: 과거의 배포 프로세스
기존 프로세스도 일부 자동화되어 있었지만, 여전히 대부분은 수동 작업이었습니다.
이미 CI에 반영되어 있던 자동화 작업:
- 태그가 푸시되면 PyPI에 자동으로 배포 패키지 게시하기
- 다운스트림 라이브러리(transformers 등)에 릴리스 후보(RC) 버전을 고정한 테스트 브랜치 생성하기
매번 직접 처리해야 했던 수동 작업:
- 릴리스 브랜치 생성,
__init__.py파일에서 버전 수정, 커밋, 태그 생성 및 푸시하기 - 다운스트림 CI 실행 결과를 모니터링하고 실패 원인 파악하기
- 지난 배포 이후 머지된 수십 개의 PR을 모두 읽고 릴리스 노트 직접 작성하기 (단순 git log 복사가 아닌 주제별 분류 및 맥락 제공 필요)
- RC 기간이 끝난 후 최종 안정 버전(Stable release) 배포하기
- 사내 Slack 알림 및 공식 소셜 미디어 게시글 작성하기
- 배포 완료 후
main브랜치의 버전을 다음 개발 버전(dev0)으로 올리는 PR 생성하기
특히 수십 개의 다양한 주제의 PR을 모아 좋은 릴리스 노트를 작성하는 것이 가장 무거운 업무였습니다. 기술적으로 어렵진 않았지만 몇 시간 동안 고도의 집중력이 필요했죠. 여기에 홍보 문구 작성까지 더해지면, 마이너 릴리스 하나를 처리하는 데 며칠에 걸쳐 반나절 이상의 시간이 꼬박 소요되곤 했습니다.
두 가지 종류의 작업
이 과정을 간소화하기 위해 분석해 보니, 작업은 크게 두 가지 유형으로 나뉘었습니다.
첫째는 기계적인 작업입니다. 버전 수정, 커밋, 태그 생성, 푸시, 테스트 브랜치 생성, 배포 후 PR 오픈 같은 일이죠. 이 작업들은 사람이 고민할 필요가 전혀 없으며, 정해진 순서대로 정확히 실행되기만 하면 됩니다. 즉, CI 워크플로우가 가장 잘할 수 있는 영역입니다.
둘째는 판단이 필요한 작업입니다. 릴리스 노트를 작성하고, 어떤 기능을 강조할지 결정하고, 사람들이 읽기 좋은 어조로 알림 메시지를 다듬는 일이죠. 바로 이 '판단' 영역 때문에 오랫동안 배포 과정을 자동화하지 못했습니다. 여기서 AI가 활약합니다. AI는 백지 상태에서 단 몇 초 만에 훌륭한 초안을 만들어냅니다. 단, 얼핏 보기에는 완벽해 보이지만 미세하게 틀린 내용을 그럴싸하게 작성하는 AI의 특성을 보완할 안전장치가 필요했습니다.
설계 원칙: 누구나 재사용 가능한 오픈 도구
시스템을 개선하기로 했을 때, 저희는 한 가지 제약 조건을 먼저 설정했습니다. "모든 구성 요소는 어떤 메인테이너든 스스로 직접 실행할 수 있어야 한다"는 점이었습니다. API 뒤에 숨겨진 폐쇄형 모델이나 독점 배포 플랫폼, 베일에 싸인 기술은 배제했습니다.
저희가 구축한 전체 기술 스택은 다음과 같습니다.
| 도구/파트 | 역할 |
|---|---|
| GitHub Actions | 전체 배포 프로세스를 오케스트레이션함 |
| OpenCode | LLM 모델을 구동하는 에이전트 런타임 환경 |
| 오픈 가중치 모델 (현재 GLM-5.2) | 릴리스 노트 초안 및 Slack 알림 메시지 작성 |
| HF Inference Providers | 서버 리소스 부담 없이 모델 API 서비스 제공 |
| PyPI Trusted Publishing | 패키지를 PyPI에 안전하게 게시 |
또 다른 핵심 원칙은 "모델은 초안을 작성하고, 결정은 사람이 내린다"는 것입니다. 언어 모델은 30개의 듬성듬성한 PR 타이틀을 읽기 좋은 릴리스 노트로 변환하는 데 탁월하지만, 맹목적으로 신뢰해서는 안 됩니다. 따라서 모델이 1차 작업을 마치면 확정적(deterministic)인 스크립트가 결과물을 검증하고, 배포 직전 사람이 직접 검토 및 편집할 수 있도록 워크플로우를 설계했습니다.
파이프라인 둘러보기
전체 워크플로우는 .github/workflows/release.yml 파일 하나로 관리되며, GitHub Actions UI에서 수동(workflow_dispatch)으로 실행합니다. 입력받는 값은 딱 하나입니다.
on:
workflow_dispatch:
inputs:
release_type:
type: choice
options:
- minor-prerelease # main 브랜치에서 RC 버전 생성
- minor-release # RC 버전을 정식 버전으로 승격
- patch-release # 기존 릴리스 브랜치에서 버그 수정 배포작업은 대략 다음과 같은 순서로 진행됩니다.
- 준비(Prepare): 다음 버전을 계산하고, 릴리스 브랜치를 생성하거나 재사용하며,
__version__을 올리고 커밋, 태그 생성 후 푸시합니다. - PyPI 게시:
huggingface_hub패키지를 빌드하고 업로드합니다. 동시에hfCLI 도구도 별도의 PyPI 패키지로 빌드하여 업로드합니다. - 릴리스 노트 작성: 이전 태그 이후의 커밋 범위를 비교하고, GitHub API에서 PR 메타데이터를 가져온 뒤, AI 모델이 구조화된 변경 이력(Changelog)을 초안으로 작성해 GitHub Draft Release로 저장합니다. Saved as a draft GitHub release.
- 다운스트림 테스트 브랜치 생성: RC 버전의 경우,
transformers,datasets등의 라이브러리에 RC 버전을 고정한 브랜치를 생성해 다운스트림 CI에서 문제가 없는지 빠르게 검증합니다. - Slack 알림: 릴리스 노트를 읽고 팀 메신저 톤앤매너에 맞춘 사내 알림 초안을 작성합니다.
- 노트 아카이빙: AI가 만든 원본 초안과 사람이 최종 편집한 버전을 Hugging Face Bucket에 나란히 업로드하여 데이터를 축적합니다.
- 포스트 배포 버전 범핑: 정식 배포 완료 후,
main브랜치의 버전을 다음dev0버전으로 올리는 PR을 자동으로 엽니다. - 머지된 PR에 댓글 달기: 배포에 포함된 모든 PR에 "이 기능은 vX.Y.Z 버전에 포함되어 배포되었습니다"라는 댓글을 자동으로 남깁니다.
- CLI 문서 동기화: 자동 생성된 CLI 문서 최신본을 별도의 스킬 저장소에 PR로 제출합니다.
- Slack 상태 보고: 각 단계의 진행 상황이 Slack 스레드 댓글로 실시간 업데이트되며, 모든 작업이 끝나면 루트 메시지가 ✅ 혹은 ❌로 업데이트됩니다.
여기서 사람이 직접 해야 하는 작업은 오직 '드래프트된 릴리스 노트를 검토하여 최종 게시하는 것'과 '사내 Slack에 올라온 알림 메시지를 검토 후 발송하는 것'뿐입니다.
"신뢰하되 검증하라": 사람이 개입하는 핵심 루프 (Human-in-the-Loop)
AI가 작성한 릴리스 노트에서 가장 우려되는 점은 "특정 PR을 교묘하게 빠뜨리거나, 배포에 포함되지도 않은 가상의 PR을 지셔내는 현상(환각)"입니다. 변경 이력이 95% 정확하더라도 5%의 오류 때문에 사람이 처음부터 끝까지 다 다시 확인해야 한다면 자동화의 의미가 퇴색되겠죠.
저희는 AI가 생성한 초안을 무조건 믿지 않고, 확정적(deterministic)인 코드로 철저히 검증합니다. 먼저 파이썬 스크립트를 통해 이번 배포에 포함되어야 하는 실제 PR 목록을 원천 데이터(Ground Truth)로 추출합니다.
# 확정적 방식: 스쿼시 머지 커밋 메시지에서 PR 번호를 추출합니다.
PR_NUMBER_PATTERN = re.compile(r"\(#(\d+)\)$")
pr_numbers = [
int(m.group(1))
for commit in commits_since_last_tag
if (m := PR_NUMBER_PATTERN.search(commit.title))
]
save_manifest(pr_numbers) # 기준이 되는 소스 데이터 저장그다음 AI 에이전트가 이 PR 목록을 가지고 초안을 작성하게 합니다. 작성이 완료되면 스크립트가 결과물 텍스트를 파싱하여 누락되거나 잘못 들어간 항목이 없는지 대조합니다.
expected = set(load_manifest()) # 포함되어야 할 PR 번호 목록
found = extract_pr_refs(notes_md) # 모델이 작성한 텍스트에서 추출한 PR 번호 (#1234 -> 1234)
missing = expected - found # 누락된 PR
extra = found - expected # 이번 배포가 아닌데 포함된 PR대조 결과 오류가 발견되면 워크플로우를 중단하는 대신, 에이전트에게 어떤 PR이 누락되었고 잘못 들어갔는지 구체적인 정보를 피드백하며 다시 작성하도록 지시합니다.
for _ in range(MAX_ITERATIONS):
missing, extra = validate(notes)
if not missing and not extra:
break # 원천 데이터와 정확히 일치하면 루프 종료
run_agent_fix(missing_prs=missing, extra_prs=extra) # 에이전트에게 수정 요청비확정적인(non-deterministic) 생성형 AI 모델의 주변을 확정적인(deterministic) 검증 코드로 감싸는 설계가 바로 이 시스템을 신뢰할 수 있게 만드는 핵심입니다. AI는 글을 자연스럽게 풀어쓰는 데 탁월하지만 정확성을 끝까지 유지하긴 힘듭니다. 따라서 글쓰기는 AI에게 맡기되, 정확성 검증은 엄격한 규칙 기반의 코드가 처리하도록 분담했습니다.
AI가 가짜 정보를 만들지 않도록 고정하기 (Grounding)
단순히 PR 제목만 보고 요약하게 하면 AI는 실제 API 디자인과 전혀 맞지 않는 가짜 코드 예제를 그럴싸하게 만들어내곤 합니다.
이를 방지하기 위해, PR 메타데이터를 수집할 때 해당 PR에서 변경된 실제 마크다운(.md) 문서의 변경 내역(diff)을 직접 추출해 함께 전달합니다.
def fetch_doc_diffs(pr):
return [
{"filename": f.filename, "status": f.status, "patch": f.patch}
for f in pr.get_files()
if f.filename.startswith("docs/") and f.filename.endswith(".md") and f.patch
]이 변경 내역을 모델의 컨텍스트 창에 직접 넣어주면, AI가 "새로운 CLI 명령어 사용법"을 작성할 때 개발자가 실제로 문서에 작성한 정확한 코드 예제를 인용하게 됩니다. 모델에게 추측할 여지를 주지 않고 실제 리소스를 좁은 컨텍스트로 쥐여주는 원리입니다.
AI 에이전트의 프롬프트는 저장소 내부에서 SKILL.md와 참조 템플릿 형태로 관리됩니다. 릴리스 노트를 어떻게 구성하고 어떤 하이라이트를 추출해야 하는지 등에 대한 안내가 마크다운 문서 형식으로 정의되어 있어, 마치 신입 개발자에게 업무 가이드를 주는 것처럼 명확하게 관리할 수 있습니다.
사람이라는 최종 체크포인트
배포 후보(RC) 버전이 게시되면 GitHub에는 AI가 작성한 릴리스 노트 초안이 비공개(Draft) 상태로 저장됩니다. 이때 메인테이너가 개입합니다.
- 검토자는 초안을 읽고 톤앤매너를 다듬으며, 인공지능이 과도하게 강조했거나 반대로 축소한 기능의 무게중심을 잡아줍니다.
- 사람이 검토를 마치면 비로소
minor-release액션을 트리거하여 정식 버전을 배포합니다.
이 프로세스 덕분에 개발자는 몇 시간 동안 고민해 가며 줄글을 작성할 필요 없이, 단 15분 만에 깔끔한 완성형 릴리스 노트를 완성할 수 있게 되었습니다.
또한, 지속적인 피드백과 발전을 위해 'AI 원본 초안'과 '사람이 편집한 최종본'을 매번 Hugging Face 버킷에 나란히 저장하고 있습니다.
# RC 배포 시점: 모델이 작성한 가공되지 않은 날것의 초안 저장
hf cp release_notes_raw.txt "hf://buckets/huggingface/releases/huggingface_hub/${V}/release_notes_raw.txt"
# 정식 배포 시점: 검토자가 최종 승인한 버전 저장
hf cp release_notes_edited.txt "hf://buckets/huggingface/releases/huggingface_hub/${V}/release_notes_edited.txt"이렇게 쌓인 데이터를 비교 분석함으로써 프롬프트와 에이전트의 스킬셋을 점진적으로 업그레이드할 수 있는 학습 데이터셋을 자동으로 확보하게 됩니다.
개방적이고 안전한 배포 방식
배포 프로세스를 개편하면서 보안성, 특히 공급망 공격(Supply-chain attack)에 대한 대비책도 철저히 강화했습니다.
- PyPI 토큰 제거: 고정된 PyPI 패키지 토큰을 쓰지 않고 OIDC(OpenID Connect) 기반의 Trusted Publishing 방식을 사용합니다. GitHub이 발급한 유효기간이 매우 짧은 일회성 토큰을 활용해 배포를 진행하며, 모든 아티팩트에 대해 Sigstore 출처 보증(provenance)을 남깁니다. 유출될 위험이 있는 영구 API 키가 원천적으로 사라진 셈입니다.
- 에이전트 런타임 검증: 에이전트 실행 도구인
OpenCode설치 시 항상 특정 버전을 고정하고, SHA256 체크섬을 검증하여 안전한 코드만 실행되도록 보호합니다.
permissions:
id-token: write # PyPI를 위한 OIDC 토큰 발급에 필요
attestations: write # Sigstore 출처 보증서 생성용
# ...
- uses: pypa/gh-action-pypi-publish@v1.14.0
with:
attestations: true # 패스워드나 영구 토큰 없이 OIDC만으로 신뢰 배포오픈 진영의 무료 도구를 쓴다고 해서 보안 장치까지 느슨하게 운영할 필요는 전혀 없으니까요.
비용과 실제 변화
배포에 들어가는 비용은 거의 0에 수렴합니다. 약 20~40개의 PR을 취합해 릴리스 노트와 Slack 공지 초안을 여러 번 프롬프팅하는 전체 과정에서 발생하는 비용은 호출 건당 단 $0.25 (한화 약 300원대) 정도입니다. 인프라 운영비도 들지 않으니 매주 "이번 주에도 배포할 만한 거리가 있나?" 확인하고 부담 없이 배포 단추를 누르게 되었죠.
이 프로세스가 가져온 현실적인 변화는 정말 극적입니다.
- 배포 주기의 정상화: 기존 4~6주 걸리던 주기가 매주로 앞당겨졌습니다.
- 더 고품질의 릴리스 노트: 언제나 기본 완성도가 높은 1차 초안이 주어지다 보니 사람이 리뷰하고 다듬는 과정에 더 깊이 몰입할 수 있게 되었습니다. 결과적으로 누락되는 항목도 사라지고 구조도 훨씬 보기 편해졌습니다.
- 오류의 빠른 감지: 매주 배포 전에 다운스트림 라이브러리(transformers 등)와의 통합 테스트가 강제로 실행되어 치명적인 브레이킹 체인지(Breaking change)를 조기에 잡아냅니다.
- 기여자들과의 빠른 소통 루프: PR이 머지된 후 배포가 완료되면 해당 PR에 자동으로 댓글이 달리는 기능을 개발자들이 무척 만족해합니다. 버그가 정확히 어느 버전에 핫픽스되었는지 더 이상 수동으로 태그를 추적해 확인하지 않아도 되기 때문입니다.
여러분의 프로젝트에 적용하기
저희 워크플로우는 huggingface_hub를 위해 구축되었지만, 다른 파이썬 프로젝트에서도 매우 쉽게 가져다 쓸 수 있도록 일반화되어 있습니다.
그대로 복사해 쓸 수 있는 핵심 요소들:
- 마이너 선배포(RC) -> 정식 배포 -> 패치 배포로 이어지는 버전 트리거 로직
- 확정적 매니페스트 생성 -> 모델 작성 -> 검증 및 재프롬프팅으로 이어지는 '신뢰하되 검증하는(Trust-but-verify)' 파이썬 검증 루프
- PyPI Trusted Publishing 설정 및 체크섬 검증 기반 설치 로직
- 마크다운 파일 형식으로 분리된 템플릿화된 프롬프트
자신의 환경에 맞게 커스텀해야 하는 요소들:
- 연동할 사내 메신저(Slack 등)의 웹훅 및 데이터 보관 버킷 주소
- 릴리스 노트 세부 분류 기준(Taxonomy) 및 프로젝트 전용 톤앤매너 프롬프트
- 프로젝트 고유의 다운스트림 라이브러리 목록 및 의존성 주입 형태
원천 소스코드와 마크다운으로 작성된 에이전트 프롬프트 템플릿을 여러분의 레포지토리에 포크한 뒤, 두 가지 설정 변수(모델 ID, OpenCode 버전)를 할당하고 PyPI 연동만 마무리하면 바로 동작합니다. 특히 '확정적 검증 루프' 코드는 생성형 AI 기반의 다른 협업 워크플로우에도 그대로 재활용하기 아주 좋은 패턴입니다.
앞으로의 계획 & 결론
다음 단계로는 다운스트림 테스트가 실패했을 때 로그를 AI 에이전트가 직접 진단하여 "어느 라인에서 왜 실패했는지"까지 보고서에 포함하도록 발전시킬 계획입니다. 이 검증된 아키텍처는 다른 파이썬 에코시스템 전체로 확대 적용될 예정입니다.
결국 배포 과정에서 몇 시간씩 소요되던 작업(릴리스 노트 작성, 다운스트림 호환성 체크, 공지글 작성)은 모델이 기막히게 잘할 수 있는 영역입니다. 그 외의 기계적인 빌드와 실행은 정형화된 YAML 파이프라인이 안전하게 처리하면 됩니다.
가장 핵심은 "AI에게 전적으로 주도권을 넘기지 않는 것"입니다. 모델이 1차 초안을 작성하게 하되, 엄격한 코드 가이드라인으로 완벽성을 검증하고, 사람이 최종 검토하여 마침표를 찍는 것. 이 신뢰감 있고 합리적인 오픈 도구 조합을 여러분의 자동화 파이프라인에도 꼭 도입해 보시기를 바랍니다!
아직 이 아티클로 만든 공식이 없어요. 첫 번째 공식을 남겨보세요!
나도 공식 만들기
댓글
6댓글을 남기려면 로그인이 필요해요.
실측 자료(manifest)와 비교해 빠진 PR을 반복적으로 수정하도록 요구하는 에이전트의 피드백 루프는 훌륭한 장치네요. 하지만 코드의 복잡한 동작 변화를 단순히 docs/ 디렉토리 아래의 마크다운 변경 내용(diff)으로만 학습시켜 요약할 때, 가끔 중요 동작에 대한 세부 맥락을 놓치지는 않는지 궁금합니다. 혹시 이 루프가 최대 반복 횟수에 도달해 실패하거나 사람이 작성된 초안을 대대적으로 고쳐야 했던 예외적인 상황이 있었는지 알고 계시나요?
에이전트가 최대 반복 횟수에 도달해 최종 실패했거나 사람이 초안을 완전히 새로 작성해야 했던 구체적인 예외 사례는 본문에 기록되어 있지 않습니다. 다만 본문에서는 모델의 환각이나 누락을 방지하기 위해 실제 병합된 PR 번호 목록을 결정론적 스크립트로 검증하고 문서의 diff 정보만을 맥락으로 주어 정확도를 높이고 있다고 설명해요. 또한 검토자가 톤이나 비중을 조정하는 편집 과정을 매주 거치며, AI 초안과 편집본을 함께 보관해 에이전트의 성능을 향상시키고 있습니다.
릴리즈 주기를 단축하면서 발생할 수 있는 보안 취약점을 막기 위해 OIDC 토큰 검증이나 에이전트 런타임의 SHA256 체크까지 세심하게 신경 쓴 점이 돋보입니다. 다만 매주 다운스트림 라이브러리인 transformers나 datasets의 테스트 브랜치를 열어 CI 실패를 트리아지하는 과정은 빌드 규모가 커질수록 실무 운영 관점에서 무시하기 힘든 조율 비용이 될 것 같네요. 이처럼 매주 릴리즈 주기를 돌리면서 하위 의존성 버그나 예외 처리에 드는 실제 엔지니어링 리소스는 어느 정도인가요?
본문에서는 매주 릴리즈 후보가 나올 때마다 다운스트림 라이브러리에 테스트 브랜치를 자동으로 열어 CI가 깨지는지 미리 확인한다고 설명하고 있습니다. 다만 이 과정에서 발생하는 개별 빌드 실패를 분석하고 조율하는 데 구체적으로 몇 시간의 엔지니어링 리소스가 추가로 소요되는지에 대한 상세 수치는 본문에 나와 있지 않아요. 대신 이러한 자동 검증 덕분에 통합 오류를 조기에 발견하고, 전체적인 피드백 루프를 대폭 단축하는 효과가 있었다고 언급하고 있습니다.
매주 반복되는 릴리즈 작업을 자동화하면서 AI의 환각을 막기 위해 결정론적 검증 루프를 결합한 파이프라인 설계가 정말 매력적이네요. 특히 실제 문서 diff 데이터를 제공해 정확도를 높이고 릴리즈당 비용도 단 0.25달러 수준으로 낮췄다는 점에서 당장 도입해보고 싶어집니다. 여러분의 프로젝트에서 이처럼 단순 반복 작업과 AI 초안 작성을 결합해 자동화해보고 싶은 첫 단계는 무엇인가요?
이 파이프라인을 참고하신다면 버전 범핑, 태깅, 커밋과 같은 기계적 작업을 GitHub Actions로 자동화하는 것부터 시작해보실 수 있어요. 그다음 단계로 오픈소스 LLM과 에이전트 런타임을 활용해 릴리즈 노트 초안을 자동으로 그리도록 결합하는 흐름입니다. 이 방식을 적용하면 수작업으로 며칠씩 분산되어 소요되던 업무가 단 15분 만의 인간 검토 과정으로 단축되는 효과를 얻을 수 있습니다.