Создание полностью трассируемого локального QA-пайплайна LLM с Opik для воспроизводимых и прозрачных оценок
'Практическое руководство по созданию, трассировке и оценке локального QA-пайплайна LLM с Opik и лёгкой моделью Hugging Face для измеримых и воспроизводимых результатов.'
Настройка и инициализация
Установите необходимые библиотеки и инициализируйте Opik. Ниже показан код для загрузки модулей, определения устройства и конфигурации проекта, чтобы все трейсы попадали в нужное рабочее пространство.
!pip install -q opik transformers accelerate torch
import torch
from transformers import pipeline
import textwrap
import opik
from opik import Opik, Prompt, track
from opik.evaluation import evaluate
from opik.evaluation.metrics import Equals, LevenshteinRatio
device = 0 if torch.cuda.is_available() else -1
print("Using device:", "cuda" if device == 0 else "cpu")
opik.configure()
PROJECT_NAME = "opik-hf-tutorial"
Это закладывает основу для воспроизводимого рабочего пространства трассировки.
Локальная модель и генератор
Загрузите лёгкую модель Hugging Face и создайте вспомогательную функцию для генерации текста локально без обращения к внешним API. Это даёт согласованный уровень генерации для пайплайна.
llm = pipeline(
"text-generation",
model="distilgpt2",
device=device,
)
def hf_generate(prompt: str, max_new_tokens: int = 80) -> str:
result = llm(
prompt,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=0.3,
pad_token_id=llm.tokenizer.eos_token_id,
)[0]["generated_text"]
return result[len(prompt):].strip()
Структурированные подсказки
Определите шаблоны подсказок для этапов планирования и ответа. Чёткие шаблоны помогают поддерживать единообразие и упрощают анализ поведения модели.
plan_prompt = Prompt(
name="hf_plan_prompt",
prompt=textwrap.dedent("""
You are an assistant that creates a plan to answer a question
using ONLY the given context.
Context:
{{context}}
Question:
{{question}}
Return exactly 3 bullet points as a plan.
""").strip(),
)
answer_prompt = Prompt(
name="hf_answer_prompt",
prompt=textwrap.dedent("""
You answer based only on the given context.
Context:
{{context}}
Question:
{{question}}
Plan:
{{plan}}
Answer the question in 2–4 concise sentences.
""").strip(),
)
Минимальное хранилище документов и функция поиска
Соберите небольшой набор документов и реализуйте функцию извлечения контекста, которую Opik будет отслеживать как инструмент. Это имитирует RAG-подход без внешней векторной базы.
DOCS = {
"overview": """
Opik is an open-source platform for debugging, evaluating,
and monitoring LLM and RAG applications. It provides tracing,
datasets, experiments, and evaluation metrics.
""",
"tracing": """
Tracing in Opik logs nested spans, LLM calls, token usage,
feedback scores, and metadata to inspect complex LLM pipelines.
""",
"evaluation": """
Opik evaluations are defined by datasets, evaluation tasks,
scoring metrics, and experiments that aggregate scores,
helping detect regressions or issues.
""",
}
@track(project_name=PROJECT_NAME, type="tool", name="retrieve_context")
def retrieve_context(question: str) -> str:
q = question.lower()
if "trace" in q or "span" in q:
return DOCS["tracing"]
if "metric" in q or "dataset" in q or "evaluate" in q:
return DOCS["evaluation"]
return DOCS["overview"]
Трассируемые функции пайплайна
Обёрните ключевые компоненты пайплайна декораторами Opik, чтобы каждая функция, спаны и вызовы LLM фиксировались и отображались в дашборде Opik.
@track(project_name=PROJECT_NAME, type="llm", name="plan_answer")
def plan_answer(context: str, question: str) -> str:
rendered = plan_prompt.format(context=context, question=question)
return hf_generate(rendered, max_new_tokens=80)
@track(project_name=PROJECT_NAME, type="llm", name="answer_from_plan")
def answer_from_plan(context: str, question: str, plan: str) -> str:
rendered = answer_prompt.format(
context=context,
question=question,
plan=plan,
)
return hf_generate(rendered, max_new_tokens=120)
@track(project_name=PROJECT_NAME, type="general", name="qa_pipeline")
def qa_pipeline(question: str) -> str:
context = retrieve_context(question)
plan = plan_answer(context, question)
answer = answer_from_plan(context, question, plan)
return answer
print("Sample answer:\n", qa_pipeline("What does Opik help developers do?"))
Так вы объединяете извлечение, планирование и ответ в полностью трассируемый QA-пайплайн.
Создание датасета в Opik
Создайте датасет и заполните его вопросами и эталонными ответами, которые будут использоваться в оценке.
client = Opik()
dataset = client.get_or_create_dataset(
name="HF_Opik_QA_Dataset",
description="Small QA dataset for HF + Opik tutorial",
)
dataset.insert([
{
"question": "What kind of platform is Opik?",
"context": DOCS["overview"],
"reference": "Opik is an open-source platform for debugging, evaluating and monitoring LLM and RAG applications.",
},
{
"question": "What does tracing in Opik log?",
"context": DOCS["tracing"],
"reference": "Tracing logs nested spans, LLM calls, token usage, feedback scores, and metadata.",
},
{
"question": "What are the components of an Opik evaluation?",
"context": DOCS["evaluation"],
"reference": "An Opik evaluation uses datasets, evaluation tasks, scoring metrics and experiments that aggregate scores.",
},
])
Задача оценки и метрики
Выберите метрики и определите задачу оценки, которая прогоняет пайплайн по элементам датасета и возвращает результат для подсчёта очков.
equals_metric = Equals()
lev_metric = LevenshteinRatio()
def evaluation_task(item: dict) -> dict:
output = qa_pipeline(item["question")]
return {
"output": output,
"reference": item["reference"],
}
Запуск эксперимента и агрегация результатов
Запустите evaluate для выполнения полного эксперимента. Для стабильности в интерактивной среде выполняйте последовательно.
evaluation_result = evaluate(
dataset=dataset,
task=evaluation_task,
scoring_metrics=[equals_metric, lev_metric],
experiment_name="HF_Opik_QA_Experiment",
project_name=PROJECT_NAME,
task_threads=1,
)
print("\nExperiment URL:", evaluation_result.experiment_url)
После завершения получите ссылку на эксперимент и агрегируйте метрики для анализа производительности.
agg = evaluation_result.aggregate_evaluation_scores()
print("\nAggregated scores:")
for metric_name, stats in agg.aggregated_scores.items():
print(metric_name, "=>", stats)
Наблюдения
Этот пример показывает компактную, но полноценную экосистему оценки LLM, полностью запущенную локально и инструментированную с помощью Opik. Трассировка, структурированные подсказки, управляемый датасет и явные метрики дают прозрачное, измеримое и воспроизводимое представление о поведении пайплайна и качестве ответов.
Switch Language
Read this article in English