Как мы провели 12,000+ API-вызовов к 11 моделям, открыли правило 60-70, и построили систему маршрутизации с ROI 4,853x
Контекст: кто пишет и о чём эта статья
Игорь Масленников. В IT с 2013 года. Последние два года развиваю AI Dev Team в DNA IT — подразделение, которое работает на мульти-модельной архитектуре. Это техническая статья о том, как мы построили систему оркестрации LLM-моделей для платформы генерации образовательных курсов.
Статья для тех, кто:
Строит AI-продукты и упирается в стоимость API
Думает о мульти-модельной архитектуре, но не знает, с чего начать
Хочет увидеть реальные цифры и код, а не абстрактные рекомендации
Что внутри: методология оценки моделей, открытие правила 60-70, архитектура маршрутизации с примерами кода, бенчмарки и финансовые расчёты.
Проблема: экономика AI на масштабе
Когда мы запускали платформу для генерации образовательных курсов, столкнулись с классической проблемой AI-стартапов: юнит-экономика на масштабе.
Исходные данные:
Целевой объём: 10,000 курсов/месяц
Каждый курс требует ~500 генераций (метаданные + контент)
Нужны модели с большими параметрами (универсальность курсов по любым темам)
Прогноз при использовании премиум-моделей (Sonnet 4.5 / GPT-5):
Стоимость за курс: $2.63 (при 500 генераций) Месячные затраты: 10,000 × $2.63 = $26,300 Годовые затраты: $26,300 × 12 = $315,600 При масштабировании до 100,000 курсов/месяц: Месячные затраты: $263,000 Годовые затраты: $3,156,000
Целевой бюджет: 0.30 за курс)
Превышение: в 8.75 раз.
Это типичная ловушка AI-продуктов: то, что работает на прототипе (100 курсов/месяц = $263), становится катастрофой на production-масштабе.
Методология: 12,000+ API-вызовов за 2 недели
Вместо угадывания "какая модель лучше" мы решили провести комплексную оценку.
Масштаб исследования
Модели (11 штук):
Qwen3 235B Thinking — 235 миллиардов параметров, thinking-режим
Kimi K2 Thinking — мульти-миллиардные параметры, топ-качество
DeepSeek V3 — open-source, хорошее соотношение цена/качество
Gemini Flash — большие контексты (1M+ токенов)
GPT-4o — baseline для сравнения
Grok 4 Fast — специалист по английским текстам
MiniMax M2 — специалист по русским текстам
Claude 3.5 Sonnet — baseline премиум-класса
И ещё 4 модели для edge cases
Сценарии (4 типа):
Метаданные EN (структура курса, цели обучения)
Метаданные RU (структура курса на русском)
Контент уроков EN (наполнение разделов)
Контент уроков RU (наполнение на русском)
Множественные прогоны:
3-5 прогонов для каждой комбинации модель/сценарий
Тестирование разных температур (0.3, 0.5, 0.7)
Проверка стабильности (процент успешных генераций)
Итого: 12,000+ реальных API-вызовов, ~$500 затрат на API, 2 недели инженерного времени.
Критерии оценки
interface ModelEvaluation { // Качество контента quality: { score: number; // 1-10 (экспертная оценка) bloomsValidation: boolean; // Валидация Bloom's Taxonomy semanticSimilarity: number; // 0-1 (Jina-v3 embeddings) structureCorrectness: boolean; // Схема соответствует ожиданиям }; // Стоимость cost: { per500Generations: number; // $ за 500 генераций perGeneration: number; // $ за 1 генерацию }; // Стабильность stability: { successRate: number; // % успешных генераций htmlGlitches: number; // Количество HTML-артефактов timeoutRate: number; // % таймаутов }; // Ключевая бизнес-метрика qualityPerDollar: number; // quality.score / cost.per500Generations }
Инфраструктура валидации
Bloom's Taxonomy Validation:
const BLOOMS_VERBS = { knowledge: ['define', 'list', 'name', 'recall', 'identify', ...], comprehension: ['explain', 'describe', 'summarize', 'interpret', ...], application: ['apply', 'demonstrate', 'solve', 'use', ...], analysis: ['analyze', 'compare', 'contrast', 'differentiate', ...], synthesis: ['create', 'design', 'develop', 'formulate', ...], evaluation: ['evaluate', 'assess', 'judge', 'critique', ...] }; function validateLearningObjectives(objectives: string[]): ValidationResult { const issues: string[] = []; for (const objective of objectives) { const hasBloomsVerb = Object.values(BLOOMS_VERBS) .flat() .some(verb => objective.toLowerCase().includes(verb)); if (!hasBloomsVerb) { issues.push(`Objective lacks Bloom's verb: "${objective}"`); } // Проверка на измеримость if (!objective.match(/\d+|specific|measurable/i)) { issues.push(`Objective may not be measurable: "${objective}"`); } } return { passed: issues.length === 0, issues, bloomsCoverage: calculateBloomsCoverage(objectives) }; }
Semantic Similarity (Jina-v3):
async function calculateSemanticSimilarity( generated: string, reference: string ): Promise { const [genEmbedding, refEmbedding] = await Promise.all([ jinaClient.embed(generated), jinaClient.embed(reference) ]); return cosineSimilarity(genEmbedding, refEmbedding); } // Порог для прохождения валидации const SEMANTIC_THRESHOLD = 0.85;
Результаты: три ключевых открытия
Открытие №1: Большие параметры != премиум-цена
Мы искали модели с "большой картинкой мира" для создания универсальных курсов. Обнаружили, что существуют модели с 235B+ параметрами, которые в 42-157 раз дешевле премиум-класса.
Сравнительная таблица (500 генераций):
Модель | Параметры | Цена | Качество | Качество/$ |
|---|---|---|---|---|
Sonnet 4.5 / GPT-5 | Premium | $110.50 | 9.8/10 | 0.089 |
Kimi K2 Thinking | Multi-B | $2.63 | 9.6/10 | 3.65 |
Qwen3 235B Thinking | 235B | $0.70 | 8.6/10 | 12.3 |
DeepSeek V3 | ~67B | $1.28 | 8.6/10 | 6.7 |
Grok 4 Fast | Large | $0.56 | 9.2/10* | 16.4* |
*Grok 4 Fast показал 10/10 только для английских метаданных
Математика:
Kimi K2 vs Premium: в 42 раза дешевле при потере 0.2 балла качества (~2%)
Qwen3 235B vs Premium: в 157 раз дешевле при потере 1.2 балла качества (~12%)
Открытие №2: Специализация превосходит универсальность
Каждая модель имеет сильные и слабые стороны:
const MODEL_SPECIALIZATIONS: Record = { 'qwen3-235b-thinking': { strengths: ['metadata-generation', 'structure-planning'], weaknesses: ['html-lesson-content'], // HTML-глитчи в уроках bestFor: ['course-metadata', 'learning-objectives'], stability: 1.0, // 100% успех для метаданных }, 'minimax-m2': { strengths: ['russian-content', 'lesson-generation'], weaknesses: ['metadata-structure'], bestFor: ['ru-lesson-content'], stability: 0.98, }, 'grok-4-fast': { strengths: ['english-metadata', 'speed'], weaknesses: ['lesson-content', 'russian'], bestFor: ['en-metadata'], stability: 0.95, }, 'kimi-k2-thinking': { strengths: ['all-tasks', 'quality'], weaknesses: ['cost'], // Дороже остальных специалистов bestFor: ['complex-courses', 'escalation'], stability: 0.99, } };
Вывод: Правильная модель для каждой задачи > одна модель для всех задач.
Открытие №3: Правило 60-70 (главное открытие)
При изучении production AI-систем (Jasper AI, Notion AI, Copy.ai) мы нашли критическую цитату:
> "Качество метаданных определяет 60-70% качества финального контента в мульти-стадийных конвейерах"
Наш конвейер генерации:
Phase 1: Topic Analysis → Phase 2: Metadata Generation → Phase 3: Content Generation → Phase 4: Validation
Эксперимент: Распределение бюджета на Phase 2 (метаданные)
Бюджет Phase 2 | Финальное качество | Примечание |
|---|---|---|
10% | 60% | Расплывчатая структура |
30% | 75% | Базовая структура |
50% | 90% | Детальная структура |
Механизм:
// Инвестиция $0.18 в высококачественные метаданные const phase2Result = await generateMetadata({ model: 'qwen3-235b-thinking', cost: 0.18, output: { courseStructure: 'detailed', learningObjectives: 'bloom-validated', sectionBreakdown: 'comprehensive' } }); // Позволяет использовать дешёвые модели в Phase 3 const phase3Result = await generateContent({ model: 'oss-120b', // $0.084 guidedBy: phase2Result.metadata, // Сильное структурное руководство quality: 'high' // Несмотря на дешёвую модель }); // Общая стоимость: $0.18 + $0.084 = $0.264 // Альтернатива без сильных метаданных: $0.03 + $0.50+ = $0.53+ // Экономия: $0.24 за курс
ROI правила 60-70:
Экономия за курс: $0.24
При 5,000 курсов/месяц: $1,200/месяц
Годовая экономия: $14,400 (только от этой оптимизации)
Архитектура: система маршрутизации
Общая схема
┌─────────────────────────────────────────────────────────────────┐ │ Request Router │ │ ┌─────────────┐ ┌──────────────┐ ┌─────────────────────┐ │ │ │ Task Type │ │ Language │ │ Complexity Score │ │ │ │ Detection │ │ Detection │ │ Calculation │ │ │ └─────────────┘ └──────────────┘ └─────────────────────┘ │ └────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Model Selection Logic │ │ │ │ IF task == 'metadata' AND lang == 'en': │ │ → grok-4-fast (10/10, $0.56) │ │ │ │ IF task == 'metadata' AND lang == 'ru': │ │ → qwen3-235b-thinking (9/10, $0.70) │ │ │ │ IF task == 'lesson-content' AND lang == 'ru': │ │ → minimax-m2 (10/10, $1.67) │ │ │ │ IF complexity > THRESHOLD: │ │ → kimi-k2-thinking (9.6/10, $2.63) │ │ │ │ DEFAULT: │ │ → oss-120b ($0.084) + escalation on failure │ └────────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Validation Layer │ │ ┌─────────────┐ ┌──────────────┐ ┌─────────────────────┐ │ │ │ Bloom's │ │ Semantic │ │ Schema │ │ │ │ Validation │ │ Similarity │ │ Validation │ │ │ └─────────────┘ └──────────────┘ └─────────────────────┘ │ │ │ │ IF validation.failed: │ │ → Escalate to premium model OR regenerate │ └─────────────────────────────────────────────────────────────────┘
Реализация маршрутизатора
interface RouterConfig { models: ModelConfig[]; escalationChain: string[]; validationRules: ValidationRule[]; } interface GenerationRequest { taskType: 'metadata' | 'lesson-content' | 'quiz' | 'summary'; language: 'en' | 'ru'; topic: string; complexityIndicators: string[]; } class ModelRouter { private config: RouterConfig; private metrics: MetricsCollector; async route(request: GenerationRequest): Promise { const complexity = this.calculateComplexity(request); const taskProfile = this.getTaskProfile(request.taskType); // Правило 1: Специализация по задаче + языку const specialist = this.findSpecialist( request.taskType, request.language ); if (specialist && complexity < 0.7) { return { model: specialist, reason: 'task-language-specialist', expectedCost: specialist.costPer500 / 500, expectedQuality: specialist.qualityScore }; } // Правило 2: Сложные задачи → премиум if (complexity >= 0.8) { return { model: this.config.models.find(m => m.id === 'kimi-k2-thinking'), reason: 'high-complexity-escalation', expectedCost: 2.63 / 500, expectedQuality: 9.6 }; } // Правило 3: Базовый уровень + эскалация при сбое return { model: this.config.models.find(m => m.id === 'oss-120b'), reason: 'cost-optimized-baseline', expectedCost: 0.084 / 500, expectedQuality: 8.2, escalationOnFailure: 'qwen3-max' }; } private calculateComplexity(request: GenerationRequest): number { const indicators = request.complexityIndicators; let score = 0; // Индикаторы сложности if (indicators.includes('multi-domain')) score += 0.3; if (indicators.includes('technical-depth')) score += 0.2; if (indicators.includes('research-required')) score += 0.25; if (indicators.includes('long-form')) score += 0.15; if (indicators.includes('creative')) score += 0.1; return Math.min(score, 1.0); } private findSpecialist( taskType: string, language: string ): ModelConfig | null { const specializations: Record> = { 'metadata': { 'en': 'grok-4-fast', 'ru': 'qwen3-235b-thinking' }, 'lesson-content': { 'en': 'oss-120b', 'ru': 'minimax-m2' } }; const modelId = specializations[taskType]?.[language]; return modelId ? this.config.models.find(m => m.id === modelId) ?? null : null; } }
Критерии эскалации
interface EscalationCriteria { bloomsValidationFailed: boolean; semanticSimilarityBelow: number; // < 0.85 htmlGlitchesDetected: boolean; contextSizeExceeded: boolean; // > 120K токенов regenerationCount: number; // > 2 } async function handleValidationFailure( result: GenerationResult, criteria: EscalationCriteria ): Promise { // Bloom's Taxonomy провалена → премиум модель if (criteria.bloomsValidationFailed) { return { action: 'escalate', targetModel: 'kimi-k2-thinking', reason: 'blooms-validation-failed' }; } // Семантическое сходство низкое → повторная генерация if (criteria.semanticSimilarityBelow < 0.85) { return { action: 'regenerate', targetModel: result.model, // Та же модель adjustments: { temperature: result.temperature - 0.1 }, reason: 'low-semantic-similarity' }; } // HTML-глитчи → переключение модели if (criteria.htmlGlitchesDetected) { return { action: 'switch-model', targetModel: 'minimax-m2', // Стабильнее для HTML reason: 'html-glitches' }; } // Большой контекст → модель с большим окном if (criteria.contextSizeExceeded) { return { action: 'switch-model', targetModel: 'gemini-flash', // 1M+ контекст reason: 'context-size' }; } // Много повторных генераций → эскалация на премиум if (criteria.regenerationCount > 2) { return { action: 'escalate', targetModel: 'kimi-k2-thinking', reason: 'excessive-regenerations' }; } return { action: 'none' }; }
Стратегический микс: финальная конфигурация
Распределение трафика
const TRAFFIC_DISTRIBUTION: Record = { // 70% базовый уровень — максимальная экономия 'qwen3-235b-thinking': { percentage: 70, costPer500: 0.70, useCases: ['metadata-ru', 'general-metadata'], qualityScore: 8.6 }, // 15% премиум качество — сложные случаи 'kimi-k2-thinking': { percentage: 15, costPer500: 2.63, useCases: ['complex-courses', 'escalation', 'validation-failures'], qualityScore: 9.6 }, // 10% специалист EN — английские метаданные 'grok-4-fast': { percentage: 10, costPer500: 0.56, useCases: ['en-metadata'], qualityScore: 10.0 // Для EN метаданных }, // 5% специалист RU — русские уроки 'minimax-m2': { percentage: 5, costPer500: 1.67, useCases: ['ru-lesson-content'], qualityScore: 10.0 // Для RU уроков } }; // Средневзвешенная стоимость function calculateAverageCost(): number { return Object.values(TRAFFIC_DISTRIBUTION) .reduce((sum, model) => { return sum + (model.costPer500 * model.percentage / 100); }, 0); } // Результат: $0.94 за 500 генераций (средневзвешенная)
Логика для Phase 2 (метаданные)
async function generatePhase2Metadata( courseRequest: CourseRequest ): Promise { const router = new ModelRouter(ROUTER_CONFIG); // Выбор модели на основе языка и сложности const selection = await router.route({ taskType: 'metadata', language: courseRequest.language, topic: courseRequest.topic, complexityIndicators: analyzeComplexity(courseRequest) }); const result = await generateWithModel(selection.model, { prompt: buildMetadataPrompt(courseRequest), temperature: 0.5, maxTokens: 4000 }); // Обязательная валидация const validation = await validateMetadata(result, { validateBlooms: true, checkStructure: true, semanticThreshold: 0.85 }); if (!validation.passed) { // Эскалация или повторная генерация const escalation = await handleValidationFailure(result, validation); if (escalation.action === 'escalate') { return generatePhase2Metadata({ ...courseRequest, forceModel: escalation.targetModel }); } } return { metadata: result.content, model: selection.model.id, cost: selection.expectedCost, quality: validation.score, validationDetails: validation }; }
Логика для Phase 3 (контент)
async function generatePhase3Content( metadata: MetadataResult, courseRequest: CourseRequest ): Promise { // Phase 3 использует результаты Phase 2 как структурное руководство const sections = metadata.metadata.sections; const results: SectionContent[] = []; for (const section of sections) { // Базовая модель для контента (разрешена сильными метаданными) let model = 'oss-120b'; // $0.084 // Исключение: русские уроки → специалист if (courseRequest.language === 'ru' && section.type === 'lesson') { model = 'minimax-m2'; // $1.67, но 10/10 качество } const content = await generateWithModel(model, { prompt: buildContentPrompt(section, metadata.metadata), temperature: 0.7, maxTokens: 8000 }); // Валидация контента const validation = await validateContent(content, section); if (!validation.passed) { // Эскалация на более качественную модель const escalatedContent = await generateWithModel('qwen3-max', { prompt: buildContentPrompt(section, metadata.metadata), temperature: 0.5, maxTokens: 8000 }); results.push({ section: section.id, content: escalatedContent, model: 'qwen3-max', escalated: true }); } else { results.push({ section: section.id, content, model, escalated: false }); } } return { sections: results }; }
Бенчмарки: сравнение подходов
Затраты при 10,000 генераций/месяц
Подход | Стоимость/генерация | Месячные затраты | Годовые затраты |
|---|---|---|---|
Premium (Sonnet 4.5) | $0.221 | $221,000 | $2,652,000 |
Single (Kimi K2) | $0.00526 | $52,600 | $631,200 |
Optimized Mix | $0.00188 | $18,800 | $225,600 |
Экономия vs Premium: $2,426,400/год (в 11.7 раз дешевле)
Экономия vs Single Kimi: $405,600/год (в 2.8 раза дешевле)
Сохранение качества
Premium (Sonnet 4.5 / GPT-5): → Качество: 9.8/10 → Стоимость: $0.221/генерация Optimized Mix: → Качество: 9.0/10 (92% от премиума) → Стоимость: $0.00188/генерация Математика компромисса: → Потеря качества: 0.8 балла (8%) → Снижение стоимости: в 117 раз (99.1%) → 92% качества при <1% стоимости
Метрика Качество/$
Подход | Качество | Стоимость | Качество/$ |
|---|---|---|---|
Premium | 9.8/10 | $110.50 | 0.089 |
Optimized Mix | 9.0/10 | $0.94 | 9.57 |
Преимущество: 107x лучше по метрике Качество/$.
ROI исследования
Инвестиции: → API-вызовы: $500 (12,000+ вызовов) → Инжен��рное время: 2 недели Результаты vs Premium: → Годовая экономия: $2,426,400 → ROI первого года: $2,426,400 / $500 = 4,853x Результаты vs Single Model (Kimi K2): → Годовая экономия: $405,600 → ROI первого года: $405,600 / $500 = 811x
Вывод: $500 и 2 недели казались дорогими в фазе исследования. ROI — от 811x до 4,853x в первый год. Лучшие потраченные деньги.
Мониторинг и адаптация
Метрики для отслеживания
interface MonitoringMetrics { // Качество averageQualityScore: number; bloomsValidationRate: number; semanticSimilarityAvg: number; // Стоимость costPerGeneration: number; costByModel: Record; escalationRate: number; // Стабильность successRate: number; timeoutRate: number; regenerationRate: number; // Распределение trafficByModel: Record; escalationReasons: Record; } class MetricsCollector { async collectDaily(): Promise { const today = new Date().toISOString().split('T')[0]; const generations = await db.generations .where('date', '==', today) .get(); return { averageQualityScore: this.avg(generations, 'qualityScore'), bloomsValidationRate: this.rate(generations, 'bloomsValidated'), semanticSimilarityAvg: this.avg(generations, 'semanticSimilarity'), costPerGeneration: this.avg(generations, 'cost'), costByModel: this.groupSum(generations, 'model', 'cost'), escalationRate: this.rate(generations, 'escalated'), successRate: this.rate(generations, 'success'), timeoutRate: this.rate(generations, 'timedOut'), regenerationRate: this.rate(generations, 'regenerated'), trafficByModel: this.groupCount(generations, 'model'), escalationReasons: this.groupCount( generations.filter(g => g.escalated), 'escalationReason' ) }; } }
Алерты
const ALERT_THRESHOLDS = { qualityScore: { min: 8.5, action: 'review-model-selection' }, escalationRate: { max: 0.25, action: 'review-base-model' }, costPerGeneration: { max: 0.005, action: 'review-traffic-distribution' }, successRate: { min: 0.95, action: 'investigate-failures' } }; async function checkAlerts(metrics: MonitoringMetrics): Promise { const alerts: Alert[] = []; if (metrics.averageQualityScore < ALERT_THRESHOLDS.qualityScore.min) { alerts.push({ severity: 'high', message: `Quality dropped to ${metrics.averageQualityScore}`, action: ALERT_THRESHOLDS.qualityScore.action }); } if (metrics.escalationRate > ALERT_THRESHOLDS.escalationRate.max) { alerts.push({ severity: 'medium', message: `Escalation rate at ${metrics.escalationRate * 100}%`, action: ALERT_THRESHOLDS.escalationRate.action }); } // ... остальные проверки return alerts; }
Практические рекомендации
1. Начните с оценки
Не угадывайте. Проведите собственное исследование:
Минимум 5-7 моделей
Минимум 100 генераций на каждую комбинацию модель/сценарий
Измеряйте Качество/$ (не только качество или стоимость)
2. Найдите мультипликаторы
Определите фазы с эффектом мультипликатора в вашем конвейере:
Где инвестиция $X предотвращает расход $10X?
Обычно это ранние фазы (планирование, структурирование, метаданные)
3. Специализируйте по задачам
Создайте профили моделей:
Какая модель лучше для какого типа задач?
Какая модель лучше для какого языка?
Маршрутизируйте на основе профилей
4. Стройте валидацию
Автоматическая валидация — необходимость:
Bloom's Taxonomy для образовательного контента
Semantic Similarity для проверки релевантности
Schema Validation для структурной корректности
5. Планируйте эскалацию
Определите критерии эскалации:
Когда использовать премиум модель?
Когда повторять генерацию?
Когда переключать модель?
Ожидаемая критика
Все цифры — из реального исследования (12,000+ API-вызовов). Код — рабочий. Методология — воспроизводимая.
Ограничения:
Цены моделей меняются (пересчитывайте регулярно)
Качество моделей улучшается (переоценивайте раз в квартал)
Ваши задачи могут отличаться (проводите собственное исследование)
Если не согласны — отлично. Воспроизведите методологию на своих данных и расскажите, что получилось. Предпочитаю технические аргументы эмоциональным реакциям.
Контакты и обратная связь
Telegram
Канал (редкие посты): https://t.me/maslennikovigor
Прямой контакт: https://t.me/maslennikovig
Буду рад услышать:
Критику — Где слабые места в архитектуре?
Вопросы — Что неясно в методологии?
Альтернативы — Как вы решаете эту проблему?
Игорь Масленников
AI Dev Team, DNA IT
В IT с 2013 года
Бизнес-версия этой статьи (для менеджеров и предпринимателей): https://vc.ru/ai/2625943-multi-modelnaya-orkestraciya-llm-strategicheskoe-reshenie-kotoroe-sekonomilo-24m-v-god
