1.6 Построение и оценка LLM-приложений
Разработка приложений на основе больших языковых моделей (LLM) — это не только грамотная интеграция, но и системная оценка качества, которая охватывает как объективные, так и субъективные аспекты. На практике приходится сочетать метрики точности, полноты и F1‑меры (когда доступны эталонные ответы) с пользовательскими рейтингами и метриками удовлетворённости (CSA), а также учитывать эксплуатационные показатели, такие как стоимость и задержка ответа. Такой набор измерений помогает диагностировать слабые места, принимать обоснованные решения о релизах и целенаправленно улучшать продукт. Типичный путь из разработки в продакшен начинается с простых промптов и небольшого набора данных для быстрых итераций; затем расширяется покрытие, усложняются сценарии, уточняются метрики и критерии качества — при этом не всегда нужна «идеальность», достаточно устойчиво решать целевые задачи в заданных ограничениях по качеству и бюджету. В сценариях высокого риска, где потенциальный вред особенно чувствителен (медицина, правоприменение, финансы), возрастает роль строгой валидации: рандомные выборки и hold‑out‑тесты, проверки на предвзятость и ошибки, а также внимание к этическим и юридическим аспектам — недопущение вреда, объяснимость решений и возможность аудита. Хороший инженерный стиль здесь подчёркивает модульность и быстрые итерации, автоматизацию регрессионных тестов и измерений, осмысленный выбор метрик под бизнес‑цели и обязательный анализ предвзятости и справедливости с регулярным ревью.
Чтобы наладить воспроизводимую оценку, удобно использовать рубрикаторы (rubric) и протоколы оценки: заранее описать критерии качества — релевантность намерению и контексту пользователя, фактическую корректность, полноту охвата и связность/беглость — а также процедуру, шкалы и пороги. В субъективных задачах уместны несколько независимых оценщиков и автоматические проверки согласованности. Там, где это возможно, полезно сравнивать ответы с идеальными (экспертными) — такой «эталон» служит ориентиром и позволяет объективнее судить о качестве. В помощь разработчику — простой каркас окружения и функций вызова модели для воспроизводимых экспериментов и оценок:
import os
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI()
def fetch_llm_response(prompts, model="gpt-4o-mini", temperature=0, max_tokens=500):
response = client.chat.completions.create(
model=model,
messages=prompts,
temperature=temperature,
max_tokens=max_tokens,
)
return response.choices[0].message["content"]
Далее можно формализовать оценку по рубрике и раздать весовые коэффициенты, чтобы получать интегральный балл и развёрнутую обратную связь. Ниже представлен шаблон, в котором модель формирует оценку по заданным критериям; разбор результата показан заглушкой и в рабочем проекте должен быть заменён на парсинг фактического формата ответа:
def evaluate_response_against_detailed_rubric(test_data, llm_response):
"""
Оценивает ответ по критериям: точность, релевантность, полнота, связность.
Возвращает интегральный балл и развёрнутую обратную связь.
"""
rubric_criteria = {
'accuracy': {'weight': 3, 'score': None, 'feedback': ''},
'relevance': {'weight': 2, 'score': None, 'feedback': ''},
'completeness': {'weight': 3, 'score': None, 'feedback': ''},
'coherence': {'weight': 2, 'score': None, 'feedback': ''}
}
total_weight = sum(c['weight'] for c in rubric_criteria.values())
system_prompt = "Оцените ответ агента службы поддержки с учётом предоставленного контекста."
evaluation_prompt = f"""\
[Вопрос]: {test_data['customer_query']}
[Контекст]: {test_data['context']}
[Ожидаемые ответы]: {test_data.get('expected_answers', 'Н/Д')}
[Ответ LLM]: {llm_response}
Оцените ответ на основе точности, релевантности, полноты и связности.
Предоставьте баллы (от 0 до 10) для каждого критерия и конкретную обратную связь.
"""
evaluation_results = fetch_llm_response([
{"role": "system", "content": system_prompt},
{"role": "user", "content": evaluation_prompt},
])
# Заглушка парсинга — замените на реальный разбор структуры ответа вашей модели
for k in rubric_criteria:
rubric_criteria[k]['score'] = 8
rubric_criteria[k]['feedback'] = "Хорошо по данному критерию."
overall = sum(v['score'] * v['weight'] for v in rubric_criteria.values()) / total_weight
detailed = {k: {"score": v['score'], "feedback": v['feedback']} for k, v in rubric_criteria.items()}
return {"overall_score": overall, "detailed_scores": detailed}
Когда необходима сверка с эталоном, удобно явно сопоставить ответ модели с идеальным экспертным ответом и на его основе выставить баллы по приоритетным критериям (фактическая точность, соответствие, полнота и связность). Ниже — каркас такой процедуры с возвратом как агрегированной оценки, так и сырого текста сравнения для аудита:
def detailed_evaluation_against_ideal_answer(test_data, llm_response):
criteria = {
'factual_accuracy': {'weight': 4, 'score': None, 'feedback': ''},
'alignment_with_ideal': {'weight': 3, 'score': None, 'feedback': ''},
'completeness': {'weight': 3, 'score': None, 'feedback': ''},
'coherence': {'weight': 2, 'score': None, 'feedback': ''}
}
total = sum(c['weight'] for c in criteria.values())
system_prompt = "Сравните ответ LLM с идеальным ответом, сосредоточившись на фактическом содержании и соответствии."
comparison_prompt = f"""\
[Вопрос]: {test_data['customer_query']}
[Идеальный ответ]: {test_data['ideal_answer']}
[Ответ LLM]: {llm_response}
"""
evaluation_text = fetch_llm_response([
{"role": "system", "content": system_prompt},
{"role": "user", "content": comparison_prompt},
])
# Заглушка парсинга
for k in criteria:
criteria[k]['score'] = 8
criteria[k]['feedback'] = "Хорошее соответствие эталону."
score = sum(v['score'] * v['weight'] for v in criteria.values()) / total
return {"overall_score": score, "details": criteria, "raw": evaluation_text}
Поверх этих базовых механизмов полезно добавлять продвинутые техники: оценивать семантическую близость через эмбеддинги и метрики схожести (а не только поверхностные совпадения), привлекать независимых рецензентов для крауд‑оценки, внедрять автоматические проверки когерентности и логики, а также строить динамические фреймворки оценки, адаптируемые под домен и тип задач. В продакшене особенно важны практики непрерывной оценки: ведение истории версий и метрик, замыкание пользовательской обратной связи на процесс разработки; разнообразие кейсов, включая крайние случаи и культурно‑языковые вариации; работа с экспертами, в том числе слепые оценки для снижения предвзятости; сравнение с альтернативными моделями и применение специализированных «оценщиков» для поиска противоречий и фактических ошибок. Всё это складывается в цикл, где строгие методики соединяются с постоянными итерациями, а рубрикаторы, эталоны, экспертные рецензии и автоматические проверки помогают строить надёжные и этичные системы.
Теоретические вопросы
- Зачем оценивать ответы LLM и по каким измерениям это следует делать?
- Приведите примеры метрик и объясните их роль в разработке.
- Как выглядит итеративный переход от разработки к продакшену?
- Почему сценарии высокого риска требуют особой строгости, и приведите примеры таких приложений?
- Перечислите лучшие практики для старта, итераций и автотестов.
- Как автоматизация тестов помогает в процессе разработки?
- Почему метрики следует настраивать под конкретную задачу?
- Как построить рубрикатор и протоколы оценки?
- Какие продвинутые техники оценки применимы и для чего?
- Как непрерывная оценка и широкий охват тест-кейсов повышают надёжность системы?
Практические задания
- Напишите функцию, которая читает API-ключ из окружения, запрашивает ответ у LLM и измеряет время выполнения и количество использованных токенов.