Langsung ke konten

Panduan

Tutorial: classifier atau keluaran terstruktur

Evaluasi fungsi Python yang memberi label pada pertanyaan dukungan, baca mengapa rilis diblokir, perbaiki kesalahannya, dan bandingkan perbaikan itu dengan versi aslinya, semuanya di mesin Anda sendiri tanpa akun, tanpa jaringan, dan tanpa model.

Apa yang akan Anda bangun

Bot dukungan yang mengembalikan objek JSON dengan answer dan label (refund, account, atau other). Anda akan mengukurnya terhadap tiga persyaratan: label cukup sering benar, keluaran selalu memiliki bentuk yang benar, dan tidak ada jawaban yang membocorkan sesuatu yang tampak seperti nomor jaminan sosial AS. Dua di antaranya adalah pemeriksaan format yang tidak memerlukan jawaban acuan; satu mengukur keberhasilan tugas terhadap label acuan. Perbedaannya penting, dan halaman ini memisahkan keduanya.

Istilah yang digunakan di bawah (kasus, eksekusi, metrik, interval, aturan, gerbang) didefinisikan dalam Konsep.

Prasyarat

  • Python 3.11 atau yang lebih baru.
  • Oloproof, dipasang ke dalam lingkungan virtual:
python3 -m venv .venv
. .venv/bin/activate
pip install oloproof
  • Proyek contoh dan perubahan kandidat, yang disertakan dalam paket. Salin keduanya ke direktori baru dan bekerjalah di direktori pertama; setiap file juga dicantumkan di bawah, sehingga Anda dapat mengetiknya sendiri:
oloproof init --example support_bot support-classifier
oloproof init --example classification support-change
cd support-classifier

Tidak ada kunci API, akun penyedia, atau akses jaringan yang digunakan di halaman ini.

File-filenya

support-classifier/
  app.py              the application under test (a Python callable)
  oloproof.yaml       the suite: dataset, system, evaluators
  release.yaml        the release policy: rules the run is decided against
  data/support.jsonl  18 cases, one JSON object per line
  rubrics/helpful.md  a judge rubric, unused here

Jalankan setiap perintah dari direktori support-classifier/. Oloproof menyimpan store-nya di .oloproof/ di sana; hapus direktori itu untuk memulai lagi dari nol.

Aplikasi dan adapternya

Aplikasi Anda dijangkau melalui sebuah adapter. Untuk aplikasi Python, adapternya adalah fungsi itu sendiri: Oloproof mengimpornya, memanggilnya sekali per kasus dengan input kasus, dan merekam dictionary yang dikembalikannya sebagai keluaran kasus itu.

# app.py
from typing import Any

from oloproof import system


@system(name="support-bot", version="slice-a-example")
def answer(case: dict[str, Any]) -> dict[str, str]:
    question = str(case["question"]).lower()
    if "refund" in question:
        return {"answer": "Refunds are available within 30 days when the order is eligible.",
                "label": "refund"}
    if "password" in question or "login" in question:
        return {"answer": "Use password reset, then contact support if the login still fails.",
                "label": "account"}
    return {"answer": "A support specialist will follow up with the next step.", "label": "other"}

Untuk mengevaluasi classifier Anda sendiri, biarkan kodenya di tempatnya dan tulis fungsi tipis seperti ini yang memanggilnya dan mengembalikan dictionary. Fungsi itu boleh async. Oloproof memanggilnya; Oloproof tidak meng-hosting, mengisolasi, atau mengatur ulang aplikasi Anda, sehingga state apa pun yang disimpan aplikasi Anda di antara panggilan menjadi tanggung jawab Anda.

oloproof.yaml menyebut fungsi itu dan evaluatornya:

version: 1
project: support-bot-example
dataset: data/support.jsonl
system:
  name: support-bot
  version: slice-a-example
  callable: app:answer
  timeout_s: 30
evaluators:
  - type: exact_match
    criterion: exact_label
    field: label
  - type: json_schema
    criterion: format_valid
    field: null
    schema:
      type: object
      required: [answer, label]
      properties:
        answer: {type: string}
        label: {type: string}
      additionalProperties: false
  - type: regex
    criterion: pii_free
    field: answer
    pattern: '\b\d{3}-\d{2}-\d{4}\b'
    pass_if: no_match

Keluaran di-cache berdasarkan source fungsi, version yang dideklarasikan, dan config. Jika fungsi membaca file lain (sebuah prompt, sebuah tabel aturan), cantumkan di bawah system.code_paths, sehingga mengeditnya menjalankan sistem lagi.

Dataset

Satu kasus per baris. input persis apa yang diterima fungsi Anda sebagai case; expected adalah acuan yang dibandingkan oleh evaluator exact_match:

{"id":"refund_00","input":{"question":"Can I get a refund for yesterday's order?"},"expected":{"label":"refund"}}
{"id":"account_04","input":{"question":"I can't sign in on my new phone."},"expected":{"label":"account"}}
{"id":"other_04","input":{"question":"I don't want a refund, I just need a copy of my receipt."},"expected":{"label":"other"}}

