LLM 답변에서 브랜드 추적을 위한 데이터 모델 설계
요약
LLM API 호출을 통한 브랜드 언급 추적의 핵심은 데이터 모델 설계에 있습니다. 본 글은 원본 답변, 프롬프트, 모델 버전을 불변(immutable)하게 기록하고, 수집과 점수화 과정을 분리하는 스키마를 제시합니다. 이를 통해 시간 경과에 따른 데이터 신뢰성을 확보할 수 있습니다.
핵심 포인트
- 원본 답변 텍스트와 출처 연결 필수: 모든 메트릭은 원본 답변을 기반으로 해야 합니다.
- 모델/프롬프트 불변성 유지: 모델 버전과 프롬프트 문구는 절대 수정하지 않고 기록해야 합니다.
- 수집(Collection)과 점수화(Scoring) 분리: 로직 개선 시 재점수화가 가능하도록 테이블을 분리합니다.
- SQLite 기반 설계 제시: 무료하고 검사하기 쉬운 SQLite를 사용했으며, Postgres나 BigQuery에도 적용 가능합니다.
LLM API를 루프(loop)로 호출하는 것은 AI 어시스턴트가 특정 브랜드를 어떻게 언급하는지 추적하는 쉬운 부분입니다. 이 데이터가 6개월 후에도 여전히 유용한지 결정하는 부분은 바로 데이터 모델입니다.
자체 제작한 'AI 가시성(visibility)' 트래커들은 같은 이유로 무너지는 경향이 있습니다: 프롬프트가 제자리에서 수정되었고, 그 아래의 모델이 변경되었으며, 원본 답변이 저장되지 않았고, 지난달 수치가 이번 달과 왜 맞지 않는지 아무도 설명할 수 없었습니다.
이 글에서는 그러한 문제들을 피하는 스키마와 스케줄러를 제시합니다. 무료이고 검사하기 쉬운 SQLite와 GitHub Actions을 사용했습니다. 이 설계는 Postgres나 BigQuery에도 적용 가능합니다.
테이블 구축 전 요구사항
나중에 답할 질문들을 적고, 그에 맞춰 설계를 해야 합니다:
- "정확히 뭐라고 했지?" 모든 메트릭은 원본 답변 텍스트와 그 출처(sources)로 연결되어야 합니다.
- "이 변화가 진짜인가?" 하루에 프롬프트당 하나가 아니라 여러 샘플이 필요합니다.
- "우리가 바꾼 건지, 엔진이 바꾼 건지?" 모델 버전과 프롬프트 문구는 절대 덮어쓰지 않고 기록되어야 합니다.
- "경쟁사 대비 어떻게 비교할까?" 브랜드 감지는 동일한 답변에 대해 여러 브랜드를 대상으로 실행되어야 합니다.
- "역사 데이터를 재점수화(re-score)할 수 있을까?" 감지 로직이 개선되었을 때, 새로운 API 호출 비용을 지불하지 않고도 저장된 답변들에 대해 다시 실행할 수 있어야 합니다.
요구사항 5는 대부분의 사람들이 놓치는 부분이며, 이것이 **수집(collection)**과 **점수화(scoring)**를 별도의 테이블로 유지해야 하는 이유입니다.
스키마
-- 우리가 질문하는 것. 프롬프트는 불변(immutable)합니다: 문구를 수정하면 새 행을 만듭니다.
CREATE TABLE prompt (
id INTEGER PRIMARY KEY,
...
설명할 가치가 있는 몇 가지 결정 사항들:
설명할 가치가 있는 몇 가지 결정 사항들:
model은 설정(config)이 아닌 응답(response)에서 가져옵니다. 만약 gpt-4.1이나 sonar와 같은 별칭(alias)을 요청하더라도, 제공 업체는 시간이 지남에 따라 더 새로운 스냅샷(snapshot)을 제공할 수 있습니다. 따라서 API가 보내주는 모델 문자열을 저장하여 차트에서 발생하는 점프를 모델 변경과 일치시킬 수 있어야 합니다.
UNIQUE (prompt_id, engine, run_date, sample_idx)는 작업을 비멱등성(idempotent)하게 만듭니다. 스케줄러가 중간에 충돌하여 재시작하더라도, INSERT OR IGNORE를 사용하면 이미 존재하는 샘플은 건너뛰고 두 번 비용을 지불할 필요가 없습니다.
raw_json은 디스크 공간을 차지하지만 나중에 비용을 절약해 줍니다. 인용(Citation) 형식은 변경됩니다. 엔진들은 필드를 추가합니다. 전체 응답을 보관하면 재쿼리(re-querying) 없이 새로운 필드(예: 출처의 페이지 제목)를 채울 수 있습니다.
scorer_version은 재점수화(re-scoring)를 안전하게 만듭니다. 별칭 정규 표현식(alias regex)을 개선하거나, v1을 v2로 올린 후 전체 이력을 재점수화하고 대시보드 전환 전에 두 버전을 나란히 비교할 수 있습니다.
컬렉터 (The collector)
컬렉션은 오직 run에만 쓰기(write)를 합니다. 브랜드는 전혀 감지하지 않습니다.
# collect.py
import json, sqlite3, datetime as dt, time
from engines import ENGINES # (text, sources, model, raw)를 반환하는 함수들
...
점수화(Scoring)는 별도의 스크립트입니다. 이 스크립트는 현재 scorer_version에 대해 score 행이 없는 run 행을 읽어와 채워 넣습니다. 이를 분리해 두면 점수화 과정에서 발생하는 버그가 API 비용으로 이어지는 것을 막을 수 있습니다.
GitHub Actions로 스케줄링하기
사이드 프로젝트나 개념 증명(proof of concept)의 경우, SQLite 파일을 저장소에 커밋하는 예약된 워크플로우가 잘 작동합니다:
# .github/workflows/collect.yml
name: collect-ai-visibility
on:
...
예약된 워크플로우에 대해 알아야 할 두 가지 사항이 있습니다. GitHub는 정확한 시작 시간을 보장하지 않으며(부하로 인해 실행이 지연될 수 있음), 공개 저장소의 예약된 워크플로우는 저장소 활동 없이 60일 후에 비활성화됩니다. 매일 데이터를 커밋하는 것은 활동으로 간주되므로 두 번째 문제는 보통 괜찮지만, 공백이 생겨도 놀라지 마세요. 이것은 `run_date`로 그룹화하고 실행 사이에 정확히 24시간을 기대하기보다는 그렇게 하는 또 다른 이유입니다.
데이터베이스가 수십 MB를 넘어서면 git에서 객체 스토리지(object storage) 또는 관리형 데이터베이스(managed database)로 옮기세요.
## 실행해 볼 만한 첫 번째 쿼리
자사 브랜드에 대한 엔진별 일일 언급률과 그 옆에 샘플 수를 표시하여 아무도 1/2일 데이터를 추세로 읽지 않도록 합니다:
SELECT r.run_date,
r.engine,
COUNT(*) AS n,
...
## 직접 구축할 것인가, 구매할 것인가
이 스키마는 단일 브랜드 팀을 다룹니다. 지역(국가별로 답변이 다름) 추가, 엔진 증가(Copilot과 Google AI Mode는 OpenAI와 Perplexity만큼 깔끔한 API를 갖지 않음), 수십 개의 브랜드를 운영하는 에이전시, 그리고 그 위에 올라가는 UI를 추가하면 더 복잡해집니다.
이것이 [Vista AI의 AI Rank Tracker](https://www.vistaai.io/features/ai-rank-tracker)가 제공하는 인프라입니다: ChatGPT, Gemini, Claude, Perplexity, Copilot 및 Google AI Mode 전반에 걸친 일일 추적, 의도 단계별로 그룹화된 프롬프트, 0–100의 가시성 지수(visibility index), 그리고 '빠른 승리'(quick win) 감지 기능입니다. 또한 이 도구의 프롬프트 리서치 도구는 예상 볼륨이 포함된 높은 의도(high-intent) 프롬프트를 제안하여 `prompt` 테이블을 채우는 데 도움을 줍니다.
만약 직접 구축한다면, 중요한 세 가지 규칙은 다음과 같습니다: **불변의 프롬프트(immutable prompts), 저장된 원본 답변(stored raw answers), 그리고 버전 관리되는 점수화(versioned scoring).**
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
