최종 수정일: 2026-07-09
와디즈 데이터 · 스토리 생성 AI
“크라우드펀딩 스토리 써줘”를 ChatGPT에 시키면 그럴듯한 글은 나오지만 바로 게시할 수 있는 스토리는 안 나옵니다. 와디즈는 이 격차를 메우려고 스토리 생성 AI를 따로 만들었습니다 — 메이커가 제품 사진 한 장과 설명 몇 줄만 던지면, 와디즈에서 실제로 성공한 스토리 골격 위에 본문·섹션 이미지·플랫폼 규격까지 맞춘 상세페이지를 통째로 내놓습니다. 범용 LLM과 무엇이 다른지, 그 격차가 어디서 나오는지가 이 글의 주제입니다.
순수 기능 소개 글은 아닙니다. 범용 LLM에 그냥 물어보는 것과 뭐가 다른지, 어떻게 쓰는지, 그리고 만드는 과정에서 무엇을 저울질했는지 — 아키텍처 결정 몇 개, 그중에서도 “굳이 안 해도 될 것 같은데 왜 했나” 싶은 결정들 — 를 근거와 함께 남기려 합니다. LLM 애플리케이션을 실서비스로 굴려 보신 분이라면 한 번쯤 부딪히는 지점들일 겁니다.
왜 만들었나 — 메이커의 진짜 장벽은 ‘스토리’다
크라우드펀딩을 준비하는 메이커에게 물어보면, 제품을 만드는 것만큼이나 겁내는 게 하나 있습니다. 펀딩 상세페이지(스토리) 작성입니다.
좋은 제품을 만들었다고 펀딩이 되는 게 아닙니다. 그 제품이 왜 필요한지, 무슨 문제를 푸는지, 왜 지금 이 가격에 후원해야 하는지를 설득하는 글과 이미지로 풀어내야 합니다. 그런데 이건 제품 개발과 완전히 다른 근육입니다. 처음 펀딩을 여는 1인 메이커, 소규모 팀에게는 특히 그렇습니다.
- 무슨 순서로 써야 하는지 모릅니다. (후킹은 어디에? 리워드는 어디에?)
- 어떤 톤이 이 카테고리에서 먹히는지 모릅니다. (테크 제품에 감성 카피를 쓰다 겉돕니다.)
- 섹션마다 넣을 이미지를 따로 디자인 외주 주거나 직접 만들어야 합니다.
그래서 스토리 작성은 펀딩 오픈을 며칠씩 늦추는, 때로는 아예 포기하게 만드는 병목이 됩니다. 실제로 많은 메이커가 여기서 가장 크게 막힙니다.
우리가 만든 건 이 장벽을 낮추는 도구입니다. 제품 사진 한 장, 혹은 제품 특성·설명 몇 줄만 입력하면 — 그것만으로 — 카테고리에 맞는 구성, 설득 카피, 섹션 이미지까지 갖춘 바로 게시 가능한 스토리를 내놓습니다. 백지에서 시작해 몇 날을 헤매던 작업을, 초안이 이미 나와 있는 상태에서 다듬는 작업으로 바꾸는 게 목표입니다.
기획이 붙잡은 질문 하나
만들기로 정한 뒤 기획에서 가장 오래 붙잡은 질문은 “그래서 무엇을 자동화하고 무엇을 자동화하지 않을 것인가“였습니다. 스토리 작성 전체를 버튼 하나로 끝내 버리면 편하지만, 두 가지가 걸렸습니다.
- 환각: 상세페이지는 광고입니다. AI가 없는 스펙·수상·리워드를 지어내면 그건 편의가 아니라 사고입니다. → 뒤 7장에서 다룰 다층 환각 차단으로 풀었습니다.
- 획일화: “AI가 써 준 티” 나는 똑같은 스토리가 쏟아지면, 오히려 메이커의 개성을 죽입니다. → 카테고리·다양성 축(뒤 5·6장)으로 완화했습니다.
그래서 목표를 “완성품을 대신 써 준다”가 아니라 “검증된 초안을 즉시 만들어, 메이커가 자기 언어로 다듬을 출발점을 준다”로 잡았습니다. 이 한 문장이 이후 거의 모든 설계 결정의 기준선이 됐습니다 — 무엇을 생성하고(5·6장), 무엇을 못 하게 막고(7장), 어디까지 다양성을 확보하고(5·6장), 편집을 어느 경로에 열지(1장 화이트리스트)까지.
“그거 그냥 ChatGPT한테 시키면 되잖아?” — 범용 LLM과 무엇이 다른가
여기서 당연한 반문이 나옵니다. 요즘 LLM이 글을 잘 쓰는데, 그냥 ChatGPT에 “크라우드펀딩 스토리 써줘” 하면 되지 않나?
써 보면 압니다. 그럴듯한 글은 나오지만 바로 게시할 수 있는 스토리는 안 나옵니다. 범용 LLM에는 없고 우리에겐 있는 게 세 가지입니다. 이게 이 프로젝트의 핵심이라 먼저 짚습니다.
1) 와디즈에서 실제로 성공한 스토리의 골격을 학습해 쓴다.
이게 가장 큰 차별점입니다. 범용 LLM은 “크라우드펀딩 스토리 일반론”을 압니다. 우리는 와디즈에서 실제로 펀딩에 성공한 스토리들의 패턴을 참조 템플릿으로 큐레이션해 두고, 제품에 맞는 걸 검색해 그 골격 위에 글을 씁니다. 후킹 → 문제 제기 → 해결 → 증거 → 리워드로 이어지는 검증된 흐름, 카테고리별로 먹히는 서술 순서와 톤이 여기서 나옵니다. “그럴듯한 글”과 “이 플랫폼에서 통하는 글”의 차이입니다. (자세한 방식은 뒤 5장에서.)
2) 플랫폼 규격에 맞는 결과물을 낸다.
와디즈 에디터(Froala)는 아무 HTML이나 받지 않습니다. 허용 태그, 클래스 규격, 인라인 스타일 제약이 있습니다. 범용 LLM이 뱉은 HTML은 여기 붙이려면 손이 많이 갑니다. 우리 출력은 에디터에 그대로 붙는 규격으로 나옵니다. “글을 받는 것”과 “게시물을 받는 것”의 차이입니다.
3) 사진 한 장에서 게시물까지, 한 번에.
범용 도구로 하려면 글은 챗봇에, 이미지는 이미지 생성 도구에, 규격 맞추기는 손으로 — 최소 세 군데를 오가야 합니다. 우리는 제품 사진(또는 짧은 설명) 입력 → 제품 분석 → 템플릿 검색 → 본문 생성 → 섹션 이미지 생성 → 규격 맞추기를 하나의 파이프라인으로 자동화했습니다. 메이커가 여러 도구를 오갈 일이 없습니다.
정리하면, 범용 LLM이 “글쓰기 도우미”라면 이건 “와디즈 펀딩 스토리 제작기”입니다. 도메인 지식(성공 패턴)과 플랫폼 통합(규격), 그리고 파이프라인 자동화가 그 격차를 만듭니다.
같은 입력, 다른 결과물 — 나란히 놓고 보기
말보다 결과물입니다. 똑같은 제품 입력(360도 홈 보안 카메라, 테크·가전, 6가지 특성)을 각각 넣었을 때 나온 결과입니다. 왼쪽은 범용 LLM에 “크라우드펀딩 스토리 써줘”라고 한 결과, 오른쪽은 WAi의 story-maker입니다.