Untuk setiap kasus, fungsi mengembalikan objek seperti {"answer": "Use password reset, ...", "label": "account"}.

Memilih evaluator

KriteriaEvaluatorMemerlukan expectedApa yang diukurnya
exact_labelexact_match pada labelyakeberhasilan tugas: labelnya adalah label yang benar
format_validjson_schema atas seluruh keluarantidakformat: objek memiliki tepat dua field string
pii_freeregex pada answer, pass_if: no_matchtidakproperti keamanan dari teks

Pemeriksaan format meloloskan jawaban salah yang bentuknya benar, sehingga tidak pernah dapat menggantikan keberhasilan tugas. Pemeriksaan tugas memerlukan acuan untuk setiap kasus; jika sebuah kasus tidak memilikinya, exact_match tidak dapat menilainya. Evaluator deterministik tidak memerlukan validasi terhadap manusia: menjalankannya dua kali memberi putusan yang sama.

Kebijakannya

release.yaml adalah dasar keputusan eksekusi:

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
warn_on: []
rules:
  - id: exact-label-floor
    metric: exact_label
    min: 0.70
  - id: valid-format
    metric: format_valid
    kind: observed_count
    max_failures: 0
  - id: pii-free
    metric: pii_free
    kind: observed_count
    max_failures: 0

exact-label-floor menyatakan bahwa label harus benar setidaknya 70% dari waktu, dan hanya lolos ketika seluruh interval 95% berada pada atau di atas 0.70. Kedua aturan observed_count tidak mengizinkan satu kegagalan pun pada kasus yang Anda jalankan; aturan itu menggambarkan kasus-kasus ini, bukan setiap pertanyaan yang akan diajukan pengguna.

Jalankan

oloproof run

Keluaran nyata, dipangkas:

Run run_01M4... [DECIDED/COMPLETE]
Gate: BLOCK (exit 3)
│ exact-label-floor │ exact_label  │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ valid-format      │ format_valid │ PASS                  │ observed_failures_within_limit │
│ pii-free          │ pii_free     │ PASS                  │ observed_failures_within_limit │
│ exact_label  │ 72.2%    │ [46.5%, 90.4%]  │ 13 / 18 observed · 0 missing · 0 excluded │
│ format_valid │ 100.0%   │ [81.4%, 100.0%] │ 18 / 18 observed · 0 missing · 0 excluded │
│ pii_free     │ 100.0%   │ [81.4%, 100.0%] │ 18 / 18 observed · 0 missing · 0 excluded │
Cache: execution 0 hit/18 miss; judgment 0 hit/54 miss

Cara membacanya:

  • 13 dari 18 label benar, 72.2%. Itu di atas 0.70, tetapi interval mencapai turun ke 46.5%: 18 kasus tidak dapat menunjukkan bahwa tingkat sebenarnya setidaknya 0.70. Jadi aturannya INSUFFICIENT_EVIDENCE, bukan PASS dan bukan FAIL.
  • Setiap keluaran memiliki bentuk yang benar dan tidak ada yang memuat angka mirip SSN, sehingga kedua aturan format lolos.
  • block_on mencantumkan INSUFFICIENT_EVIDENCE, sehingga gerbang memblokir dan perintah keluar dengan 3. Keluar 0 berarti tidak ada yang diblokir kebijakan; Gerbang CI mencantumkan setiap kode.

Jalankan lagi dan baris cache berbunyi execution 18 hit/0 miss: tidak ada yang berubah, sehingga fungsi tidak dipanggil.

Periksa kegagalannya

oloproof inspect RUN_ID --failures
oloproof inspect RUN_ID --case refund_04

RUN_ID adalah id pada baris pertama keluaran eksekusi.

5 of 18 cases failed, errored or did not finish

refund_04
  output: {"answer": "A support specialist will follow up with the next step.", "label": "other"}
  exact_label: failed
...
other_04
  output: {"answer": "Refunds are available within 30 days when the order is eligible.", "label": "refund"}
  exact_label: failed
case refund_04
input: {
  "question": "I was charged twice this month and want my money back."
}
expected: {
  "label": "refund"
}
execution: OK, 1 ms
output: {
  "answer": "A support specialist will follow up with the next step.",
  "label": "other"
}
judgments:
  exact_label: failed
  format_valid: passed
  pii_free: passed

Polanya jelas begitu Anda membaca inputnya: "money back", "reverse the payment", "sign in", dan "two-factor" tidak ada dalam daftar kata kunci, dan other_04 mengatakan "I don't want a refund", yang tetap cocok dengan kata "refund". Perhatikan bahwa refund_04 lolos kedua pemeriksaan format padahal salah: itulah celah antara memeriksa format dan mengukur keberhasilan.

Dua tindakan berikutnya bermakna di sini. Perbaiki kesalahannya (di bawah), atau tambahkan kasus: dengan lebih banyak kasus pada akurasi yang sama intervalnya menyempit, dan oloproof plan RUN_ID --run memperkirakan berapa banyak.

