Comet Opik
Comet Opik
이 노트북에서는 Opik을 Ragas와 함께 사용해 RAG(Retrieval-Augmented Generation) 파이프라인을 모니터링·평가하는 방법을 보여줘요. Opik을 Ragas와 함께 쓰는 방법은 크게 두 가지예요.
- Ragas 메트릭으로 trace에 점수 매기기
- Ragas evaluate 함수로 데이터셋에 점수 매기기
출처: 문서
본문
설정
Comet은 Opik 플랫폼의 호스팅 버전을 제공해요. 계정을 만들고 API 키를 받기만 하면 됩니다. Opik 플랫폼을 로컬에서 실행할 수도 있어요. 자세한 내용은 설치 가이드를 참고하세요.
import getpass
import os
os.environ["OPIK_API_KEY"] = getpass.getpass("Opik API Key: ")
os.environ["OPIK_WORKSPACE"] = input(
"Comet workspace (often the same as your username): "
)
Opik 플랫폼을 로컬에서 실행한다면 간단히 설정하세요.
# import os
# os.environ["OPIK_URL_OVERRIDE"] = "http://localhost:5173/api"
환경 준비
먼저 필요한 라이브러리를 설치하고, OpenAI API 키를 구성하고, 새 Opik 데이터셋을 만들어요.
%pip install opik --quiet
import getpass
import os
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
Opik을 Ragas와 통합
Ragas 메트릭으로 trace에 점수 매기기
Ragas는 RAG 파이프라인의 품질을 평가하는 데 쓸 수 있는 메트릭 집합을 제공해요. 여기에는 answer_relevancy, answer_similarity, answer_correctness, context_precision, context_recall, context_entity_recall, summarization_score 등이 포함되지만 이에 국한되지 않아요. 전체 메트릭 목록은 Ragas 문서에서 찾을 수 있어요.
이 메트릭들은 즉석(on the fly)으로 계산해 Opik의 trace나 스팬에 로깅할 수 있어요. 이 예시에서는 간단한 RAG 파이프라인을 만들고 answer_relevancy 메트릭으로 점수를 매겨 볼게요.
Ragas 메트릭 만들기
evaluate 함수를 사용하지 않고 Ragas 메트릭을 사용하려면 RunConfig 객체와 LLM 프로바이더로 메트릭을 초기화해야 해요. 이 예시에서는 Opik tracer를 활성화한 상태로 LangChain을 LLM 프로바이더로 사용할 거예요.
먼저 Ragas 메트릭을 초기화해 보겠습니다.
# Import the metric
# Import some additional dependencies
from langchain_openai.chat_models import ChatOpenAI
from langchain_openai.embeddings import OpenAIEmbeddings
from ragas.embeddings import LangchainEmbeddingsWrapper
from ragas.llms import LangchainLLMWrapper
from ragas.metrics import AnswerRelevancy
# Initialize the Ragas metric
llm = LangchainLLMWrapper(ChatOpenAI())
emb = LangchainEmbeddingsWrapper(OpenAIEmbeddings())
answer_relevancy_metric = AnswerRelevancy(llm=llm, embeddings=emb)
메트릭이 초기화되면 샘플 질문에 점수를 매기는 데 사용할 수 있어요. 메트릭 점수 매기는 비동기로 수행되므로, 점수 함수를 실행하려면 asyncio 라이브러리를 사용해야 해요.
# Run this cell first if you are running this in a Jupyter notebook
import nest_asyncio
nest_asyncio.apply()
import asyncio
from ragas.dataset_schema import SingleTurnSample
from ragas.integrations.opik import OpikTracer
# Define the scoring function
def compute_metric(metric, row):
row = SingleTurnSample(**row)
opik_tracer = OpikTracer()
async def get_score(opik_tracer, metric, row):
score = await metric.single_turn_ascore(row, callbacks=[OpikTracer()])
return score
# Run the async function using the current event loop
loop = asyncio.get_event_loop()
result = loop.run_until_complete(get_score(opik_tracer, metric, row))
return result
# Score a simple example
row = {
"user_input": "What is the capital of France?",
"response": "Paris",
"retrieved_contexts": ["Paris is the capital of France.", "Paris is in France."],
}
score = compute_metric(answer_relevancy_metric, row)
print("Answer Relevancy score:", score)
Answer Relevancy score: 1.0
이제 Opik으로 이동하면 Default Project 프로젝트에 새 trace가 생성된 것을 볼 수 있어요.
trace에 점수 매기기
update_current_trace 함수를 사용해 현재 trace를 가져오고 피드백 점수를 그 함수에 전달하면 trace에 점수를 매길 수 있어요. 이 접근법의 장점은 trace에 점수 스팬이 추가되어 RAG 파이프라인을 더 세밀하게 분석할 수 있다는 거예요. 다만 Ragas 메트릭 계산을 동기적으로 실행하므로 프로덕션 사용 사례에는 적합하지 않을 수 있어요.
from opik import track
from opik.opik_context import update_current_trace
@track
def retrieve_contexts(question):
# Define the retrieval function, in this case we will hard code the contexts
return ["Paris is the capital of France.", "Paris is in France."]
@track
def answer_question(question, contexts):
# Define the answer function, in this case we will hard code the answer
return "Paris"
@track(name="Compute Ragas metric score", capture_input=False)
def compute_rag_score(answer_relevancy_metric, question, answer, contexts):
# Define the score function
row = {"user_input": question, "response": answer, "retrieved_contexts": contexts}
score = compute_metric(answer_relevancy_metric, row)
return score
@track
def rag_pipeline(question):
# Define the pipeline
contexts = retrieve_contexts(question)
answer = answer_question(question, contexts)
score = compute_rag_score(answer_relevancy_metric, question, answer, contexts)
update_current_trace(
feedback_scores=[{"name": "answer_relevancy", "value": round(score, 4)}]
)
return answer
rag_pipeline("What is the capital of France?")
'Paris'
from datasets import load_dataset
from ragas import evaluate
from ragas.metrics import answer_relevancy, context_precision, faithfulness
fiqa_eval = load_dataset("vibrantlabsai/fiqa", "ragas_eval")
# Reformat the dataset to match the schema expected by the Ragas evaluate function
dataset = fiqa_eval["baseline"].select(range(3))
dataset = dataset.map(
lambda x: {
"user_input": x["question"],
"reference": x["ground_truth"],
"retrieved_contexts": x["contexts"],
}
)
opik_tracer_eval = OpikTracer(tags=["ragas_eval"], metadata={"evaluation_run": True})
result = evaluate(
dataset,
metrics=[context_precision, faithfulness, answer_relevancy],
callbacks=[opik_tracer_eval],
)
print(result)
Evaluating: 0%| | 0/6 [00:00<?, ?it/s]
{'context_precision': 1.0000, 'faithfulness': 0.7375, 'answer_relevancy': 0.9889}