블로그 벌크 시딩의 한국어 제목 추출을 LLM으로 통일
목차
블로그 벌크 시딩 스크립트에서 제목(title) 추출 로직을 LLM 기반으로 변경했다. 마크다운 첫 줄 H1에서 한국어 제목을 명시적으로 추출하도록 강제한 작업인데, 처음엔 단순한 버그 픽스처럼 보이지만 사실 콘텐츠 품질과 시스템 신뢰성에 꽤 깊은 이슈가 숨어 있었다.
왜 제목 추출을 "강제"해야 했나?
블로그를 운영하면서 메타데이터 누락 문제가 계속 나타났다. 특히 다국어 지원을 하는 경우, 시스템이 자동으로 제목을 파싱할 때 몇 가지 경로가 생긴다:
- 마크다운 첫 줄 H1 헤더 (
# 제목) - YAML 프론트매터의 title 필드
- 파일명에서 추론
- 기본값 폴백
문제는 여러 경로가 있으면 일관성이 깨진다는 것이다. 누군가는 H1을 썼고, 누군가는 프론트매터를 썼고, 누군가는 둘 다 빠뜨렸다. 벌크 시딩으로 대량의 문서를 초기화할 때 이 불일치가 배로 드러난다.
더 심각한 건, 한국어 제목이 생략되고 영어 폴백이 일어나는 상황이었다. 팀이 한국어 블로그를 운영하는데 제목이 영어로 표시되면 사용자 경험이 깨진다. 그리고 SEO 관점에서도 한국어 키워드가 헤더에 있어야 유리하다.
해결: H1 첫 줄에서 한국어 강제 추출
# 의도: 마크다운 첫 번째 H1에서만 제목을 가져온다
# 이렇게 하면 프론트매터, 파일명 등 다른 경로를 무시
def extract_korean_title_from_h1(content: str) -> str:
lines = content.split('\n')
for line in lines:
if line.startswith('# '):
# LLM 검증: 이 줄이 정말 한국어인가?
# 혹은 LLM으로 첫 번째 H1 자체를 강제 생성?
return line[2:].strip()
return None # 폴백 없음 - 엄격함
LLM을 활용한 이유는:
- 단순 regex 보다 robust: "# " 다음이 정말 제목인지 확인 가능
- 다국어 감지: 한국어인지 영어인지 구분, 잘못된 것만 걸러냄
- 의미론적 검증: 단순 문자 추출이 아니라 "이게 제목으로 손색없는가?"를 판단
벌크 시딩 시 모든 문서를 이 규칙으로 일괄 처리하면 데이터 일관성을 보장할 수 있다.
트레이드오프: 속도 vs 정확성
이 변경을 검토할 때 팀과 나눈 고민:
| 관점 | 기존 방식 (다중 경로) | 새 방식 (H1 강제) |
|---|---|---|
| 속도 | 빠름 (fallback 많음) | 약간 느림 (LLM 호출) |
| 일관성 | 낮음 (경로 다양) | 높음 (단일 경로) |
| 한국어 보장 | 약함 (폴백 위험) | 강함 (검증) |
| 기존 문서 마이그레이션 | 쉬움 (자동 적응) | 어려움 (수동 정렬 필요) |
벌크 시딩은 일회성 또는 저빈도 작업이므로, 속도보다 정확성을 택했다. 매일 실행되는 작업이라면 LLM 비용이 문제가 되겠지만, 초기화나 재구성할 때 한 번씩 도는 작업이면 품질 투자가 맞다.
배운 것: 메타데이터 추출의 원칙
이런 작업을 몇 번 하다 보니 패턴이 보인다:
- 단일 source of truth 정하기 — 여러 경로를 두지 말 것. H1은 H1만, 프론트매터는 프론트매터만.
- 강제성이 필요한 곳엔 validation을 붙일 것 — "제목이 없으면 에러" 같은 명시적 규칙.
- 다국어면 명확한 언어 정책 — "기본은 한국어, 영어는 보조" 같은 원칙을 코드에 태운다.
- 벌크 작업일수록 엄격할 것 — 한두 개 문서는 수동 수정 가능하지만, 100개 이상이면 자동화의 정확성이 팀의 시간을 좌우한다.
LLM이 만능은 아니지만, "문서 첫 줄이 정말 제목인지", "이게 한국어인지"를 사람처럼 판단해야 할 때는 꽤 유용하다. 정규표현식이나 단순 텍스트 매칭으로는 놓칠 예외들을 잡아낼 수 있으니.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.