1. 왜 워크플로를 측정해야 할까
요약하면: 분석이 없으면 여러분은 “그럴 것 같다” 모드로 살고, 분석이 있으면 “확실히 안다” 모드로 삽니다.
이 모듈의 이전 강의에서 우리는 이미 시나리오를 단계로 나누고, GPT·위젯·MCP에 역할을 분배했으며, tool‑gating과 단계 간 상태 저장을 논의했습니다. 이제 같은 구성을 분석의 시각으로 봅시다: 모든 것이 의도대로 작동하는지, 그리고 사용자가 실제로 어디에서 막히는지.
일반적인 웹에서는 퍼널이 익숙합니다: 몇 명이 랜딩에 왔는지, 몇 명이 장바구니에 담았는지, 몇 명이 결제까지 갔는지. ChatGPT App에서도 거의 같습니다. 다만 페이지 대신 워크플로의 단계가 있고, “구매 버튼 클릭” 대신 사용자 발화, 도구 호출, 위젯 상호작용의 조합이 있습니다.
지표 없이 복잡한 시나리오를 만들면 다음을 보지 못합니다:
- 어느 단계에서 사람들이 가장 많이 “이탈”하는지;
- 어디서 오래 머물며 1분씩 읽는지(혹은 그냥 차를 마시러 갔다가 돌아오지 않는지);
- 어떤 단계는 전혀 가치를 주지 못하고 오히려 짜증만 유발하는지;
- 프롬프트나 tool gating 변경이 행동에 어떤 영향을 주는지.
단계별 분석의 목표는 단순합니다: 완료된 시나리오의 비율을 높이고, 결과까지의 시간을 줄이며, 오류와 고객 지원 문의를 줄이는 것입니다.
이 시점부터 워크플로는 단지 아키텍처 객체이자 UX 퀘스트만이 아닙니다. 숫자로 측정 가능한 대상이기도 합니다.
2. ChatGPT App의 시나리오 퍼널
클래식 웹에서 퍼널은 선형입니다: Landing → Product → Cart → Checkout. ChatGPT App에서는 그림이 조금 더 역동적입니다: 사용자가 말로 어떤 단계를 “건너뛰기”도 하고, 모델이 때로는 단계를 생략하기도 하며, 위젯과 대화 텍스트가 비동기화될 수도 있습니다.
그럼에도 기본 개념은 같습니다: 일련의 단계가 있고, 각 단계마다 일부 사용자는 다음으로 진행하고 일부는 그렇지 않습니다.
우리의 GiftGenius를 예로 들어봅시다:
- collect_recipient — ChatGPT와 위젯이 수신자 기본 정보를 수집합니다(성별, 나이, 관계, 관심사).
- collect_budget — 예산과 통화를 확인합니다.
- suggest_ideas — MCP/에이전트가 아이디어를 골라 위젯에 선물 카드들을 반환합니다.
- review_selection — 사용자가 아이디어에 좋아요/숨김을 표시하고 1–2개의 후보를 고릅니다.
- checkout — 커머스 인텐트를 생성하고 주문을 진행합니다.
퍼널로 그리면 다음과 같습니다:
flowchart TD
A[워크플로 시작] --> B["1\. 받는 사람"]
B --> C["2\. 예산"]
C --> D["3\. 선물 아이디어"]
D --> E["4\. 선물 선택"]
E --> F["5\. Checkout"]
하지만 기억해야 할 점: 사용자가 “바로 결제로 가자” 또는 “먼저 비싼 옵션을 보여줘”라고 쓰면 모델이 일부 단계를 건너뛰도록 결정할 수 있습니다. 따라서 ChatGPT App의 단계별 분석은 UI 화면만이 아니라 모델의 행동까지 포함합니다. 실제로 어떤 단계들을 어떤 순서로 거쳤는지, 그리고 누가 전환을 촉발했는지(사용자, 위젯, GPT)를 봐야 합니다.
3. 단계별 기본 지표
제품 분석의 고전부터 시작해 ChatGPT App에 살짝 맞춰보겠습니다.
각 워크플로마다 최소한 네 가지 기본 지표가 필요합니다.
편의를 위해 표로 정리해 봅시다:
| 지표 | 무엇을 의미 | 전형적인 질문 |
|---|---|---|
| Start rate | 시나리오를 실제로 시작한 사용자 수 | 우리 App은 실제로 누구에게 노출되고 있나? |
| Completion rate | 얼마나 많은 사용자가 마지막까지 도달했는가 | 시나리오가 결과까지 잘 이끌어 주는가? |
| Conversion per step | N 단계에서 N+1 단계로 이동한 사용자의 비율 | 정확히 어느 단계가 “구멍”인가? |
| Drop-off per step | N 단계에서 이탈한 사용자의 비율 | 어느 단계에서 사람들이 가장 자주 포기하는가? |
여기에 보통 노력 지표를 덧붙입니다:
- 단계당 평균 시간(어디서 “머무는지”);
- 단계당 상호작용 수(메시지/클릭이 얼마나 필요했는지);
- 오류로 끝나거나 재시도를 요구한 단계의 비율.
LLM 시나리오 맥락에서는 모델의 도구 선택 정확도나 특정 단계에서의 “헛소리” 응답 비율처럼 더 특화된 것들도 추가됩니다. 다만 이는 고급 주제로, 마지막 모듈에서 다룰 예정입니다.
커머스 시나리오에서는 단계 위에 비즈니스 지표가 얹힙니다:
- 워크플로 시작 대비 결제 전환율;
- 특정 단계(예: “아이디어 추천”) 대비 결제 전환율;
- 평균 객단가;
- 취소/환불 비율.
중요: 이 숫자들은 서로 독립적으로 존재하지 않습니다. 인과관계가 있습니다. 드롭오프가 큰 단계가 항상 나쁜 것은 아닙니다. 부적합한 사용자를 걸러내서, 이후 단계로는 실제로 시나리오가 유용한 사용자만 가는 것일 수도 있기 때문입니다. 그래서 분석은 단순히 “퍼센트를 세기”가 아니라 데이터로 이야기를 구성하는 능력입니다.
이 모든 퍼센트와 퍼널을 계산하려면 원시 이벤트가 필요합니다: 누가, 언제, 어떤 단계를 통과했는지(또는 못 했는지). 다음 섹션에서 이런 이벤트의 포맷을 합의합니다.
4. 분석 이벤트는 어떻게 생겼나
코드를 쓰기 전에, 위젯과 백엔드에서 보낼 “이벤트”의 포맷을 정의해야 합니다.
일반적으로 분석 이벤트는 다음을 포함합니다:
- 누가: 사용자 또는 최소한 세션 식별자;
- 어떤 워크플로이며 그 버전은 무엇인지;
- 어떤 단계인지;
- 무슨 일이 발생했는지(이벤트 타입);
- 성공 여부와 소요 시간;
- 약간의 메타데이터(로케일, 디바이스 등).
워크플로 이벤트의 간단한 스키마는 다음과 같습니다:
export type WorkflowEventType =
| "workflow_started"
| "workflow_finished"
| "step_started"
| "step_completed"
| "step_failed";
export interface WorkflowAnalyticsEvent {
eventId: string; // uuid
timestamp: string; // ISO 문자열
userId?: string; // 가능하면
conversationId?: string; // ChatGPT 대화 ID(가능한 경우)
workflowId: string; // 내부 식별자
workflowType: "gift_selection";
workflowVersion: string; // 예: "1.2.0" 또는 "1.2.0-A"
stepName?: string; // collect_budget, suggest_ideas 등
eventType: WorkflowEventType;
toolName?: string; // tool-call과 관련된 경우
success?: boolean;
errorCode?: string | null;
durationMs?: number;
metadata?: Record<string, unknown>;
}
몇 가지 포인트:
첫째, workflowVersion은 A/B 테스트를 할 생각이라면 매우 중요합니다. 없으면 어떤 시나리오 변형이 더 좋은 숫자를 내는지 절대 알 수 없습니다.
둘째, conversationId나 다른 상관관계 ID는 이벤트를 연결해 줍니다: 위젯의 단계, MCP에서의 도구 호출, 그리고 텍스트 대화. 이후 모듈에서 트레이싱과 옵저버빌리티를 더 이야기하겠지만, 처음부터 “엔드투엔드” 식별자를 염두에 두는 습관이 매우 유용합니다.
셋째, 이벤트에 이것저것 다 넣을 필요는 없습니다. 메시지의 전체 텍스트, e‑mail, 주소 같은 PII는 가급적 피하거나 강하게 익명화해야 합니다 — 이에 대해서는 끝부분에서 다시 이야기합니다.
5. 위젯 계측하기(Next.js + Apps SDK)
이제 가장 흥미로운 부분입니다: 사용자가 시나리오를 진행할 때 GiftGenius 위젯이 스스로 조용히 단계를 리포트하게 만드는 방법.
이전 강의에서 이미 다음과 비슷한 것을 만들었다고 가정합시다:
// components/GiftWizard.tsx
type StepId = "recipient" | "budget" | "ideas" | "review" | "checkout";
export function GiftWizard() {
const [currentStep, setCurrentStep] = useState<StepId>("recipient");
const [workflowId] = useState(() => crypto.randomUUID());
// ... 여기서 다양한 단계를 렌더링
}
작은 “분석 레이어”를 훅 형태로 추가해 봅시다.
useWorkflowAnalytics 훅
workflowId, workflowVersion을 알고, 우리 Next.js API 라우트 /api/workflow-analytics로 이벤트를 보낼 수 있는 래퍼를 만듭니다.
// lib/useWorkflowAnalytics.ts
import { useCallback } from "react";
import type { WorkflowAnalyticsEvent, WorkflowEventType } from "./types";
const WORKFLOW_VERSION = "1.0.0";
export function useWorkflowAnalytics(
workflowId: string,
workflowType: WorkflowAnalyticsEvent["workflowType"] = "gift_selection"
) {
const sendEvent = useCallback(
async (payload: Omit<WorkflowAnalyticsEvent, "eventId" | "timestamp" | "workflowType" | "workflowVersion" | "workflowId">) => {
const event: WorkflowAnalyticsEvent = {
eventId: crypto.randomUUID(),
timestamp: new Date().toISOString(),
workflowId,
workflowType,
workflowVersion: WORKFLOW_VERSION,
...payload,
};
// 간단히 API로 전송; 프로덕션에서는 버퍼/디바운스 추가 가능
await fetch("/api/workflow-analytics", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(event),
});
},
[workflowId, workflowType]
);
const trackStepEvent = useCallback(
async (stepName: string, eventType: WorkflowEventType, extra?: Partial<WorkflowAnalyticsEvent>) => {
await sendEvent({ stepName, eventType, ...extra });
},
[sendEvent]
);
return { sendEvent, trackStepEvent };
}
여기서 중요한 점은 훅이 특정 UI 단계에 의존하지 않는다는 것입니다. stepName과 eventType만 알 뿐입니다. 구체적인 컴포넌트가 “단계를 시작했다”, “단계를 끝냈다”처럼 알려줄 것입니다.
workflow_started와 workflow_finished 전송
GiftWizard 컴포넌트에서 마운트/언마운트 시점에 시나리오의 시작과 종료를 기록할 수 있습니다:
// components/GiftWizard.tsx
export function GiftWizard() {
const [currentStep, setCurrentStep] = useState<StepId>("recipient");
const [workflowId] = useState(() => crypto.randomUUID());
const { sendEvent } = useWorkflowAnalytics(workflowId);
useEffect(() => {
void sendEvent({ eventType: "workflow_started" });
return () => {
void sendEvent({ eventType: "workflow_finished" });
};
}, [sendEvent]);
// ...
}
물론 언마운트로 종료를 판단하는 것은 거친 근사치입니다. 사용자가 채팅을 최소화하거나 다른 대화로 이동할 수 있으니까요. 하지만 이런 거친 메트릭만으로도 시나리오가 “어디까지든” 도달한 비율을 감 잡을 수 있습니다.
단계별 이벤트 추적
이제 각 단계가 스스로 분석에 신호를 보내도록 만듭시다. 먼저 간단한 래퍼를 추가합니다:
interface StepProps {
stepId: StepId;
onNext: () => void;
trackStepEvent: (stepName: string, eventType: WorkflowEventType, extra?: Partial<WorkflowAnalyticsEvent>) => Promise<void>;
}
function StepRecipient({ stepId, onNext, trackStepEvent }: StepProps) {
useEffect(() => {
void trackStepEvent(stepId, "step_started");
}, [stepId, trackStepEvent]);
const handleSubmit = async () => {
// ... 검증, widgetState에 저장
await trackStepEvent(stepId, "step_completed");
onNext();
};
return (
<div>
{/* 받는 사람 폼 필드 */}
<button onClick={handleSubmit}>다음</button>
</div>
);
}
GiftWizard에서 trackStepEvent를 전달합니다:
export function GiftWizard() {
// ...
const { trackStepEvent } = useWorkflowAnalytics(workflowId);
const goToNext = () => {
setCurrentStep((prev) => NEXT_STEP[prev]);
};
if (currentStep === "recipient") {
return (
<StepRecipient
stepId="recipient"
onNext={goToNext}
trackStepEvent={trackStepEvent}
/>
);
}
// 나머지 단계...
}
마찬가지로 잠재적인 오류가 있는 단계(예: suggest_ideas에서 외부 API 요청)에서는 실패 시 "step_failed"를 errorCode와 함께 보내고, 성공적으로 옵션을 불러왔다면 "step_completed"를 보낼 수 있습니다.
이렇게 하면 다음을 얻습니다:
- 단계가 언제 시작·종료되는지 명확한 이벤트 목록;
- "step_started"와 "step_completed"의 차이로 단계 소요 시간 계산 가능;
- "step_failed"로 가장 자주 실패하는 단계를 가시화.
6. 백엔드/MCP에서의 계측
클라이언트 분석도 좋지만, 위젯은 다소 취약한 세계에 살고 있습니다: 사용자의 브라우저, iframe, 샌드박스 제약 등. 그러므로 병행해서 서버 측 — MCP 도구나 App의 백엔드 API — 에서도 이벤트를 로깅하는 것이 좋습니다.
예를 들어 suggest_gifts라는 도구가 실제로 무거운 일을 합니다: product feed를 조회하고, 필터를 적용해 선물을 반환합니다. 이 도구 내부에서 비즈니스 로직과 분석 이벤트를 함께 로깅할 수 있습니다.
TypeScript로 된 MCP 도구 핸들러의 예시는 다음과 같습니다:
// mcp/tools/suggestGifts.ts
import type { SuggestGiftsArgs } from "../schemas";
import { logWorkflowEvent } from "../analytics/log";
export async function handleSuggestGifts(args: SuggestGiftsArgs, context: { workflowId: string; stepName: string }) {
const startedAt = Date.now();
try {
// ... 아이디어 추천의 메인 로직
await logWorkflowEvent({
workflowId: context.workflowId,
workflowType: "gift_selection",
workflowVersion: "1.0.0",
stepName: context.stepName,
eventType: "step_completed",
toolName: "suggest_gifts",
success: true,
durationMs: Date.now() - startedAt,
});
return {
content: [{ type: "text", text: "선물 아이디어 5개를 찾았습니다." }],
_meta: {
// 위젯을 위한 원시 데이터
},
};
} catch (e) {
await logWorkflowEvent({
workflowId: context.workflowId,
workflowType: "gift_selection",
workflowVersion: "1.0.0",
stepName: context.stepName,
eventType: "step_failed",
toolName: "suggest_gifts",
success: false,
errorCode: "SUGGEST_FAILED",
durationMs: Date.now() - startedAt,
});
throw e;
}
}
그리고 logWorkflowEvent는 프런트에서 오는 이벤트를 적재하는 동일한 테이블/스토리지에 기록하되, "source": "backend"라는 표시를 붙일 수 있습니다.
서버 측 분석이 더 신뢰할 수 있는 이유
첫째, 도구 호출은 발생했거나 아니거나 둘 중 하나입니다 — “사용자가 아마 버튼을 눌렀다”는 식의 휴리스틱이 아니라 분명한 사실입니다.
둘째, 서버에서는 데이터 집계가 더 쉽습니다. 각 도구가 몇 번 호출되는지, 평균 durationMs는 얼마인지, 오류로 끝나는 비율은 얼마인지 셀 수 있습니다.
셋째, UX 문제(사용자가 해당 단계까지 오지 못함)와 기술 문제(단계까지는 오지만 도구가 자주 실패함)의 차이를 구분해 볼 수 있습니다.
7. 데이터를 읽는 법: 병목 찾기
위젯과 MCP에서 "workflow_started", "step_started", "step_completed", "step_failed" 전송을 이미 구현했고, 저장소에 데이터가 충분히 쌓였다고 가정해 봅시다. GiftGenius에 대해 어느 정도 데이터가 모였고, 단계별 요약 통계를 얻었습니다. 아래 표는 1000개의 워크플로 시작을 기준으로 한 가상의 수치입니다:
| 단계 | 시작 수 | 완료 수 | 해당 단계 드롭오프 | 평균 시간(초) |
|---|---|---|---|---|
| recipient | 1000 | 950 | 5% | 12 |
| budget | 950 | 700 | 26% | 35 |
| ideas | 700 | 680 | 3% | 8 |
| review | 680 | 500 | 26% | 40 |
| checkout | 500 | 420 | 16% | 20 |
여기서 볼 점:
첫째, budget 단계는 명확한 병목입니다. 드롭오프가 높고(26%), 평균 시간도 눈에 띄게 깁니다. 통화/세금에 대해 너무 많이 묻거나, 문구가 이해하기 어렵거나, 사용자에게 예산에 대한 확신이 없을 수 있습니다. 이 단계는 단계를 단순화하거나 두 개의 하위 단계로 나누거나 질문 문구를 바꿔 볼 좋은 후보입니다.
둘째, review에서도 이탈이 큽니다. 선물 카드 UI가 과도하게 복잡하거나, “좋아요”의 의미가 불명확할 수 있습니다. 모델이 너무 많은 옵션을 반환해 위젯이 끝없는 목록처럼 보일 수도 있습니다. 여기서는 숫자뿐 아니라 스크린샷/세션 기록(운영 중이라면)도 함께 보고, 최소한 사용자처럼 시나리오를 직접 따라가 보는 것이 좋습니다.
셋째, checkout에서 16%를 잃습니다 — 커머스 시나리오에서는 큰 손실입니다. 하지만 어디서 잃는지 파악해야 합니다: 주문 작성 단계, 결제 제공업체의 오류, 혹은 사용자가 마음을 바꾼 건지. 이는 순수한 UX 문제만이 아니라 UX + 비즈니스 제약의 결합입니다.
UI 문제와 모델 문제를 구분할 수 있어야 합니다.
- 사용자가 이전 단계로 자주 돌아가 답을 바꾸면 — 이해하기 어렵거나 문구가 좋지 않은 질문 신호입니다.
- 단계는 빠르게 끝나지만 해당 단계의 도구 호출이 자주 실패한다면 — backend/MCP 문제입니다.
- 단계가 오래 걸리는데 오류도 없고 되돌아감도 없다면, 사용자가 그다지 필요하지 않은 장문의 텍스트를 읽고 있을 가능성이 있습니다.
8. 실험과 워크플로 A/B 테스트
숫자 그 자체가 무언가를 개선해 주지는 않습니다. 분석을 유용하게 만들려면 실험을 할 수 있어야 합니다: 단계를 바꾸고 나아졌는지 비교해야 합니다.
ChatGPT App 맥락에서 전형적인 실험은 두 가지 버전의 단계나 단계 순서를 비교하는 것입니다:
- 여러 개의 간단한 화면으로 나눈 긴 위저드 vs 하나의 복잡한 폼;
- 질문 문구의 차이;
- 단계 순서의 차이(예: 예산을 더 일찍/늦게 묻기);
- 서로 다른 tool gating 전략(1단계에서 도구를 적게, 2단계에서 더 많이 등).
좋은 습관은 workflowVersion에 시나리오 버전을 고정하고, 실험 식별자를 추가하는 것입니다. 예: "1.3.0-A", "1.3.0-B".
가장 간단한 A/B 분할(위젯)
실서비스에서는 사용자 또는 세션 단위의 안정적인 어사인먼트(백엔드를 통해)가 필요하겠지만, 학습 예제로는 난수 기반 선택이면 충분합니다.
// lib/useWorkflowVariant.ts
import { useMemo } from "react";
export type WorkflowVariant = "A" | "B";
export function useWorkflowVariant(): WorkflowVariant {
return useMemo(() => {
return Math.random() < 0.5 ? "A" : "B";
}, []);
}
GiftWizard에서 변형을 결정하고 분석에 전달합니다:
export function GiftWizard() {
const [workflowId] = useState(() => crypto.randomUUID());
const variant = useWorkflowVariant();
const { sendEvent, trackStepEvent } = useWorkflowAnalytics(
workflowId,
"gift_selection"
);
useEffect(() => {
void sendEvent({
eventType: "workflow_started",
metadata: { variant },
});
}, [sendEvent, variant]);
// 이후 variant에 따라 텍스트/단계 구조를 바꿀 수 있습니다
}
서버에서는 하드코딩된 "1.0.0" 대신 "1.1.0-A", "1.1.0-B"처럼 바꾸거나, 그냥 metadata.variant를 로깅한 뒤 분석에서 그룹화해도 됩니다.
A/B 테스트의 핵심은 사전에 목표 지표를 정하는 것입니다. 예: “시나리오 completion rate를 42%에서 50%로 올리기” 또는 “budget 단계 시간을 20% 줄이기”. 목표 지표 없이 워크플로를 재구성하면 “장롱을 옮겨서 보기 좋아진 듯한” 개보수에 그치기 쉽습니다.
9. 프라이버시와 데이터 윤리
앞서 metadata와 분석 이벤트에 PII를 그대로 넣지 않는 것이 좋다고 언급했습니다. 메트릭을 논의하다 보면 욕심이 나서 이것저것 로깅하고 싶어집니다. 그러나 여러분은 ChatGPT 내부에서 작업하고 있고, 사용자는 자신의 개인 메시지가 외부 분석으로 원문 그대로 나가지 않기를 합리적으로 기대할 수 있다는 점을 기억해야 합니다.
보안과 스토어 모듈로 가기 전에, 지금 당장 지켜볼 만한 간단한 원칙들:
- 첫째, 사용자의 메시지 원문 전체를 로깅하지 마십시오. 대신 메시지 길이, 응답 유형(숫자, “예/아니오”, 목록 중 선택), 혹은 “응답이 비어 있음/불완전함/수정됨” 같은 익명화된 특성을 저장할 수 있습니다.
- 둘째, 비즈니스 로직에 필요하지 않다면 명시적으로 식별 가능한 정보(PII) — e‑mail, 전화번호, 주소, 전체 이름 — 를 로깅하지 마십시오. 꼭 필요하다면 별도의 보호된 경계에 저장하고 접근을 엄격히 제한하십시오.
- 셋째, 대화 컨텍스트를 신중히 다루십시오. conversationId를 저장한다면, 분석에서 별개의 대화를 정당한 이유와 법적 근거 없이 “슈퍼 프로필”로 묶지 않도록 하십시오.
- 넷째, OpenAI 정책과 스토어 요구사항(출시와 보안을 다루는 모듈에서 자세히 다룰 예정)을 살펴보십시오. ChatGPT 밖으로 반출 가능한 데이터와 그렇지 않은 데이터가 명시되어 있습니다. 분석을 설계할 때부터 익명화와 데이터 최소화를 설계해 두면, 나중에 시스템의 절반을 갈아엎지 않아도 됩니다.
마지막으로, UX 분석은 전면적 감시가 아니며 Big Brother류의 surveillance와는 전혀 다릅니다. 목표는 시나리오를 개선하고 사용자 좌절을 줄이는 것입니다. “누가 새벽 2:37에 checkout까지 가지 못했는지”를 보여주는 Big Brother식 대시보드를 만드는 것이 아닙니다.
10. 워크플로 UX 분석에서 흔한 실수
실수 №1: “아직 프로덕션이 아니니, 메트릭은 나중에”.
개발자들은 App이 이미 실제 사용자에게 쓰이기 시작한 시점에야 분석을 생각하는 경우가 많습니다. 그 결과 이벤트가 “사후”로 도입되어 데이터가 들쭉날쭉해지고, 예전 버전과 새 버전의 시나리오를 비교하기가 거의 불가능해집니다. 최소 퍼널("workflow_started", "step_started", "step_completed", "workflow_finished")은 코드가 비교적 단순할 때 미리 넣어 두는 것이 좋습니다.
실수 №2: 성공만 로깅하고 오류는 무시.
때때로 로그에는 "step_completed"만 있고, "step_failed"는 아무도 기록하지 않습니다. “원래 실패하면 안 되니까요.” 그 결과 어떤 단계에 적은 사용자만 도달한다는 사실은 보이지만, 사용자가 스스로 떠난 것인지 오류로 튕겨나간 것인지 알 수 없습니다. 최소한의 errorCode와 함께 단계의 성공과 실패를 항상 모두 로깅하십시오.
실수 №3: 워크플로 버전에 대한 연결 고리 부재.
텍스트, 단계 순서, tool gating을 바꾸면서도 이벤트에는 늘 workflowVersion: "1.0.0"만 남아 있는 경우가 있습니다. 한 달 뒤 그래프를 보면 무엇이 변경 전이고 무엇이 변경 후인지 알 수 없습니다. 시나리오 버전 고정과, 필요하다면 A/B 변형 표시를 분석의 필수 요소로 포함시키십시오.
실수 №4: 이유 없는 과도한 세분화 분석.
반대 극단은 곧바로 필드 50개짜리 “완벽한” 이벤트 스키마를 만들고, 픽셀 단위 클릭과 타이핑 한 글자까지 모두 로깅하는 것입니다. 첫째, 프라이버시를 침해할 수 있습니다. 둘째, 이런 데이터는 분석이 어려워 노이즈에 파묻힙니다. 실제로 특정 제품 질문에 답하는 작은 이벤트·메트릭 집합부터 시작하고, 필요에 따라 점진적으로 확장하는 것이 좋습니다.
실수 №5: 단계/시나리오 명칭 불일치.
코드에서는 budget, 분석에서는 collect_budget, 보고서에서는 “돈에 관한 질문 단계”처럼 제각각 부르는 경우가 있습니다. 몇 주만 지나도 아무도 무엇이 무엇인지 기억하지 못합니다. 워크플로 설계 단계에서 안정적인 단계 식별자(stepName)를 합의하고, UI·로그·보고서에서 동일하게 사용하십시오.
실수 №6: 아무도 쓰지 않는 메트릭.
가장 슬픈 경우: 공들여 데이터를 모으고, 위젯과 MCP에서 이벤트 전송을 설정했지만, 아무도 대시보드를 열어 의사결정을 하지 않습니다. 분석을 위한 분석은 필요 없습니다. 항상 스스로에게 물어보십시오: “이 메트릭으로 어떤 결정을 내릴 수 있는가?” 답이 없다면 — 그 메트릭은 아직 필요하지 않습니다.
GO TO FULL VERSION