Panduan
Tutorial: gambar, dengan pemeriksaan dan juri yang melihatnya
Evaluasi fungsi yang membuat gambar, di sini pembuat thumbnail produk yang juga menulis keterangan (caption). Periksa thumbnail dengan pengukuran yang tidak memerlukan model, nilai keterangannya dengan model yang melihat setiap thumbnail, ukur juri itu terhadap seseorang, lalu rilis perubahan nyata. Setiap langkah berjalan di mesin ini tanpa model dan tanpa jaringan, dan sebuah langkah opsional menggantinya dengan model vision sungguhan.
Apa yang akan Anda bangun
Sebuah layanan katalog menerima foto produk, menyimpan thumbnail, dan menulis keterangan satu baris yang menyebut warna produk. Tiga pertanyaan menentukan apakah sebuah versi boleh dirilis:
- Apakah setiap thumbnail sesuai dengan katalog: format web, paling besar 256 kali 256 piksel, paling besar 50 kB? Itu sebuah pengukuran, yang dilakukan media_check dari byte thumbnail.
- Apakah setiap thumbnail masih merupakan foto produknya, dan bukan gambar kosong, potongan, atau produk lain? image_matches_reference membandingkannya dengan foto itu melalui perceptual hash.
- Apakah setiap keterangan menyebut warna yang dilihat pembeli? Itu membutuhkan mata, sehingga juri rubrik ditunjukkan thumbnail-nya.
Foto dan thumbnail tetap berada di folder proyek. Sistem merekamnya berdasarkan referensi (media/v1): di mana setiap file berada, tipenya, ukurannya, dan sha256-nya. Istilah seperti kasus, eksekusi, juri, dan gerbang didefinisikan di Konsep inti; segala hal tentang media ada di Gambar, audio, dan video.
Prasyarat
- Python 3.11 atau yang lebih baru, dan Oloproof dengan ekstra media-nya, yang menambahkan Pillow untuk membandingkan gambar:
python3 -m venv .venv
. .venv/bin/activate
pip install 'oloproof[media]'- Proyek contoh, yang disertakan dalam paket. Salin ke direktori baru dan bekerjalah di sana:
oloproof init --example media product-thumbnails
cd product-thumbnails- Port 8798 kosong untuk juri pengganti (ubah di kedua tempat jika tidak).
Setiap langkah hingga "Opsional: model vision sungguhan" bersifat offline dan deterministik: tanpa kunci API, tanpa akun penyedia, tanpa biaya.
File-filenya
product-thumbnails/
app.py the thumbnailer under test (baseline)
app_v2.py the candidate change
judge_server.py a stand-in vision judge speaking the OpenAI API on 127.0.0.1
rubrics/caption_names_colour.md the judge's rubric
oloproof.yaml the suite
release.yaml rules for a run
compare.yaml a rule for a comparison
data/products.jsonl 20 cases
photos/ the 20 product photos the cases name
make_photos.py how the photos were drawn
labels/reviewer_verdicts.csv one person's verdicts on the baseline's captions
fill_labels.py copies those verdicts into a labelling sheetJalankan setiap perintah dari product-thumbnails/.
Aplikasi merekam gambarnya
# app.py (excerpt)
@system(name="thumbnailer", version=VERSION, records=("media/v1",))
def describe(case: dict[str, Any]) -> dict[str, str]:
photo_path = HERE / case["photo"]
photo = Image.open(photo_path).convert("RGB")
thumb = photo.copy()
thumb.thumbnail((320, 320))
out = HERE / "thumbs" / VERSION / photo_path.name
out.parent.mkdir(parents=True, exist_ok=True)
thumb.save(out)
given = media_file(photo_path, role="input")
made = media_file(out, width=thumb.width, height=thumb.height)
current_case().media([given, made])
centre = photo.getpixel((photo.width // 2, photo.height // 2))
return {"caption": f"A {colour_name(centre)} product."}media_file(path) mendeskripsikan sebuah file: lokasi file://-nya, tipe MIME, ukuran, dan sha256, dinamai menurut nama file-nya. role="input" menandai foto yang diberikan kepada sistem; thumbnail adalah keluaran, yang merupakan bawaan. current_case().media(...) merekam keduanya sebagai satu artefak media/v1, dan records: [media/v1] di oloproof.yaml mendeklarasikan bahwa sistem merekamnya. Tidak ada yang disalin: pemeriksaan atau juri membaca kembali setiap file nanti dan menolak file yang byte-nya tidak lagi cocok dengan rekamannya.
Baseline ini memiliki dua kesalahan. Thumbnail-nya selebar 320 piksel, dan keterangannya menyebut warna piksel tengah foto, yang merupakan latar belakang setiap kali produk berada di satu sisi. Setiap versi menulis thumbnail-nya di bawah thumbs/<version>/, sehingga eksekusi berikutnya tidak pernah menimpa file yang direkam eksekusi sebelumnya.
Dataset
{"id": "p03", "input": {"photo": "photos/p03.png"}, "expected": {"photo": "photos/p03.png", "colour": "yellow", "shape": "triangle"}}input adalah apa yang diterima sistem. expected.photo adalah acuan yang dibandingkan dengan thumbnail; colour dan shape ada untuk orang yang membaca kasus itu, dan tidak ada evaluator yang membacanya.
Memilih evaluator
evaluators:
# The catalogue's limits, measured from the thumbnail's bytes: a web format, at most 256 by
# 256 pixels, at most 50 kB.
- type: media_check
criterion: thumbnail_fits
kind: image
formats: [png, jpeg, webp]
max_width: 256
max_height: 256
max_bytes: 50000
# The thumbnail is still the product's photo: a perceptual hash within 10 of 64 bits.
- type: image_matches_reference
criterion: same_photo
reference_field: photo
max_distance: 10
# The caption, judged by a model that sees the thumbnail.
- type: rubric_judge
criterion: caption_names_colour
provider: openai_compatible
model: stand-in-vision
base_url: http://127.0.0.1:8798/v1
rubric_file: rubrics/caption_names_colour.md
media: outputmedia_check mengukur setiap gambar keluaran: format dari byte pembukanya, ukuran dari header-nya, tidak pernah dari apa yang dideklarasikan sistem. image_matches_reference meng-hash thumbnail dan foto yang disebut expected.photo, dan lolos ketika hash-nya berbeda paling banyak 10 dari 64 bit; pengubahan ukuran atau kompresi ulang menggeser hash beberapa bit, gambar lain menggesernya banyak bit. Keduanya tidak memanggil model, sehingga keduanya memutuskan sejak eksekusi pertama.
media: output melampirkan gambar keluaran kasus itu ke permintaan juri, masing-masing disebut namanya dalam prompt. Juri tidak memutuskan apa pun sampai label manusia menunjukkan bahwa juri itu sepakat dengan mereka, sehingga aturan ketiga menunggu hal itu.
Juri pengganti
Juri rubrik mengirim prompt dan gambar yang dilampirkan ke sebuah model dan membaca kembali {"pass": true|false, "rationale": "..."}. Di sini modelnya adalah judge_server.py, yang berbicara dengan API yang sama di 127.0.0.1 dan bukan model: server ini mendekode thumbnail yang dilampirkan, menemukan warnanya yang paling umum selain putih dan abu-abu latar belakang, dan meloloskan keterangan yang menyebut warna itu. Jalankan di terminal kedua dan biarkan tetap berjalan:
python judge_server.py --port 8798Kebijakannya
version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
require_validated_evaluators: true
rules:
- id: thumbnails-fit
metric: thumbnail_fits
kind: observed_count
max_failures: 0
- id: same-photo
metric: same_photo
kind: observed_count
max_failures: 0
- id: caption-floor
metric: caption_names_colour
min: 0.80Setiap thumbnail harus sesuai dan harus merupakan fotonya. Setidaknya 80% keterangan harus menyebut warna yang benar, yang diputuskan hanya ketika batas bawah interval melampaui 80%.
Jalankan
oloproof runGate: BLOCK (exit 1)
│ thumbnails-fit │ thumbnail_fits │ FAIL │ observed_failures_exceed_limit │
│ same-photo │ same_photo │ PASS │ observed_failures_within_limit │
│ caption-floor │ caption_names_colour │ INSUFFICIENT_EVIDENCE │ evaluator_not_validated │
│ thumbnail_fits │ 0.0% │ [0.0%, 16.9%] │ 0 / 20 observed · 0 missing · 0 excluded │
│ same_photo │ 100.0% │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │
│ caption_names_colour │ 60.0% │ [36.0%, 80.9%] │ 12 / 20 observed · 0 missing · 0 excluded │Tidak ada thumbnail yang sesuai, setiap thumbnail merupakan fotonya, dan 12 dari 20 keterangan menyebut warna yang benar. Aturan juri belum diputuskan karena belum ada yang mengukur juri itu.
Periksa kegagalannya
oloproof inspect RUN_ID --failuresp03
output: {"caption": "A white product."}
thumbnail_fits: failed
measured: p03.png: width 320 px is above 256 px
caption_names_colour: failed
judge text, not verified: the product is yellow; the caption says 'a white product.'Alasan sebuah pemeriksaan adalah pengukuran, ditandai measured; alasan juri adalah kata-katanya sendiri, yang belum diperiksa siapa pun. Foto dan thumbnail juga muncul di samping setiap putusan di halaman kasus di workbench, setelah oloproof export RUN_ID, dibaca dari folder ini; ruang kerja yang di-hosting membuat browser Anda mengambilnya dari oloproof collect dan tidak pernah menyimpannya (Gambar, audio, dan video).
Ukur juri terhadap seseorang
Ambil sampel acak dari kasus-kasus eksekusi ke dalam sebuah lembar, tanpa putusan juri, minta seseorang melihat setiap thumbnail dan keterangannya, lalu impor apa yang dikatakannya. Di sini fill_labels.py menggantikan orang itu, dengan menyalin putusannya dari labels/reviewer_verdicts.csv:
oloproof labels export RUN_ID --criterion caption_names_colour --sample 20 --local --out sample.csv
python fill_labels.py sample.csv
oloproof labels import sample.csvLalu ukur juri terhadap label-label itu, dan catat siapa yang melakukannya:
oloproof evaluators list
oloproof evaluators validate EVALUATOR_ID --by alicecaption_names_colour: sha256:53605dd6... is now VALIDATED
agreement 100.0% [83.1%, 100.0%] · 20 of 20 labelled cases agreed · 0 labelled but not judged · kappa 1.000Juri yang melihat gambar diukur persis seperti juri yang membaca teks. Di ruang kerja yang di-hosting, antrean tinjauan menunjukkan gambar setiap kasus kepada peninjau, diambil oleh browser mereka dari kolektor Anda (Juri).
oloproof gate RUN_ID --policy release.yamlthumbnails-fit: FAIL (observed_failures_exceed_limit)
same-photo: PASS (observed_failures_within_limit)
caption-floor: INSUFFICIENT_EVIDENCE (interval_overlaps_threshold)
Gate: BLOCK (exit 1)Juri sekarang boleh memutuskan, dan 60% tidak cukup.
Lakukan perubahan nyata
app_v2.py membuat thumbnail 256 piksel dan menyebut warna foto yang paling umum selain latar belakang, di mana pun produknya berada. Salin menimpa app.py, tetapkan version: main-colour di bawah system di oloproof.yaml, biarkan juri tetap berjalan, lalu:
oloproof runGate: ALLOW (exit 0)
│ thumbnails-fit │ thumbnail_fits │ PASS │ observed_failures_within_limit │
│ same-photo │ same_photo │ PASS │ observed_failures_within_limit │
│ caption-floor │ caption_names_colour │ PASS │ lower_bound_meets_minimum │Juri adalah versi evaluator yang sama yang telah divalidasi, sehingga putusannya dihitung.
Bandingkan kandidat dengan baseline
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlthumbnail_fits: +100.0 points [+52.9, +100.0] · 20 paired · 0 missing · 0 excluded
caption_names_colour: +40.0 points [+1.8, +72.7] · 20 paired · 0 missing · 0 excluded
captions-better caption_names_colour superiority PASS difference_above_zeroOpsional: model vision sungguhan
Langkah ini meninggalkan jalur offline. Langkah ini memerlukan model yang dapat membaca gambar: secara lokal, Ollama dengan model vision (ollama pull qwen2.5vl), tanpa kunci dan tanpa biaya; di cloud, provider: anthropic atau openai dengan api_key_env, ditagih per gambar sebagaimana per kata.
# live_judge.yaml
type: rubric_judge
criterion: caption_names_colour
provider: openai_compatible
model: qwen2.5vl
base_url: http://localhost:11434/v1
rubric_file: rubrics/caption_names_colour.md
media: output
timeout_s: 300oloproof evaluators try live_judge.yamlPerintah itu menilai kasus-kasus yang diberi label oleh peninjau Anda dengan model sungguhan dan melaporkan kesepakatannya, tanpa mengadopsinya. Untuk mengadopsinya, masukkan ke oloproof.yaml menggantikan juri pengganti: model baru adalah versi evaluator baru, sehingga validasi terhadap label seperti di atas.
Pemecahan masalah
| Gejala | Penyebab dan perbaikan |
|---|---|
| caption_names_colour semuanya hilang | Server juri tidak berjalan atau tidak berada di base_url; oloproof inspect RUN_ID --failures menunjukkan alasannya. |
| image_matches_reference menghentikan eksekusi, dengan menyebut Pillow | Pasang ekstra media: pip install 'oloproof[media]'. |
| Sebuah kasus hilang dengan media_unavailable | File yang direkam dipindahkan atau dihapus setelah eksekusi. Simpan file yang direkam sebuah eksekusi selama Anda menyimpan eksekusi itu. |
| Eksekusi berhenti dengan is not the recorded content | File yang direkam diubah setelah eksekusi. Pemeriksaan atau juri tidak pernah membaca byte yang berbeda sebagai byte yang direkam; tulis file setiap versi ke tempatnya sendiri. |
| evaluator_not_validated setelah Anda memvalidasi | Anda mengubah juri (model, endpoint, port, rubrik, media) dan membuat versi baru. Validasi versi itu. |
Keterbatasan
- Juri pengganti menghitung piksel. Juri itu mendemonstrasikan alur kerja, bukan kualitas penilaian.
- Perceptual hash membaca tata letak dan cahaya, bukan warna: hash ini membedakan thumbnail foto itu dari gambar kosong atau adegan yang berbeda, tetapi tidak membedakan satu produk dari produk lain di studio yang sama. Grafik datar dengan area kosong yang luas menggesernya lebih banyak daripada foto.
- Dua puluh label memberi interval kesepakatan yang lebar. Beri label lebih banyak, secara acak dan buta, untuk juri yang Anda andalkan.
- Audio dan video bekerja dengan cara yang sama dengan pengaturan lain: lihat Gambar, audio, dan video.