Panduan
Tutorial: pembuatan teks dengan juri rubrik
Evaluasi fungsi yang menulis teks bebas, di sini peringkas tiket, dengan pemeriksaan format dan juri rubrik; ukur juri itu terhadap label seseorang sebelum ia boleh memutuskan apa pun; lalu bandingkan perubahan nyata. Juri berjalan di mesin ini tanpa model dan tanpa jaringan, dan langkah opsional menggantinya dengan model sungguhan.
Apa yang akan Anda bangun
Peringkas yang mengubah tiket dukungan menjadi satu atau dua kalimat. "Baik" adalah sebuah penilaian, bukan kecocokan string, sehingga keberhasilan tugas diputuskan oleh juri LLM dengan rubrik: apakah ringkasan menyatakan fakta yang dibutuhkan seorang agen? Dua evaluator deterministik memeriksa format, yang tidak memerlukan acuan. Istilah seperti kasus, eksekusi, metrik, juri, dan gerbang didefinisikan dalam Konsep.
Bentuk yang sama cocok untuk ekstraksi atau generasi lain apa pun: sebuah fungsi mengembalikan teks dalam dictionary, acuan menyatakan apa yang harus dimuat jawaban yang baik, dan rubrik menyatakan cara memutuskannya.
Prasyarat
- Python 3.11 atau yang lebih baru, dan Oloproof di lingkungan virtual:
python3 -m venv .venv
. .venv/bin/activate
pip install oloproof- Proyek contoh, yang disertakan dalam paket. Salin ke direktori baru dan bekerjalah di sana:
oloproof init --example generation ticket-summaries
cd ticket-summaries- Port 8799 kosong untuk juri pengganti (ubah di kedua tempat jika tidak).
Setiap langkah hingga "Opsional: model sungguhan sebagai juri" bersifat offline dan deterministik: tanpa kunci API, tanpa akun penyedia, tanpa biaya.
File-filenya
ticket-summaries/
app.py the summariser under test (baseline)
app_v2.py the candidate change
judge_server.py a stand-in judge speaking the OpenAI API on 127.0.0.1
rubrics/covers_facts.md the judge's rubric
oloproof.yaml the suite
release.yaml rules for a run
compare.yaml a rule for a comparison
data/tickets.jsonl 20 cases
labels/reviewer_verdicts.csv one person's verdicts on the baseline's summaries
fill_labels.py copies those verdicts into a labelling sheetJalankan setiap perintah dari ticket-summaries/.
Juri pengganti, dan apa yang bukan dirinya
Juri rubrik adalah evaluator yang mengirim prompt (rubrik, input kasus, expected-nya, dan keluaran) ke sebuah model lalu membaca kembali {"pass": true|false, "rationale": "..."}. Oloproof berbicara dengan server apa pun yang memakai API chat OpenAI, dan server di localhost tidak memerlukan kunci.
judge_server.py adalah server seperti itu, tetapi bukan model. Server ini meloloskan ringkasan hanya jika ringkasan itu memuat setiap frasa di bawah must_mention dalam expected kasus, tanpa memperhatikan huruf besar atau kecil. Itu aturan tetap, sehingga tutorial memberi angka yang sama di setiap mesin. Server ini tidak dapat menyadari fakta yang dikarang, padahal juri model sungguhan diminta melakukannya. Jalankan di terminal kedua dan biarkan tetap berjalan:
python judge_server.py --port 8799stand-in judge on http://127.0.0.1:8799/v1Aplikasi dan adapternya
# app.py
@system(name="ticket-summariser", version="first-sentence")
def summarise(case: dict[str, Any]) -> dict[str, str]:
return {"summary": sentences(str(case["ticket"]))[0]}Adapter untuk aplikasi Python adalah fungsinya: fungsi itu menerima input kasus dan mengembalikan dictionary. Untuk generator Anda sendiri, panggil model atau chain Anda di dalamnya dan kembalikan teksnya di bawah sebuah kunci. Oloproof memanggilnya sekali per kasus dan meng-cache keluarannya berdasarkan source fungsi dan version yang dideklarasikan; Oloproof tidak mengelola klien model, prompt, atau state Anda. Cantumkan file yang dibaca fungsi, seperti templat prompt, di bawah system.code_paths.
Dataset
{"id":"t01","input":{"ticket":"Hello. Order 1042 arrived with a cracked screen. I would like a replacement, not a refund."},"expected":{"must_mention":["1042","cracked","replacement"]}}
{"id":"t06","input":{"ticket":"Please cancel my subscription at the end of this month. I am moving abroad."},"expected":{"must_mention":["cancel","end of this month"]}}input adalah apa yang diterima fungsi. expected adalah acuan yang dibaca juri: di sini daftar fakta yang harus dibawa ringkasan, bukan ringkasan acuan yang lengkap, karena banyak ringkasan yang berbeda dapat benar. Keluaran untuk t01 adalah {"summary": "Hello."}.
Memilih evaluator
version: 1
project: ticket-summaries
dataset: data/tickets.jsonl
system:
name: ticket-summariser
version: first-sentence
callable: app:summarise
timeout_s: 30
evaluators:
- type: json_schema
criterion: format_valid
field: null
schema:
type: object
required: [summary]
properties:
summary: {type: string, minLength: 1}
additionalProperties: false
- type: regex
criterion: short_enough
field: summary
pattern: '^.{1,160}$'
pass_if: match
- type: rubric_judge
criterion: covers_facts
provider: openai_compatible
model: stand-in-judge
base_url: http://127.0.0.1:8799/v1
rubric_file: rubrics/covers_facts.md| Kriteria | Evaluator | Memerlukan expected | Mengukur |
|---|---|---|---|
| format_valid | json_schema | tidak | format: satu field string yang tidak kosong |
| short_enough | regex | tidak | format: paling banyak 160 karakter |
| covers_facts | rubric_judge | ya | keberhasilan tugas, sebagaimana didefinisikan rubrik |
Hello. lolos kedua pemeriksaan format. Hanya juri yang mengatakan bahwa itu ringkasan yang tidak berguna. Juri juga dapat berjalan tanpa acuan: rubrik seperti "PASS if the summary contains no greeting" hanya membaca input dan keluaran, dan kasus tanpa expected tetap dinilai. Yang tidak dapat dilakukannya saat itu adalah memeriksa fakta terhadap jawaban yang Anda percayai.
Rubriknya:
PASS when the summary states every fact listed under must_mention in the expected answer, in
words a support agent would recognise, and adds nothing the ticket does not say.
FAIL when any listed fact is missing, changed or contradicted.Kebijakannya
version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
require_validated_evaluators: true
rules:
- id: valid-format
metric: format_valid
kind: observed_count
max_failures: 0
- id: short-enough
metric: short_enough
kind: observed_count
max_failures: 0
- id: covers-facts-floor
metric: covers_facts
min: 0.60require_validated_evaluators: true adalah bawaan mesin, ditulis eksplisit di sini karena itulah inti tutorial ini: juri yang belum pernah dibandingkan siapa pun dengan manusia tidak boleh memutuskan sebuah aturan.
Jalankan
oloproof runRun run_01M4... [DECIDED/COMPLETE]
Gate: BLOCK (exit 3)
│ valid-format │ format_valid │ PASS │ observed_failures_within_limit │
│ short-enough │ short_enough │ PASS │ observed_failures_within_limit │
│ covers-facts-floor │ covers_facts │ INSUFFICIENT_EVIDENCE │ evaluator_not_validated │
covers-facts-floor: the judge (or model or custom evaluator) behind this rule has not been measured against
people yet, so it may not decide.
Label a sample: oloproof review run_01M4... --criterion covers_facts --by YOU --sample 20
Then measure it: oloproof evaluators validate EVALUATOR_ID --by YOU (ids: oloproof evaluators list)
│ format_valid │ 100.0% │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │
│ short_enough │ 100.0% │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │
│ covers_facts │ 45.0% │ [23.0%, 68.5%] │ 9 / 20 observed · 0 missing · 0 excluded │
Cache: execution 0 hit/20 miss; judgment 0 hit/60 missAturan format lolos. Juri meloloskan 9 dari 20 ringkasan, tetapi aturannya INSUFFICIENT_EVIDENCE dengan alasan evaluator_not_validated, dan gerbang memblokir dengan keluar 3. Aturan tidak memutuskan berdasarkan 45% itu: tingkat kesalahan juri tidak diketahui sampai diukur, sehingga interval yang dibangun dari putusannya akan membawa kesalahan yang tidak dinyatakan. Mesin melaporkannya sebagai INSUFFICIENT_EVIDENCE, bukan MANUAL_REVIEW atau FAIL: bukti untuk memutuskan belum ada, dan keluaran mencetak dua perintah yang menyediakannya.
Periksa kegagalannya
oloproof inspect RUN_ID --failures11 of 20 cases failed, errored or did not finish
t01
output: {"summary": "Hello."}
covers_facts: failed
judge text, not verified: missing: 1042, cracked, replacement
t02
output: {"summary": "I was charged twice for order 2210."}
covers_facts: failed
judge text, not verified: missing: 49
...Alasan juri ditampilkan sebagai "judge text, not verified": itu penjelasan model, bukan bukti. Polanya tetap jelas: kalimat pertama sering kali berupa sapaan.
Ukur juri terhadap seseorang
Validasi membandingkan putusan juri dengan putusan seseorang pada jawaban yang sama. Ambil sampel acak dari kasus-kasus eksekusi ke dalam sebuah lembar. Putusan juri tidak dimasukkan, sehingga pemberi label tidak terpengaruh olehnya:
oloproof labels export RUN_ID --criterion covers_facts --sample 20 --local --out sample.csvWrote 20 cases to sample.csv, drawn at random with seed 2701013296, without the judge's verdict.
This is a local sample, good-faith only, because it was drawn on this machine.
Fill in `passed` (pass or fail) and `labelled_by` on each row you judge, then run `oloproof labels import sample.csv`.--local mengambil sampel di mesin ini tanpa meminta ruang kerja yang di-hosting; mesin memilih seed-nya. Dengan 20 kasus, sampel 20 berarti semuanya. Dalam praktiknya, seseorang membaca tiket dan ringkasan di setiap baris lalu mengisi passed. Untuk tutorial ini, labels/reviewer_verdicts.csv memuat putusan yang diberikan seorang peninjau pada ringkasan baseline, dan fill_labels.py menyalinnya ke dalam lembar:
python fill_labels.py sample.csv
oloproof labels import sample.csvfilled 20 rows of sample.csv
Recorded 20 labels from sample.csv (20 measurement).Peninjau berbeda pendapat dengan juri satu kali: pada t02 ("I was charged twice for order 2210.") mereka menilai jumlah yang tidak disebut itu tidak material dan meloloskannya. Label menyebut jawaban persis yang dinilainya, sehingga putusan ini hanya berlaku untuk eksekusi baseline.
Temukan id versi juri dan validasi:
oloproof evaluators list
oloproof evaluators validate EVALUATOR_ID --by alicecovers_facts LLM_JUDGE UNVALIDATED (declared) sha256:a662...
covers_facts: sha256:a662... is now VALIDATED
agreement 95.0% [75.1%, 99.9%] · 19 of 20 labelled cases agreed · 0 labelled but not judged · kappa 0.900
bias -5.0 points [-32.4, +20.7] · the judge's pass rate minus the people's · 20 cases · 0 labelled but not judged
passes what people pass 90.0% [55.4%, 99.8%] · the judge passed 9 of 10 cases people passed · 0 labelled but not judged
fails what people fail 100.0% [69.1%, 100.0%] · the judge failed 10 of 10 cases people failed · 0 labelled but not judgedBacalah intervalnya, bukan 95%-nya: 20 label menunjukkan kesepakatan setidaknya 75.1%. Kebijakan dapat menuntut lebih dengan minimum_evaluator_agreement, yang membandingkan batas bawah itu, dan validate menolak juri di bawahnya. Panduan Juri membahas standarnya, bias, probe, dan oloproof review untuk memberi label di terminal.
Sekarang putuskan ulang eksekusi tersimpan tanpa memanggil peringkas maupun juri:
oloproof gate RUN_ID --policy release.yamlvalid-format: PASS (observed_failures_within_limit)
short-enough: PASS (observed_failures_within_limit)
covers-facts-floor: INSUFFICIENT_EVIDENCE (interval_overlaps_threshold)
no sample size would make this PASS: the observed rate (0.500) is itself below the threshold (0.600), so more cases would move it toward FAIL
Gate: BLOCK (exit 3)Juri sekarang boleh memutuskan, dan keputusannya tentang peringkas: tingkat yang dikutipnya, 0.500, bukan 45% milik juri. Karena eksekusi ini memiliki sampel label pengukuran yang buta dan acak, gerbang membaca juri yang dikoreksi oleh label-label itu ("Judge-corrected gates" dalam panduan Juri). Koreksinya adalah PPI, prediction-powered inference: koreksi ini memakai sampel berlabel untuk mengukur seberapa jauh tingkat juri dari tingkat manusia, lalu menggeser estimasi dan melebarkan interval sebesar itu. Itu juga yang dimaksud catatan tentang PPI pada ekspor. Bagaimanapun juga, baseline tidak memenuhi batas bawah, dan lebih banyak kasus tidak akan mengubahnya.
Lakukan perubahan nyata
app_v2.py melewati basa-basi pendek dan mempertahankan dua kalimat berikutnya. Salin menimpa app.py, tetapkan version: skip-pleasantries di bawah system di oloproof.yaml, biarkan juri tetap berjalan, lalu:
oloproof runGate: ALLOW (exit 0)
│ covers-facts-floor │ covers_facts │ PASS │ lower_bound_meets_minimum │
│ covers_facts │ 100.0% │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │
Cache: execution 0 hit/20 miss; judgment 6 hit/54 missJuri adalah versi tervalidasi yang sama, sehingga aturannya memutuskan secara langsung. Enam penilaian berasal dari cache, pada ringkasan yang ditulis identik oleh kedua versi. Tidak ada yang memberi label pada ringkasan-ringkasan baru ini; validasi jurilah yang membuat putusannya berlaku.
Bandingkan kandidat dengan baseline
version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
require_validated_evaluators: true
rules:
- id: covers-more-facts
kind: superiority
metric: covers_factsoloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlformat_valid: +0.0 points [-23.6, +23.6] · 20 paired · 0 missing · 0 excluded
short_enough: +0.0 points [-23.6, +23.6] · 20 paired · 0 missing · 0 excluded
covers_facts: +55.0 points [+13.0, +84.4] · 20 paired · 0 missing · 0 excluded
Decisions
covers-more-facts covers_facts superiority PASS difference_above_zero
Gate: ALLOW (exit 0)Perbandingan tidak menerapkan koreksi PPI: perbandingan membandingkan putusan juri itu sendiri pada kedua eksekusi, itulah sebabnya peningkatan dimulai dari 45% milik juri dan bukan dari 0.500 yang dikoreksi di atas. Sebelas ringkasan membaik dan tidak ada yang memburuk; interval peningkatannya sepenuhnya di atas nol, sehingga aturan superioritas lolos dan perintah keluar dengan 0. Format dijaga oleh aturan eksekusi, yang tidak mengizinkan kegagalan, bukan oleh perbandingan: atas 20 kasus, perbandingan dua skor format yang sempurna hanya dapat mengatakan bahwa selisihnya berada dalam 23.6 poin.
Opsional: model sungguhan sebagai juri
Langkah ini meninggalkan jalur offline. Langkah ini memerlukan server model, dan dengan penyedia cloud memerlukan kunci dan uang.
- Lokal, tanpa kunci dan tanpa biaya: Ollama, LM Studio, atau llama.cpp di localhost. Unduh model chat (untuk Ollama, ollama pull llama3.1).
- Cloud: provider: anthropic atau openai dengan api_key_env yang menyebut variabel berisi kunci Anda, atau openai_compatible dengan base_url dan api_key_env. Setiap kasus adalah satu panggilan juri (dua jika balasan pertama bukan JSON yang valid), ditagih sesuai tarif penyedia Anda, dan Oloproof tidak pernah memanggil juri lagi untuk jawaban yang sudah dinilainya.
Tulis draf juri di file tersendiri, seperti yang akan muncul di bawah evaluators::
# live_judge.yaml
type: rubric_judge
criterion: covers_facts
provider: openai_compatible
model: llama3.1
base_url: http://localhost:11434/v1
rubric_file: rubrics/covers_facts.mdlalu coba terhadap jawaban yang sudah diberi label oleh peninjau Anda, tanpa memvalidasi atau mengadopsinya:
oloproof evaluators try live_judge.yamlServer lokal secara bawaan menjawab satu permintaan sekaligus; tambahkan concurrency: {system: 2, judge: 2} ke oloproof.yaml agar panggilan yang mengantre tidak habis waktu. Eksekusi langkah ini dengan model lokal kecil (qwen2.5vl) di laptop mencetak:
covers_facts: draft sha256:b88a... on 20 labelled cases · 20 judged now, 0 from cache, 11 errored
agreement 88.9% [19.1%, 99.9%] · 8 of 9 labelled cases agreed · 11 labelled but not judged · kappa 0.769Sebelas panggilan habis waktu, dan interval kesepakatan menghitung masing-masing ke dua arah, sehingga turun hingga 19.1%: juri yang tidak menjawab tidak terukur. Model yang lebih besar, batas waktu yang lebih panjang, atau lebih sedikit panggilan bersamaan adalah perbaikannya. Untuk mengadopsi model, masukkan ke oloproof.yaml menggantikan juri pengganti. Itu versi evaluator yang baru: konfigurasinya (model, endpoint, rubrik) adalah identitasnya, sehingga validasi juri pengganti tidak terbawa. Jalankan baseline lagi dengannya dan validasi terhadap label, seperti di atas.
Pemecahan masalah
| Gejala | Penyebab dan perbaikan |
|---|---|
| covers_facts semuanya hilang, no_observations | Server juri tidak berjalan atau tidak berada di base_url. Setiap panggilan juri mengalami error; oloproof inspect RUN_ID --failures menunjukkan alasannya. |
| evaluator_not_validated setelah Anda memvalidasi | Anda mengubah juri (model, endpoint, port, rubrik) dan membuat versi baru. Validasi versi itu. |
| labels import menolak file dan menyebut sebuah baris | Baris itu menyebut kasus atau eksekusi yang tidak dimiliki eksekusi; ekspor lagi dari eksekusi yang Anda beri label. |
| labels export mengatakan ruang kerja tidak dapat dijangkau | Anda login ke salah satunya, sehingga ia diminta mengambil sampel. --local mengambil sampel di sini. |
| Juri cloud gagal sebelum panggilan apa pun | Kuncinya tidak ada di variabel yang disebut api_key_env. |
Keterbatasan
- Juri pengganti adalah pencocokan frasa. Juri itu mendemonstrasikan alur kerja, bukan kualitas penilaian.
- Tidak ada evaluator BLEU, ROUGE, atau kemiripan embedding. Di SDK, tulis sendiri dengan @evaluator; oloproof.yaml belum dapat menyebut evaluator kustom.
- Juri melihat teks: JSON dari input, acuan, dan keluaran. Juri tidak melihat gambar atau audio.
- Dua puluh label memberi interval kesepakatan yang lebar. Beri label lebih banyak, secara acak dan buta, untuk juri yang Anda andalkan.
- Sampel lokal hanya bersifat itikad baik. Untuk juri yang diandalkan orang lain, push eksekusinya dan biarkan ruang kerja yang di-hosting mengambil sampelnya (Juri).