차이가 한눈에 보입니다. 범용 LLM은 밋밋한 텍스트 문단을 나열합니다 — 섹션 이미지가 없고, “여러분의 소중한 일상을 안전하게” 같은 근거 없는 일반론 카피에, 와디즈 에디터 규격도 맞지 않습니다. 반면 우리 것은 히어로 → 문제 제기 → 솔루션으로 이어지는 검증된 구조에, 수치를 정리한 스펙 표, 섹션마다 생성된 이미지, “수직 90도·수평 360도로 사각지대 최소화” 같은 구체·수치 카피를 담습니다. 그대로 게시할 수 있는 완성된 스토리입니다.
메이커가 받는 건 “글 초안”이 아니라 “와디즈에 바로 올릴 수 있는 상세페이지”입니다. 이 격차가 어디서 나오는지 — 성공 스토리 골격, 플랫폼 규격, 파이프라인 자동화 — 를 이 글의 나머지에서 풉니다.
위 우리 쪽 이미지는 실제 생성 결과의 상단 일부입니다. 전체는 히어로부터 리워드·펀딩금 사용 계획·메이커 소개·리스크 안내까지 13개 섹션으로 이어집니다.
이렇게 쓰면 됩니다 — 사진 한 장에서 스토리까지
기술 이야기로 들어가기 전에, 메이커가 실제로 이걸 어떻게 쓰는지 먼저 보겠습니다. 별도 사이트에 가입할 필요 없이, 와디즈의 AI 에이전트 WAi에 말을 걸면 됩니다.
먼저 와디즈 어디서든 화면 오른쪽 아래 AI Agent WAi 버튼으로 들어갑니다.

