С того момента, когда вы начинаете использовать LLM в production, вы осознаёте необходимость дисциплины классической инженерии ПО — test suite. Что происходит с консистентностью выхода при изменении промпта? Как меняется соотношение стоимость-качество при обновлении версии модели? Как конвертировать ощущение "Claude ответил лучше" в численную метрику? В 2026 году, когда LLM-операции достигли зрелости, побеждают те, кто систематически, а не вручную отвечает на эти вопросы. Инструменты как Promptfoo и LangSmith, а также evaluation pipeline'ы — это страховка для поддержания LLM в production.

Изменение промпта = Изменение кода

Представьте workflow генерации маркетингового контента. Вы отправляете промпт Claude API, получаете черновик блога. В первой версии вы пишете "напиши", во второй добавляете в system prompt "Пиши для Roibase, инженерный тон", в третьей добавляете список "ЗАПРЕЩЁННЫЕ СЛОВА". Каждое изменение влияет на выход, но как вы измеряете это влияние?

В классическом ПО есть unit-тесты — вход фиксирован, выход детерминирован. В LLM вход фиксирован, но выход стохастичен. Одного запуска недостаточно. Необходимо запустить один и тот же промпт 10 раз с разными seed'ами, посмотреть на среднее количество токенов, latency, оценку coherence. Поэтому версионирование промпта критично как версионирование кода. Вы отслеживаете изменения промпта в Git commit'ах, но можете не отслеживать изменения выхода. Здесь вступает в дело evaluation suite: при каждом commit'е автоматически запускаются тесты, вы видите регрессию метрик.

Конкретный сценарий: в n8n workflow вы генерируете контент через Claude. Изменив в промпте "1500 слов" на "1400-1600 слов", средняя длина падает с 1520 до 1480 слов, стоимость токенов снижается на 3%, но оценка читаемости теряет 0.2 пункта. Чтобы увидеть этот трейдофф без ручных экспериментов, необходим автоматический evaluation pipeline.

Promptfoo: Regression Test Suite для промптов

Promptfoo — это open-source CLI-инструмент, где вы определяете промпты в YAML-конфиге, задаёте test case'ы в CSV или JSON, пишете assertion'ы. Команда promptfoo eval запускает все варианты, выдаёт таблицу успех/неудач.

Типичный promptfoo.yaml выглядит так:

prompts:
  - id: baseline
    text: "Write a blog post about {{topic}}"
  - id: roibase-tone
    text: "Write a blog post about {{topic}}. Use engineering discipline tone. No hype words."

providers:
  - anthropic:messages:claude-3-5-sonnet-20241022

tests:
  - vars:
      topic: "server-side GTM setup"
    assert:
      - type: contains
        value: "first-party"
      - type: javascript
        value: output.length > 1400 && output.length < 1600
      - type: cost
        threshold: 0.05

Запустив этот конфиг, Promptfoo отправляет оба промпта в Claude, проверяет assertion'ы: появляется ли слово "first-party", находится ли объём в пределах 1400-1600 слов, стоит ли стоимость API ниже $0.05? При ошибке показывает, в каком промпте она произошла. Интегрировав в CI/CD, вы получаете автоматическое тестирование изменений промпта в pull request'е — как классический unit-тест.

Почему автоматизация, а не ручное тестирование?

Ручное тестирование: вы отправляете 5 разных тем в Claude, просматриваете выходы, даёте оценку "хорошо". На следующий день меняете промпт и снова тестируете вручную. К 10-й итерации вы забыли, какое изменение как повлияло на какую метрику.

Автоматизация: у вас есть 50 test case'ов (реальные ключевые слова из GSC), при каждом изменении промпта они запускаются автоматически. Таблица регрессии: "baseline prompt — в среднем 1520 слов, новый промпт — 1480 слов, снижение 2.6%". Решение основано на метрике, не на чувстве.

LangSmith: Production Observability

Promptfoo — это инструмент тестирования на этапе разработки. LangSmith (от команды LangChain) позволяет отслеживать, что происходит в production. Каждый вызов LLM логируется в LangSmith: вход, выход, latency, количество токенов, метаданные. В dashboard'е вы видите trace — retrieval, construction промпта, вызов LLM, post-processing цепь шаг за шагом.

Пример: в работах Roibase по оптимизации генеративных движков мы строим LLM pipeline для отслеживания citation'ов ChatGPT. Pipeline: вопрос пользователя → embedding → Pinecone retrieval → injection контекста → Claude → extraction citation'ов. LangSmith записывает каждый шаг. Если rate citation'ов падает ниже 15%, приходит alert — сразу видна проблема с drift промпта или качеством retrieval.

Trace vs Logging

Классический logging: "отправил этот промпт в Claude API, получил этот ответ". Trace: "Retrieval занял 120мс, вернул 5 документов, construction промпта — 15мс, Claude — 2.3 сек, total latency — 2.45 сек, SLA не нарушен". Trace показывает весь end-to-end pipeline. В LLM цепях критично найти узкое место: если retrieval медленный — оптимизируйте индекс БД, если LLM медленный — изменяйте версию модели или уменьшайте токены промпта.

