블로그 자동 포스팅 파이프라인에서 태그와 글투 손보기 (연재 3/6)
내가 운영하는 블로그에 커밋/PR 기반으로 글이 자동으로 올라오는 파이프라인이 있는데, 거기서 붙는 태그랑 글투가 계속 거슬려서 오늘 손을 봤다.
학습 주제
주제는 "블로그 자동화 파이프라인의 태그 필터링과 글쓰기 스타일 개선"이다. DB에 저장된 태그를 정리하고, 앞으로 같은 문제가 재발하지 않게 코드 레벨에서 막고, 마지막으로 글 자체의 톤을 바꾸는 작업까지 한 번에 진행했다. 날짜는 2026년 7월 24일.
탐구 과정
시작은 단순했다. 블로그 글을 쭉 훑어보니 "본인", "학습", "커밋" 같은 태그가 붙어 있는 글이 각각 40~50개씩 있었다. 이게 실제로 글 내용을 설명하는 태그가 아니라 어떤 자동화 스크립트가 기계적으로 붙인 흔적처럼 보였다. 일단 DB에서 이 세 태그를 지우는 건 어렵지 않았다. 100개 글의 tags 배열에서 해당 값들을 걸러내니 끝. 태그 목록 API가 DB에서 동적으로 계산되는 구조라 프론트엔드를 따로 재시작할 필요도 없었다.
문제는 그다음이었다. 태그만 지운다고 근본적으로 해결된 게 아니었다. 글을 다시 읽어보니 "제가 활동한 내용을 누군가 대신 써준 것 같은" 느낌이 강했다. ## 요약, ## 배경 및 목적, ## 구현 내용, ## 기술적 의사결정, ## 배운 점 같은 정형화된 섹션 구조에, PR이나 커밋을 3인칭으로 서술하는 톤. 딱 봐도 리포트 양식이지 내가 직접 쓴 글 같지 않았다.
이걸 어디서 고쳐야 하는지 찾는 게 생각보다 오래 걸렸다. 처음엔 블로그 저장소 자체를 뒤졌는데 관련 코드가 없었다. 결국 다른 프로젝트에서 GitHub 커밋과 PR을 수집해서 초안을 만들고 자동으로 올리는 파이프라인(github_collector.py, LearningCollector 계열)을 찾아냈다. 신기하게도 이 자동화 시스템 자체를 설명하는 글이 이미 블로그에 올라와 있었는데("GitHub 커밋 작성자 필터링, 서버 단에서부터 걸러내기"), 그 글을 읽고 나서야 구조가 명확해졌다.
핵심 학습 내용
가장 먼저 정리한 건 태그 필터링 로직이다. 기존에는 _inject_identity_tags라는 함수가 초안을 저장할 때마다 본인, 커밋 같은 태그를 무조건 붙이고 있었다. 이걸 없애는 것만으론 부족해서, 아예 금지 태그 목록을 모듈 레벨 상수로 만들고 저장 직전에 걸러내는 헬퍼 함수를 하나 추가했다.
BANNED_TAGS = {"본인", "학습", "커밋"}
def _strip_banned_tags(tags):
return [t for t in tags if t not in BANNED_TAGS]
이 필터를 초안이 저장되는 두 지점 — dev/PR 워커와 study 워커 — 양쪽에 모두 걸었다. study 워커는 단일 세그먼트/다중 세그먼트 분기가 따로 있어서 두 군데 다 확인해야 했다. 중간에 예전 코드에서 지운 변수(type_tag)를 참조하는 fallback 라인이 남아있어서 그것도 같이 정리했다.
그다음이 더 재밌었던 부분인데, 글쓰기 프롬프트 자체를 손보는 작업이었다. 기존 프롬프트가 보고서 형식을 요구하고 있었고, 이걸 실제 사람이 겪은 순서대로 자연스럽게 흘러가는 1인칭 서술로 바꾸도록 지시문을 수정했다. 말로만 바꾸는 게 아니라 실제로 기존 글 하나(스모크 테스트 도입 관련 글)를 새 톤으로 다시 써서 확인해봤다.
바꾸는 과정에서 예상 못 한 버그도 하나 잡았다. 원래 포스트들은 제목(title)이 본문(content)과 별도로 저장되는 구조라 본문에 H1 제목을 넣지 않는 규칙이었는데, 다시 쓴 글에 실수로 H1을 넣어버려서 렌더링 확인 후에 빼야 했다.
이해한 내용
이번에 확실히 이해한 건 "글투를 바꾼다"는 게 프롬프트 문구 하나만 고쳐서 끝나는 일이 아니라는 점이다. 정형화된 섹션 구조(## 요약 같은)를 없애는 것, 3인칭 서술을 1인칭으로 바꾸는 것, 사실관계(엔드포인트 개수, 포트 번호, 코드 diff 같은 구체적인 정보)는 그대로 유지하면서 표현 방식만 바꾸는 것 — 이 세 가지가 별개의 작업이었다.
특히 애매했던 부분이 하나 있었는데, 어떤 글에 "리뷰 피드백을 받아 방식을 바꿨다"는 문장이 있었다. 이게 내가 PR 작성자이고 리뷰어가 따로 있었다는 뜻이라면, 그 PR을 통째로 1인칭으로 다시 쓰는 게 맞는지 애매했다. 협업 과정에서 나온 피드백을 자연스러운 1인칭 서술 안에 녹여내는 방식으로 처리했는데, 이 부분은 사실 케이스마다 판단이 달라질 수 있어서 완전히 확신이 서진 않는다.
또 하나는 자동화 파이프라인의 구조에 대한 이해다. 커밋/PR을 수집하는 collector, 초안을 만드는 프롬프트 로직, 그리고 실제로 DB에 저장하는 워커(dev/pr 워커, study 워커)가 분리되어 있고, 태그 주입이나 필터링 같은 후처리 로직이 이 저장 지점들 앞뒤로 붙는 구조라는 걸 파악했다.
실전 적용
당장은 남은 53개 글을 순차적으로 새 톤으로 다시 쓰는 작업이 남아있다. 하나씩 확인하면서 진행해야 사실관계가 틀어지지 않을 것 같다. 이번에 만든 _strip_banned_tags 같은 필터 패턴은 다른 자동화 파이프라인에서도 "화이트리스트/블랙리스트 후처리" 형태로 재사용할 수 있을 것 같다.
추가 학습 계획
프롬프트로 글의 구조와 톤을 통제하는 부분을 더 깊이 파보고 싶다. 지금은 지시문을 수정하고 결과를 눈으로 확인하는 방식인데, 여러 개의 결과물을 일관되게 만들려면 좀 더 체계적인 검증 방법이 필요할 것 같다. 그리고 나머지 글들을 다시 쓰면서 "리뷰어 이름이 등장하는 경우" 같은 애매한 케이스들을 어떻게 일관되게 처리할지 원칙을 정리해두려 한다.