뉴스 요약 표를 정리하면서 “확인 불가” 대신 ”-“를 쓰기로 했는데, 정작 왜 날짜를 못 가져오는 기사가 이렇게 많은지는 그때 넘어갔었다. 이번엔 그 원인을 제대로 봤다.
날짜가 없는 게 아니라, 안 가져오고 있었다
크롤러 코드(crawler.py)를 보니, 기사 본문을 뽑아올 때 trafilatura라는 라이브러리를
쓰고 있었다.
text = trafilatura.extract(html, include_comments=False, include_tables=True)
이 함수는 본문 텍스트만 뽑아준다. 그러고 나면 LLM에게 이 본문 텍스트만 던져주고
“여기서 날짜 찾아봐”라고 시키는 구조였는데, 대부분의 언론사 사이트는 날짜를 기사
본문 문장 속에 안 적고 상단 메타 정보(바이라인, <time> 태그 등)에 따로 적어둔다.
본문만 떼어놓고 보면 날짜가 없는 게 당연했다.
그런데 trafilatura는 이런 메타데이터도 따로 뽑아주는 기능이 있다. 7월 9일 기사에서
날짜를 못 가져온 기사 4개를 직접 테스트해봤다.
meta = trafilatura.extract_metadata(html)
print(meta.date)
# 2026-07-08
4개 전부 정확한 날짜가 나왔다. 정보 자체는 사이트에 이미 있었고, 코드가 그냥 그 기능을 안 쓰고 있었을 뿐이었다.
왜 처음부터 이렇게 짜여 있었을까
이 파이프라인은 원래 지금 같은 모습이 아니었다. 맨 처음엔 파이썬 크롤링 라이브러리 같은 게 따로 없었고, Gemini한테 URL을 던져주면 LLM이 알아서 페이지를 읽고 요약까지 한 번에 처리하는 방식이었다. 그러다가 안정성과 비용 문제로, 이 과정을 파이썬 파이프라인으로 옮기는 작업을 AI 에이전트(Hermes)에게 맡겼다. 이 전환 과정 자체도 삽질이 꽤 많았고, 심지어 LLM한테 완전히 속아 넘어간 적도 있었다. 그건 따로 글로 정리할 생각이다.
그 리팩터링 과정에서 “기사 본문을 가져오는 기능”은 제대로 옮겨졌다. 근데 “본문 속에서 날짜도 같이 인식하던” 예전의 LLM-only 방식의 능력은 옮겨지지 않았다. 아마 그때 “본문 잘 가져오나”만 확인하고 넘어갔을 거고, 날짜 인식은 애초에 명시적으로 요구하거나 테스트하지 않았을 거다. 그러니 에이전트 입장에서는 빠뜨렸다는 인식조차 없었을 거다 — 시킨 일은 다 했으니까.
에이전트에게 일을 시킬 때 남는 교훈
이번 건 그나마 ”-“로 눈에 띄게 티가 나서 발견하기 쉬웠다. 만약 결과물이 겉보기엔 멀쩡해 보이는 형태로 빠졌다면, 훨씬 오래 몰랐을 수도 있다. 리팩터링이나 마이그레이션을 AI 에이전트에게 맡길 때는 “이 코드가 지금 하는 일”을 사람이 먼저 전부 나열해두고, 그중 뭐가 옮겨졌고 뭐가 빠졌는지 하나씩 확인해야 한다는 걸 다시 느꼈다. 에이전트는 시킨 일은 잘 하지만, 시키지 않은 일(원래 암묵적으로 되고 있던 것)까지 알아서 챙겨주진 않는다.
고친 내용
crawler.py에 날짜 추출 함수를 하나 추가했다.
def extract_date_from_html(html: str):
if not HAS_TRAFILATURA:
return None
try:
meta = trafilatura.extract_metadata(html)
except Exception:
return None
if meta and meta.date:
return meta.date.replace("-", ".")
return None
그리고 이 값을 LLM 프롬프트에 “이미 확인된 값이니 그대로 쓰라”고 명시적으로 넘기도록 바꿨다. 이제 LLM이 본문에서 날짜를 추측할 필요가 없다 — 못 찾을 때만 예전처럼 본문에서 찾아보고, 그마저 없으면 ”-“를 쓰게 폴백을 남겨뒀다.
이 수정은 7월 10일 기사부터 적용됐다. 실제로 7월 10일 기사를 확인해보니 날짜 빠진 기사가 하나도 없었다.
날짜 하나 고치는 거였는데, 파다 보니 몇 달 전 리팩터링까지 거슬러 올라갔다. 자동화 파이프라인을 계속 고쳐나가다 보면, 지금 눈앞의 증상보다 훨씬 이전 결정이 원인인 경우가 종종 있다.