Kesalahan metadata katalog seperti kategori produk yang salah, atribut spesifikasi yang hilang, atau pelanggaran penamaan sering lolos dari unit test konvensional. Pendekatan berbasis aturan regex gagal menangkap konteks semantik, sedangkan review manual memperlambat siklus rilis. Mengintegrasikan pola LLM Jury ke dalam pipeline CI/CD memungkinkan evaluasi otomatis berbasis konsensus multi-model sebelum metadata di-merge ke branch produksi.
Arsitektur Pola LLM Jury
Pola LLM Jury menggunakan minimal dua atau tiga model yang berbeda (atau prompt yang diisolasi) untuk mengevaluasi data masukan secara independen. Keputusan rilis didasarkan pada majority voting atau tingkat kesepakatan (consensus score).
- Model Heterogen: Menggabungkan model dari penyedia berbeda (misalnya OpenAI GPT-4o-mini dan Anthropic Claude 3.5 Haiku) mencegah bias inheren atau failure mode yang sama dari satu model keluarga.
- Structured Output & Skema JSON: Output evaluasi dipaksa mengikuti JSON schema ketat yang divalidasi dengan runtime parser (seperti Pydantic atau Zod).
- Gatekeeper CI: Pipeline akan
exit 1jika konsensus gagal tercapai atau nilai validitas metadata berada di bawah ambang batas minimum.
Script Evaluasi Multi-Model (Python)
Script berikut menerima file JSON berisi metadata produk, mengirimkannya secara paralel ke dua penyedia LLM, memvalidasi respons menggunakan Pydantic, dan menghitung konsensus kelayakan rilis.
import os
import sys
import json
import asyncio
from typing import Literal
from pydantic import BaseModel, Field, ValidationError
from openai import AsyncOpenAI
import anthropic
class EvaluationResult(BaseModel):
passed: bool = Field(description="Apakah metadata memenuhi kriteria katalog")
category_accurate: bool
title_compliant: bool
reason: str = Field(description="Alasan evaluasi maksimal 2 kalimat")
PROMPT = """Evaluasi metadata katalog berikut:
Judul: {title}
Kategori: {category}
Atribut: {attributes}
Aturan:
1. Judul tidak boleh clickbait dan harus mencakup merek serta tipe.
2. Kategori harus relevan secara spesifik.
3. Atribut tidak boleh mengandung HTML atau karakter rusak.
Kembalikan hasil dalam format JSON persis sesuai skema:
{{"passed": boolean, "category_accurate": boolean, "title_compliant": boolean, "reason": string}}
"""
async def judge_openai(client: AsyncOpenAI, payload: dict) -> EvaluationResult:
content = PROMPT.format(**payload)
resp = await client.chat.completions.create(
model="gpt-4o-mini",
temperature=0.0,
response_format={"type": "json_object"},
messages=[{"role": "user", "content": content}]
)
raw = json.loads(resp.choices[0].message.content)
return EvaluationResult.model_validate(raw)
async def judge_anthropic(client: anthropic.AsyncAnthropic, payload: dict) -> EvaluationResult:
content = PROMPT.format(**payload)
resp = await client.messages.create(
model="claude-3-5-haiku-20241022",
max_tokens=256,
temperature=0.0,
messages=[{"role": "user", "content": content}]
)
raw = json.loads(resp.content[0].text)
return EvaluationResult.model_validate(raw)
async def main():
if len(sys.argv) < 2:
print("Usage: python eval.py <metadata.json>")
sys.exit(2)
with open(sys.argv[1], "r") as f:
catalog_items = json.load(f)
oa_client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"])
ant_client = anthropic.AsyncAnthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
failed_items = []
for item in catalog_items:
try:
r1, r2 = await asyncio.gather(
judge_openai(oa_client, item),
judge_anthropic(ant_client, item)
)
# Majority vote: kedua model harus sepakat lolos
if not (r1.passed and r2.passed):
failed_items.append({
"sku": item.get("sku"),
"gpt_reason": r1.reason,
"claude_reason": r2.reason,
"disagreement": r1.passed != r2.passed
})
except (ValidationError, json.JSONDecodeError) as e:
print(f"Validation failure on item {item.get('sku')}: {e}")
failed_items.append({"sku": item.get("sku"), "error": str(e)})
if failed_items:
print(f"CI Check Failed: {len(failed_items)} item tidak valid.")
print(json.dumps(failed_items, indent=2))
sys.exit(1)
print("Semua metadata katalog lolos evaluasi LLM Jury.")
sys.exit(0)
if __name__ == "__main__":
asyncio.run(main())
Konfigurasi GitHub Actions Workflow
Eksekusi evaluator dibatasi hanya saat ada perubahan file pada direktori metadata atau file seed katalog. Menggunakan secret credentials secara aman dan menghasilkan ringkasan langsung pada step summary.
name: Catalog Metadata LLM Evaluator
on:
pull_request:
paths:
- 'catalog/seeds/**.json'
- 'catalog/metadata/**.json'
jobs:
llm-jury:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install Dependencies
run: |
pip install openai anthropic pydantic
- name: Run LLM Jury Evaluation
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# Evaluasi data seed katalog produk
python scripts/eval_catalog.py catalog/seeds/products.json
Mitigasi Non-Deterministik dan Flaky Tests
Evaluasi model di CI/CD rentan terhadap masalah flakiness. Gunakan langkah-langkah berikut untuk memastikan hasil deterministik:
- Temperature 0: Selalu set parameter
temperature=0.0dantop_p=1.0untuk menekan variansi token generation. - Pinned Model Versions: Hindari menggunakan tag alias dinamis seperti
gpt-4o-minijika penyedia mendukung snapshot versioning berbasis tanggal (misalgpt-4o-mini-2024-07-18). - Retry dengan Backoff: Pasang retry logic khusus untuk menangani status
429 (Rate Limit)dan5xx, bukan untuk mengulang penilaian yang gagal.
Analisis Trade-Off: Latency vs Akurasi
Penerapan konsensus multi-model memperkenalkan overhead biaya API dan waktu pipeline yang sebanding dengan penurunan false positive/negative.
| Strategi Evaluator | Rata-rata Latency | Biaya per 1.000 Item | Akurasi Semantik | Risiko Flakiness |
|---|---|---|---|---|
| Single Small Model (e.g. GPT-4o-mini) | ~600ms | Sangat Rendah (~$0.02) | Moderat | Sedang (bias rentan) |
| Multi-Model Consensus (2 Model paralel) | ~1.2s (bounded by slower model) | Rendah-Moderat (~$0.05) | Tinggi | Rendah (terfilter disagreement) |
| Single Frontier Model (e.g. Claude 3.5 Sonnet) | ~2.5s | Tinggi (~$0.30) | Sangat Tinggi | Rendah |
Untuk efisiensi build time, batasi input yang dievaluasi dalam CI hanya pada data yang mengalami git diff terhadap target branch, bukan keseluruhan basis data katalog.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!