Langsung ke konten

Panduan

Tutorial: aplikasi di balik endpoint HTTP

Evaluasi layanan yang Anda jangkau lewat HTTP, tanpa mengimpor kodenya: arahkan Oloproof ke URL-nya, jalankan suite, temukan apa yang terlewat, deploy perubahan, lalu bandingkan. Layanan lokal kecil menggantikan layanan Anda, sehingga semuanya berjalan offline.

Apa yang akan Anda bangun

Layanan penerimaan pesanan yang membaca pesan pelanggan dan mengekstrak dua field: intent (where_is_order, cancel, return, atau other) dan order_id (empat digit, atau null). Anda akan memeriksa format setiap respons, yang tidak memerlukan acuan, dan mengukur apakah setiap field benar, yang memerlukannya. Istilah seperti kasus, eksekusi, metrik, dan gerbang didefinisikan dalam Konsep.

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 (httpx, yang diimpor client.py, dipasang bersama Oloproof):
oloproof init --example http order-intake
cd order-intake
  • Port 8765 kosong di mesin ini. Jika sudah dipakai, pilih yang lain dan ubah baik di perintah server maupun di oloproof.yaml.

Tidak ada yang di sini menggunakan penyedia, kunci API, atau internet: layanan mendengarkan di 127.0.0.1.

File-filenya

order-intake/
  server.py             the stand-in service (Python standard library only)
  client.py             a callable that calls the service with a token (used near the end)
  oloproof.yaml         the suite: dataset, HTTP system, evaluators
  release.yaml          rules for a run
  compare.yaml          a rule for a comparison
  data/messages.jsonl   20 cases

Jalankan perintah dari order-intake/. Jalankan layanan di terminal kedua dan biarkan tetap berjalan:

python server.py --port 8765
intake service (v1) on http://127.0.0.1:8765/extract

Kontrak HTTP

Untuk setiap kasus Oloproof mengirim satu permintaan: input kasus sebagai body JSON, dengan metode yang Anda deklarasikan (POST secara bawaan). Oloproof membaca respons sebagai JSON. Status 400 atau lebih, batas waktu habis, atau koneksi yang ditolak direkam sebagai error eksekusi untuk kasus itu, tidak pernah sebagai jawaban yang salah.

Permintaan dan respons untuk satu kasus:

POST /extract
{"message": "Where is order 1042? It has not arrived."}

200 OK
{"result": {"intent": "where_is_order", "order_id": "1042"}, "service": {"rules": "v1"}}

output_path: result memberi tahu Oloproof untuk hanya menyimpan result sebagai keluaran kasus; tanpanya seluruh body adalah keluarannya. Path bertitik seperti data.answer menjangkau lebih dalam.

version: 1
project: order-intake
dataset: data/messages.jsonl
system:
  name: order-intake
  http:
    url: http://127.0.0.1:8765/extract
    method: POST
    version: rules-v1
    output_path: result
    timeout_s: 30
evaluators:
  - type: json_schema
    criterion: format_valid
    field: null
    schema:
      type: object
      required: [intent, order_id]
      properties:
        intent: {enum: [where_is_order, cancel, return, other]}
        order_id: {type: [string, "null"], pattern: '^\d{4}$'}
      additionalProperties: false
  - type: exact_match
    criterion: intent_correct
    field: intent
  - type: exact_match
    criterion: order_id_correct
    field: order_id

Sistem HTTP harus mendeklarasikan version. Oloproof tidak dapat melihat sebuah deployment: Oloproof meng-cache keluaran setiap kasus berdasarkan URL, metode, path keluaran, dan versi itu, sehingga versi adalah cara Anda memberitahunya bahwa layanan berubah. Lupa mengubahnya, dan deployment baru tidak pernah dipanggil.

Header dan autentikasi belum dapat dikonfigurasi pada system.http. Bagian tentang token di bawah menunjukkan cara mengatasinya.

Dataset

{"id":"m04","input":{"message":"Has order #5120 shipped yet?"},"expected":{"intent":"where_is_order","order_id":"5120"}}
{"id":"m07","input":{"message":"Do you ship to Canada?"},"expected":{"intent":"other","order_id":null}}
{"id":"m16","input":{"message":"Please refund and take back the lamp from order #1560."},"expected":{"intent":"return","order_id":"1560"}}