WAi 대화창에서 입력창 아래 스토리 생성 AI를 고르면 스토리 생성 흐름으로 들어갑니다.

그다음은 대화만 하면 됩니다.
- 스토리 생성 AI로 요청합니다. “크라우드펀딩 스토리 만들어 줘”처럼 말을 걸면 생성 흐름이 시작됩니다.
- 제품 사진 한 장, 또는 설명 몇 줄을 줍니다. 사진이 있으면 제품을 분석해 반영하고, 없으면 설명만으로도 진행합니다. 필요한 정보가 부족하면 WAi가 되물어 채웁니다.
- 잠시 뒤 완성된 스토리를 받습니다. 본문·섹션 이미지·규격까지 맞춰진 상세페이지가 뷰어 링크로 오고, 그대로 게시하거나 다듬으면 됩니다.
들어오는 문은 하나(WAi)지만, 그 뒤에서 꽤 여러 컴포넌트가 움직입니다. 지금부터가 그 이야기입니다 — 왜 이렇게 만들었고, 어떤 결정들이 이 결과물을 만드는지.
먼저, 이상하게 보이는 그림 하나
전체 호출 흐름은 이렇습니다.

여기서 개발자라면 바로 눈에 걸리는 게 하나 있습니다.
워커(에이전트)가 생성 엔진을 부르는 데 왜 중간에
mcp_server를 한 겹 끼워 넣었지? 그냥 워커가 엔진 Lambda를 직접invoke하면 단계가 하나 주는데.
맞는 의심입니다. 실제로 흐름만 보면 mcp_server는 없어도 되는 중계 단계처럼 보입니다. 이 글의 절반은 이 질문에 대한 답입니다. 나머지 절반은 그 과정에서 딸려 온 다른 결정들(비동기 콜백, 이미지 폴백, 카테고리 RAG)입니다.
1. MCP 서버는 “중계”가 아니라 “도구를 정의하는 레이어”다
결론부터 말하면, mcp_server는 요청을 실어 나르는 프록시가 아닙니다. 도구(tool)를 한곳에 정의해 두는 레이어입니다. 이 관점 차이가 전부입니다.
순진한 버전
처음엔 누구나 이렇게 그립니다.
worker ──▶ story-maker Lambda (직접 invoke)단계가 적고, 코드도 적습니다. 워커가 페이로드를 만들어 lambda.invoke를 때리면 끝입니다. 실제로 초기 프로토타입은 이 구조였습니다.
문제는 클라이언트가 하나가 아니라는 데서 시작됩니다.
현실: 진입 경로가 여러 개다
스토리 생성 엔진을 부르는 경로는 WAi만이 아닙니다.
- WAi 경로: supervisor → 워커 → 생성
- Claude Desktop 경로: MCP 클라이언트가 직접 붙어 편집 도구까지 사용
- 앞으로 붙을 다른 MCP 클라이언트들
이제 “워커가 엔진을 직접 invoke” 구조의 대가가 드러납니다. 도구를 부르는 규칙 — 페이로드 스키마, 인자 검증, 비동기 호출 방식, 결과 회수 방법 — 을 클라이언트마다 중복 구현해야 합니다. 스토리 생성 도구 스펙이 바뀌면 모든 클라이언트를 같이 고쳐야 합니다. 전형적인 산탄총 수술(shotgun surgery)입니다.
MCP 레이어는 이 문제를 정면으로 없앱니다. 스토리 생성·편집·이미지 교체·캡션 처리 같은 기능을 표준 MCP 도구로 이 서버에 딱 한 번만 정의합니다. 클라이언트는 그냥 이 서버에 붙어 도구를 호출할 뿐, 엔진을 어떻게 부르는지는 몰라도 됩니다.

