정부 연동 데이터 INSERT 시 SEO 메타데이터 자동 생성
목차
gov-bot을 통해 INSERT되는 데이터들에 대해 SEO 메타데이터(metaTitle, metaDescription)를 LLM으로 자동 생성하는 기능을 추가했다. db.py에서 INSERT 로직이 호출될 때 seo_generate 함수를 연쇄 실행하도록 만들어서, 외부 데이터가 들어올 때마다 검색 최적화된 메타데이터가 함께 저장되게 한 것이다.
왜 LLM으로 메타데이터를 생성해야 했나
정부 연동 시스템(gov-bot)에서 들어오는 데이터는 기본적으로 '공식 콘텐츠'인데, 보통 내부 행정 시스템의 구조에 맞춰 제공된다. 즉, 공개 웹에 노출되기 위한 SEO를 고려한 타이틀이나 메타 설명은 원본에 포함되지 않는다.
처음엔 "데이터 담당팀이 직접 메타데이터를 제공해주면 안 되나" 생각했는데, 현실은 그렇지 않았다:
- 정부 시스템의 응답 스펙은 고정적 (메타데이터 필드가 처음부터 없음)
- 연동 담당자도 메타데이터 생성이 그들의 책임이라고 보지 않음
- 데이터 품질이 들쑥날쑥해서 통일된 형식으로 추가하기 어려움
그래서 수집 쪽에서 자동으로 처리하는 게 나을 거 같았다. 선택지는 크게 두 가지였다:
| 접근 | 장점 | 단점 |
|---|---|---|
| 템플릿 기반 (정해진 포맷으로 조합) | 빠름, 비용 거의 0 | 뻔한 메타데이터, 검색 효율 낮음 |
| LLM 기반 (생성형) | 자연스럽고 다양함, 검색 최적화 가능 | LLM 비용, 레이턴시 증가 |
팀과 논의 후 LLM 방식으로 결정했다. 이유는 SEO가 수익과 직결되는 부분이고, 메타데이터 품질이 검색 노출에 큰 영향을 주기 때문이었다. 템플릿으로 만들면 1000개의 동일한 제목이 나올텐데, 그건 검색 알고리즘에서 페널티를 받을 수 있다.
구현의 타이밍과 책임 경계
가장 고민이 많았던 부분이 "INSERT 시점에 즉시 호출할 건가, 아니면 나중에 배치로 처리할 건가" 였다.
# 선택한 방식: INSERT 직후 동기 호출
def insert_content(gov_data):
# 1. 원본 데이터 저장
content_id = db.insert(table='contents', data=gov_data)
# 2. 즉시 SEO 메타 생성
seo_data = seo_generate(content_id, gov_data)
db.update(table='contents', id=content_id, seo=seo_data)
return content_id
장점:
- 데이터가 나머지 시스템에 노출될 때 이미 메타데이터가 완성됨
- 부분 실패해도 콘텐츠 자체는 DB에 있고, 메타는 나중에 재생성 가능
단점:
- gov-bot 응답 시간이 길어짐 (LLM 호출 latency)
- LLM 서비스 장애 시 전체 INSERT가 실패할 수 있음
여기서 팀 내 코드리뷰를 거쳤는데, 리뷰어가 "만약 LLM 응답이 늦으면?" 이라고 물었다. 그래서 타임아웃 처리와 폴백(fallback) 로직을 추가했다:
def seo_generate_safe(content_id, data, timeout=5):
try:
return seo_generate(content_id, data, timeout=timeout)
except TimeoutError:
# 기본값으로 fallback: 원본 데이터의 처음 N글자
return {
'metaTitle': data.get('title', '')[0:60],
'metaDesc': data.get('summary', '')[0:160]
}
except LLMError as e:
logger.error(f"seo_generate failed: {e}")
return {} # 빈 메타로 일단 진행
db.py에 이 로직이 들어간 이유는, INSERT 시점이 가장 확실한 "진입점"이기 때문이다. ORM 레이어나 API 엔드포인트에 산재시키면 어딘가 빠질 가능성이 높다.
이런 자동화 패턴의 일반론
비슷한 사례들이 많다:
- 이미지 썸네일 생성: 이미지 파일 업로드 후 동기/비동기로 thumbs 생성
- 검색 인덱싱: 문서 저장 후 전문 검색(full-text search) 인덱스 갱신
- 알림 전송: 주문/결제 완료 후 고객에게 알림 발송
공통 질문들:
- 동기 vs 비동기: 데이터 일관성이 중요하면 동기, 레이턴시가 중요하면 비동기 + 재시도 큐
- 에러 처리: partial success 허용하기 vs 전체 롤백 (우리는 전자 선택)
- 모니터링: 얼마나 많은 생성 요청이 실패하는가 추적 필수
회고
이 작업을 하면서 느낀 점:
-
외부 시스템 연동에는 "데이터 정규화" 계층이 필요하다
원본 스펙과 우리 서비스의 요구사항은 거의 항상 다르다. 그 차이를 메우는 게 자동화 도구의 중요한 책임이다. -
LLM을 비즈니스 로직 안에 직접 넣을 때는 폴백을 먼저 설계해야 한다
"항상 정상 작동한다"는 가정은 위험하다. -
"여기가 맞는 책임인가" 물어보기
처음엔 API 응답에 메타데이터 필드를 추가할 생각도 했고, 별도 서비스로 만들 생각도 했다. 결국 db.py의 INSERT 시점이 가장 자연스러웠다.
다음은 이 패턴을 다른 메타데이터(카테고리 자동 분류, 태그 생성)로도 확장할 예정이다. 한 번 구조가 잡히니 추가하기가 수월할 것 같다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.