Реализовать cost attribution per feature
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать cost attribution per feature
1. Цель задачи
Научиться оценивать вклад каждого компонента AI-системы (RAG, reranking, агенты, базовая LLM генерация) в общую стоимость инференса. Разработать систему сбора метрик и расчёта себестоимости на уровне отдельных фич, чтобы выявить самые дорогие компоненты и принять решения по их оптимизации.
Ключевой результат Таблица cost attribution (фича → стоимость на один запрос / в час), dashboard с визуализацией и текстовый отчёт с рекомендациями по снижению затрат.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Работающая AI-система с RAG, reranking, agent loops | Пет-проект / production система (например, Q&A-бот на RAG) |
| Логи запросов с разбивкой по компонентам: время исполнения, потреблённые токены (input/output), вызовы API | LangSmith, логи сервера (JSON), или собственный мониторинг |
| Стоимость единицы ресурса: цена за 1K токенов для каждой LLM, цена за 1K embeddings, цена GPU-часа | Официальные прайс-листы OpenAI, Anthropic, Hugging Face, AWS/Azure/GCP |
| Инструмент для сбора метрик в реальном времени (опционально) | Prometheus + Grafana / Datadog / CloudWatch |
| Исторические данные за 1‑2 недели (для анализа трендов) | База данных логов (ClickHouse, Postgres, S3 + Athena) |
Если нет реального инструмента — симулируем:
- Создать тестовый сценарий (например, 500 запросов к Q&A-боту) с измерением времени и токенов на каждом шаге (RAG → reranker → LLM ответ).
- Использовать LangChain/LlamaIndex с callback-ами, которые записывают latency и token usage в csv-файл.
- Запустить сценарий на Python‑скрипте, который выводит результаты в консоль и сохраняет их в JSON.
- Для имитации reranker взять публичную модель (cohere rerank v3) или просто последовательный LLM-вызов с известной стоимостью.
- Использовать фиксированные цены из документации OpenAI (gpt-4o: $5/1M input, $15/1M output; ada-002: $0.13/1M, etc.).
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Основной фреймворк | Python + LangChain / LlamaIndex | Построение пайплайна с RAG + reranker + agent |
| Логирование метрик | LangSmith / WandB / кастомный Python Logger | Сбор token usage, latency per step |
| Хранилище метрик | SQLite / CSV / JSON | Локальное хранение для анализа |
| Cost calculator | Python + pandas + numpy | Расчёт стоимость каждого компонента по его метрикам |
| Визуализация | Plotly / Streamlit / Grafana (через Prometheus) | Dashboard затрат по фичам |
| Ценовой справочник | YAML / JSON файл | Хранение текущих цен на LLM и embeddings |
| Инфраструктура (если production) | Docker + Kubernetes + Prometheus | Развёртывание сбора метрик |
4. Этапы выполнения
Этап 1: Проектирование схемы cost attribution (30 минут)
Действия
-
Определить компоненты для атрибуции
embedding– создание и поиск эмбеддингов (стоимость API эмбеддинга + хранение)- retrieval – поиск в векторной БД (Qdrant/Weaviate) – считаем только API вызовы, если есть; иначе фиксированная стоимость за поиск
- reranking – вызов модели reranker
agent_loop– каждый вызов LLM внутри цикла агента (планирование, вызов инструментов)llm_generation– финальный генеративный вызов (без reranker)
-
Спроектировать структуру логов
{ "timestamp": "2025-03-15T10:00:00Z", "request_id": "abc123", "components": [ {"name": "embedding", "tokens_input": 100, "tokens_output": 0, "latency_ms": 50, "cost": 0.0}, {"name": "retrieval", "tokens_input": 0, "tokens_output": 0, "latency_ms": 120, "cost": 0.0001}, {"name": "reranker", "tokens_input": 500, "tokens_output": 0, "latency_ms": 200, "cost": 0.0005}, {"name": "agent_step_1", "tokens_input": 800, "tokens_output": 150, "latency_ms": 1500, "cost": 0.004}, {"name": "llm_generation", "tokens_input": 1200, "tokens_output": 400, "latency_ms": 3000, "cost": 0.008} ], "total_cost": 0.0126 } -
Определить формулу расчёта стоимости для каждого типа компонента:
- Для LLM вызова (включая агента, reranker на LLM): cost = tokens_input * price_per_input_token + tokens_output * price_per_output_token
- Для внешних API (embedding, reranker SaaS): cost = num_calls * price_per_call, или cost = tokens * price_per_token
- Для инфраструктурных компонентов (хостинг GPU, векторная БД): пропорционально времени использования / количеству запросов.
Завести файл prices.yaml:
llm: gpt-4o: input: 0.005 # $ per 1K tokens output: 0.015 gpt-4o-mini: input: 0.00015 output: 0.0006 embedding: text-embedding-3-small: input: 0.00013 cohere-embed-english-v3.0: input: 0.0001 reranker: cohere-rerank-v3: per_1k_tokens: 0.001 vector_db: qdrant_cloud: per_request: 0.00001
Ожидаемый результат этапа Документ с описанием компонентов и структурой логов, заполненный prices.yaml.
Этап 2: Реализация сбора метрик (2 часа)
Действия
-
Создать кастомный callback handler для LangChain (или LlamaIndex), который перехватывает события в момент вызова LLM, эмбеддинга, ретрайвера, реранкера и записывает:
- имя компонента
- количество входных и выходных токенов
- латентность
- модель / эндпоинт
- request_id (передаётся через
run_idили генерируется UUID)
Фрагмент кода на Python:
from langchain.callbacks.base import BaseCallbackHandler from datetime import datetime import json class CostCallback(BaseCallbackHandler): def __init__(self, cost_calculator, output_file="cost_log.jsonl"): self.calculator = cost_calculator self.output_file = output_file self.logs = [] def on_llm_start(self, serialized, prompts, **kwargs): self._current_call = {"type": "llm", "start": datetime.utcnow(), "prompts": prompts} def on_llm_end(self, response, **kwargs): self._current_call["end"] = datetime.utcnow() generation = response.generations[0][0] tokens = generation.generation_info.get("token_usage", {}) self._current_call["tokens"] = tokens cost = self.calculator.llm_cost(tokens, model=response.llm_output.get("model_name", "")) self._current_call["cost"] = cost self._write_log(self._current_call) -
Протестировать сбор метрик на одном запросе без reranker и агента. Убедиться, что в лог попадают token_usage и latency.
-
Добавить компонент reranker (через LangChain
create_retrieval_chainсRerankDocumentsChainили отдельным вызовом Cohere API) и дополнить callback. -
Добавить агента (LangChain AgentExecutor с инструментами) – каждый шаг агента будет отдельным вызовом LLM, все они должны фиксироваться.
-
Запустить batch из 100-500 запросов (имитация обычной нагрузки) и собрать логи в файл
cost_log.jsonl.
Ожидаемый результат этапа Работающий пайплайн, который для каждого запроса генерирует записи в JSONL с разделением по компонентам.
Этап 3: Расчёт cost attribution (1.5 часа)
Действия
-
Загрузить логи в pandas DataFrame
import pandas as pd import json with open("cost_log.jsonl") as f: lines = [json.loads(line) for line in f] df = pd.json_normalize(lines) # расшифровка вложенных структур, если нужно -
Агрегировать стоимость по компонентам
df.groupby("component_name")["cost"].agg(["sum", "mean", "count"])- Посчитать долю каждого компонента в общей стоимости.
-
Дополнительно разбить по типам запросов (если есть метка типа вопроса: простой / сложный / с агентскими вызовами). Если метки нет – сгенерировать через кластеризацию эмбеддингов запросов.
-
Построить графики
- Столбчатая диаграмма: компонент → средняя стоимость на запрос.
- Pie chart: доля каждого компонента.
- Boxplot: разброс стоимости по запросам.
-
Выявить «тяжёлые» фичи например, агентские циклы занимают 60% всех затрат, а reranker – 15%.
Ожидаемый результат этапа Таблица cost_attribution.csv и набор визуализаций.
Этап 4: Оптимизация и рекомендации (1 час)
Действия
-
Определить возможные оптимизации для самого дорогого компонента:
- Если дорогой reranker → попробовать заменить на другой (Cohere→ cheaper alternative) или снизить top‑k передаваемых документов.
- Если дорогой agent loop → уменьшить количество шагов, использовать более дешёвую модель для промежуточных шагов (например, gpt-4o-mini вместо gpt-4o).
- Если дорогой LLM generation → использовать more aggressive caching, сократить длину контекста, перейти на streaming с ранним завершением.
-
Симулировать эффект оптимизации
- На основе логов пересчитать стоимость с новыми параметрами (гипотетически: заменить модель в agent loop на gpt-4o-mini, уменьшить top‑k для reranker с 20 до 5).
- Оценить процент экономии и влияние на качество (хотя бы гипотетически, без реальных замеров качества).
-
Сформировать текстовый отчёт
- Current state (стоимость по компонентам)
- Top-1 дорогой компонент
- Предложенные изменения
- Estimated saving (в процентах и $/месяц)
- Trade-offs (риски по качеству)
Ожидаемый результат этапа Отчёт с рекомендациями (файл optimization_report.md).
Этап 5: Создание dashboard (1 час) – опционально, но желательно
Действия
- Использовать Streamlit или Plotly Dash для динамической визуализации cost attribution.
- Добавить фильтры по периоду времени, типу запроса, модели.
- Отобразить
- Сделать кнопку «Скачать отчёт», сохраняющую текущие графики и таблицу.
Ожидаемый результат этапа Работающий dashboard на Streamlit (файл app.py или ссылка на deployment).
5. Критерии приемки (Definition of Done)
- Для каждого вызова LLM, эмбеддинга, reranker, шага агента известны затраты в $.
- Метрики собраны не менее чем на 100 запросах (реальных или симулированных).
- Создана таблица
cost_attribution.csvс колонками: компонент, total_cost, avg_cost_per_request, p50_cost, p95_cost. - Визуализировано распределение стоимости по компонентам (не менее двух типов графиков).
- Выявлен самый дорогой компонент и записано рекомендация по его оптимизации.
- Оценена экономия от предложенной оптимизации (в % от текущих затрат).
- Dashboard (если делали) отображает cost attribution в реальном времени (или на статичных данных).
- Код сборки метрик, калькулятора и отчёта лежит в git-репозитории с README.
-
prices.yamlсодержит цены для всех используемых моделей и сервисов.
6. Ожидаемый результат
Основной артефакт Папка с проектом, содержащая:
cost_log.jsonl– сырые логи с метриками (пример 100+ записей)cost_attribution.csv– агрегированная таблицаoptimization_report.md– текстовый отчётprices.yaml– конфиг ценapp.py(dashboard) – опциональноrequirements.txt
Дополнительно Возможность запустить всю цепочку заново (сбор метрик → расчёт → отчёт) одной командой python run_pipeline.py.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Отсутствие логирования token usage у некоторых API (например, у embedding API не всегда возвращается количество токенов) | Использовать tiktoken для подсчёта токенов на стороне клиента по тексту. Для reranker-сервисов – брать из документации среднюю цену за символ/токен. |
| Сложность разделения затрат между компонентами при одновременных вызовах (параллельные запросы) | Добавить в логи уникальный request_id и span_id, группировать по request_id. Использовать контекстный менеджер для каждого компонента. |
| Нет точных цен на GPU-часы для self-hosted моделей | Взять среднюю ставку spot instance по региону (например, $0.5/час для A10G). Разделить на количество запросов в час при 80% утилизации. |
| Разные модели для одного компонента (A/B тестирование) | Указывать в логах имя модели и отдельно считать цену по prices.yaml в момент расчёта. |
| Изменение цен у провайдеров | Периодически обновлять prices.yaml. Предусмотреть флаг --price-version для воспроизводимости. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Проектирование схемы | 30 мин |
| Этап 2: Реализация сбора метрик | 2 ч |
| Этап 3: Расчёт cost attribution | 1 ч 30 мин |
| Этап 4: Оптимизация и рекомендации | 1 ч |
| Этап 5: Создание dashboard (опц.) | 1 ч |
| Итого (без опционального этапа) | 5 ч |
| С опциональным этапом | 6 ч |
Примечание Для первого исполнения задачи рекомендуется закладывать +2 часа на отладку callback-ов и неожиданные проблемы с форматами логирования.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 715 | Основные затраты в RAG: embedding, retrieval, LLM |
| 720 | Стоимость reranker: open-source vs SaaS |
| 723 | Cost per token vs cost per request: best practices |
| 733 | Оптимизация agent loops: уменьшение шагов и дешёвые модели |
| 738 | Мониторинг затрат с помощью LangSmith |
| 742 | A/B тестирование моделей и влияние на cost |
| 755 | Caching и его влияние на стоимость |
| 767 | Бюджетирование AI-систем: прогнозирование на основе исторических метрик |
| 789 | Multi-model routing для снижения затрат |
| 802 | Автоматический алертинг при превышении бюджета по компоненту |
10. Чек-лист самопроверки
- Я выбрал реальный сценарий или создал симуляцию, в которой есть хотя бы 3 разных компонента (RAG, reranker, агент).
- Я проверил, что callback handler перехватывает все вызовы LLM и не пропускает ни один step агента.
- Я верифицировал, что расчёт стоимости корректен: просуммировал все компоненты по одному запросу и сравнил с общей стоимостью, посчитанной вручную.
- Я создал хотя бы одну визуализацию (plot) и интерпретировал её текстом.
- Я написал конкретную рекомендацию по оптимизации с численной оценкой экономии, основанной на моих данных.
- Все файлы (логи, код, конфиги) лежат в git; README содержит инструкцию по запуску.
- (если делал dashboard) Dashboard загружается и показывает корректные цифры.