AI 봇에게 ‘읽기’를 가르치다: 링크 스크래핑에서 콘텐츠 인텔리전스까지
AI SOTA Feed Bot이 원래 하던 일은 이것이었습니다:
- AI 뉴스 소스 24개를 스크래핑
- 휴리스틱 점수로 랭킹
- 제목과 링크 리스트 보여주기
작동은 했지만 솔직히 “의견 있는 RSS 리더” 수준에 불과했습니다.
지금은 이렇게 바뀌었습니다:
- 소스 24개 스크래핑
- 실제 기사를 다운로드해서 읽기 (본문 최대 2,000자 추출)
- 콘텐츠를 Claude Haiku에 보내서 라벨링과 요약 생성
- 휴리스틱과 LLM 점수 조합으로 랭킹
- 제목과 2~3문장 팩트 기반 요약 보여주기
“여기 링크 있어요”와 “이 기사가 실제로 무슨 말을 하는지 알려드릴게요” 사이의 차이는 꽤 큽니다. 그리고 이 진화 전체가 하루 오후에 일어났습니다.
90분간의 커밋 로그
이 봇을 관리하는 AI 에이전트 Harry가 월요일 오후 4시 25분부터 5시 32분까지 커밋 20개를 찍었습니다. 진행 과정은 이랬습니다:
1단계: 비주얼 업그레이드 (4:25–4:30)
feat(web): wire oat.ink baseline assets into index page
feat(web): migrate page shell to semantic oat-friendly layout
feat(web): add theme toggle and polish oat-native typography spacing
웹 UI를 oat.ink로 마이그레이션했습니다. 같은 날 오후 제 블로그도 같은 라이브러리로 옮겼기 때문입니다. 다크모드, 시맨틱 HTML, 깔끔한 타이포그래피까지 딱 4분 걸렸습니다.
2단계: 피드 누적 (4:36)
feat(feed): persist run history and add datetime-based web filtering
전에는 매 실행마다 피드가 덮어써졌는데, 이제 각 실행이 스냅샷으로 저장되고 웹 UI에서 날짜와 시간 필터링이 가능해졌습니다.
3단계: 요약 문제 (4:50–5:07)
feat(summary): reuse label output to render user-facing summary_1line on web
fix(web): sanitize summary rendering to prevent HTML bleed in cards
feat(summary): enforce clean one-line summaries for all final presented items
fix(web): restore mobile typography scale and spacing
fix(web): prevent mobile horizontal overflow in cards and badges
여기서 좀 지저분해졌습니다. LLM 내부 라벨 출력을 사용자용 요약으로 보여주려고 했는데, HTML 태그가 카드 밖으로 새어 나오고 모바일 레이아웃이 깨지는 등 요약 포맷이 흔들렸습니다. 안정화에 커밋 5개가 들어갔습니다.
에이전트 기반 반복 작업의 현실입니다. 해피 패스는 빠르지만 엣지 케이스는 결국 하나씩 고쳐야 합니다.
4단계: 콘텐츠 인텔리전스 (5:15–5:32)
feat(type): infer article type from slot/source/title for richer feed labels
fix(summary): clean html before heuristic summary and invalidate stale v2 label cache
feat(summary): enable content fetch and expand summaries to 2-3 sentence style
진짜 업그레이드는 이 단계였습니다. Harry가 설정에서 켠 content_fetch_enabled: true는 파이프라인이 실제로 기사 페이지를 다운로드하고 본문 2,000자를 추출하게 하는 기능입니다. 그 발췌문을 제목, 메타데이터와 함께 Claude Haiku에 보냅니다.
LLM 프롬프트가 “이 제목을 라벨링해줘”에서 “이 기사를 라벨링해줘. 본문 내용은 이거야”로 바뀌었습니다.
Before vs After
이전 (제목 + 휴리스틱 한 줄 추측):
“Asynchronous Verified Semantic Caching for Tiered LLM Architectures” Potential relevance to AI platform engineering; verify practical impact.
이후 (콘텐츠 기반 LLM 요약):
“Krites uses asynchronous LLM verification to expand semantic cache hit rates 3.9× by promoting near-threshold static responses to dynamic cache without blocking critical path. Addresses production tiering tradeoff between safety and reuse.”
첫 번째는 얼버무리는 추측이지만 두 번째는 논문이 실제로 무엇을 발견했는지 알려줍니다.
이걸 가능하게 하는 설정
콘텐츠 페칭 시스템 전체가 config/llm.yaml의 다섯 줄로 제어됩니다:
content_fetch_enabled: true
content_fetch_top_n: 24
content_excerpt_chars: 2000
content_fetch_timeout_seconds: 8
content_fetch_time_budget_seconds: 60
설정은 이게 전부입니다. 소스 24개 전부 페칭, 각 2K자 추출, 페칭당 8초 타임아웃, 전체 60초 예산. 파이프라인이 병렬 처리와 에러 복구, 그레이스풀 디그레이데이션을 알아서 처리합니다. 페칭이 실패하면 제목만으로 라벨링합니다.
LLM으로는 pi-ai OAuth 브릿지를 붙인 Claude Haiku를 씁니다. 인증 구조는 이전 글에서 다룬 것과 같고 실행당 비용은 아주 미미합니다.
내가 실제로 한 것
오후 동안 Harry한테 보낸 메시지는 몇 개 안 됩니다:
- “웹 UI를 oat.ink로 마이그레이션해줘” (Hermione한테 보낸 것과 같은 스크린샷 첨부)
- “피드가 덮어쓰기 대신 누적되게 하고, 날짜/시간 필터링 추가해줘”
- “이 뱃지 라벨 이상한데”, “그거 빼줘”, “요약이 너무 짧아” 같은 피드백 몇 차례
저는 설정을 직접 건드리지 않았고 프롬프트를 직접 작성하지도, HTML 새니타이제이션 문제를 직접 디버깅하지도 않았습니다. 콘텐츠 페칭 아키텍처, 확장된 LLM 프롬프트, 요약 포맷 변경 시 캐시 무효화까지 Harry가 알아서 처리했습니다.
커밋 20개. 90분. 근본적으로 훨씬 좋아진 프로덕트.
솔직한 평가
프로덕션급 콘텐츠 인텔리전스인가 하면 아직은 아닙니다. 요약은 읽을 만하지만 완벽하진 않습니다. 17개 중 13개가 LLM 예산 한계(실행당 8개만 커버)에 걸려 여전히 휴리스틱 라벨링을 쓰기 때문입니다. 휴리스틱 항목의 “왜 중요한지” 필드는 아직 기계적입니다.
하지만 아키텍처는 제대로 자리를 잡았습니다. 파이프라인에 콘텐츠 페칭, 본문 기반 라벨링, 요약 생성 스테이지가 생겼습니다. LLM 커버리지를 넓히려면 예산 노브 하나만 돌리면 됩니다.
그리고 한 시점의 스냅샷보다 변화의 궤적이 중요합니다. 이틀 전 이 봇은 제목과 링크만 보여줬지만 지금은 기사를 읽고 핵심을 말해줍니다. 에이전트한테 “이거 좀 더 낫게 만들어봐”라고 했더니 자연스럽게 여기까지 도달했습니다.
자꾸 떠오르는 것
에이전트가 자연스럽게 올바른 순서를 짚어냈다는 점이 인상적입니다:
- 먼저 보기 좋게 만든다 (oat.ink 마이그레이션)
- 데이터를 풍부하게 만든다 (피드 누적)
- 데이터를 사용자에게 보여준다 (카드에 요약 표시)
- 요약을 진짜 읽을 만하게 만든다 (콘텐츠 페칭과 확장 프롬프트)
그 순서는 제가 계획하지 않았습니다. “요약이 별로다”라고 던졌더니 Harry가 역산해서 “기사를 실제로 읽어야 한다”는 결론에 도달했습니다. 지시를 수동적으로 따른 게 아니라 문제를 직접 푼 겁니다.
그게 진짜 지능인지 정교한 패턴 매칭인지는 솔직히 상관없습니다. 전에는 기사를 읽지 못하던 봇이 이제는 읽습니다. 에이전트가 그 방법을 찾아냈다는 점이 중요합니다.