Как мы провели 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