덤으로 얻는 것들
도구 정의를 한곳에 모으니 그 위에 자연스럽게 얹히는 것들이 있습니다.
노출 제어(화이트리스트). 어떤 클라이언트에 어떤 도구를 보여줄지 서버에서 통제합니다. WAi 경로는 화이트리스트(_WORKER_ALLOWED_TOOL_NAMES)에 생성 도구(create_crowdfunding_story) 딱 1종만 노출됩니다. 편집·삭제·부분 재생성은 런타임 가드로 아예 막힙니다. 같은 서버지만 Claude Desktop 경로는 편집 도구까지 씁니다. 클라이언트별로 능력이 갈리는 이 통제가 서버 한곳에 있습니다.
인증과 호출자 식별. Bearer 토큰 인증과 X-Caller 헤더로 누가 부르는지 식별하는 로직도 여기 한 번만 있으면 됩니다.
상태 관리와 URL 발급. 뒤에서 이야기할 비동기 콜백, 요청 상태 저장(DynamoDB), 업로드/뷰어 URL 발급 — 이 성가신 것들이 전부 이 레이어에 모입니다.
정리하면, mcp_server는 워커와 엔진 사이의 불필요한 한 걸음이 아니라 여러 진입 경로가 공유하는 계약(contract)의 단일 소스입니다. 단계 수로 세면 손해처럼 보이지만, 클라이언트가 둘 이상이 되는 순간 이득이 비용을 넘습니다.
설계 원칙 하나로 압축하면: N개의 클라이언트 × M개의 도구를 N×M번 구현하지 말고, M번만 구현하고 노출을 제어하라. MCP는 이 “M번만”을 위한 표준 인터페이스다.
2. “에이전트가 둘”처럼 보이지만 사실 하나다
또 하나 자주 나오는 오해가 있어 정리해 둡니다. 위 그림엔 LLM이 여러 번 등장합니다. 워커도 LLM을 쓰고, 생성 엔진도 LLM으로 본문을 씁니다. 그래서 “에이전트가 여러 개 연쇄된 멀티 에이전트냐”는 질문을 받습니다.
아닙니다. 에이전트 역할을 하는 건 워커 하나입니다.
핵심은 “LLM을 쓴다”와 “에이전트다”가 같은 말이 아니라는 점입니다.
| 컴포넌트 | LLM 사용 | 하는 일 | 에이전트인가 |
|---|---|---|---|
story-maker-worker | O | 의도 파악, 어떤 도구를 부를지 판단 | O |
mcp_server | X | 도구 정의·중계 | X |
story-maker (생성 엔진) | O | 본문·이미지 생성(실행) | X |
생성 엔진은 LLM으로 글을 생성하지만, 요청을 어디로 보낼지 판단하지 않습니다. 정해진 입력을 받아 결과를 만드는 실행기(executor)입니다. 반면 워커는 “지금 사용자가 뭘 원하나, 생성 도구를 불러야 하나 아니면 되물어야 하나”를 판단합니다. 이 판단이 에이전트를 에이전트로 만듭니다.
WAi supervisor → story-maker-worker (에이전트) → MCP → 생성 엔진 (실행기)구조는 supervisor → 단일 에이전트 → 실행기입니다. 우리 쪽 경로 안에서 에이전트가 연쇄로 이어지지는 않습니다. 이 구분을 흐리면 소유권·책임 경계가 같이 흐려지기 때문에(누가 프롬프트를 바꾸나, 누가 배포하나) 역할 기준으로 못을 박아 둡니다.
3. 왜 동기 호출이 아니라 비동기 콜백인가
스토리 생성은 분 단위 작업이라 동기 호출로 기다리면 돈과 타임아웃을 태웁니다. 그래서 엔진을 비동기(Event) invoke로 던지고 콜백으로 결과를 받습니다. 근거가 되는 실측부터 봅니다(최근 30일, 정상 부하).
- 중앙값 약 2분
- 상위 75% 약 2.7분
- 상위 5~10%는 4~5분대, 최대 7분 사례도 있음
분포의 꼬리가 깁니다. 본문 생성(gpt-4.1) 한 번에, 섹션 이미지 5~6장을 생성 모델로 뽑고, 실패하면 폴백까지 도는 파이프라인이라 그렇습니다.
이 시간을 동기 호출로 기다리면 어떻게 될까요. Lambda가 Lambda를 동기 invoke로 부르면 호출한 쪽도 그 시간만큼 살아서 대기합니다. 2~7분을 아무 일 없이 붙잡혀 있는 겁니다. 비용(과금은 실행 시간 기준)과 타임아웃 리스크가 그대로 쌓입니다. API Gateway를 앞에 뒀다면 29초 하드 리밋에 그냥 죽습니다.
그래서 이렇게 끊었습니다.
mcp_server ──▶ story-maker Lambda (async Event invoke, 즉시 리턴)
mcp_server ◀── /webhook/lambda-result (엔진이 끝나면 콜백으로 결과 통보)mcp_server는 생성 엔진을 비동기(Event) 타입으로 던지고 곧바로 손을 뗍니다. 엔진은 일이 끝나면 콜백 엔드포인트(/webhook/lambda-result)로 결과를 돌려줍니다. 그동안의 요청 상태는 DynamoDB에 들고 있습니다. 오래 걸리는 생성 작업에서 “누가 누구를 붙잡고 기다리느냐”를 없앤 구조입니다.