При A/B-тестировании в production LangSmith используется так: 50% трафика идёт на baseline промпт, 50% на новый — каждый вариант записывается отдельной trace-группе, метрики сравниваются в реальном времени. Baseline: средняя latency 2.1 сек, новый промпт: 1.9 сек, но оценка качества выхода падает с 0.85 до 0.80 — таблица трейдоффа видна live.

Evaluation Pipeline: Автоматическая оценка качества

Выход LLM субъективен — как автоматизировать вопрос "хорошо ли это или плохо"? Два подхода: rule-based assertion'ы и LLM-as-a-judge.

Rule-based: assertion'ы как в Promptfoo — contains, length, regex-match. Правила типа "1400-1600 слов", "ни одного восклицательного знака", "как минимум 1 внутренняя ссылка". Быстро, детерминировано, но не захватывает семантическое качество.

LLM-as-a-judge: вы отправляете выход другой LLM (обычно GPT-4 или Claude) на оценку. Пример: "Соответствует ли этот пост инженерному тону? Оцени от 1 до 10". Если judge выдаёт 7.5 — пройдено, если 6 — не пройдено. Этот метод захватывает семантическое качество, но недетерминирован — сама judge-модель стохастична. Решение: каждую eval запускать 3 раза и брать среднее.

В content production workflow Roibase evaluation pipeline выглядит так:

  1. Claude генерирует черновик блога
  2. Отправляем черновик в Promptfoo
  3. Rule-based: проверяем количество слов, количество внутренних ссылок, запрещённые слова
  4. LLM-as-a-judge: GPT-4 оценивает "соответствие тону" от 1 до 10
  5. Все метрики записываются в Notion
  6. Если средняя оценка ниже 8 — alert в Slack

Благодаря этому pipeline'у при генерации 1000 статей стандарты качества сохраняются. Вместо того чтобы manual QA-команда читала каждую статью, она смотрит только на ошибки eval — экономия 90% времени.

A/B-тест: Два промпта, два трейдоффа стоимость-качество

A/B-тест промптов в production работает как классический feature flag. Используете LaunchDarkly или custom flag service: 50% пользователей видят prompt_v1, 50% — prompt_v2. Для каждого варианта собираете метрики: среднее количество токенов, latency, downstream conversion (например, редактор утверждает ли черновик?).

Конкретный пример: в Roibase тестируем новую версию промпта с category-specific guidance. Baseline — общий промпт, новый — содержит дополнительные инструкции по категориям. A/B-тест идёт 2 недели:

МетрикаBaselineНовый промптДельта
Средний токен (input+output)32003450+7.8%
Средняя latency (сек)2.12.3+9.5%
Стоимость/статья ($)0.0420.046+9.5%
Процент одобрения редактором72%81%+12.5%
Точность внутренних ссылок65%89%+36.9%

Новый промпт на 10% дороже, но процент одобрения редактором вырастает на 12.5% — стоимость revisions редактора ниже. Точность внутренних ссылок возрастает на 36.9% — SEO выигрыш покрывает стоимость. Решение: новый промпт побеждает, идёт в production.

На время A/B-теста в LangSmith создаются отдельные trace-группы для каждого варианта. Если заметите anomaly (например, у нового промпта 5% HTTP 429 rate limit ошибок), сразу это увидите.

Версионирование: Git + Метаданные

Версию промпта храните в Git как код, но с отдельными метаданными. Папка prompts/:

prompts/
  roibase-blog-v1.md
  roibase-blog-v2.md
  roibase-blog-v3.md

Каждый файл содержит frontmatter метаданные:

---
version: 3
model: claude-3-5-sonnet-20241022
temperature: 0.7
max_tokens: 8000
created: 2026-07-15
deprecated: false
test_suite: promptfoo-blog-eval.yaml
---

# РОЛЬ
Вы пишете для Roibase.
...

Git commit message: "prompt v3: добавлена category-specific guidance, расширен список запрещённых слов". Когда CI/CD видит commit, автоматически запускает Promptfoo test suite. Если тесты прошли — deploy на staging, 24 часа A/B-теста, если успешно — идёт в production.

Благодаря версионированию rollback быстрый: если в production проблема, git revert, за 5 минут старый промпт активен.

Оптимизация стоимости: Token Audit

В LLM приложениях стоимость определяется формулой: input token + output token. Цена Claude Sonnet 3.5 API: $3 за 1M input token'ов, $15 за 1M output token'ов (цена 2026 года). Черновик блога из 1500 слов — ~2000 output token'ов, system prompt + user prompt — ~1200 input token'ов, итого ~$0.042 за статью.

Если вы генерируете 1000 статей в месяц, это $42. Если оптимизировать промпт на 10% снижение output token'ов, сэкономите $6.3/месяц — $75.6/год. Кажется малым, но масштабируется. При 10,000 статей/месяц это $756/год.

В Promptfoo eval suite добавляете cost assertion:

assert:
  - type: cost
    threshold: 0.045

Если после изменения промпта стоимость превышает $0.045, тест не пройдёт. Вы устанавливаете этот threshold'ы, связывая его с business метриками (процент одобрения редактором, conversion).

Для token audit смотрите на LangSmith trace'ы: какой компонент промпта потребляет больше всего токенов? Например, раздел "ЗАПРЕТЫ" в system prompt занимает 300 токенов — действительно ли он нужен при каждом выз