##이번 포스팅은 무아지경으로 바이브코딩한거라..그대로 붙여넣을생각이니... 읽으시는분들은 흐름이 이상하다고 느끼신다면...
그게맞습니다...

브레인스토밍 모듈 트렌드 검색 통합 및 API 리팩토링

개요

브레인스토밍 아이디어 생성의 품질 향상을 위해 실시간 트렌드 검색 기능을 추가하고, 이를 실제 API에 적용하기 위한 아키텍처 리팩토링을 진행했다.

1. 트렌드 검색 기능 추가

1.1 트렌드 검색 소스 통합

3개의 트렌드 검색 소스를 통합하여 다양한 관점의 트렌드 키워드를 수집한다.

소스 파일 특징
네이버 뉴스 search/naver_news.py 국내 뉴스 기반 트렌드
DuckDuckGo search/duckduckgo.py 글로벌 검색 트렌드
네이버 데이터랩 search/naver_datalab.py 검색어 트렌드 통계

1.2 트렌드 검색 흐름

def fetch_trend_keywords(self, purpose: str) -> List[str]:
    all_keywords = []

    # 1. 네이버 뉴스 검색
    naver_keywords = await self.trend_searcher.extract_trend_keywords(purpose, num_articles=5)
    all_keywords.extend(naver_keywords)

    # 2. DuckDuckGo 검색
    ddg_keywords = await self.duckduckgo_searcher.extract_trend_keywords(purpose, num_articles=5)
    all_keywords.extend(ddg_keywords)

    # 3. 네이버 데이터랩 검색
    datalab_keywords = await self.datalab_searcher.extract_trend_keywords(purpose)
    all_keywords.extend(datalab_keywords)

    # 4. 중복 제거
    return list(dict.fromkeys(all_keywords))

1.3 트렌드 키워드 필터링

사용자 입력 키워드와의 유사도를 기반으로 관련성 높은 트렌드만 선별한다.

def filter_trend_keywords(self, trend_keywords: List[str], top_k: int = 10) -> List[str]:
    """
    트렌드 키워드를 사용자 입력 기준으로 필터링

    1. 트렌드 키워드 임베딩
    2. 사용자 키워드와 코사인 유사도 계산
    3. 상위 top_k개 선택
    """

2. 80:20 비중 적용

2.1 비중 설계 원칙

구분 비중 역할
사용자 키워드 80% 아이디어의 핵심 방향
트렌드 키워드 20% 시의성 추가

2.2 프롬프트 적용

【🔴 핵심: 사용자 브레인스토밍 키워드 (비중 80%)】
{사용자 키워드}

※ 위 키워드는 사용자가 직접 떠올린 것입니다. 이 키워드를 중심으로 아이디어를 구성하세요.

【🔵 참고: 최신 트렌드 키워드 (비중 20%)】
{트렌드 키워드}

※ 트렌드는 참고만 하세요. 사용자 키워드가 핵심입니다.

3. 새로운 출력 형식

3.1 기존 형식

핵심문제 → 개선방안 → 기대효과 → 발상기법 → 분석결과

3.2 변경된 형식

아이디어 제목: [제목]
주제: [어떤 문제/니즈를 해결하는지]
실행 방향: [무엇을 할지 - 구체적 도구나 수치 단정 금지]
확인 필요 사항: [실행 전 조사해봐야 할 것들]
기대효과: [예상 결과 - 숫자 단정 금지]
적용된 기법: [기법명]

3.3 할루시네이션 방지 규칙

❌ 특정 도구/서비스의 기능을 단정짓기 금지
   예: "네이버 클로바 API가 자동으로 자막 생성"
❌ 통계, 비용, 시장규모 지어내기 금지
   예: "월 100만원 수익 가능", "시장 규모 40조"
✅ 모르는 건 "확인 필요"로 표시
   예: "플랫폼별 최적 길이 조사 필요"

4. 평가 결과

4.1 GPT-5 Judge 기준

항목 Before After 변화
RAG 활용도 기준점 +1.2 향상
전체 점수 기준점 +0.18 향상

4.2 실용적 창의성 관점

항목 Before After 변화
조합 창의성 5.3 6.3 +1.0
트렌드 시의성 4.3 6.3 +2.0
구조적 완성도 6.0 9.0 +3.0
신뢰성 5.0 8.0 +3.0
전체 5.6 7.4 +1.8

5. API 아키텍처 리팩토링

5.1 문제 발견

트렌드 검색 기능을 idea_generator.py에 구현했으나, 실제 API 엔드포인트는 이를 호출하지 않고 자체 로직을 사용하고 있었다.

실제 API 경로:
brainstorming-popup.html
    ↓
brainstormingService.js
    ↓
endpoints/brainstorming.py  ← 직접 OpenAI 호출 (약 400줄)
                              ❌ idea_generator.py 호출 안 함
                              ❌ 트렌드 검색 없음

5.2 파일별 상태

파일 트렌드 검색 새 프롬프트 역할
idea_generator.py 콘솔 테스트용
runner.py 평가용
brainstorming.py 실제 API