LLM 파이프라인이 길어질수록 이 패턴은 선택이 아니라 필수에 가까워집니다. 응답이 초 단위가 아니라 분 단위인 순간, 동기 호출은 그냥 돈과 타임아웃을 태우는 일이 됩니다.
4. 이미지 생성, 왜 GPT를 1순위로 두고 Gemini를 폴백으로 뒀나
이미지 생성 모델을 하나만 쓰지 않고 gpt-image-2를 1순위, gemini-2.5-flash-image를 폴백으로 이중화했습니다. 각 3회 재시도합니다. 이유가 취향이 아니라 실측이라 근거를 남깁니다.
왜 GPT가 메인인가. 상업 제품 이미지에서 안전 필터 오탐 차단이 현저히 적습니다. Gemini 계열(특히 Imagen)은 지극히 평범한 제품 사진에도 안전 필터가 오작동해 생성을 거부하는 일이 잦았고, API 레벨에서 이 필터를 끌 수가 없었습니다. 크라우드펀딩 제품 이미지를 뽑는 서비스에서 이건 치명적입니다. 여기에 참조 이미지 지원(images/edits로 제품 원본 사진을 최대 16장까지 반영), 유사한 생성 속도(섹션당 15~19초), 기존 OpenAI 키 재사용까지 겹쳐 GPT를 메인으로 뒀습니다.
그런데 왜 Gemini를 버리지 않고 폴백으로 남겼나. GPT API 장애나 rate limit이 났을 때 서비스가 통째로 멈추면 안 되기 때문입니다. 한쪽이 죽어도 다른 쪽으로 이어 붙이는 게 이중화의 본질입니다.
비용은? 대략 이렇습니다(1024×1024 기준).
| 모델 | 장당 비용 | 위치 |
|---|---|---|
| gpt-image-2 | ~$0.032 | 1순위 |
| gemini-2.5-flash-image | ~$0.039 | 폴백 |
폴백이 오히려 20%가량 비쌉니다. 그래도 폴백은 “GPT가 실패했을 때만” 타므로 평상시 비용에는 거의 영향이 없고, 대신 가용성을 삽니다.
여기서 놓치기 쉬운 실서비스 감각 하나. 한 장이 끝내 실패해도 스토리 전체는 안 깨집니다. 그 섹션 이미지만 비고 본문과 나머지 섹션은 정상 생성됩니다. 부분 실패가 전체 실패로 번지지 않게 격리해 두는 것 — LLM 파이프라인에서 의외로 자주 빠뜨리는 부분입니다.
5. 카테고리 강조 전략 — 프롬프트에 지식을 주입하는 법
앞에서 “범용 LLM과 다른 가장 큰 지점은 와디즈 성공 스토리의 골격을 쓰는 것”이라 했습니다. 그 구현이 여기입니다. “AI가 알아서 잘 쓰겠지”에 기대지 않고, 와디즈에서 검증된 카테고리별 서술 지식을 검색해 프롬프트에 주입합니다. 개발자에게는 RAG 설계 이야기이고, 기획·마케팅 관점에서는 “왜 이 스토리가 그럴듯한 글이 아니라 통하는 글인가”의 답입니다.
참조 템플릿 102개 + soft boost 검색
와디즈에서 실제로 펀딩에 성공한 스토리들의 작성 패턴(레이아웃·내러티브·톤)을 학습용으로 큐레이션한 참조 템플릿 102개를 Elasticsearch 인덱스에 넣어 뒀습니다. 21개 전 카테고리(테크·가전, 패션, 뷰티, 푸드, 여행 …)를 커버하고, 카테고리마다 감성/신뢰/트렌디/검증/실용 같은 다양성 축을 둬서 같은 카테고리라도 제품 성격에 따라 다른 톤의 템플릿이 걸리게 했습니다.
검색 방식이 핵심입니다. 카테고리를 hard filter(후보 제한)가 아니라 soft boost(가산점)로 씁니다.
후보 = 전체 템플릿에서 벡터 유사도(KNN)로 추출
+ 같은 카테고리 템플릿에 가점카테고리로 후보를 먼저 잘라 버리면, 라벨이 조금만 어긋나도(예: “홈” vs “홈·리빙”) 좋은 템플릿이 통째로 누락됩니다. soft boost는 후보를 항상 전체에서 의미 유사도로 뽑되 카테고리가 맞으면 위로 올려 줍니다. 라벨 불일치에 강하면서 카테고리 정합성도 챙기는, RAG 검색에서 자주 쓰는 트레이드오프입니다.
before / after — 지식 주입이 실제로 결과를 바꾸나
같은 제품·같은 이미지로 강조 전략 주입 전/후를 비교했습니다. 인트로 카피만 봐도 결이 다릅니다.
| 제품 | 주입 전 | 주입 후 |
|---|---|---|
| 조미료 | “한 번에 완성되는 깊은 맛!” | “70년 발효 노하우, 1초 만에 감칠맛” |
| 홈캠 | “360°로 지키는 우리 집의 안심” | “360도, 빈틈없는 집안 보안” / “설치 5분, 360도 실시간 감시” |
주입 후가 더 구체적이고 근거 있는 카피로 이동합니다. 태그 사용 빈도로 봐도, 테크 제품(홈캠)은 수치 강조(민트색)가 26→41로 늘고 감성 강조(옐로우)가 18→0으로 사라집니다. “테크는 감성보다 구체 증거로 설득한다”는 카테고리 원칙이 실제 산출물에 반영된 겁니다.
정직하게 남기는 한계
지식을 강하게 주입하는 방식의 대가도 있습니다. 같은 카테고리 스토리들이 비슷한 톤·구성으로 수렴할 여지가 있습니다. 문장 자체는 제품마다 새로 쓰이니 똑같아지진 않지만, 섹션 순서·인트로 방식·강조색 같은 “서술의 결”이 닮아갈 수 있습니다. 다양성 축으로 완화하고 있지만 완전히 없앤 문제는 아닙니다. 이런 트레이드오프는 감추기보다 적어 두는 편이 낫다고 봅니다.
6. “뷰티 템플릿이 2개뿐이었다” — 템플릿을 102개로 늘린 이야기
5장의 구조가 잘 돌아가려면 전제가 하나 필요합니다. 참조할 좋은 템플릿이 카테고리마다 충분히 있어야 합니다. 여기서 실제로 부딪힌 문제와, 그걸 풀면서 왜 검색 방식까지 바꿨는지를 남깁니다. 사용성 관점에서 “왜 우리 스토리가 더 나은가”의 실증이기도 합니다.
문제: 카테고리 편중
초기 템플릿은 50개였는데, 카테고리 분포가 고르지 않았습니다. 대표적으로 뷰티가 단 2개였습니다. 뷰티 제품이 들어오면 매번 그 2개 안에서만 골라 쓰니, 결과 스토리가 서로 닮을 수밖에 없었습니다. 5장에서 말한 “톤 수렴”이 데이터 빈곤 때문에 증폭되던 상황입니다.
선택 1 — 데이터를 늘린다 (50 → 102)
먼저 템플릿 풀을 50개에서 102개로 늘려 21개 전 카테고리를 빈틈없이 채웠습니다. 그냥 개수만 늘린 게 아니라, 카테고리마다 다양성 축(감성 스토리텔링 / 정보·신뢰 / 트렌디 비주얼 / 안심·검증 / 가성비·실용)을 나눠 배분했습니다. 같은 뷰티라도 “감성으로 파는 제품”과 “성분·임상으로 신뢰를 파는 제품”은 다른 골격을 타야 하니까요.

