Przewodniki
Samouczek: aplikacja za punktem końcowym HTTP
Oceń usługę, do której docierasz przez HTTP, bez importowania jej kodu: skieruj Oloproof na URL, uruchom zestaw, znajdź, czego usługa nie trafia, wdróż zmianę i porównaj. Malutka lokalna usługa zastępuje Twoją, więc wszystko działa offline.
Co zbudujesz
Usługę przyjmowania zamówień, która czyta wiadomość klienta i wyodrębnia dwa pola: intent (where_is_order, cancel, return lub other) oraz order_id (cztery cyfry albo null). Sprawdzisz format każdej odpowiedzi, co nie wymaga wzorca, i zmierzysz, czy każde pole jest poprawne, co go wymaga. Terminy takie jak przypadek, przebieg, metryka i bramka są zdefiniowane w Pojęciach.
Wymagania wstępne
- Python 3.11 lub nowszy oraz Oloproof w środowisku wirtualnym:
python3 -m venv .venv
. .venv/bin/activate
pip install oloproof- Przykładowy projekt, dostarczany z pakietem. Skopiuj go do nowego katalogu i pracuj tam (httpx, które importuje client.py, instaluje się razem z Oloproof):
oloproof init --example http order-intake
cd order-intake- Wolny port 8765 na tej maszynie. Jeśli jest zajęty, wybierz inny i zmień go zarówno w poleceniu serwera, jak i w oloproof.yaml.
Nic tutaj nie korzysta z dostawcy, klucza API ani internetu: usługa nasłuchuje na 127.0.0.1.
Pliki
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 casesUruchamiaj polecenia z order-intake/. Uruchom usługę w drugim terminalu i zostaw ją włączoną:
python server.py --port 8765intake service (v1) on http://127.0.0.1:8765/extractKontrakt HTTP
Dla każdego przypadku Oloproof wysyła jedno żądanie: input przypadku jako treść JSON, z metodą, którą zadeklarujesz (domyślnie POST). Odpowiedź czyta jako JSON. Status 400 lub wyższy, przekroczenie limitu czasu lub odrzucone połączenie jest zapisywane jako błąd wykonania dla tego przypadku, nigdy jako błędna odpowiedź.
Żądanie i odpowiedź dla jednego przypadku:
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 mówi Oloproof, by jako wynik przypadku zachował tylko result; bez tego wynikiem jest cała treść. Ścieżka z kropkami, taka jak data.answer, sięga głębiej.
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_idSystem HTTP musi zadeklarować version. Oloproof nie widzi wdrożenia: cache'uje wynik każdego przypadku według URL, metody, ścieżki wyniku i tej wersji, więc wersja to sposób, w jaki mówisz mu, że usługa się zmieniła. Zapomnij ją zmienić, a nowe wdrożenie nigdy nie zostanie wywołane.
Nagłówków i uwierzytelniania nie da się jeszcze skonfigurować w system.http. Sekcja o tokenach poniżej pokazuje obejście.
Zbiór danych
{"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 to dokładnie treść żądania. expected zawiera wzorzec dla każdego pola; null to prawdziwa wartość wzorcowa, oznaczająca "w tej wiadomości nie ma numeru zamówienia".
Wybór ewaluatorów
| Kryterium | Ewaluator | Wymaga expected | Mierzy |
|---|---|---|---|
| format_valid | json_schema na wyniku | nie | format: znana intencja i poprawnie zbudowany identyfikator |
| intent_correct | exact_match na intent | tak | sukces zadania dla pierwszego pola |
| order_id_correct | exact_match na order_id | tak | sukces zadania dla drugiego pola |
Schemat przepuściłby {"intent": "other", "order_id": null} dla każdej wiadomości: poprawnie zbudowane i bezużyteczne. Tylko sprawdzenia względem wzorca mówią, czy usługa wykonała swoje zadanie. Ocenianie pól osobno pokazuje, które z nich zawodzi, co jedno łączne sprawdzenie by ukryło.
release.yaml nie dopuszcza żadnego błędu formatu i wymaga, by każde pole było poprawne w co najmniej 70% przypadków, ocenianych na przedziale 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.70Uruchom
oloproof runRun 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 missKażda odpowiedź jest poprawnie zbudowana. Każde pole jest poprawne 15 razy na 20, ale 20 przypadków zostawia przedział sięgający w dół do 50,8%, więc żaden z progów 70% nie jest wykazany: INSUFFICIENT_EVIDENCE, a bramka blokuje z kodem 3.
Przejrzyj niepowodzenia
oloproof inspect RUN_ID --failures8 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: failedPrzeczytaj obok nich wejścia (oloproof inspect RUN_ID --case m04), a pojawią się dwa błędy: wzorzec identyfikatora dopasowuje tylko "order 1234", a nie "order #5120", "order no. 8123" ani samo "#1673"; a sformułowania takie jak "send back", "stop order" i "where's my parcel" nie odpowiadają żadnej intencji. To jest następne działanie: poszerz obie reguły.
Wdróż zmianę
Zatrzymaj usługę i uruchom kandydata, który zawiera te poprawki:
python server.py --port 8765 --rules v2Zmień version: rules-v1 na version: rules-v2 w oloproof.yaml, ponieważ URL się nie zmienił, a Oloproof w przeciwnym razie użyłby ponownie starych wyników. Następnie:
oloproof runGate: 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 │Oba progi przechodzą, a polecenie kończy się kodem 0.
Porównaj dwa wdrożenia
compare.yaml pyta, czy intencje kandydata są lepsze niż intencje punktu odniesienia:
version: 1
confidence_level: 0.95
block_on: [FAIL, INSUFFICIENT_EVIDENCE, MANUAL_REVIEW]
rules:
- id: intent-better
kind: superiority
metric: intent_correctoloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy compare.yamlformat_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)Kandydat spełnia własne progi, a jednak porównanie nie może wykazać, że jest lepszy: zmieniło się pięć przypadków, a na 20 sparowanych przypadkach przedział zysku nadal obejmuje zero. Oba stwierdzenia są prawdziwe jednocześnie. "Spełnia wymaganie" i "pokonuje punkt odniesienia" to osobne pytania, a tak mały zestaw odpowiada na drugie tylko przy dużych efektach. Lekarstwem jest więcej prawdziwych wiadomości.
Usługa, która wymaga tokena
Uruchom usługę tak, aby żądała tokena bearer:
INTAKE_TOKEN=s3cret python server.py --port 8765 --rules v2 --require-tokensystem.http nie wysyła własnych nagłówków, więc przy nowej version (na przykład rules-v2-auth) każde wywołanie jest odrzucane:
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 │a oloproof inspect RUN_ID --failures pokazuje execution ERROR: TransientError: system returned HTTP 401 przy każdym przypadku. Błędy wykonania to brakujące dowody, a nie niepowodzenia: niczego nie zaobserwowano, więc każda reguła ma stan INSUFFICIENT_EVIDENCE.
Obejściem jest funkcja wywoływalna w Pythonie, która sama wykonuje żądanie. client.py dodaje nagłówek ze zmiennej środowiskowej, więc token nigdy nie trafia do oloproof.yaml ani do żadnego zapisanego rekordu:
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"]Zastąp blok http: w oloproof.yaml tym:
system:
name: order-intake
version: rules-v2
callable: client:extracti uruchom z tokenem w środowisku:
INTAKE_TOKEN=s3cret oloproof runWszystkie 20 przypadków jest znowu obserwowanych, a bramka przepuszcza. Cache funkcji podąża za jej własnym kodem źródłowym i version, a nie za usługą za nią, więc obowiązuje ta sama zasada: zmień version, gdy wdrażasz.
Rozwiązywanie problemów
| Objaw | Przyczyna i rozwiązanie |
|---|---|
| system connection failed (ConnectError) przy każdym przypadku | Usługa nie działa albo nasłuchuje na innym porcie. |
| system connection failed (RemoteProtocolError) | Na tym porcie odpowiada coś innego. Wybierz wolny. |
| KeyError: "missing output path 'results'" | output_path wskazuje pole, którego odpowiedź nie ma. |
| system returned HTTP 401 lub 403 | Punkt końcowy wymaga poświadczeń: użyj obejścia z funkcją wywoływalną. |
| Wdrożyłeś zmianę, a wiersz cache pokazuje same trafienia | version się nie zmieniła, więc użyto ponownie zapisanych wyników. |
| an HTTP system needs a declared version | Dodaj version pod system lub system.http. |
Ograniczenia
- Brak własnych nagłówków, uwierzytelniania, parametrów zapytania i szablonów żądań w system.http: input przypadku jest treścią JSON w obecnej postaci. Do wszystkiego innego użyj funkcji wywoływalnej.
- Odpowiedzi muszą być w JSON. Odpowiedzi strumieniowe nie są czytane jako strumień.
- Oloproof nie potrafi wykryć wdrożenia; zadeklarowana version to cała tożsamość tego, co odpowiedziało.
- Twoja usługa jest właścicielem swojego stanu: Oloproof wysyła żądania i zapisuje odpowiedzi; nie resetuje, nie izoluje ani nie wycofuje niczego, co zmienia żądanie.