소상공인과 개인 창작자를 대상으로

AI를 활용해 SNS 콘텐츠를 정기적으로 생성하고 자동 업로드까지 지원하는 웹 서비스입니다.

 

  • 운영 기간: 2025.03 ~ 2026.01
  • 인원: FE 1 / BE 1 / Designer 1
  • 실제 사용자: 약 70+명
  • 생성 콘텐츠: 약 250+건

 

🔗 https://toknow.kr

 

TokNow

 

toknow.kr

 

프로젝트 배경

소상공인과 개인 창작자들은 SNS 마케팅의 중요성을 인지하고 있지만,

지속적으로 콘텐츠를 기획하고 제작하는 데 어려움을 겪고 있습니다.

 

특히 다음과 같은 문제가 존재했습니다.

  • 정기적인 콘텐츠 제작에 필요한 시간 부족
  • 콘텐츠 아이디어 고갈
  • 여러 SNS 플랫폼에 반복적으로 업로드해야 하는 번거로움

이 문제를 해결하기 위해

“콘텐츠 생성부터 업로드까지 자동화할 수 있는 서비스”를 기획하게 되었습다.

 

시스템 개요

TokNow는 다음과 같은 흐름으로 동작합니다.

  1. 사용자가 브랜드 정보 및 키워드 입력
  2. AI(Gemini)를 활용한 SNS 콘텐츠 생성
  3. 생성된 콘텐츠를 DB에 저장
  4. 예약된 시간에 맞춰 SNS API를 통해 자동 업로드

 

또한 Instagram, Facebook, Threads, X(Twitter) 등

다양한 SNS 플랫폼과 연동하여 멀티 플랫폼 업로드를 한 번에 할 수 있습니다.

 

 

🧠  기술 고민: AI 콘텐츠 품질을 어떻게 보장할 것인가? ( 콘텐츠 중복과 ai 탐지 회피)

 

초기에는 단순히 AI를 통해 콘텐츠를 생성한 뒤 그대로 업로드하는 구조였습니다.

하지만 실제 운영 과정에서 두 가지 문제가 발생했습니다.

 

 

1. 구조적 중복 콘텐츠 발생

스케줄러는 동일한 injectedData를 반복 사용합니다.

입력 데이터가 동일한 상황에서 LLM은 표현만 바꿀 뿐, 동일한 메시지 구조를 반복 생성했습니다.

  • 7일 기준 평균 3~4건 유사 패턴 발생
  • SNS 플랫폼에서 저품질 콘텐츠로 분류될 가능성 증가

 

2. AI 생성 텍스트 패턴 노출

LLM은 특정 전환 표현을 반복 사용하는 경향이 있습니다.

 

예:

  • “뿐만 아니라”
  • “이를 통해”
  • “다양한 측면에서”

 

이러한 패턴은 SNS 플랫폼의 AI 콘텐츠 탐지 신호로 활용될 수 있으며,

탐지 시 노출 제한 또는 라벨링으로 이어질 수 있습니다.

 

접근 방식

문제의 원인은 LLM 출력에 대한 통제 부재였습니다.

프롬프트만으로는 결과를 강제할 수 없기 때문에,

생성 결과를 코드 레벨에서 검증하는 구조로 변경했습니다.

 

구현

1. AI 패턴 제거 필터 (aiTell Filter)

 

LLM이 자주 사용하는 전환 표현을 사전에 정의하고,

생성 결과에서 해당 패턴이 포함될 경우 재생성을 수행합니다.

const AI_TELL_PATTERNS = [
  "뿐만 아니라", "이를 통해", "특히 주목할 점은",
  "다양한 측면에서", "더불어", "이와 같이",
  "중요한 것은", "결론적으로"
];

function hasAiTell(content) {
  return AI_TELL_PATTERNS.some(pattern => content.includes(pattern));
}
  • 탐지 시 즉시 재생성
  • 프롬프트 의존 제거
  • 추가 API 호출 없이 처리

 

2. 유사도 기반 중복 검사

최근 생성된 콘텐츠와 신규 콘텐츠 간의 자카드 유사도를 계산해 중복 여부를 판단합니다.

function getSimilarity(a, b) {
  const setA = new Set(a.split(''));
  const setB = new Set(b.split(''));
  const intersection = new Set([...setA].filter(x => setB.has(x)));
  const union = new Set([...setA, ...setB]);
  return intersection.size / union.size;
}

function isDuplicate(newContent, recentContents, threshold = 0.72) {
  return recentContents.some(
    existing => getSimilarity(newContent, existing) >= threshold
  );
}

 

  • 비교 대상: 최근 7일 생성 콘텐츠
  • 임계값: 0.72 (실제 샘플 분석 기반 설정)
0.72 이상: 구조 및 흐름이 동일한 수준
0.72 미만: 의미는 유사하나 표현 차이 존재

 

 

3. 재생성 루프

두 조건 중 하나라도 실패하면 재생성을 수행합니다.

 

AI 생성 → 패턴 검사 → 유사도 검사
             ↓ 실패 시
        재생성 (최대 3회)

 

  • 3회 실패 시 flagged 상태로 저장
  • 관리자 검토 가능

 

전체 흐름

[AI 콘텐츠 생성]
        │
        ▼
[코드 검증 레이어]
  ├─ AI 패턴 감지 (aiTell)
  ├─ 유사도 기반 중복 검사
        │
   ┌────┴────┐
   │         │
 통과      실패
   │         │
 저장     재생성 (최대 3회)
             │
         반복 실패 시
         flagged 처리

 

 

결과

지표/ 개선 전 / 개선 후

AI 패턴 포함률 ~38% 0%
중복 콘텐츠 비율 ~41% ~9%
추가 API 비용 0원
응답 시간 증가 +수ms

 

 

기술적 판단

왜 프롬프트가 아닌 코드로 해결했는가

프롬프트는 확률적으로만 반영됩니다.

동일 조건에서도 결과가 달라질 수 있습니다.

 

반면 코드 기반 검증은

  • 동일 조건 → 동일 결과
  • 비용 없음
  • 처리 속도 일정

 

비즈니스 규칙은 코드에서 강제하는 것이 적합하다고 판단했습니다.

 

한계

  • 자카드 유사도는 의미 유사도를 완전히 반영하지 못함
  • 패턴 기반 필터는 문맥까지 판단하지 못함
  • 표현 다양성 확보에는 한계 존재

 

→ 향후 embedding 기반 유사도 및 문장 구조 분석으로 확장 가능

 

배운 점

  • LLM은 제어 대상이며, 결과 품질은 시스템 설계로 보완해야 한다
  • 중복 판단 기준은 단순 구현보다 임계값 설계가 더 중요하다
  • 프롬프트보다 코드 레이어가 서비스 안정성에 직접적인 영향을 준다

+ Recent posts