AI로 28,840개 레코드 강화: 대규모 데이터 처리에서 얻은 교훈
지난 분기 우리는 겉으로는 간단해 보이는 프로젝트를 맡았습니다: 28,840개의 제품 레코드를 AI 생성 설명, 카테고리 및 메타데이터로 강화하는 것이었습니다. 클라이언트는 헤드리스 CMS로 마이그레이션하는 거대한 이커머스 카탈로그를 보유하고 있었고, 모든 단일 레코드에 더 나은 콘텐츠가 필요했습니다. 그 결과는 수만 개의 레코드를 AI API에 던질 때 뭔가 잘못될 수 있고 올바를 수 있는 모든 것에 대한 마스터클래스였습니다.
이것은 이론적인 가이드가 아닙니다. 우리가 구축한 실제 아키텍처, 우리가 지불한 정확한 비용, 우리가 맞닥뜨린 장애 모드 및 우리를 구한 패턴을 안내해드리겠습니다. 자신의 프로젝트를 위해 AI 대량 콘텐츠 강화를 고려 중이라면, 이것이 몇 주일의 고통스러운 발견을 절약해줄 것입니다.
목차
- 수동 작업 대신 AI 강화를 선택한 이유
- 아키텍처: 파이프라인을 구축한 방법
- 대량 처리를 위해 Claude API 선택하기
- 대규모 프롬프트 엔지니어링
- 속도 제한, 재시도 및 차단되지 않는 기술
- 품질 관리: 인간 개입 현실
- 실제 비용 분석
- 우리가 잘못한 것
- 다음에 다르게 할 것
- 자주 묻는 질문
수동 작업 대신 AI 강화를 선택한 이유
비용 계산은 냉정했습니다. 클라이언트는 28,840개의 제품 레코드를 보유하고 있었고 각각은 재작성된 설명(150-300 단어), 세 개의 SEO 친화적 카테고리 태그, 메타 설명 및 비정형 텍스트에서 추출한 구조화된 속성이 필요했습니다. 인간 카피라이터를 위해 레코드당 8분의 보수적 추정으로, 그것은 3,845시간의 작업입니다. 시간당 $35로, 당신은 $134,575를 보고 있고 작은 팀으로는 대략 6개월의 경과 시간입니다.
우리는 API 비용 $3,200 미만, 그리고 약 80시간의 엔지니어링 및 QA 시간으로 11일 내에 AI 강화를 완료했습니다. 우리의 개발 시간을 포함해도, 총 비용은 수동 접근 방식의 약 10분의 1이었습니다.
하지만 여기 아무도 당신에게 말해주지 않는 것이 있습니다: 어려운 부분은 API를 호출하는 것이 아닙니다. 그것은 주변의 모든 것입니다. 데이터 정리, 프롬프트 조정, 품질 검증, 오류 처리 및 당신의 경력 선택에 의문을 갖게 만드는 피할 수 없는 엣지 케이스입니다.
아키텍처: 파이프라인을 구축한 방법
우리는 Node.js 애플리케이션으로 강화 파이프라인을 구축했으며, 이것은 Next.js 개발과 TypeScript에서 우리 팀의 전문성을 고려할 때 의미가 있었습니다. 높은 수준의 아키텍처는 다음과 같습니다:
Source CSV → Parser → Batch Queue → Claude API → Response Validator → Output Store → QA Dashboard
데이터 레이어
우리는 SQLite를 로컬 처리 데이터베이스로 사용했습니다. 매력적이지 않게 들리나요? 하지만 이와 같은 배치 처리에는 완벽합니다. 관리할 서버가 없고, 트랜잭션이 빠르며, 쉽게 결과를 조회할 수 있습니다. 각 레코드는 그 여정을 추적하는 상태 열을 얻었습니다:
interface EnrichmentRecord {
id: string;
original_title: string;
original_description: string;
raw_attributes: string;
status: 'pending' | 'processing' | 'completed' | 'failed' | 'needs_review';
enriched_description: string | null;
enriched_categories: string[] | null;
enriched_meta: string | null;
structured_attributes: Record<string, string> | null;
attempts: number;
last_error: string | null;
token_usage: number;
created_at: string;
updated_at: string;
}
큐 시스템
우리는 Redis로 지원하는 BullMQ를 사용하여 간단한 작업 큐를 구현했습니다. 각 작업은 단일 레코드 강화를 나타냈습니다. 우리는 다음으로 구성했습니다:
- 동시성: 5개의 병렬 워커(이 숫자를 선택한 이유는 나중에 자세히 설명)
- 최대 재시도: 레코드당 3회
- 백오프: 지수, 30초부터 시작
- 작업 타임아웃: 60초
const enrichmentQueue = new Queue('enrichment', {
connection: redisConnection,
defaultJobOptions: {
attempts: 3,
backoff: {
type: 'exponential',
delay: 30000,
},
timeout: 60000,
removeOnComplete: false, // Keep for auditing
},
});
처리 워커
각 워커는 레코드를 가져오고, 프롬프트를 구성하고, Claude의 API를 호출하고, 응답 구조의 유효성을 검증하고, 결과를 다시 작성했습니다. 응답이 우리의 예상 JSON 스키마와 일치하지 않으면, 우리 데이터세트를 자동으로 손상시키는 대신 needs_review 버킷으로 이동했습니다.
대량 처리를 위해 Claude API 선택하기
우리는 Claude(특히 Claude 3.5 Sonnet, 그리고 나중에 더 간단한 작업을 위해 Claude 3.5 Haiku)를 선택하기 전에 세 가지 옵션을 평가했습니다:
| 기능 | Claude 3.5 Sonnet | GPT-4o | Gemini 1.5 Pro |
|---|---|---|---|
| 입력 비용(1M 토큰당) | $3.00 | $2.50 | $1.25 |
| 출력 비용(1M 토큰당) | $15.00 | $10.00 | $5.00 |
| 속도 제한(RPM, Tier 2) | 1,000 | 500 | 360 |
| JSON 모드 신뢰성 | 우수 | 좋음 | 불안정 |
| 구조화된 출력 품질 | 동급 최고 | 매우 좋음 | 좋음 |
| 배치 API 할인 | 50% | 50% | 해당 없음 |
Q1 2025 기준 가격. 현재 가격을 확인하세요 -- 이것들은 자주 변합니다.
우리가 Claude를 선택한 이유는 몇 가지입니다. 첫째, 구조화된 출력에 대한 명령어 준수가 우리의 500 레코드 테스트 실행 중 대안보다 눈에 띄게 더 좋았습니다. 거의 29K 레코드를 처리할 때, 형식 준수에서도 2% 개선이 수백 개의 수동 수정을 절약합니다. 둘째, Anthropic의 배치 API는 시간에 민감하지 않은 작업에 50% 할인을 제공했으며, 이것은 경제를 훨씬 더 유리하게 만들었습니다.
솔직히, GPT-4o도 문제없었을 것입니다. 이 규모에서의 차이는 원시 품질보다 속도 제한 및 가격에 관한 것입니다. 하지만 JSON 출력에 대한 Claude의 일관성이 결정 요인이었습니다.
왜 우리는 Sonnet과 Haiku를 모두 사용했는가
이것은 API 비용의 약 40%를 절약한 트릭입니다: 우리는 모든 것에 동일한 모델을 사용하지 않았습니다. 제품 설명에는 Sonnet의 품질이 필요했습니다. 하지만 카테고리 분류 및 속성 추출? Haiku는 비용의 일부로 그것을 잘 처리했습니다.
우리는 강화를 두 번의 패스로 나눴습니다:
- 패스 1(Haiku): 카테고리 분류, 속성 추출, 기본 메타데이터 -- $0.25/1M 입력, $1.25/1M 출력
- 패스 2(Sonnet): 설명 재작성, 메타 설명, SEO 콘텐츠 -- $3.00/1M 입력, $15.00/1M 출력
대규모 프롬프트 엔지니어링
이것은 대부분의 튜토리얼이 실패하는 지점입니다. 그들은 당신에게 단일 프롬프트를 보여주고 그것을 하루라고 합니다. 28,840개의 레코드를 동일한 프롬프트 템플릿을 통해 실행할 때, 작은 결함은 거대한 문제로 증폭됩니다.
프롬프트 템플릿
약 15번의 반복(예, 우리는 git에서 추적했습니다) 후, 작동한 대략적인 구조는 다음과 같습니다:
const buildPrompt = (record: SourceRecord): string => `
You are enriching product data for an e-commerce catalog. Generate the following for the product below:
1. A product description (150-300 words, second person, benefit-focused)
2. Exactly 3 category tags from this allowed list: ${CATEGORY_LIST}
3. A meta description (120-155 characters)
4. Structured attributes as key-value pairs
Rules:
- Do NOT invent features not present in the source data
- If information is ambiguous, use the "uncertain" flag
- Match the brand's tone: professional but approachable
- Description must be unique -- do not repeat the title verbatim in the first sentence
Respond ONLY with valid JSON matching this schema:
${JSON_SCHEMA}
Source product data:
Title: ${record.title}
Existing description: ${record.description}
Raw attributes: ${record.attributes}
Price: ${record.price}
Brand: ${record.brand}
`;
대규모 프롬프트에 대한 교훈
출력 형식에 대해 터무니없이 구체적으로 작성하세요. 우리는 모든 요청에 전체 JSON 스키마를 포함했습니다. 예, 토큰을 추가합니다. 아니요, 건너뛰지 마세요. 우리가 시스템 명령에만 의존해보려던 유일한 시간에, 우리의 형식 준수는 97%에서 81%로 떨어졌습니다.
출력 어휘를 제한하세요. 카테고리 태그의 경우, 우리는 명시적인 허용 목록을 제공했습니다. 개방형 분류는 우리의 테스트 배치 전체에 걸쳐 847개의 고유 카테고리를 생성했습니다. 제한된 버전은? 우리가 원했던 42개 정확히.
환각에 대한 보호장치를 추가하세요. 제품은 때때로 그들이 가지지 않은 기능을 자랑할 것입니다. "소스 데이터에 없는 기능을 발명하지 마세요"를 추가하면 환각 속성을 약 70% 감소시켰습니다. uncertain 플래그를 추가하면 대부분의 남은 사례를 포착했습니다.
온도가 생각보다 더 중요합니다. 우리는 0.3으로 정했습니다. 그보다 낮으면 유사한 제품들 간에 설명이 반복되었습니다. 높으면 브랜드 음성과 일치하지 않는 창의적인 작문을 시작했습니다.
속도 제한, 재시도 및 차단되지 않는 기술
이 섹션은 실제로 "가장 많은 엔지니어링 시간이 걸린 부분"이라고 불러야 합니다. Anthropic의 속도 제한은 잘 문서화되어 있지만 문서를 읽는 것보다 지속적인 부하 하에서 다르게 작동합니다.
우리의 속도 제한 전략
Tier 2(지출 $40+ 후 얻음)에서, Claude는 분당 1,000개의 요청과 분당 80,000개의 토큰을 제공합니다. 우리의 평균 요청이 약 1,200개의 입력 토큰과 800개의 출력 토큰이라는 것을 깨달을 때까지 관대해 보입니다. 그것은 우리의 실제 제한이 토큰 제한에 도달하기 전에 약 40개의 동시 요청을 의미했습니다.
우리는 5개의 동시 워커를 실행했고, 각각은 한 번에 하나의 레코드를 처리했으며, 요청 사이에 200ms의 지연이 있었습니다. 이것은 우리에게 대략 분당 15-20개의 요청을 제공했습니다 -- RPM 제한을 잘 아래에, 그리고 토큰 예산 내에서 편안하게.
const rateLimiter = new Bottleneck({
maxConcurrent: 5,
minTime: 200, // ms between requests
reservoir: 900, // requests per minute (leaving buffer)
reservoirRefreshAmount: 900,
reservoirRefreshInterval: 60 * 1000,
});
왜 이렇게 보수적인가? 속도 제한에 도달하면 연쇄 실패를 야기하기 때문입니다. 하나의 429 응답은 재시도를 트리거하고, 이것은 큐에 추가되고, 이것은 동시성 압력을 증가시킵니다. 우리는 첫 번째 실제 실행의 3시간째에 이것을 어렵게 배웠고, 공격적인 설정은 재시도 폭풍을 일으켰고 이것은 효과적으로 45분 동안 파이프라인을 정지시켰습니다.
배치 API 대안
프로젝트 중반에, 우리는 부분적으로 Anthropic의 배치 API로 전환했습니다. 개별 요청을 하는 대신, 요청의 JSONL 파일을 업로드하고 24시간 내에 결과를 돌려받습니다. 트레이드오프: 50% 비용 감소, 하지만 실시간 피드백은 상실합니다.
우리는 패스 1(Haiku 분류)에 배치 API를 사용했고 패스 2(Sonnet 설명)에 실시간 API를 사용했습니다. 이 하이브리드 접근 방식은 우리에게 최적의 지점이었습니다 -- 비싼 창의적인 작업에 대한 빠른 피드백, 상품 분류에 대한 배치 경제.
품질 관리: 인간 개입 현실
AI 강화가 완전히 자동화되었다고 말하는 누군가는 거짓을 말하고 있거나 대규모로 그것을 하지 않았습니다. 우리는 문제를 조기에 포착하고 쓰레기가 프로덕션에 들어가는 것을 방지하는 QA 프로세스를 구축했습니다.
자동화된 검증
모든 API 응답은 수락되기 전에 검증을 거쳤습니다:
const validateEnrichment = (result: EnrichmentResult): ValidationOutcome => {
const issues: string[] = [];
// Length checks
if (result.description.length < 400 || result.description.length > 2000) {
issues.push('description_length');
}
// Category validation
const invalidCats = result.categories.filter(c => !ALLOWED_CATEGORIES.includes(c));
if (invalidCats.length > 0) issues.push('invalid_categories');
// Meta description length
if (result.meta.length > 160) issues.push('meta_too_long');
// Hallucination signals
const hallucination_phrases = ['I think', 'probably', 'might be', 'as an AI'];
if (hallucination_phrases.some(p => result.description.includes(p))) {
issues.push('possible_hallucination');
}
// Duplicate detection (fuzzy match against already-processed records)
if (isDuplicateDescription(result.description)) {
issues.push('duplicate_content');
}
return {
valid: issues.length === 0,
issues,
needsReview: issues.length > 0 && issues.length < 3,
rejected: issues.length >= 3,
};
};
수동 검토 샘플링
우리는 처리된 모든 레코드의 5%(약 1,440)를 수동 검토를 위해 샘플링했습니다. 우리 QA 팀은 각각을 정확성, 브랜드 음성 및 완전성에 대해 점수를 매겼습니다. 다음은 우리의 실제 검토 수치입니다:
| 메트릭 | 점수 |
|---|---|
| 사실적 정확도 | 94.2% |
| 브랜드 음성 일치 | 87.6% |
| 형식 준수 | 97.1% |
| 카테고리 정확도 | 91.8% |
| 수정이 필요한 레코드 | 8.3% |
| 완전히 거부된 레코드 | 1.9% |
이 8.3%는 중요한 맥락입니다. 그것은 약 2,400개의 레코드가 인간 편집이 필요했음을 의미합니다. 여전히 모든 28,840을 수동으로 작성하는 것보다 훨씬 적습니다 -- 하지만 0이 아닙니다. 그것을 예산에 포함시키세요.
실제 비용 분석
투명성의 시간입니다. 우리가 실제로 지출한 것은 다음과 같습니다:
| 비용 범주 | 금액 |
|---|---|
| Claude 3.5 Haiku(패스 1 - 배치 API) | $312 |
| Claude 3.5 Sonnet(패스 2 - 실시간) | $2,147 |
| 실패/재시도 요청(~6% 오버헤드) | $189 |
| Redis 호스팅(2주) | $15 |
| 엔지니어링 시간(80시간 × $150) | $12,000 |
| QA 검토 시간(40시간 × $45) | $1,800 |
| 합계 | $16,463 |
| API 비용만 | $2,648 |
완전히 수동 작업에 대한 $134,575 추정과 비교해보세요. 모든 엔지니어링 및 QA 시간을 포함해도, 우리는 수동 비용의 약 12%입니다. 그리고 파이프라인은 재사용 가능합니다 -- 다음에 유사한 프로젝트를 실행할 때, 엔지니어링 비용은 거의 0에 떨어집니다.
레코드당 API 비용은 약 $0.092였습니다. 레코드당 AI 강화를 위해 10센트 미만입니다. 그것은 임원진이 자리에서 일어나게 만드는 숫자입니다.
우리가 잘못한 것
데이터 정리 과소평가
API에 보내기 전에 소스 데이터를 정리하는 데만 3일을 보냈습니다. 레코드에는 HTML 엔티티, Unicode 쓰레기, 잘린 설명 및 잘못된 열의 필드가 있었습니다. 쓰레기가 들어오면 쓰레기가 나간다는 것은 단지 진부한 말이 아닙니다 -- 그것은 대량 AI 처리의 기본 법칙입니다.
처음부터 배치 API를 사용하지 않음
우리는 패스 1을 배치 API로 실행하기 전에 배치 API가 절반의 비용이 될 것을 발견하기 전에 API 비용으로 약 $400을 태웠습니다. 시작하기 전에 전체 문서를 읽으세요. 전부.
불충분한 중복 검사
우리의 초기 중복 검사는 너무 순진했습니다 -- 단순 문자열 일치. Claude는 유사한 제품에 대해 구조적으로 동일하지만 약간 다른 단어를 사용한 설명을 생성할 것입니다. 우리는 의미론적 유사성 검사(임베딩 사용)를 구현해야 했고, 이것은 1일의 작업을 추가했습니다.
JSON 파싱 실패
응답의 약 2.4%는 잘못된 JSON으로 돌아왔습니다. 때때로 뒤따르는 쉼표, 때때로 제품 설명에서 이스케이프되지 않은 따옴표. 처음부터 경관대로 하는 대신 더 관대한 JSON 파서를 구현했어야 했습니다.
// What we should have done from day one
const parseResponse = (raw: string): EnrichmentResult | null => {
try {
return JSON.parse(raw);
} catch {
// Try to extract JSON from markdown code blocks
const jsonMatch = raw.match(/```json?\n?([\s\S]*?)\n?```/);
if (jsonMatch) {
try { return JSON.parse(jsonMatch[1]); } catch { /* fall through */ }
}
// Try jsonrepair library as last resort
try { return JSON.parse(jsonrepair(raw)); } catch { return null; }
}
};
다음에 다르게 할 것
1,000 레코드 파일럿으로 시작하세요 전체 실행에 커밋하기 전에. 우리는 500을 했고 그것은 모든 엣지 케이스를 표면화하기에 충분하지 않았습니다.
처음부터 구조화된 출력을 사용하세요. Anthropic은 이제 정의된 스키마를 가진 도구 사용을 지원하며, 이것은 대부분의 JSON 파싱 문제를 제거합니다. 우리는 중반에 이것으로 이주했고 처음부터 시작했기를 바랍니다.
먼저 QA 대시보드를 구축하세요. 우리는 반응적으로 문제가 나타난 후 구축했습니다. 처음부터 가지고 있으면 첫 2,000 레코드 대신 처음 100 레코드에서 문제를 포착했을 것입니다.
더 나은 임베딩에 중복 제거 투자하세요. 우리는 처음부터 의미론적 중복 검사를 위해 전용 임베딩 모델(예:
text-embedding-3-small)을 사용할 것입니다.하이브리드 모델 라우팅을 고려하세요. 일부 레코드는 간단합니다(기본 속성이 있는 티셔츠) 일부는 복잡합니다(수십 개의 사양이 있는 전자제품). 간단한 레코드를 Haiku로, 복잡한 레코드를 Sonnet으로 라우팅 -- 설명도 -- 이것은 API 비용의 또 다른 20-30%를 절약했을 것입니다.
유사한 프로젝트를 계획 중이고 고통스러운 부분을 건너뛰고 싶다면, 우리는 우리의 헤드리스 CMS 개발 실제로 이 종류의 작업에 대해 재사용 가능한 파이프라인을 구축했습니다. 더 많은 세부 사항을 공유하고 싶습니다.
자주 묻는 질문
28,000개 이상의 레코드를 AI로 강화하는 데 얼마나 걸리나요? 우리의 실제 처리 시간은 파이프라인 개발, 테스트, 처리 및 QA 검토를 포함하여 약 11일이었습니다. API 처리 자체(요청 전송 및 응답 수신)는 대략 48시간의 연속 실행이 걸렸습니다. 배치 API를 독점적으로 사용하는 경우, 처리에 24-48시간을 예상하고 엔지니어링 및 QA에 3-5일을 예상하세요.
AI 콘텐츠 강화에 대한 레코드당 비용은 얼마인가요? Claude 3.5 Sonnet 및 Haiku를 조합하여 사용하면, 우리의 API 비용은 제품 설명, 카테고리, 메타 설명 및 구조화된 속성을 생성하기 위해 레코드당 약 $0.092였습니다. 귀하의 결과는 입출력 길이 및 선택하는 모델에 따라 다를 것입니다. 배치 API 처리는 이를 대략 절반으로 줄입니다.
대량 데이터 강화를 위해 Claude가 더 나을까요 아니면 GPT-4? 둘 다 잘 작동합니다. 우리는 테스트 중에 Claude 3.5 Sonnet의 우수한 JSON 형식 준수(GPT-4o의 ~94%와 비교하여 97.1%)로 인해 Claude를 선택했습니다. 그러나 GPT-4o는 출력 토큰에 대해 약간 더 저렴합니다. 강화가 주로 콘텐츠 생성이 아닌 분류인 경우, 차이는 무시할 수 있습니다. 커밋하기 전에 500개의 레코드로 둘 다 테스트하세요.
수천 개의 API 호출을 할 때 속도 제한을 어떻게 처리하나요? Bottleneck과 같은 속도 제한 라이브러리를 사용하고, 보수적인 동시성(5-10개의 병렬 요청)을 설정하고, 재시도에 지수 백오프를 구현하고, 게시된 속도 제한 아래에 10-15% 버퍼를 남겨둡니다. 시간에 민감하지 않은 작업의 경우, Anthropic의 배치 API는 속도 제한 문제를 완전히 피하고 50% 저렴합니다.
AI 강화 레코드의 몇 퍼센트가 인간 검토가 필요할까요? 우리의 프로젝트에서, 처리된 레코드의 8.3%는 어떤 형태의 인간 편집이 필요했고 1.9%는 완전히 거부되고 수동으로 다시 작성되었습니다. 귀하의 숫자는 데이터 품질, 프롬프트 엔지니어링 및 수용 가능한 품질 임계값에 따라 다를 것입니다. 현실적인 기준선으로 5-15% 인간 개입을 계획하세요.
AI 대량 강화가 여러 언어를 처리할 수 있을까요? 예, 하지만 품질은 언어에 따라 크게 다릅니다. Claude와 GPT-4는 주요 유럽 언어를 잘 처리하지만, 덜 일반적인 언어의 정확도는 떨어집니다. 우리는 언어당 별도의 프롬프트 템플릿을 실행하고 QA 샘플에 모국어 사용자를 갖도록 권장합니다. 영어가 아닌 콘텐츠에 대해 인간 검토 백분율이 대략 두 배가 될 것으로 예상하세요.
AI 제품 데이터에서 환각을 어떻게 방지할까요? 3가지 레이어: 발명된 기능을 명시적으로 금지하는 프롬프트 명령어, 모호한 데이터에 대한 "uncertain" 플래그, 강화된 속성을 소스 데이터와 비교하는 자동화된 검증. 우리는 또한 의미론적 유사성 점수를 사용하여 원본 제품 정보에서 너무 멀리 벗어난 설명에 플래그를 지었습니다. 이것은 환각 속성을 약 70% 감소시켰습니다.
기존 도구를 사용해야 할까요 아니면 사용자 정의 파이프라인을 구축해야 할까요? 1,000개 미만의 레코드의 경우, Clay, Bardeen 또는 잘 구조화된 Google Sheets + Apps Script 설정과 같은 도구를 작동할 수 있습니다. 그 이상에서, 사용자 정의 파이프라인은 빠르게 자신을 위해 비용을 지불합니다. 재시도 로직, 품질 검증 및 비용 최적화에 대한 제어는 사용자 정의 솔루션에서 제공하는 것이 필수적입니다. 우리의 파이프라인은 대략 2,000줄의 TypeScript였습니다 -- 사소하지 않지만 거대한 프로젝트도 아닙니다. 당신의 사용 사례를 위해 우리가 하나를 구축하도록 하고 싶다면 우리의 가격 페이지를 확인하세요.