Tutorial Opik: Platform Evaluasi dan Observabilitas LLM
Opik adalah platform open-source yang dikembangkan oleh Comet untuk evaluasi, testing, dan monitoring aplikasi berbasis Large Language Model (LLM). Dalam ekosistem AI modern, membangun aplikasi LLM saja tidak cukup. Kita perlu memastikan bahwa respons model konsisten, akurat, dan sesuai ekspektasi. Opik menyediakan toolkit lengkap untuk tracing, evaluasi otomatis, dan monitoring produksi yang membantu tim AI mengembangkan aplikasi LLM dengan percaya diri.
Tutorial ini akan membahas cara menggunakan Opik mulai dari instalasi, tracing request LLM, membuat evaluasi otomatis, hingga monitoring aplikasi di produksi. Semua contoh kode bisa langsung dijalankan di environment Python lokal Anda.
Mengapa Opik?
Saat membangun aplikasi LLM, ada beberapa tantangan utama yang sering dihadapi:
Opik mengatasi semua tantangan ini dengan menyediakan:
- Tracing: Mencatat setiap langkah dalam pipeline LLM secara detail
- Evaluation: Framework evaluasi otomatis dengan metrik bawaan dan custom
- Dataset Management: Mengelola test dataset untuk evaluasi yang reproducible
- Monitoring Dashboard: Visualisasi real-time performa aplikasi LLM
Instalasi
Instalasi via pip
pip install opik
Konfigurasi Opik
Ada dua cara menggunakan Opik: menggunakan Comet Cloud (hosted) atau self-hosted.
Opsi 1: Comet Cloud (Recommended untuk memulai)
opik configure
Perintah ini akan meminta API key dari akun Comet Anda. Daftar gratis di comet.com jika belum punya akun.
Opsi 2: Self-Hosted dengan Docker
# Clone repository
git clone https://github.com/comet-ml/opik.git
cd opik
Jalankan dengan Docker Compose
docker compose up -d
Setelah berjalan, Opik dashboard tersedia di http://localhost:5173.
Konfigurasi client untuk self-hosted:
import opik
opik.configure(uselocal=True)
Verifikasi Instalasi
import opik
client = opik.Opik()
print("Opik connected successfully!")
print(f"Workspace: {client.workspace}")
Tracing: Mencatat Setiap Langkah Pipeline LLM
Tracing adalah fitur inti Opik yang memungkinkan Anda merekam setiap langkah dalam pipeline LLM. Ini sangat berguna untuk debugging dan analisis performa.
Basic Tracing dengan Decorator
Cara termudah menggunakan tracing adalah dengan decorator @opik.track:
import opik
from openai import OpenAI
client = OpenAI()
@opik.track
def generateresponse(prompt: str) -> str:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
@opik.track
def processquery(userquery: str) -> dict:
enhancedprompt = f"Jawab pertanyaan berikut dengan jelas dan ringkas:\n{userquery}"
response = generateresponse(enhancedprompt)
return {
"query": userquery,
"response": response
}
result = processquery("Apa itu machine learning?")
print(result["response"])
Setiap pemanggilan fungsi yang di-decorate dengan @opik.track akan otomatis dicatat sebagai span dalam trace. Fungsi nested akan membentuk hierarki parent-child secara otomatis.
Tracing dengan Metadata
Anda bisa menambahkan metadata tambahan ke trace untuk memperkaya informasi:
import opik
from opik import opikcontext
@opik.track
def classifytext(text: str, categories: list) -> str:
opikcontext.updatecurrenttrace(
tags=["classification", "production"],
metadata={
"model": "gpt-4o-mini",
"numcategories": len(categories),
"textlength": len(text)
}
)
prompt = f"""Klasifikasikan teks berikut ke salah satu kategori: {', '.join(categories)}
Teks: {text}
Kategori:"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
result = response.choices[0].message.content.strip()
opikcontext.updatecurrentspan(
metadata={"resultcategory": result}
)
return result
result = classifytext(
"Harga saham BBCA naik 2% hari ini",
["finance", "technology", "sports", "politics"]
)
print(f"Kategori: {result}")
Integrasi dengan OpenAI
Opik menyediakan integrasi langsung dengan OpenAI sehingga semua API call otomatis di-trace:
from opik.integrations.openai import trackopenai
from openai import OpenAI
client = OpenAI()
client = track
openai(client)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Kamu adalah asisten yang membantu."},
{"role": "user", "content": "Jelaskan konsep RAG dalam 2 kalimat."}
]
)
print(response.choices[0].message.content)
Integrasi dengan LangChain
Jika Anda menggunakan LangChain, Opik menyediakan callback handler:
from opik.integrations.langchain import OpikTracer
from langchainopenai import ChatOpenAI
from langchaincore.prompts import ChatPromptTemplate
opiktracer = OpikTracer()
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.frommessages([
("system", "Kamu adalah ahli {topic}."),
("user", "{question}")
])
chain = prompt | llm
response = chain.invoke(
{"topic": "data science", "question": "Apa perbedaan supervised dan unsupervised learning?"},
config={"callbacks": [opiktracer]}
)
print(response.content)
Tracing Pipeline RAG
Salah satu use case paling umum adalah tracing pipeline RAG (Retrieval-Augmented Generation):
import opik
from openai import OpenAI
client = OpenAI()
@opik.track(name="embedquery")
def embedquery(query: str) -> list:
response = client.embeddings.create(
model="text-embedding-3-small",
input=query
)
return response.data[0].embedding
@opik.track(name="retrievedocuments")
def retrievedocuments(queryembedding: list, topk: int = 3) -> list:
documents = [
{"id": 1, "text": "Python adalah bahasa pemrograman yang populer untuk data science.", "score": 0.92},
{"id": 2, "text": "Machine learning adalah cabang dari artificial intelligence.", "score": 0.87},
{"id": 3, "text": "Data preprocessing adalah langkah penting sebelum training model.", "score": 0.83},
]
return documents[:topk]
@opik.track(name="generateanswer")
def generateanswer(query: str, contextdocs: list) -> str:
context = "\n".join([doc["text"] for doc in contextdocs])
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": f"Jawab berdasarkan konteks berikut:\n{context}"},
{"role": "user", "content": query}
]
)
return response.choices[0].message.content
@opik.track(name="ragpipeline")
def ragpipeline(query: str) -> dict:
embedding = embedquery(query)
documents = retrievedocuments(embedding)
answer = generateanswer(query, documents)
return {
"query": query,
"numdocsretrieved": len(documents),
"answer": answer
}
result = ragpipeline("Bagaimana cara memulai belajar data science?")
print(result["answer"])
Di Opik dashboard, Anda akan melihat trace lengkap dengan hierarki: ragpipeline -> embedquery -> retrievedocuments -> generateanswer, lengkap dengan input/output setiap langkah.
Evaluasi Otomatis
Evaluasi adalah fitur yang membuat Opik sangat berguna. Anda bisa mengevaluasi output LLM secara otomatis menggunakan metrik bawaan atau custom.
Membuat Dataset
Pertama, buat dataset untuk evaluasi:
import opik
client = opik.Opik()
dataset = client.getorcreatedataset(name="qa-evaluation-dataset")
dataset.insert([
{
"input": {"question": "Apa itu Python?"},
"expectedoutput": "Python adalah bahasa pemrograman tingkat tinggi yang populer untuk data science, web development, dan scripting."
},
{
"input": {"question": "Apa kegunaan pandas?"},
"expectedoutput": "Pandas adalah library Python untuk manipulasi dan analisis data, terutama data tabular."
},
{
"input": {"question": "Jelaskan apa itu neural network."},
"expectedoutput": "Neural network adalah model komputasi yang terinspirasi dari otak manusia, terdiri dari layer-layer neuron yang saling terhubung untuk memproses informasi."
},
{
"input": {"question": "Apa perbedaan SQL dan NoSQL?"},
"expectedoutput": "SQL menggunakan skema relasional dengan tabel terstruktur, sedangkan NoSQL menggunakan model data fleksibel seperti dokumen, key-value, atau graph."
},
{
"input": {"question": "Apa itu API?"},
"expectedoutput": "API (Application Programming Interface) adalah antarmuka yang memungkinkan dua aplikasi berkomunikasi satu sama lain."
}
])
print(f"Dataset '{dataset.name}' created with {len(dataset)} items")
Menggunakan Metrik Bawaan
Opik menyediakan beberapa metrik bawaan untuk evaluasi LLM:
from opik.evaluation.metrics import Hallucination, AnswerRelevance, ContextRecall
from opik.evaluation import evaluate
@opik.track
def qatask(inputdata: dict) -> dict:
question = inputdata["question"]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": question}]
)
answer = response.choices[0].message.content
return {
"output": answer,
"context": [f"Pertanyaan terkait: {question}"]
}
hallucinationmetric = Hallucination()
relevancemetric = AnswerRelevance()
results = evaluate(
dataset=dataset,
task=qatask,
scoringmetrics=[hallucinationmetric, relevancemetric],
experimentname="qa-evaluation-v1"
)
print(f"Evaluation complete!")
print(f"Average Hallucination Score: {results.averagescores.get('hallucination', 'N/A')}")
print(f"Average Relevance Score: {results.averagescores.get('answerrelevance', 'N/A')}")
Membuat Custom Metric
Anda juga bisa membuat metrik evaluasi sendiri:
from opik.evaluation.metrics import basemetric, scoreresult
class ResponseLengthMetric(base
metric.BaseMetric):
def init(self, minlength: int = 50, maxlength: int = 500):
self.name = "responselength"
self.minlength = minlength
self.maxlength = maxlength
def score(self, output: str, kwargs) -> scoreresult.ScoreResult:
length = len(output)
if self.minlength <= length <= self.maxlength:
scorevalue = 1.0
reason = f"Response length ({length}) is within acceptable range [{self.minlength}, {self.maxlength}]"
elif length < self.minlength:
scorevalue = length / self.minlength
reason = f"Response too short ({length} < {self.minlength})"
else:
scorevalue = max(0, 1 - (length - self.maxlength) / self.maxlength)
reason = f"Response too long ({length} > {self.maxlength})"
return scoreresult.ScoreResult(
name=self.name,
value=scorevalue,
reason=reason
)
class KeywordPresenceMetric(basemetric.BaseMetric):
def init(self, requiredkeywords: list):
self.name = "keywordpresence"
self.requiredkeywords = [kw.lower() for kw in requiredkeywords]
def score(self, output: str, kwargs) -> scoreresult.ScoreResult:
outputlower = output.lower()
found = [kw for kw in self.requiredkeywords if kw in outputlower]
scorevalue = len(found) / len(self.requiredkeywords) if self.requiredkeywords else 1.0
return scoreresult.ScoreResult(
name=self.name,
value=scorevalue,
reason=f"Found {len(found)}/{len(self.requiredkeywords)} keywords: {found}"
)
lengthmetric = ResponseLengthMetric(minlength=30, maxlength=300)
keywordmetric = KeywordPresenceMetric(requiredkeywords=["python", "programming"])
results = evaluate(
dataset=dataset,
task=qatask,
scoringmetrics=[lengthmetric, keywordmetric],
experimentname="qa-custom-metrics-v1"
)
Evaluasi dengan LLM-as-Judge
Opik mendukung penggunaan LLM sebagai evaluator, yang sangat berguna untuk menilai kualitas respons secara semantik:
from opik.evaluation.metrics import LLMJudge
judgemetric = LLMJudge(
name="qualityjudge",
model="gpt-4o-mini",
prompttemplate="""Evaluasi kualitas jawaban berikut berdasarkan pertanyaan yang diberikan.
Pertanyaan: {input}
Jawaban: {output}
Jawaban yang diharapkan: {expectedoutput}
Berikan skor 0-1 berdasarkan kriteria:
- Akurasi: Apakah jawaban benar?
- Kelengkapan: Apakah jawaban mencakup poin-poin penting?
- Kejelasan: Apakah jawaban mudah dipahami?
Skor (0-1):""",
)
results = evaluate(
dataset=dataset,
task=qatask,
scoringmetrics=[judgemetric],
experimentname="qa-llm-judge-v1"
)
Membandingkan Eksperimen
Salah satu kekuatan Opik adalah kemampuan membandingkan hasil antar eksperimen:
@opik.track
def qataskdetailed(inputdata: dict) -> dict:
question = inputdata["question"]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Jawab dengan detail dan berikan contoh jika memungkinkan. Gunakan bahasa yang mudah dipahami."},
{"role": "user", "content": question}
],
temperature=0.3
)
return {"output": response.choices[0].message.content}
resultsv2 = evaluate(
dataset=dataset,
task=qataskdetailed,
scoringmetrics=[hallucinationmetric, relevancemetric, lengthmetric],
experimentname="qa-evaluation-v2-detailed"
)
Di Opik dashboard, Anda bisa membandingkan qa-evaluation-v1 dan qa-evaluation-v2-detailed secara side-by-side untuk melihat dampak perubahan prompt.
Monitoring Produksi
Opik juga bisa digunakan untuk monitoring aplikasi LLM di produksi.
Logging Feedback dari User
import opik
client = opik.Opik()
@opik.track(name="productionquery", projectname="my-llm-app-production")
def handleuserquery(query: str, userid: str) -> str:
from opik import opikcontext
opikcontext.updatecurrenttrace(
tags=["production"],
metadata={
"userid": userid,
"environment": "production"
}
)
response = openaiclient.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": query}]
)
answer = response.choices[0].message.content
traceid = opikcontext.getcurrenttracedata().id
return answer, traceid
def submitfeedback(traceid: str, score: float, reason: str = ""):
client.logtracesfeedback(
traceids=[traceid],
scores=[score],
reasons=[reason],
name="usersatisfaction"
)
answer, traceid = handleuserquery(
query="Bagaimana cara menggunakan Docker?",
userid="user123"
)
submitfeedback(
traceid=traceid,
score=0.9,
reason="Jawaban lengkap dan mudah dipahami"
)
Online Scoring Rules
Anda bisa mengatur scoring rules yang berjalan otomatis untuk setiap trace di produksi:
client.createonlinescoringrule(
projectname="my-llm-app-production",
name="auto-hallucination-check",
metric=Hallucination(),
samplingrate=0.1
)
Ini akan otomatis mengevaluasi 10% dari semua trace di produksi menggunakan metrik hallucination.
Prompt Management
Opik juga menyediakan fitur prompt management untuk versioning dan tracking prompt:
import opik
client = opik.Opik()
prompt = client.createprompt(
name="qa-system-prompt",
prompt="Kamu adalah asisten AI yang membantu menjawab pertanyaan tentang {topic}. "
"Jawab dengan jelas, akurat, dan ringkas. "
"Jika tidak tahu jawabannya, katakan dengan jujur."
)
print(f"Prompt version: {prompt.commit}")
retrievedprompt = client.getprompt(name="qa-system-prompt")
formatted = retrievedprompt.format(topic="machine learning")
print(formatted)
Versioning Prompt
promptv2 = client.createprompt(
name="qa-system-prompt",
prompt="Kamu adalah asisten AI ahli di bidang {topic}. "
"Berikan jawaban yang terstruktur dengan poin-poin jika diperlukan. "
"Sertakan contoh praktis jika memungkinkan. "
"Jika tidak tahu jawabannya, arahkan user ke sumber yang relevan."
)
print(f"Updated prompt version: {promptv2.commit}")
history = client.getpromptversions(name="qa-system-prompt")
for version in history:
print(f"Version {version.commit}: created at {version.createdat}")
Best Practices
1. Struktur Tracing yang Baik
Beri nama yang deskriptif pada setiap trace dan span:
@opik.track(name="customersupportpipeline")
def handlesupportticket(ticket: dict):
intent = classifyintent(ticket["message"])
context = retrieveknowledge(intent, ticket["message"])
response = generateresponse(ticket["message"], context)
return response
2. Gunakan Tags untuk Filtering
@opik.track
def processrequest(request: dict):
from opik import opikcontext
opikcontext.updatecurrenttrace(
tags=[
f"model:{request.get('model', 'default')}",
f"env:{request.get('environment', 'dev')}",
f"priority:{request.get('priority', 'normal')}"
]
)
3. Evaluasi Secara Berkala
Jalankan evaluasi secara berkala, terutama saat:
- Mengubah prompt atau system message
- Upgrade versi model
- Menambahkan data baru ke knowledge base
- Sebelum dan sesudah deploy perubahan
4. Pisahkan Project per Environment
@opik.track(projectname="my-app-development")
def dev
pipeline(query: str):
pass
@opik.track(projectname="my-app-staging")
def stagingpipeline(query: str):
pass
@opik.track(projectname="my-app-production")
def prodpipeline(query: str):
pass
5. Simpan Hasil Evaluasi sebagai Baseline
Setiap kali mendapatkan hasil evaluasi yang baik, simpan sebagai baseline:
results = evaluate(
dataset=dataset,
task=qatask,
scoringmetrics=[hallucinationmetric, relevancemetric],
experimentname=f"baseline-v1-{datetime.now().strftime('%Y%m%d')}"
)
Integrasi dengan Framework Lain
Selain OpenAI dan LangChain, Opik juga mendukung integrasi dengan:
- LlamaIndex:
from opik.integrations.llamaindex import LlamaIndexCallbackHandler - Anthropic:
from opik.integrations.anthropic import trackanthropic - Google Gemini:
from opik.integrations.gemini import trackgemini - Ollama: Melalui integrasi OpenAI-compatible
- LiteLLM:
from opik.integrations.litellm import tracklitellm - Haystack:
from opik.integrations.haystack import OpikConnector - CrewAI:
from opik.integrations.crewai import trackcrewai
Contoh integrasi dengan LlamaIndex:
from opik.integrations.llamaindex import LlamaIndexCallbackHandler
from llama
index.core import Settings, VectorStoreIndex, SimpleDirectoryReader
from llamaindex.core.callbacks import CallbackManager
opikhandler = LlamaIndexCallbackHandler()
Settings.callbackmanager = CallbackManager([opikhandler])
documents = SimpleDirectoryReader("./data").loaddata()
index = VectorStoreIndex.fromdocuments(documents)
queryengine = index.asqueryengine()
response = queryengine.query("Apa itu vector database?")
print(response)
Kesimpulan
Opik menyediakan toolkit lengkap untuk mengelola lifecycle aplikasi LLM dari development hingga produksi. Dengan fitur tracing, Anda bisa mendapatkan visibilitas penuh ke dalam pipeline LLM. Fitur evaluasi memungkinkan testing otomatis yang konsisten dan reproducible. Dan fitur monitoring memastikan aplikasi tetap berjalan sesuai harapan di produksi.
Keunggulan utama Opik dibandingkan tools serupa adalah sifatnya yang open-source, mudah di-setup (bisa self-hosted atau cloud), dan memiliki integrasi yang luas dengan berbagai framework AI populer. Untuk tim yang serius membangun aplikasi LLM production-grade, Opik adalah pilihan yang layak dipertimbangkan sebagai bagian dari stack observabilitas AI Anda.
Langkah selanjutnya yang disarankan:
- Eksplorasi Opik dashboard untuk visualisasi trace dan evaluasi
- Implementasikan tracing di pipeline LLM yang sudah ada
- Buat dataset evaluasi dari data produksi nyata
- Setup monitoring rules untuk deteksi dini masalah kualitas