여담이지만, 이 52개를 늘리는 작업 자체도 비용을 신경 썼습니다. 템플릿 골격(spec)을 회사 OpenAI 키(gpt-4.1)로 생성하고 스크립트로 채우는 방식이라, 49개를 만드는 데 약 $1.5가 들었습니다. “AI를 만드는 일”에도 “AI로 재료를 만드는” 파이프라인을 끼워 넣은 셈입니다.
선택 2 — 그럼에도 검색 방식을 바꿨다 (hard filter → soft boost)
데이터를 늘린 것만으로는 부족했습니다. 늘리고 나서도 “홈” vs “홈·리빙”처럼 카테고리 라벨이 조금만 어긋나면 후보에서 통째로 빠지는 문제가 남았습니다. 원인은 검색이 카테고리를 hard filter(후보 제한)로 쓰고 있었기 때문입니다.
그래서 5장에서 설명한 soft boost로 전환했습니다. 후보는 항상 전체에서 의미 유사도(KNN)로 뽑고, 카테고리가 맞으면 가점(boost = 0.15)만 줍니다. 이 0.15라는 숫자도 그냥 정한 게 아닙니다. dev 인덱스에서 실측해 보니 KNN 코사인 점수가 0.65~0.7 부근인데, 여기에 +0.15면 “같은 카테고리를 1순위로 올리되, 카테고리 안에서의 미세한 의미 변별(0.05~0.07 점수차)은 뭉개지 않는” 균형점이었습니다. 예전에 쓰던 큰 boost(6.0 같은)로는 같은 카테고리 점수가 다 붙어 버려 내부 순위가 무의미해졌습니다. 작은 상수 하나에도 근거가 있습니다.
정리하면, “뷰티 2개” 문제는 데이터 확장 + 검색 방식 전환을 한꺼번에 요구한 사건이었고, 지금의 102개 + soft boost 구조는 그 결과물입니다.
템플릿 하나하나가 단순한 예시 글이 아니라는 점도 짚어 둡니다. 각 템플릿은 톤 키워드·문장 스타일·색 팔레트·내레이션 모드·강조 문구, 그리고 섹션별 골격(히어로 → 문제 제기 → 솔루션 …)까지 구조화된 명세를 갖습니다. 생성 엔진은 이 골격을 프롬프트에 주입받아 그 위에 제품 내용을 채웁니다.