5.3 리팩토링 구조

Before:

endpoints/brainstorming.py
    ↓
    직접 OpenAI 호출 (~400줄)

After:

endpoints/brainstorming.py  → 라우팅만 (~30줄)
    ↓
domain/brainstorming/idea_generator.py  → 실제 로직
    ├─ 트렌드 검색 (3개 소스)
    ├─ 키워드 추출
    ├─ 영구 RAG 검색
    ├─ 아이디어 생성 (새 프롬프트)
    └─ SWOT 분석

5.4 idea_generator.py에 추가된 API용 메서드

async def generate_ideas_for_api(
    self, 
    session_id: str, 
    purpose: str, 
    associations: List[str]
) -> List[Dict]:
    """API에서 호출 가능한 아이디어 생성 메서드"""

    # 1. Ephemeral RAG 초기화
    ephemeral_rag = EphemeralRAG(session_id=session_id)

    # 2. 연상 키워드 추출 (유사도 기반)
    keywords_data = ephemeral_rag.extract_keywords_by_similarity(purpose=purpose, top_k=7)

    # 3. 트렌드 키워드 검색 (3개 소스)
    trend_keywords = await self._fetch_trend_keywords_async(purpose)

    # 4. 트렌드 키워드 필터링
    trend_keywords = ephemeral_rag.filter_trend_keywords(trend_keywords, top_k=10)

    # 5. 영구 RAG에서 브레인스토밍 기법 검색
    techniques_results = self._search_permanent_rag_for_api(query=purpose, n_results=3)

    # 6. 아이디어 생성
    ideas = self._generate_ideas_with_prompt(purpose, keywords, techniques, trend_keywords)

    # 7. SWOT 분석 추가
    for idea in ideas:
        swot = self._perform_swot_analysis(idea)
        idea['analysis'] = swot_text

    return ideas

5.5 brainstorming.py 엔드포인트 수정

@router.get("/ideas/{session_id}", response_model=IdeaResponse)
async def generate_ideas(session_id: str):
    """
    idea_generator.py의 generate_ideas_for_api 메서드를 호출
    (트렌드 검색 + 80:20 비중 + 할루시네이션 방지 적용)
    """
    session = session_manager.get_session(session_id)
    purpose = session.get('q1_purpose')
    associations = session.get('q3_associations', [])

    from idea_generator import IdeaGenerator
    generator = IdeaGenerator()
    ideas = await generator.generate_ideas_for_api(
        session_id=session_id,
        purpose=purpose,
        associations=associations
    )

    return IdeaResponse(ideas=ideas)

5.6 config.py 수정

네이버 검색 API 키 필드 추가:

# Naver Search API (트렌드 검색용)
NAVER_SEARCH_CLIENT_ID: str = ""
NAVER_SEARCH_CLIENT_SECRET: str = ""

6. 테스트 결과

6.1 서버 로그

[API] 아이디어 생성 시작 - 세션: c92d5acd-...
[API] 추출된 키워드: ['여러가지', '글을 쓸거에요', ...]
[API] 네이버 뉴스: 8개
[API] DuckDuckGo: 8개
[API] 네이버 데이터랩: 6개
[API] 트렌드 키워드 (필터링 전): 22개
[API] 트렌드 키워드 (필터링 후): ['K-유통 체험', '사용자 생성 콘텐츠', ...]
   💡 감지된 직군: 크리에이터
[API] 아이디어 생성 완료: 3개

6.2 검증 항목

항목 상태
트렌드 검색 3개 소스 작동
트렌드 필터링
직군 감지
SWOT 분석
API → idea_generator 호출

7. 파일 구조

backend/app/domain/brainstorming/
├── idea_generator.py          # 아이디어 생성 (콘솔 + API 공용)
├── ephemeral_rag.py           # JSON 기반 임시 RAG
├── domain_hints.py            # 직군별 힌트
├── search/
│   ├── naver_news.py          # 네이버 뉴스 검색
│   ├── duckduckgo.py          # DuckDuckGo 검색
│   └── naver_datalab.py       # 네이버 데이터랩 검색
└── evaluation/
    └── runner.py              # 평가용 러너

backend/app/api/v1/endpoints/
└── brainstorming.py           # API 엔드포인트 (라우팅만)

8. 교훈

  1. 콘솔 테스트 ≠ 실제 서비스: 별도 코드베이스면 개선이 전파되지 않음
  2. 엔드포인트는 라우팅만: 비즈니스 로직을 엔드포인트에 직접 구현하면 재사용 불가
  3. 책임 분리: 도메인 로직과 API 레이어를 명확히 분리해야 유지보수 가능
  4. 평가 기준의 한계: GPT-5 Judge는 "파괴적 혁신"만 높이 평가, 실용적 조합 창의성은 저평가

9. 향후 작업

  • runner.py 리팩토링 (idea_generator.py import 방식으로 전환)
  • 창의성 점수 향상 방안 연구 (트렌드 비중 조정, 기법 다양화)

+ Recent posts