Hướng dẫn
Hướng dẫn: một ứng dụng đằng sau một endpoint HTTP
Đánh giá một dịch vụ bạn gọi qua HTTP, mà không import mã của nó: trỏ Oloproof vào URL, chạy bộ kiểm thử, tìm những gì nó bỏ sót, triển khai một thay đổi, và so sánh. Một dịch vụ cục bộ nhỏ đứng thay cho dịch vụ của bạn, nên mọi thứ chạy ngoại tuyến.
Bạn sẽ xây dựng gì
Một dịch vụ tiếp nhận đơn hàng đọc tin nhắn của khách và trích xuất hai trường: một intent (where_is_order, cancel, return hoặc other) và một order_id (bốn chữ số, hoặc null). Bạn sẽ kiểm tra định dạng của mọi phản hồi, việc không cần tham chiếu, và đo xem từng trường có đúng không, việc cần tham chiếu. Các thuật ngữ như trường hợp, lần chạy, chỉ số và cổng được định nghĩa trong Khái niệm.
Điều kiện tiên quyết
- Python 3.11 trở lên, và Oloproof trong một môi trường ảo:
python3 -m venv .venv
. .venv/bin/activate
pip install oloproof- Dự án ví dụ, đi kèm với gói. Sao chép nó vào một thư mục mới và làm việc ở đó (httpx, mà client.py import, được cài cùng Oloproof):
oloproof init --example http order-intake
cd order-intake- Cổng 8765 còn trống trên máy này. Nếu nó đã bị chiếm, hãy chọn cổng khác và đổi nó ở cả lệnh khởi động máy chủ lẫn oloproof.yaml.
Không có gì ở đây dùng nhà cung cấp, khóa API hay internet: dịch vụ lắng nghe trên 127.0.0.1.
Các tệp
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 casesChạy các lệnh từ order-intake/. Khởi động dịch vụ trong một terminal thứ hai và để nó chạy:
python server.py --port 8765intake service (v1) on http://127.0.0.1:8765/extractHợp đồng HTTP
Với mỗi trường hợp, Oloproof gửi một yêu cầu: input của trường hợp làm thân JSON, với phương thức bạn khai báo (mặc định là POST). Nó đọc phản hồi dưới dạng JSON. Một mã trạng thái từ 400 trở lên, một lần hết thời gian hoặc một kết nối bị từ chối được ghi lại là lỗi thực thi cho trường hợp đó, không bao giờ là một câu trả lời sai.
Yêu cầu và phản hồi cho một trường hợp:
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 bảo Oloproof chỉ giữ result làm đầu ra của trường hợp; không có nó thì toàn bộ thân phản hồi là đầu ra. Một đường dẫn có dấu chấm như data.answer đi sâu hơn.
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_idMột hệ thống HTTP phải khai báo một version. Oloproof không thể nhìn thấy một lần triển khai: nó lưu đệm đầu ra của từng trường hợp theo URL, phương thức, đường dẫn đầu ra và phiên bản đó, nên phiên bản là cách bạn báo cho nó rằng dịch vụ đã thay đổi. Quên đổi nó thì một lần triển khai mới sẽ không bao giờ được gọi.
Header và xác thực chưa thể cấu hình trên system.http. Phần về token bên dưới cho thấy cách giải quyết tạm thời.
Tập dữ liệu
{"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 chính xác là thân yêu cầu. expected chứa tham chiếu cho từng trường; null là một giá trị tham chiếu thật, nghĩa là "không có mã đơn hàng nào trong tin nhắn này".
Chọn các bộ đánh giá
| Tiêu chí | Bộ đánh giá | Cần expected | Đo |
|---|---|---|---|
| format_valid | json_schema trên đầu ra | không | định dạng: một intent đã biết và một mã đúng hình thức |
| intent_correct | exact_match trên intent | có | thành công của tác vụ cho trường thứ nhất |
| order_id_correct | exact_match trên order_id | có | thành công của tác vụ cho trường thứ hai |
Schema sẽ cho qua {"intent": "other", "order_id": null} với mọi tin nhắn: đúng hình thức và vô dụng. Chỉ các kiểm tra theo tham chiếu mới nói được dịch vụ có làm đúng việc của nó không. Chấm điểm riêng từng trường cho thấy trường nào thất bại, điều mà một kiểm tra gộp sẽ che giấu.
release.yaml không cho phép thất bại định dạng nào và yêu cầu mỗi trường đúng ít nhất 70% số lần, được đánh giá trên khoảng 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.70Chạy
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 missMọi phản hồi đều đúng hình thức. Mỗi trường đúng 15 lần trên 20, nhưng 20 trường hợp để lại một khoảng xuống tới 50,8%, nên không mức sàn 70% nào được chứng minh: INSUFFICIENT_EVIDENCE, và cổng chặn với mã thoát 3.
Xem xét các thất bại
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: failedĐọc các đầu vào bên cạnh chúng (oloproof inspect RUN_ID --case m04) và hai lỗi hiện ra: mẫu mã đơn hàng chỉ khớp "order 1234", không khớp "order #5120", "order no. 8123" hay một "#1673" đứng riêng; và các cách diễn đạt như "send back", "stop order" và "where's my parcel" không ánh xạ tới intent nào. Đó là hành động tiếp theo: mở rộng cả hai quy tắc.
Triển khai một thay đổi
Dừng dịch vụ và khởi động ứng viên, mang các bản sửa đó:
python server.py --port 8765 --rules v2Đổi version: rules-v1 thành version: rules-v2 trong oloproof.yaml, vì URL không thay đổi và nếu không Oloproof sẽ tái sử dụng các đầu ra cũ. Rồi:
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 │Cả hai mức sàn đều đạt và lệnh thoát với 0.
So sánh hai lần triển khai
compare.yaml hỏi xem các intent của ứng viên có tốt hơn của đường cơ sở không:
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)Ứng viên đạt các mức sàn của chính nó, nhưng phép so sánh không thể cho thấy nó tốt hơn: năm trường hợp thay đổi, và trên 20 trường hợp ghép cặp, khoảng cho mức tăng vẫn chứa 0. Cả hai khẳng định đều đúng cùng lúc. "Đáp ứng yêu cầu" và "vượt đường cơ sở" là hai câu hỏi riêng, và một bộ kiểm thử nhỏ như vậy chỉ trả lời câu thứ hai với các hiệu ứng lớn. Thêm tin nhắn thật là cách khắc phục.
Một dịch vụ cần token
Khởi động dịch vụ sao cho nó đòi một bearer token:
INTAKE_TOKEN=s3cret python server.py --port 8765 --rules v2 --require-tokensystem.http không gửi header tùy chỉnh nào, nên với một version mới (chẳng hạn rules-v2-auth) mọi lần gọi đều bị từ chối:
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 │và oloproof inspect RUN_ID --failures cho thấy execution ERROR: TransientError: system returned HTTP 401 ở mỗi trường hợp. Lỗi thực thi là bằng chứng bị thiếu, không phải thất bại: không có gì được quan sát, nên mọi quy tắc là INSUFFICIENT_EVIDENCE.
Cách giải quyết tạm thời là một callable Python tự gửi yêu cầu. client.py thêm header từ một biến môi trường, nên token không bao giờ đi vào oloproof.yaml hay bất kỳ bản ghi được lưu nào:
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"]Thay khối http: trong oloproof.yaml bằng:
system:
name: order-intake
version: rules-v2
callable: client:extractvà chạy với token trong môi trường:
INTAKE_TOKEN=s3cret oloproof runCả 20 trường hợp lại được quan sát và cổng cho phép. Bộ nhớ đệm của callable theo mã nguồn và version của chính nó, không theo dịch vụ đằng sau, nên cùng quy tắc vẫn áp dụng: đổi version khi bạn triển khai.
Khắc phục sự cố
| Triệu chứng | Nguyên nhân và cách sửa |
|---|---|
| system connection failed (ConnectError) ở mọi trường hợp | Dịch vụ không chạy, hoặc lắng nghe trên một cổng khác. |
| system connection failed (RemoteProtocolError) | Có thứ khác trả lời trên cổng đó. Hãy chọn một cổng trống. |
| KeyError: "missing output path 'results'" | output_path nêu một trường mà phản hồi không có. |
| system returned HTTP 401 hoặc 403 | Endpoint cần thông tin xác thực: hãy dùng cách giải quyết bằng callable. |
| Bạn đã triển khai một thay đổi và dòng bộ nhớ đệm ghi toàn bộ là hit | version không đổi, nên các đầu ra đã lưu được tái sử dụng. |
| an HTTP system needs a declared version | Thêm version dưới system hoặc system.http. |
Giới hạn
- Không có header tùy chỉnh, xác thực, tham số truy vấn hay mẫu yêu cầu trên system.http: input của trường hợp là thân JSON nguyên trạng. Hãy dùng một callable cho mọi thứ khác.
- Phản hồi phải là JSON. Phản hồi streaming không được đọc như một luồng.
- Oloproof không thể phát hiện một lần triển khai; version được khai báo là toàn bộ danh tính của thứ đã trả lời.
- Dịch vụ của bạn sở hữu trạng thái của nó: Oloproof gửi yêu cầu và ghi lại câu trả lời; nó không đặt lại, cô lập hay hoàn tác bất cứ điều gì mà một yêu cầu thay đổi.