그래서 결과물이 카테고리마다 달라진다
이 골격·다양성 축이 실제로 하는 일은 하나입니다. 카테고리에 따라 서술 전략 자체를 바꾸는 것. 범용 LLM은 카테고리를 몰라 어느 제품에나 비슷한 톤으로 쓰지만, 우리는 그러지 않습니다.
- 테크·가전: 감성 카피를 걷어내고 수치·스펙·증거로 설득합니다. (앞의 홈캠 사례에서 감성 강조가 18→0으로 사라지고 수치 강조가 26→41로 는 게 이것입니다.)
- 뷰티: 반대로 감성 공감을 앞세우되, 성분·인증 같은 신뢰 요소를 축으로 보강합니다.
- 푸드: 구체적 증거(원료·제조·수상)를 전면에, 사회적 증거(리뷰·재구매)를 보조로 씁니다.
같은 “좋은 제품입니다”라도, 테크에서는 “설치 5분, 360도 실시간 감시”로, 뷰티에서는 전혀 다른 결로 나옵니다. 카테고리가 결과물의 골격·톤·강조색까지 바꾼다 — 도입부에서 보여드린 “같은 입력, 다른 결과물”의 격차가 바로 여기서 나옵니다. 범용 도구로는 재현하기 어려운 지점입니다.
7. 환각을 막는 자리
크라우드펀딩 상세페이지는 광고입니다. AI가 없는 스펙을 지어내면 그건 그냥 허위광고입니다. 그래서 환각 차단을 여러 층에 뒀습니다.
- 수치 환각 차단: 이미지에서 “9.8mm” 같은 치수를 읽어내 지어내는 걸 막습니다. 이미지 분석 경로에 제품 features가 빠져 있던 게 근본 원인이었고, 설명 경로에는 있던 걸 이미지 경로에만 없어 생긴 회귀였습니다.
- 리워드·배송 환각 차단: 사용자가 준 정보는 반영하되, LLM이 없는 리워드 구성이나 배송 일정을 창작하는 건 막습니다.
- 생성 후 광고 검수: 생성 직후 본문과 이미지를 사내 광고 심의 Lambda에 통과시켜 컴플라이언스를 확보합니다. 반려돼도 재생성하지 않고 결과에 첨부·기록만 합니다(생성과 검수의 책임 분리).
- AI 생성 표기: 생성 이미지 메타데이터(PNG
tEXt/ JPEGCOM마커)에AI-generated를 심어 AI 생성물 고지 정책에 선제 대응합니다.
LLM 애플리케이션에서 “무엇을 생성하느냐”만큼 “무엇을 생성하지 못하게 하느냐”가 중요하다는 걸, 광고 도메인은 특히 빡세게 가르쳐 줍니다.
8. 워커는 누가 소유해야 하나 — 그래프 위치가 아니라 변경의 진원지
마지막으로 조직·아키텍처가 만나는 지점 하나. 워커는 WAi의 그래프 안에서 호출됩니다. 그럼 “워커는 WAi가 소유해야 하지 않나”라는 질문이 나옵니다.
우리 결론은 아닙니다. 근거는 “그래프에서 호출된다 = 소유”가 성립하지 않기 때문입니다.
워커는 WAi 그래프에 코드로 박혀 있는 게 아니라 boto3.invoke로 부르는 외부 Lambda입니다. WAi는 워커의 ARN만 알 뿐 안의 코드·프롬프트·도구는 모릅니다. “호출하니까 소유”라면 WAi가 invoke하는 모든 외부 서비스를 WAi가 소유해야 한다는 뜻이 되어 성립하지 않습니다.
소유권은 변경의 진원지로 정합니다. 워커가 바뀌는 사건 — 카테고리 강조 전략 변경, HTML 규격 변경, 섹션 규칙·환각 정책 조정, 프롬프트 튠, 회귀 대응 — 은 전부 스토리 도메인 사정에서 발생합니다. 그 판단을 하는 쪽이 소유해야 배포 사이클이 종속되지 않습니다. 실제로 워커를 별도 Lambda로 떼어낸 목적 자체가 WAi 배포 큐에 묶이지 않고 스토리쪽이 단독으로 변경을 반영하기 위함이었습니다(make deploy-worker-dev/prod).
경계선은 boto3.invoke 호출 지점입니다. 입출력 계약은 양측 공동 합의, 경계 안쪽 구현은 각자 소유. 서비스 분리의 교과서적인 선 긋기지만, LLM 에이전트가 얽히면 “누가 이 프롬프트를 소유하나”가 은근히 헷갈립니다. 이 선을 일찍 그어 두는 게 나중에 배포 병목을 줄입니다.
마치며
이 서비스가 풀려는 문제는 하나입니다. 메이커가 가장 크게 막히는 스토리 작성이라는 장벽을, 사진 한 장으로 넘게 하는 것. 그리고 그걸 범용 LLM이 아니라 와디즈에서 통하는 결과물로 만드는 것 — 성공 스토리 골격, 플랫폼 규격, 파이프라인 자동화가 그 격차를 만듭니다.
그 위에서 내린 개발자 관점의 결정은 대략 이렇습니다.
- MCP 도구 정의 레이어: 여러 클라이언트가 공유하는 계약의 단일 소스. 단계 하나 늘어 보여도 N×M 구현을 M으로 줄인다.
- 비동기 콜백: 분 단위 생성 작업에서 동기 대기는 돈과 타임아웃을 태운다.
- 이미지 이중화: 안전 필터·가용성 근거로 GPT 1순위 + Gemini 폴백, 부분 실패 격리.
- 카테고리 RAG + 템플릿 확장: 검증된 성공 스토리 102개를 soft boost로 주입하고, 카테고리마다 서술 전략을 바꿔 “통하는 스토리”를 만든다.
- 환각 차단·소유권 경계: 광고 도메인과 조직 구조가 강제하는 제약을 설계에 반영.
그리고 이 모든 결정의 기준선은 처음에 기획이 잡은 한 문장이었습니다 — “완성품을 대신 써 주는 게 아니라, 검증된 초안을 즉시 만들어 메이커가 자기 언어로 다듬을 출발점을 준다.” 범용 LLM 대신 이걸 쓰는 이유가 거기 있습니다. 그냥 글이 아니라, 와디즈에서 통하도록 설계된 출발점이라는 것.
화려한 기법 하나로 되는 일이 아니라, “이 결정의 대가가 뭔가”를 매번 저울질한 결과의 누적입니다. 비슷한 걸 만드시는 분께 저울질의 근거로 쓰이면 좋겠습니다.
궁금한 점이나 다르게 풀 수 있는 지점이 보이면 편하게 얘기 걸어 주세요.