input persis body permintaan. expected memuat acuan untuk setiap field; null adalah nilai acuan yang nyata, yang berarti "tidak ada id pesanan dalam pesan ini".

Memilih evaluator

KriteriaEvaluatorMemerlukan expectedMengukur
format_validjson_schema atas keluarantidakformat: intent yang dikenal dan id yang bentuknya benar
intent_correctexact_match pada intentyakeberhasilan tugas untuk field pertama
order_id_correctexact_match pada order_idyakeberhasilan tugas untuk field kedua

Skema akan meloloskan {"intent": "other", "order_id": null} untuk setiap pesan: bentuknya benar dan tidak berguna. Hanya pemeriksaan acuan yang mengatakan apakah layanan menjalankan tugasnya. Menilai field secara terpisah menunjukkan field mana yang gagal, yang akan disembunyikan oleh satu pemeriksaan gabungan.

release.yaml tidak mengizinkan kegagalan format dan meminta setiap field benar setidaknya 70% dari waktu, dinilai pada interval 95%:

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
rules:
  - id: valid-format
    metric: format_valid
    kind: observed_count
    max_failures: 0
  - id: intent-floor
    metric: intent_correct
    min: 0.70
  - id: order-id-floor
    metric: order_id_correct
    min: 0.70

Jalankan

oloproof run
Run run_01M4... [DECIDED/COMPLETE]
Gate: BLOCK (exit 3)
│ valid-format   │ format_valid     │ PASS                  │ observed_failures_within_limit │
│ intent-floor   │ intent_correct   │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ order-id-floor │ order_id_correct │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold    │
│ format_valid     │ 100.0%   │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │
│ intent_correct   │ 75.0%    │ [50.8%, 91.4%]  │ 15 / 20 observed · 0 missing · 0 excluded │
│ order_id_correct │ 75.0%    │ [50.8%, 91.4%]  │ 15 / 20 observed · 0 missing · 0 excluded │
Cache: execution 0 hit/20 miss; judgment 0 hit/60 miss

Setiap respons berbentuk benar. Setiap field benar 15 kali dari 20, tetapi 20 kasus menyisakan interval yang turun hingga 50.8%, sehingga tidak satu pun batas bawah 70% terbukti: INSUFFICIENT_EVIDENCE, dan gerbang memblokir dengan keluar 3.

Periksa kegagalannya

oloproof inspect RUN_ID --failures
8 of 20 cases failed, errored or did not finish

m04
  output: {"intent": "where_is_order", "order_id": null}
  order_id_correct: failed

m06
  output: {"intent": "other", "order_id": "7011"}
  intent_correct: failed
...
m18
  output: {"intent": "other", "order_id": null}
  intent_correct: failed
  order_id_correct: failed

Baca input di sampingnya (oloproof inspect RUN_ID --case m04) dan dua kesalahan muncul: pola id hanya cocok dengan "order 1234", bukan "order #5120", "order no. 8123", atau "#1673" saja; dan frasa seperti "send back", "stop order", dan "where's my parcel" tidak dipetakan ke intent mana pun. Itulah tindakan berikutnya: perluas kedua aturan.

Deploy perubahan

Hentikan layanan dan jalankan kandidat, yang membawa perbaikan tersebut:

python server.py --port 8765 --rules v2

Ubah version: rules-v1 menjadi version: rules-v2 di oloproof.yaml, karena URL tidak berubah dan Oloproof jika tidak akan memakai ulang keluaran lama. Lalu:

oloproof run
Gate: ALLOW (exit 0)
│ intent_correct   │ 100.0%   │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │
│ order_id_correct │ 100.0%   │ [83.1%, 100.0%] │ 20 / 20 observed · 0 missing · 0 excluded │

Kedua batas bawah lolos dan perintah keluar dengan 0.

Bandingkan kedua deployment

compare.yaml menanyakan apakah intent kandidat lebih baik daripada intent baseline:

version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
rules:
  - id: intent-better
    kind: superiority
    metric: intent_correct
oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yaml
format_valid: +0.0 points [-23.6, +23.6] · 20 paired · 0 missing · 0 excluded
intent_correct: +25.0 points [-8.5, +58.3] · 20 paired · 0 missing · 0 excluded
order_id_correct: +25.0 points [-8.5, +58.3] · 20 paired · 0 missing · 0 excluded
Decisions
  intent-better  intent_correct  superiority  INSUFFICIENT_EVIDENCE  interval_overlaps_zero
Gate: BLOCK (exit 3)

Kandidat lolos batas bawahnya sendiri, tetapi perbandingan tidak dapat menunjukkan bahwa kandidat lebih baik: lima kasus berubah, dan atas 20 kasus berpasangan interval peningkatannya masih memuat nol. Kedua pernyataan itu benar sekaligus. "Memenuhi persyaratan" dan "mengalahkan baseline" adalah pertanyaan yang terpisah, dan suite sekecil ini hanya menjawab yang kedua untuk efek yang besar. Lebih banyak pesan nyata adalah obatnya.

Layanan yang memerlukan token

Jalankan layanan sehingga menuntut bearer token:

INTAKE_TOKEN=s3cret python server.py --port 8765 --rules v2 --require-token

system.http tidak mengirim header kustom, sehingga dengan version baru (misalnya rules-v2-auth) setiap panggilan ditolak:

Gate: BLOCK (exit 3)
│ valid-format   │ format_valid     │ INSUFFICIENT_EVIDENCE │ no_observations │
│ intent_correct   │          │ [0.0%, 100.0%] │ 0 / 0 observed · 20 missing · 0 excluded │

dan oloproof inspect RUN_ID --failures menampilkan execution ERROR: TransientError: system returned HTTP 401 pada setiap kasus. Error eksekusi adalah bukti yang hilang, bukan kegagalan: tidak ada yang teramati, sehingga setiap aturan berstatus INSUFFICIENT_EVIDENCE.

Cara mengatasinya adalah callable Python yang membuat permintaan sendiri. client.py menambahkan header dari variabel lingkungan, sehingga token tidak pernah masuk ke oloproof.yaml atau rekaman tersimpan mana pun:

URL = os.environ.get("INTAKE_URL", "http://127.0.0.1:8765/extract")


def extract(case: dict[str, Any]) -> dict[str, Any]:
    headers = {"Authorization": f"Bearer {os.environ['INTAKE_TOKEN']}"}
    response = httpx.post(URL, json=case, headers=headers, timeout=30)
    response.raise_for_status()
    return response.json()["result"]

Ganti blok http: di oloproof.yaml dengan:

system:
  name: order-intake
  version: rules-v2
  callable: client:extract

dan jalankan dengan token di lingkungan:

INTAKE_TOKEN=s3cret oloproof run

Ke-20 kasus kembali teramati dan gerbang mengizinkan. Cache callable mengikuti source dan version miliknya sendiri, bukan layanan di baliknya, sehingga aturan yang sama berlaku: ubah version saat Anda melakukan deploy.

Pemecahan masalah

GejalaPenyebab dan perbaikan
system connection failed (ConnectError) pada setiap kasusLayanan tidak berjalan, atau mendengarkan di port lain.
system connection failed (RemoteProtocolError)Sesuatu yang lain menjawab di port itu. Pilih port yang kosong.
KeyError: "missing output path 'results'"output_path menyebut field yang tidak ada dalam respons.
system returned HTTP 401 atau 403Endpoint memerlukan kredensial: gunakan cara callable.
Anda men-deploy perubahan dan baris cache berisi semua hitversion tidak berubah, sehingga keluaran tersimpan dipakai ulang.
an HTTP system needs a declared versionTambahkan version di bawah system atau system.http.

Keterbatasan

  • Tidak ada header kustom, autentikasi, parameter query, atau templat permintaan pada system.http: input kasus adalah body JSON apa adanya. Gunakan callable untuk hal lain.
  • Respons harus JSON. Respons streaming tidak dibaca sebagai stream.
  • Oloproof tidak dapat mendeteksi deployment; version yang dideklarasikan adalah seluruh identitas dari apa yang menjawab.
  • Layanan Anda memiliki state-nya sendiri: Oloproof mengirim permintaan dan merekam jawaban; Oloproof tidak mengatur ulang, mengisolasi, atau membatalkan apa pun yang diubah sebuah permintaan.