English translation is not available yet. Showing Russian content.

Реализовать 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), вызовы APILangSmith, логи сервера (JSON), или собственный мониторинг
Стоимость единицы ресурса: цена за 1K токенов для каждой LLM, цена за 1K embeddings, цена GPU-часаОфициальные прайс-листы OpenAI, Anthropic, Hugging Face, AWS/Azure/GCP
Инструмент для сбора метрик в реальном времени (опционально)Prometheus + Grafana / Datadog / CloudWatch
Исторические данные за 1‑2 недели (для анализа трендов)База данных логов (ClickHouse, Postgres, S3 + Athena)

Если нет реального инструмента — симулируем:

  1. Создать тестовый сценарий (например, 500 запросов к Q&A-боту) с измерением времени и токенов на каждом шаге (RAG → reranker → LLM ответ).
  2. Использовать LangChain/LlamaIndex с callback-ами, которые записывают latency и token usage в csv-файл.
  3. Запустить сценарий на Python‑скрипте, который выводит результаты в консоль и сохраняет их в JSON.
  4. Для имитации reranker взять публичную модель (cohere rerank v3) или просто последовательный LLM-вызов с известной стоимостью.
  5. Использовать фиксированные цены из документации 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 calculatorPython + pandas + numpyРасчёт стоимость каждого компонента по его метрикам
ВизуализацияPlotly / Streamlit / Grafana (через Prometheus)Dashboard затрат по фичам
Ценовой справочникYAML / JSON файлХранение текущих цен на LLM и embeddings
Инфраструктура (если production)Docker + Kubernetes + PrometheusРазвёртывание сбора метрик

4. Этапы выполнения

Этап 1: Проектирование схемы cost attribution (30 минут)

Действия

  1. Определить компоненты для атрибуции

    • embedding – создание и поиск эмбеддингов (стоимость API эмбеддинга + хранение)
    • retrieval – поиск в векторной БД (Qdrant/Weaviate) – считаем только API вызовы, если есть; иначе фиксированная стоимость за поиск
    • reranking – вызов модели reranker
    • agent_loop – каждый вызов LLM внутри цикла агента (планирование, вызов инструментов)
    • llm_generation – финальный генеративный вызов (без reranker)
  2. Спроектировать структуру логов

    {
      "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
    }
    
  3. Определить формулу расчёта стоимости для каждого типа компонента:

    • Для 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 часа)

Действия

  1. Создать кастомный 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)
    
  2. Протестировать сбор метрик на одном запросе без reranker и агента. Убедиться, что в лог попадают token_usage и latency.

  3. Добавить компонент reranker (через LangChain create_retrieval_chain с RerankDocumentsChain или отдельным вызовом Cohere API) и дополнить callback.

  4. Добавить агента (LangChain AgentExecutor с инструментами) – каждый шаг агента будет отдельным вызовом LLM, все они должны фиксироваться.

  5. Запустить batch из 100-500 запросов (имитация обычной нагрузки) и собрать логи в файл cost_log.jsonl.

Ожидаемый результат этапа Работающий пайплайн, который для каждого запроса генерирует записи в JSONL с разделением по компонентам.


Этап 3: Расчёт cost attribution (1.5 часа)

Действия

  1. Загрузить логи в 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)
    # расшифровка вложенных структур, если нужно
    
  2. Агрегировать стоимость по компонентам

    • df.groupby("component_name")["cost"].agg(["sum", "mean", "count"])
    • Посчитать долю каждого компонента в общей стоимости.
  3. Дополнительно разбить по типам запросов (если есть метка типа вопроса: простой / сложный / с агентскими вызовами). Если метки нет – сгенерировать через кластеризацию эмбеддингов запросов.

  4. Построить графики

    • Столбчатая диаграмма: компонент → средняя стоимость на запрос.
    • Pie chart: доля каждого компонента.
    • Boxplot: разброс стоимости по запросам.
  5. Выявить «тяжёлые» фичи например, агентские циклы занимают 60% всех затрат, а reranker – 15%.

Ожидаемый результат этапа Таблица cost_attribution.csv и набор визуализаций.


Этап 4: Оптимизация и рекомендации (1 час)

Действия

  1. Определить возможные оптимизации для самого дорогого компонента:

    • Если дорогой reranker → попробовать заменить на другой (Cohere→ cheaper alternative) или снизить top‑k передаваемых документов.
    • Если дорогой agent loop → уменьшить количество шагов, использовать более дешёвую модель для промежуточных шагов (например, gpt-4o-mini вместо gpt-4o).
    • Если дорогой LLM generation → использовать more aggressive caching, сократить длину контекста, перейти на streaming с ранним завершением.
  2. Симулировать эффект оптимизации

    • На основе логов пересчитать стоимость с новыми параметрами (гипотетически: заменить модель в agent loop на gpt-4o-mini, уменьшить top‑k для reranker с 20 до 5).
    • Оценить процент экономии и влияние на качество (хотя бы гипотетически, без реальных замеров качества).
  3. Сформировать текстовый отчёт

    • Current state (стоимость по компонентам)
    • Top-1 дорогой компонент
    • Предложенные изменения
    • Estimated saving (в процентах и $/месяц)
    • Trade-offs (риски по качеству)

Ожидаемый результат этапа Отчёт с рекомендациями (файл optimization_report.md).


Этап 5: Создание dashboard (1 час) – опционально, но желательно

Действия

  1. Использовать Streamlit или Plotly Dash для динамической визуализации cost attribution.
  2. Добавить фильтры по периоду времени, типу запроса, модели.
  3. Отобразить
    • Total cost (суммарная и средняя)
    • Cost per component (stacked bar per day)
    • Top-10 самых дорогих запросов (с возможностью заглянуть в лог)
    • Тренд стоимости за последние N дней.
  4. Сделать кнопку «Скачать отчёт», сохраняющую текущие графики и таблицу.

Ожидаемый результат этапа Работающий 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 attribution1 ч 30 мин
Этап 4: Оптимизация и рекомендации1 ч
Этап 5: Создание dashboard (опц.)1 ч
Итого (без опционального этапа)5 ч
С опциональным этапом6 ч

Примечание Для первого исполнения задачи рекомендуется закладывать +2 часа на отладку callback-ов и неожиданные проблемы с форматами логирования.


9. Связанные вопросы из базы знаний

ВопросТема
715Основные затраты в RAG: embedding, retrieval, LLM
720Стоимость reranker: open-source vs SaaS
723Cost per token vs cost per request: best practices
733Оптимизация agent loops: уменьшение шагов и дешёвые модели
738Мониторинг затрат с помощью LangSmith
742A/B тестирование моделей и влияние на cost
755Caching и его влияние на стоимость
767Бюджетирование AI-систем: прогнозирование на основе исторических метрик
789Multi-model routing для снижения затрат
802Автоматический алертинг при превышении бюджета по компоненту

10. Чек-лист самопроверки

  • Я выбрал реальный сценарий или создал симуляцию, в которой есть хотя бы 3 разных компонента (RAG, reranker, агент).
  • Я проверил, что callback handler перехватывает все вызовы LLM и не пропускает ни один step агента.
  • Я верифицировал, что расчёт стоимости корректен: просуммировал все компоненты по одному запросу и сравнил с общей стоимостью, посчитанной вручную.
  • Я создал хотя бы одну визуализацию (plot) и интерпретировал её текстом.
  • Я написал конкретную рекомендацию по оптимизации с численной оценкой экономии, основанной на моих данных.
  • Все файлы (логи, код, конфиги) лежат в git; README содержит инструкцию по запуску.
  • (если делал dashboard) Dashboard загружается и показывает корректные цифры.