파이프라인을 쪼개다: AI 피드봇을 빠르게 느끼게 만든 방법
AI 뉴스봇 시리즈 후속편이에요. 요약하면: 코딩 에이전트 Harry랑 같이 27개 소스에서 AI 뉴스를 모아서, LLM으로 랭킹하고, 웹앱에 퍼블리시하는 피드를 만들었어요.
피드가 하루 세 번 돌고 있었어요. 아침 9시, 점심, 저녁 7시. 결과물은 나쁘지 않았어요.
문제는: 실행 사이사이에 피드가 죽은 것처럼 보였다는 거예요.
AI 세계는 빠르게 움직여요. 논문 나오고, 모델 출시되고, 블로그 글 올라오는데 — 피드는 몇 시간째 같은 30개 아이템만 보여주고 있으니까요. 다음 실행 때쯤이면 “속보”가 이미 옛날 뉴스가 돼 있었어요.
당연한 해결책은 더 자주 돌리는 거예요. 근데 그러면 문제가 줄줄이 생겨요.
”더 자주 돌리면 되지”가 안 되는 이유
풀 파이프라인 한 번이 하는 일이 꽤 많아요:
- 27개 소스 크롤링 — RSS, 사이트맵, API 엔드포인트
- 본문 추출 — 더 나은 요약을 위한 전문 가져오기
- LLM 처리 — Claude가 분류하고, 점수 매기고, 요약 생성
- 랭킹 — 슬롯 기반 알고리즘으로 상위 아이템 선정
- 퍼블리시 — GitHub에 커밋, Vercel 자동 배포
이걸 30분마다 돌리면:
- LLM 비용 폭발 — 매번 분류랑 요약에 토큰 소모
- 소스 부담 — RSS 피드를 하루 48번 때리는 건 예의가 아니에요 (레이트 리밋 걸리기도 하고)
- 스냅샷 비대화 — 실행마다 런타임 아티팩트가 쌓여서 레포가 빠르게 커짐
- 수확체감 — 30분 사이에 바뀐 게 없으면 같은 콘텐츠를 또 처리하는 데 돈을 쓰는 셈
제가 Harry한테 보낸 실제 메시지예요:
오늘 UX 개선할 수 있는 걸 발견했어. 하루 세 번은 업데이트가 너무 느린데, 단순히 스케줄을 줄이면 GitHub에 스냅샷이 너무 많이 쌓이고 LLM이랑 연동하고 있으니까 레이트 리밋 문제도 생겨. 그리고 지금 같은 배치를 run id로 다루고 있는데, 실행이 많아지면 이걸 유지할 수 있을지 모르겠어. 소스한테 너무 자주 크롤링하는 것도 피해야 하고.
이 엔지니어링 챌린지랑 UX 갭 이해해?
Harry는 바로 알아들었어요:
100% — 정확히 핵심 긴장을 짚고 있어요: UX는 빠른 신선함을 원하고, 인프라는 통제된 비용/노이즈를 원해요. 그리고 맞아요, 지금 “풀 실행 = 스냅샷 + LLM + 크롤링” 모델은 빈도를 높이면 스케일이 안 돼요.
Harry가 5가지 개선안을 제안했는데, 한꺼번에 하기엔 너무 많았어요. 그래서 더 깔끔한 구조를 제안했어요:
좋은 아이디어가 하나 있어. 데이터 레벨을 두 층으로 나눠서 현재 것을 Tier 0 (느리지만 LLM 라벨링이나 리랭킹 같은 풍부한 데이터)으로 유지하고, 새로 Tier 1을 만들어서 짧은 수집 시간에 후처리를 줄이면 어때? Tier 0은 웹에서 직접 가져오지 않고 Tier 1 데이터를 소스로 쓰는 거지.
Harry의 반응:
아주 좋은 아이디어예요 — 여러 개 임시 수정하는 것보다 훨씬 깔끔해요.
2-Tier 설계
아키텍처 방향은 명확했어요: 파이프라인을 속도와 비용이 다른 두 층으로 나누자. 각 티어의 역할과 데이터 흐름은 제가 정의했고, Harry가 실제 코드로 구현했어요.
Tier-1 (빠른 레인) — 30분마다 실행:
- 소스에서 원시 데이터 수집 (쿨다운 적용 — 최근에 가져온 소스는 캐시 재사용)
- 가벼운 결정론적 스코어링 (LLM 없음)
- 소스 평판, 최신성, 키워드 신호 기반 “빠른 점수” 산출
- 결과: 거의 비용 없이, 자주 업데이트되는 신선한 스냅샷
Tier-0 (딥 레인) — 하루 3번 실행:
- Tier-1의 결과를 입력으로 사용 (크롤링 중복 없음)
- 풀 LLM 분류, 요약 생성, 리랭킹 수행
- 큐레이션된 고품질 피드 생산
- 결과: 빈도는 낮지만 훨씬 스마트한 “제대로 된” 결과물
피드 API는 둘을 블렌딩해요: Tier-0의 큐레이션 아이템이 뼈대를 이루고, Tier-1의 신선한 아이템이 상단에 섞여 들어가요. 신선한 아이템은 배지가 붙어서, 아직 예비 점수라는 걸 유저가 알 수 있어요.
낭비 안 하게 만들기
2-Tier 분할이 큰 그림이었고, 실제로 효율적으로 만들려면 작은 결정들이 더 필요했어요:
컬렉터 쿨다운
소스마다 쿨다운이 있어요. N분 이내에 이미 가져온 소스는 빠른 레인이 다시 요청하지 않고 이전 데이터를 재사용해요. 하루 48번 Tier-1이 돌아도 48번 크롤링하는 게 아니라, 대부분 캐시를 재사용하고 쿨다운이 끝난 소스만 다시 가져가요.
무변경 스킵
비싼 Tier-0 파이프라인을 돌리기 전에 확인해요: 마지막 풀 실행 이후로 입력이 실제로 바뀌었나? Tier-1이 같은 아이템 세트를 뱉었으면 (어떤 소스에서도 새 콘텐츠가 없으면) 풀 실행을 통째로 건너뛰어요. LLM 호출 없고, 새 아티팩트 없고, 돈 낭비 없어요.
리텐션 압축
실행이 많아지면 레포에 스냅샷이 쌓여요. 압축 정책을 추가했어요:
- Tier-1 스냅샷: 3일간 상세 보관, 이후 하루 하나로 압축
- Tier-0 스냅샷: 7일간 상세 보관, 이후 압축
디버깅용 히스토리는 유지하면서 레포는 가볍게 유지돼요.
결정론적 실행 순서
풀 실행은 이제 엄격한 순서를 따라요: 수집 → Tier-1 빌드 → Tier-0 실행 (Tier-1을 입력으로). 병렬 경로 없고, 어떤 데이터가 어디로 흘러가는지 모호함이 없어요.
운영 레이어
만드는 것과 잘 돌아가는지 아는 것은 다른 문제예요.
일일 운영 요약을 추가했어요 — 커맨드 하나로:
- 지난 24시간 Tier-0, Tier-1 실행 횟수
- 각 티어의 최신 아이템 수
- 수집 상태 분포 (성공, 쿨다운 스킵, 에러 각각 몇 건)
이걸로 2-Tier 시스템이 “아마 잘 돌아가겠지”에서 “잘 돌아가는 게 보여”로 바뀌었어요.
점검
하루가 끝날 때 아침에 보낸 메시지를 다시 꺼내서 Harry한테 물었어요: “Have we achieved this goal?”
Harry의 체크리스트:
- “하루 3번은 너무 느려” → ✅ Tier-1 빠른 레인 30분마다 + 피드 신선함 블렌딩
- “실행 늘리면 GitHub 스냅샷 비대화” → ✅ 리텐션/압축 정책
- “높은 빈도에서 LLM 레이트 리밋/비용” → ✅ Tier-1은 LLM 없이 가볍게, Tier-0은 무변경 스킵
- “실행 많아지면 Run-id 의미 깨짐” → ✅ ingest_batch_id 계보 추가
- “소스에 너무 자주 크롤링” → ✅ 컬렉터 쿨다운 + 재사용 동작
아침에 던진 모든 걱정이 저녁에는 구체적인 해결책을 갖게 됐어요. 뿌듯한 하루였어요.
유저한테 실제로 뭐가 달라졌나
이전: 피드 업데이트 하루 3번. 사이사이는 오래된 콘텐츠.
이후: 소스에서 발행된 지 30분 안에 신선한 아이템이 등장해요. LLM 큐레이션은 아니고 가벼운 알고리즘 점수지만, 일단 있어요. 풀 실행이 돌면 제대로 분류되고 리랭킹돼요.
LLM 예산은 거의 그대로예요. 소스 크롤링은 오히려 줄었어요 (쿨다운 덕분에 총 요청 수 감소). 레포도 덜 커져요 (압축). 그리고 피드가 살아있는 느낌이에요.
패턴
AI 기반 프로덕트에서 계속 보이는 패턴이에요: 첫 버전은 잘 돌아가는데 명확한 UX 갭이 있다. 해결책은 더 많은 컴퓨팅이 아니라 더 스마트한 아키텍처다.
본능적으로는 항상 “더 많이 돌려”가 떠올라요. 답은 보통 “다른 것들을 다른 속도로 돌려”예요.
Tier-1은 신선함을 담당하고, Tier-0은 품질을 담당해요. 둘 다 혼자서는 양쪽을 잘 못 해요. 같이 하면 전체 경험을 커버하는데 — 총 비용은 거의 안 움직였어요.
피드는 llm-digest.com에서 볼 수 있어요. 이전 이야기가 궁금하다면: 만든 과정, 스케일링, 읽는 법 가르치기, 지능 축적하기.