Lakukan perubahan nyata

Salin ../support-change/app.py menimpa app.py. File itu menambahkan frasa yang terlewat:

REFUND_WORDS = ("refund", "money back", "reverse the payment")
ACCOUNT_WORDS = ("password", "login", "sign in", "two-factor")


@system(name="support-bot", version="keywords-v2")
def answer(case: dict[str, Any]) -> dict[str, str]:
    question = str(case["question"]).lower()
    if any(word in question for word in REFUND_WORDS):
        ...

lalu tetapkan version: keywords-v2 di bawah system di oloproof.yaml, sehingga eksekusi direkam sebagai versi baru. Lalu:

oloproof run
Gate: ALLOW (exit 0)
│ exact-label-floor │ exact_label  │ PASS  │ lower_bound_meets_minimum      │
│ exact_label  │ 94.4%    │ [72.7%, 99.9%]  │ 17 / 18 observed · 0 missing · 0 excluded │

17 dari 18 benar dan batas bawah interval, 72.7%, melampaui 0.70, sehingga aturan lolos dan perintah keluar dengan 0. other_04 masih gagal: perbaikan itu tidak menyentuh negasi.

Bandingkan kandidat dengan baseline

Aturan eksekusi menanyakan apakah kandidat memenuhi batas bawah Anda. Perbandingan menanyakan bagaimana kandidat berbeda dari baseline, kasus demi kasus. Salin ../support-change/compare.yaml ke dalam proyek; file itu memuat satu aturan perbandingan:

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
rules:
  - id: label-no-regression
    kind: non_inferiority
    metric: exact_label
    margin: 0.10
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yaml
Comparison sha256:de76... of run_01M4...TJAD against run_01M4...ECVEF · 18 paired cases
exact_label: +22.2 points [-12.9, +57.0] · 18 paired · 0 missing · 0 excluded
format_valid: +0.0 points [-25.8, +25.8] · 18 paired · 0 missing · 0 excluded
pii_free: +0.0 points [-25.8, +25.8] · 18 paired · 0 missing · 0 excluded
Decisions
  label-no-regression  exact_label  non-inferiority, margin 10.0 points  INSUFFICIENT_EVIDENCE  interval_overlaps_margin
    about 3 more paired cases would decide it, if the difference holds (21 in total at 22% discordance)
Gate: BLOCK (exit 3)

Kandidat memperbaiki empat kasus dan tidak merusak satu pun, perkiraan peningkatan 22 poin. Tetapi hanya empat kasus yang berubah, dan 18 kasus berpasangan menyisakan interval dari 12.9 poin lebih buruk hingga 57 poin lebih baik, yang melintasi margin 10 poin. Perbandingan belum dapat menyingkirkan kemungkinan bahwa kandidat lebih buruk melebihi yang Anda terima, sehingga hasilnya INSUFFICIENT_EVIDENCE dan keluar dengan 3. Baris di bawahnya adalah perkiraan ukuran. Tanpa --policy, compare mencetak selisihnya, menyatakan bahwa release.yaml proyek tidak mendeklarasikan aturan perbandingan, dan keluar dengan 0 karena tidak ada yang diputuskan.

Membandingkan kandidat dengan baseline menjelaskan margin dan jenis aturan lainnya.

Pemecahan masalah

GejalaPenyebab dan perbaikan
ModuleNotFoundError untuk appJalankan dari direktori yang memuat app.py, atau beri callable path modul yang dapat diimpor dari sana.
Aturan menyebut metrik yang tidak dihasilkan evaluator mana punmetric aturan harus sama dengan criterion sebuah evaluator; error mencantumkan metrik yang ada.
Anda mengedit classifier dan eksekusi memakai ulang setiap keluaranCache mengikuti source callable; file pembantu yang dibacanya harus dicantumkan di bawah system.code_paths.
exact_label melaporkan kasus sebagai hilangEksekusi itu memunculkan exception atau habis waktu; oloproof inspect RUN_ID --failures menampilkan setiap error.
Eksekusi keluar dengan 3 meski estimasinya tinggiYang memutuskan adalah interval, bukan estimasi. Tambahkan kasus atau terima batas bawah yang lebih rendah, yang diputuskan sebelum eksekusi.

Keterbatasan

  • SDK dan YAML melaporkan tingkat kelulusan per evaluator. Tidak ada confusion matrix atau presisi dan recall per kelas untuk classifier seperti ini; blok predictive: menyediakannya untuk model yang memberi skor (Model prediktif).
  • Aturan observed_count menggambarkan kasus yang Anda jalankan; aturan itu tidak membuat klaim tentang input yang tidak terlihat.
  • Perbandingan atas 18 kasus hanya dapat memisahkan selisih yang besar. Lima puluh kasus nyata atau lebih adalah batas bawah yang lebih berguna.
  • oloproof.yaml tidak dapat menyebut @evaluator kustom; itu memerlukan SDK (SDK).