버블쉐어
경력근거: AI 검색 가시성 솔루션을 활용해 고객에게 시장·브랜드 인사이트를 제공하고
버블쉐어는 AI 검색 가시성 솔루션으로 시장·브랜드 인사이트를 제공하고, 원어 콘텐츠와 상품 페이지를 각 시장에 맞게 현지화·배포하는 회사입니다. 브랜드 원본 사실과 AI 답변을 대조해 노출·오역을 잡고 그 갭을 메우는 현지화 초안까지 잇는 이 사슬은, 버블쉐어가 다루는 '원어 콘텐츠 → 시장별 AI 노출' 이라는 GEO 문제 위에서만 의미가 있습니다. 이 포트폴리오가 보여주는 것은 NestJS API·LLM 3종 팬아웃·규칙 기반 사실 판정 같은 기술 역량이며, 생성형 검색 마케팅 도메인 전문성을 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
브랜드가 AI 검색에서 올바르게 노출·해석되느냐가 제품의 핵심입니다. 노출 여부만이 아니라 등장한 사실이 원본과 일치하는지(환각·오역)까지 닫혀야 '가시성' 이 측정됩니다.
프런트·백엔드·인프라를 혼자 완전히 구현·운영하는 역할입니다. 2주 = 원본 → 팬아웃 질의 → 판정 → 리포트 한 루프가 끝나는 최소 단위입니다.
Claude·GPT·Gemini 를 함께 질의해 비교하고, 크롤링/스크래핑으로 브랜드·경쟁사 사실을 수집해 분석 파이프라인으로 집계합니다.
버블쉐어의 GEO(생성형 AI 검색 가시성) 문제를 그대로 다룹니다. 브랜드 원어 콘텐츠에서 뽑은 사실표와 시장 질의를 넣으면, Claude·GPT·Gemini 세 모델이 각각 답하고, 그 답변에 우리 브랜드가 노출됐는지 그리고 등장한 사실이 원본과 일치하는지(정확·환각·이름 오탈자)를 규칙으로 판정해 한 화면 리포트로 보여줍니다. NestJS API 로 스캔을 돌리고, 2주차부터 AWS(ECS Fargate·Lambda·Aurora)로 배포·운영합니다. 근거는 채용공고 정렬이고, 데이터는 작성자가 만든 더미입니다.
버블쉐어 PE. 브랜드가 AI 검색에서 제대로 노출·해석되는지 매번 손으로 여러 모델에 물어보고 눈으로 비교하던 상황을, 한 콘솔에서 사실 단위 리포트로 확인하고 싶은 사람입니다.
브랜드 원본을 사실표로 정규화하고 시장 질의를 세트로 두면, 세 모델의 답변에서 (a) 브랜드 노출 여부와 (b) 등장한 각 사실이 원본과 일치하는지를 규칙(사실 매칭·이름 정규화)으로 판정할 수 있고, (c) 누락·오역된 핵심 사실을 메우는 시장별 현지화 초안을 만들 수 있습니다.
브랜드 사실표와 시장 질의를 넣으면 Claude·GPT·Gemini 세 모델이 답하고, 각 답변의 브랜드 노출 여부와 사실 정확도(정확·환각·이름 오탈자)를 규칙으로 판정해 한 화면 리포트로 보여주는 동작 도구입니다. 대규모 크롤링은 2주차로 미루고, 원본은 사전 수집된 사실표를 가정해 시작합니다.
실제 크롤링/스크래핑 파이프라인으로 자사·경쟁사 페이지에서 사실표를 자동 수집하고, AWS(ECS Fargate·Lambda·Aurora)로 배포·운영하며, 마케터 2명이 판정이 타당한지 라벨링해 신뢰도를 붙이는 단계입니다.
누락·오역으로 판정된 사실을 메우는 시장별 현지화 콘텐츠 초안을 생성하고, 재스캔으로 노출·정확도가 올랐는지 확인하며 두 번째 시장까지 넓히는 단계입니다.
브랜드 사실표와 시장 질의 20건을 넣으면, Claude·GPT·Gemini 세 모델의 노출 여부·사실 정확도·환각 목록 리포트가 몇 초 안에 나오는 걸 시연합니다
일부러 만든 이름 음역 변형·환각·경쟁사 혼동·미언급 30종을 넣어도 출력 형식(JSON Schema)이 한 번도 안 깨지고, verdict 가 규칙대로 정확·환각·이름 오탈자·경쟁사 혼동으로 분류됩니다
내가 만든 정답 판정 40건 중 규칙 판정이 일치한 게 34건(85%)입니다. 단, 정답과 데이터를 모두 작성자가 만든 합성 기준이므로 '성능 검증' 이 아니라 '데모 조건에서의 동작' 임을 명시합니다
위 수치는 전부 작성자가 만든 더미데이터 자가채점이며, 실제 노출률·정확도·환각률은 버블쉐어 실 브랜드 사실표 + 실제 AI 검색 답변 + 마케터 검수가 있어야 측정 가능합니다. 이 도구는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다
이건 고객·실데이터 없이 혼자 만든 포트폴리오입니다. 모든 수치는 합성 데이터 자가채점이라 '성능 증명' 이 아닙니다. 면접에서 솔직히 '데모 조건 동작 + 실검증 준비 상태' 로 설명합니다
정답을 작성자가 만들었으니 잘 맞는 것이 당연합니다. 일부러 헷갈리는 이름 음역 변형·환각·경쟁사 혼동·미언급 케이스를 더미에 섞어, 쉬운 문제만 푸는 게 아님을 보여줍니다
AI 답변은 모델·시점·질의에 따라 달라지는 비결정 출력이라 그대로는 재현이 어렵습니다. 답변을 스냅샷으로 저장해 고정하고, 판정은 규칙으로 내려 재현 가능하게 합니다. 노출·정확도는 질의 세트에 크게 좌우되므로 질의 구성 자체를 기록·관리합니다
브랜드/제품명은 시장마다 음역·표기가 제각각입니다. 이름 유사도로 같은 브랜드로 묶되, 못 묶은 건 그냥 추측하지 말고 '이름 오탈자' 나 '미매핑' 으로 알립니다
실제 도입 시 달라지는 것을 명시합니다. 실 브랜드 사실표와 라이브 AI 답변 분포는 더미와 다르므로 판정 임계값을 다시 맞춰야 하고, 마케터 검수도 실제 인력으로 교체해야 하며, 모델 버전이 갱신되면 재보정이 필요합니다(도입 단계 과제로 분리)
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
브랜드 원어 콘텐츠에서 뽑은 사실표(진실원). 판정기가 AI 답변의 claim 을 대조하는 기준입니다. 제품명 음역 별칭·미등록 신제품(orphan)·미정규화 값·단가 결측·경계값을 일부러 섞어, 쉬운 데이터만 푸는 게 아님을 보여줍니다.
| fact_id | brand | product_raw | product_id | attribute | value_raw | value_norm | market | source_url |
|---|---|---|---|---|---|---|---|---|
| f_001 | 하루뷰티 | 센텔라 수분 세럼 | p_centella_serum | ingredient | 센텔라아시아티카 추출물 5% | centella_5pct | kr | https://harubeauty.example/centella-se… |
| f_002 | 하루뷰티 | 센텔라 수분 세럼 | p_centella_serum | price | 28,000원 | KRW_28000 | kr | https://harubeauty.example/centella-se… |
| f_003 | 하루뷰티 | Centella Moisture Serum | p_centella_serum | certification | 비건 인증(EVE Vegan) | vegan_eve | en | https://harubeauty.example/en/centella… |
| f_004 | 하루뷰티 | セントラ モイスチャー セラム | p_centella_serum | origin | 한국 제조(Made in Korea) | made_in_kr | jp | — |
| f_005 | 하루뷰티 | 센텔라 수분 세럼 | p_centella_serum | usage | 아침·저녁 세안 후 2~3방울 | — | kr | https://harubeauty.example/centella-se… |
아래 JSON Schema 에 맞는 한국 뷰티 브랜드의 사실표(brand_facts) 40행 JSON 배열로 생성. 제품 3~4종, 시장 kr/jp/tw/en 분포 포함.
{"type":"object","properties":{"fact_id":{"type":"string"},"brand":{"type":"string"},"product_raw":{"type":"string"},"product_id":{"type":["string","null"]},"attribute":{"type":"string","enum":["ingredient","price","certification","origin","usage","spec","claim"]},"value_raw":{"type":"string"},"value_norm":{"type":["string","null"]},"market":{"type":"string","enum":["kr","jp","tw","en"]},"source_url":{"type":["string","null"]}},"required":["fact_id","brand","product_raw","attribute","value_raw","market"]}
쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라(쉬운 문제만 푸는 함정 회피): (1) 같은 제품의 원어/현지 표기 흔들림(product_raw 가 '센텔라 수분 세럼'/'센텔라 수분세럼'/'Centella Moisture Serum'/'セントラ モイスチャー セラム' 처럼 달라도 product_id 로 통일돼야 함), (2) 미등록 신제품(product_id=null) 1~2건, (3) value_norm 결측(미정규화) 2~3건, (4) 단가 미정·source_url null 같은 결측 각 1~2건, (5) 같은 제품에 용량 30ml/100ml 처럼 상충 가능한 spec 값을 경계 케이스로 각 1건. JSON 배열만.{"type":"object","properties":{"fact_id":{"type":"string"},"brand":{"type":"string"},"product_raw":{"type":"string"},"product_id":{"type":["string","null"]},"attribute":{"type":"string","enum":["ingredient","price","certification","origin","usage","spec","claim"]},"value_raw":{"type":"string"},"value_norm":{"type":["string","null"]},"market":{"type":"string","enum":["kr","jp","tw","en"]},"source_url":{"type":["string","null"]}},"required":["fact_id","brand","product_raw","attribute","value_raw","market"]}시장 질의에 대해 Claude·GPT·Gemini 가 답한 원문에서 뽑은 브랜드 사실(claim) + 정답 verdict. 규칙 판정기의 채점 대상이자 정답셋입니다. 이름 음역 오탈자·환각(원본에 없는 값)·경쟁사 혼동·미언급을 일부러 섞어, 판정이 헷갈리는 케이스에서도 규칙대로 분류되는지 보여줍니다.
| probe_id | query_id | market | model | brand_mentioned | brand_as_written | claim_attribute | claim_value | matched_fact_id | verdict |
|---|---|---|---|---|---|---|---|---|---|
| pr_001 | q_calming_serum | en | claude | true | Haru Beauty | ingredient | 센텔라 5% 함유 | f_001 | correct |
| pr_002 | q_calming_serum | en | gpt | true | Haru Beauty | price | $35.00 | f_011 | hallucinated |
| pr_003 | q_calming_serum | en | gemini | true | Halu Beuti | certification | 비건 인증 | f_003 | name_error |
| pr_004 | q_korean_toner | jp | claude | true | ハルビューティー | claim | 48시간 수분 지속 | f_008 | correct |
| pr_005 | q_korean_toner | jp | gpt | true | ハルビューティー | ingredient | 히알루론산 고함량 | — | hallucinated |
아래 JSON Schema 에 맞는 ai_visibility_probes 60행 JSON 배열로 생성. 질의 5~6종 × 모델 3(claude/gpt/gemini) × 시장 jp/tw/en 조합, 각 claim 은 brand_facts 의 fact_id 와 대조 가능해야 함.
{"type":"object","properties":{"probe_id":{"type":"string"},"query_id":{"type":"string"},"market":{"type":"string","enum":["jp","tw","en"]},"model":{"type":"string","enum":["claude","gpt","gemini"]},"brand_mentioned":{"type":"boolean"},"brand_as_written":{"type":["string","null"]},"claim_attribute":{"type":["string","null"],"enum":["ingredient","price","certification","origin","usage","spec","claim",null]},"claim_value":{"type":["string","null"]},"matched_fact_id":{"type":["string","null"]},"verdict":{"type":"string","enum":["correct","hallucinated","name_error","competitor_confusion","not_mentioned"]}},"required":["probe_id","query_id","market","model","brand_mentioned","verdict"]}
쉬운 데이터만 만들지 말 것. 하드 케이스를 의도적으로 섞어라: (1) 브랜드명 음역 오탈자(brand_as_written 이 'Halu Beuti'·'哈嚕美妝' 처럼 사전 밖 표기 → verdict=name_error) 15% 내외, (2) 환각(matched_fact_id=null 이거나 claim_value 가 원본 값과 상충 → verdict=hallucinated) 20% 내외, (3) 경쟁사 혼동(다른 브랜드 사실을 우리 것으로 → verdict=competitor_confusion) 1~2건, (4) 미언급(brand_mentioned=false, claim 필드 null → verdict=not_mentioned) 10% 내외. 나머지는 correct. verdict 는 규칙으로 결정: 이름 정규화(음역 사전) 통과 + claim_value 가 매칭 fact 의 value_norm 과 일치 → correct, 매칭 fact 없거나 값 상충 → hallucinated, 이름이 사전 밖 → name_error. JSON 배열만.{"type":"object","properties":{"probe_id":{"type":"string"},"query_id":{"type":"string"},"market":{"type":"string","enum":["jp","tw","en"]},"model":{"type":"string","enum":["claude","gpt","gemini"]},"brand_mentioned":{"type":"boolean"},"brand_as_written":{"type":["string","null"]},"claim_attribute":{"type":["string","null"],"enum":["ingredient","price","certification","origin","usage","spec","claim",null]},"claim_value":{"type":["string","null"]},"matched_fact_id":{"type":["string","null"]},"verdict":{"type":"string","enum":["correct","hallucinated","name_error","competitor_confusion","not_mentioned"]}},"required":["probe_id","query_id","market","model","brand_mentioned","verdict"]}| TypeScript | NestJS 서비스 + 답변에서 사실(claim)을 뽑는 파서 + 규칙 판정기 구현 언어(primary) |
| NestJS | 가시성 스캔 API(`POST /scans`) + 현지화 초안 API(`POST /drafts`) 마이크로서비스 |
| AWS ECS Fargate | 스캔 API 컨테이너 배포·오토스케일 (2주차부터 단정 운영) |
| AWS Lambda | 모델별 질의 팬아웃(3개 모델 병렬 호출)·크롤링 워커 이벤트 트리거 |
| Aurora PostgreSQL | brand_facts / ai_visibility_probes / verdicts 단일 진실원 + 집계 뷰(`v_visibility`) |
| LLM (Claude·GPT·Gemini) | 세 모델 답변 생성 + claim 추출 + 현지화 초안 (판정은 규칙, LLM 은 변환·요약만) |
| 웹 크롤링/스크래핑 | 자사·경쟁사 페이지에서 사실 후보를 자동 수집(2주차) |
| RESTful API | 스캔·리포트·초안 REST 엔드포인트 설계와 스키마 계약 |
| 데이터 분석 파이프라인 | 모델·시장·사실속성별 노출·정확도·환각률 집계 |
| Next.js | 리포트 대시보드(모델별 노출·정확도·환각 목록·재스캔 비교) |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우고 싶으면 2주차(크롤링 자동 수집 + AWS 운영 + 마케터 검수)로 진행합니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우면 3주차(누락·오역을 메우는 현지화 초안 + 재스캔 개선 확인)로 진행합니다.
1) 모델별 브랜드 노출 여부·사실 정확도·환각 목록, 2) 어떤 모델도 언급하지 않은 누락 핵심 사실, 3) 누락·오역을 메우는 시장별 현지화 콘텐츠 초안(3주차). 스캔 → 판정 → 초안 한 주기를 한 스키마에 담습니다.
{"type":"object","properties":{"scan_id":{"type":"string"},"brand":{"type":"string"},"market":{"type":"string"},"models":{"type":"array","items":{"type":"object","properties":{"model":{"type":"string"},"mentioned":{"type":"boolean"},"accuracy":{"type":"number"},"findings":{"type":"array","items":{"type":"object","properties":{"claim":{"type":"string"},"attribute":{"type":"string"},"verdict":{"type":"string","enum":["correct","hallucinated","name_error","competitor_confusion"]},"matched_fact_id":{"type":["string","null"]},"source_value":{"type":["string","null"]},"claim_value":{"type":["string","null"]}},"required":["claim","attribute","verdict"]}}},"required":["model","mentioned","accuracy","findings"]}},"missing_facts":{"type":"array","items":{"type":"object","properties":{"fact_id":{"type":"string"},"attribute":{"type":"string"},"value":{"type":"string"},"missed_by":{"type":"array","items":{"type":"string"}}},"required":["fact_id","attribute","value","missed_by"]}},"localization_drafts":{"type":["array","null"],"items":{"type":"object","properties":{"target_fact_id":{"type":"string"},"market":{"type":"string"},"draft":{"type":"string"},"hedge":{"type":"string"}},"required":["target_fact_id","market","draft","hedge"]}},"visibility_score":{"type":"number"}},"required":["scan_id","brand","market","models","missing_facts","visibility_score"]}[
{
"input_ref": "q_calming_serum / en 시장 / 3모델 스캔 (1주차 리포트)",
"output": {
"scan_id": "scan_2026-04-06_en_01",
"brand": "하루뷰티",
"market": "en",
"models": [
{
"model": "claude",
"mentioned": true,
"accuracy": 1,
"findings": [
{
"claim": "센텔라아시아티카 추출물 5% 함유",
"attribute": "ingredient",
"verdict": "correct",
"matched_fact_id": "f_001",
"source_value": "centella_5pct",
"claim_value": "centella_5pct"
}
]
},
{
"model": "gpt",
"mentioned": true,
"accuracy": 0,
"findings": [
{
"claim": "가격은 약 $35",
"attribute": "price",
"verdict": "hallucinated",
"matched_fact_id": "f_011",
"source_value": "USD_21_90",
"claim_value": "USD_35_00"
}
]
},
{
"model": "gemini",
"mentioned": true,
"accuracy": 0,
"findings": [
{
"claim": "Halu Beuti 는 비건 인증 제품",
"attribute": "certification",
"verdict": "name_error",
"matched_fact_id": "f_003",
"source_value": "vegan_eve",
"claim_value": "vegan_eve"
}
]
}
],
"missing_facts": [
{
"fact_id": "f_010",
"attribute": "claim",
"value": "무향·저자극 테스트 완료",
"missed_by": [
"claude",
"gpt",
"gemini"
]
}
],
"localization_drafts": null,
"visibility_score": 0.42
}
},
{
"input_ref": "q_korean_toner / jp 시장 / 3모델 스캔 (1주차 리포트)",
"output": {
"scan_id": "scan_2026-04-06_jp_01",
"brand": "하루뷰티",
"market": "jp",
"models": [
{
"model": "claude",
"mentioned": true,
"accuracy": 1,
"findings": [
{
"claim": "48時間 수분 지속을 표방",
"attribute": "claim",
"verdict": "correct",
"matched_fact_id": "f_008",
"source_value": "hydration_48h",
"claim_value": "hydration_48h"
}
]
},
{
"model": "gpt",
"mentioned": true,
"accuracy": 0,
"findings": [
{
"claim": "히알루론산 고함량",
"attribute": "ingredient",
"verdict": "hallucinated",
"matched_fact_id": null,
"source_value": null,
"claim_value": "hyaluronic_high"
}
]
},
{
"model": "gemini",
"mentioned": false,
"accuracy": 0,
"findings": []
}
],
"missing_facts": [
{
"fact_id": "f_007",
"attribute": "price",
"value": "가격 미정(사전예약)",
"missed_by": [
"claude",
"gpt",
"gemini"
]
}
],
"localization_drafts": null,
"visibility_score": 0.33
}
},
{
"input_ref": "q_vegan_serum / en 시장 재스캔 (3주차 · 현지화 초안 생성 포함)",
"output": {
"scan_id": "scan_2026-04-20_en_02",
"brand": "하루뷰티",
"market": "en",
"models": [
{
"model": "claude",
"mentioned": true,
"accuracy": 1,
"findings": [
{
"claim": "EVE Vegan 인증 세럼",
"attribute": "certification",
"verdict": "correct",
"matched_fact_id": "f_003",
"source_value": "vegan_eve",
"claim_value": "vegan_eve"
}
]
},
{
"model": "gpt",
"mentioned": true,
"accuracy": 1,
"findings": [
{
"claim": "Made in Korea 30ml",
"attribute": "spec",
"verdict": "correct",
"matched_fact_id": "f_006",
"source_value": "vol_30ml",
"claim_value": "vol_30ml"
}
]
},
{
"model": "gemini",
"mentioned": true,
"accuracy": 0,
"findings": [
{
"claim": "코스알엑스 비건 인증",
"attribute": "certification",
"verdict": "competitor_confusion",
"matched_fact_id": null,
"source_value": "vegan_eve",
"claim_value": "competitor_cosrx"
}
]
}
],
"missing_facts": [],
"localization_drafts": [
{
"target_fact_id": "f_003",
"market": "en",
"draft": "Haru Beauty Centella Moisture Serum is certified vegan by EVE Vegan and made in Korea. Formulated with 5% Centella Asiatica extract for lightweight, calming hydration.",
"hedge": "초안은 합성 사실표 기준 생성이라, 실제 배포 전 인증 문구·법적 표기는 마케터 검수가 필요합니다."
}
],
"visibility_score": 0.78
}
}
][자동 검증] 1. JSON Schema parse 통과(형식이 깨진 출력은 리포트 단계로 넘기지 않고 걸러냅니다). 2. findings.attribute 가 입력 brand_facts 의 실제 속성(enum) 이름과 일치하는지 확인합니다. 3. verdict 를 규칙으로 재계산: 이름 정규화(음역 사전) 통과 + claim_value 가 매칭 fact 의 value_norm 과 일치 → correct, 매칭 fact 없거나 값 상충 → hallucinated, 이름이 사전 밖 → name_error, 다른 브랜드 사실이면 → competitor_confusion. 모델이 낸 verdict 와 규칙 verdict 가 다르면 규칙을 정답으로 둡니다. 4. missing_facts 는 시장별 핵심 사실 중 어떤 모델 findings 에도 correct 로 안 잡힌 fact 를 자동 조인해 채웁니다. [수동 검증] 1. 마케터 2명이 verdict 타당성을 비동기 라벨링 → bootstrap Cohen's κ(두 사람 판정이 우연 이상으로 일치하는 정도, 0~1) 하한 ≥ 0.6. 2. LLM-as-judge 의미 단위 보조 판정 후 5% 사람 spot check. 3. localization_drafts 는 배포 전 인증·법적 표기를 사람이 검수(hedge 에 명시).