Hướng dẫn
Hướng dẫn: sinh văn bản với một giám khảo rubric
Đánh giá một hàm viết văn bản tự do, ở đây là một bộ tóm tắt ticket, bằng các kiểm tra định dạng và một giám khảo rubric; đo giám khảo đó so với nhãn của một người trước khi nó được phép quyết định bất cứ điều gì; rồi so sánh một thay đổi thật. Giám khảo chạy trên máy này mà không cần mô hình và không cần mạng, và một bước tùy chọn thay vào một mô hình thật.
Bạn sẽ xây dựng gì
Một bộ tóm tắt biến một ticket hỗ trợ thành một hoặc hai câu. "Tốt" là một phán xét, không phải một phép khớp chuỗi, nên thành công của tác vụ được quyết định bởi một giám khảo LLM với một rubric: bản tóm tắt có nêu các dữ kiện mà một nhân viên hỗ trợ cần không? Hai bộ đánh giá tất định kiểm tra định dạng, việc không cần tham chiếu. Các thuật ngữ như trường hợp, lần chạy, chỉ số, giám khảo và cổng được định nghĩa trong Khái niệm.
Cùng hình dạng đó phù hợp với trích xuất hoặc bất kỳ kiểu sinh văn bản nào khác: một hàm trả về văn bản trong một dictionary, tham chiếu nói một câu trả lời tốt phải chứa gì, và một rubric nói cách quyết định.
Đ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 ở đó:
oloproof init --example generation ticket-summaries
cd ticket-summaries- Cổng 8799 còn trống cho giám khảo thay thế (nếu không, hãy đổi nó ở cả hai nơi).
Mọi bước cho tới "Tùy chọn: một mô hình thật làm giám khảo" đều ngoại tuyến và tất định: không khóa API, không tài khoản nhà cung cấp, không chi phí.
Các tệp
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 sheetChạy mọi lệnh từ ticket-summaries/.
Giám khảo thay thế, và những gì nó không phải
Một giám khảo rubric là một bộ đánh giá gửi một prompt (rubric, đầu vào của trường hợp, expected của nó và đầu ra) tới một mô hình và đọc lại {"pass": true|false, "rationale": "..."}. Oloproof nói chuyện với bất kỳ máy chủ nào nói API chat của OpenAI, và một máy chủ trên localhost không cần khóa.
judge_server.py là một máy chủ như vậy, nhưng nó không phải một mô hình. Nó chỉ cho qua một bản tóm tắt khi bản đó chứa mọi cụm từ dưới must_mention trong expected của trường hợp, không phân biệt hoa thường. Đó là một quy tắc cố định, nên bài hướng dẫn cho cùng các con số trên mọi máy. Nó không thể nhận ra một dữ kiện bịa đặt, điều mà một giám khảo mô hình thật được yêu cầu làm. Khởi động nó trong một terminal thứ hai và để nó chạy:
python judge_server.py --port 8799stand-in judge on http://127.0.0.1:8799/v1Ứng dụng và adapter của nó
# 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 cho một ứng dụng Python là hàm đó: nó nhận input của trường hợp và trả về một dictionary. Với bộ sinh văn bản của chính bạn, hãy gọi mô hình hoặc chuỗi xử lý của bạn bên trong nó và trả về văn bản dưới một khóa. Oloproof gọi nó một lần cho mỗi trường hợp và lưu đệm đầu ra theo mã nguồn của hàm và version đã khai báo; nó không quản lý client mô hình, prompt hay trạng thái của bạn. Liệt kê các tệp mà hàm đọc, chẳng hạn một mẫu prompt, dưới system.code_paths.
Tập dữ liệu
{"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 là thứ hàm nhận. expected là tham chiếu mà giám khảo đọc: ở đây là một danh sách dữ kiện mà bản tóm tắt phải mang, không phải một bản tóm tắt tham chiếu đầy đủ, vì nhiều bản tóm tắt khác nhau đều đúng. Đầu ra cho t01 là {"summary": "Hello."}.
Chọn các bộ đánh giá
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| Tiêu chí | Bộ đánh giá | Cần expected | Đo |
|---|---|---|---|
| format_valid | json_schema | không | định dạng: một trường chuỗi không rỗng |
| short_enough | regex | không | định dạng: tối đa 160 ký tự |
| covers_facts | rubric_judge | có | thành công của tác vụ, như rubric định nghĩa |
Hello. đạt cả hai kiểm tra định dạng. Chỉ giám khảo nói rằng đó là một bản tóm tắt vô dụng. Một giám khảo cũng có thể chạy mà không cần tham chiếu: một rubric như "PASS if the summary contains no greeting" chỉ đọc đầu vào và đầu ra, và một trường hợp không có expected vẫn được chấm. Điều nó không thể làm khi đó là kiểm tra dữ kiện so với một câu trả lời mà bạn tin cậy.
Rubric:
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.Chính sách
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 là mặc định của engine, được viết ra ở đây vì đó là trọng tâm của bài hướng dẫn này: một giám khảo chưa ai so sánh với con người thì không được quyết định một quy tắc.
Chạy
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 missCác quy tắc định dạng đạt. Giám khảo cho qua 9 trên 20 bản tóm tắt, nhưng quy tắc là INSUFFICIENT_EVIDENCE với lý do evaluator_not_validated, và cổng chặn với mã thoát 3. Quy tắc không quyết định dựa trên con số 45%: tỷ lệ lỗi của một giám khảo là chưa biết cho tới khi được đo, nên một khoảng xây trên các phán quyết của nó sẽ mang một sai số không được nêu. Engine báo điều này là INSUFFICIENT_EVIDENCE, không phải MANUAL_REVIEW hay FAIL: bằng chứng để quyết định còn thiếu, và đầu ra in ra hai lệnh cung cấp bằng chứng đó.
Xem xét các thất bại
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
...Lời giải thích của giám khảo được hiển thị là "judge text, not verified": đó là lời giải thích của mô hình, không phải bằng chứng. Dù vậy quy luật vẫn rõ: câu đầu tiên thường là một lời chào.
Đo giám khảo so với một người
Việc xác thực so sánh các phán quyết của giám khảo với phán quyết của một người trên cùng các câu trả lời. Rút một mẫu ngẫu nhiên các trường hợp của lần chạy vào một bảng tính. Các phán quyết của giám khảo bị để ra ngoài, để người gán nhãn không bị neo theo chúng:
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 rút mẫu trên máy này mà không hỏi một không gian làm việc được lưu trữ; engine chọn seed. Với 20 trường hợp, một mẫu 20 là tất cả. Trên thực tế, một người đọc ticket và bản tóm tắt của từng dòng rồi điền passed. Trong bài hướng dẫn này, labels/reviewer_verdicts.csv chứa các phán quyết mà một người xem xét đã đưa ra trên các bản tóm tắt của đường cơ sở, và fill_labels.py sao chép chúng vào bảng tính:
python fill_labels.py sample.csv
oloproof labels import sample.csvfilled 20 rows of sample.csv
Recorded 20 labels from sample.csv (20 measurement).Người xem xét bất đồng với giám khảo một lần: ở t02 ("I was charged twice for order 2210.") họ cho rằng số tiền bị thiếu là không quan trọng và cho qua. Các nhãn nêu chính xác câu trả lời mà chúng đã phán xét, nên các phán quyết này chỉ áp dụng cho lần chạy đường cơ sở.
Tìm mã phiên bản của giám khảo và xác thực nó:
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 judgedHãy đọc các khoảng, không phải con số 95%: 20 nhãn cho thấy mức đồng thuận ít nhất là 75,1%. Một chính sách có thể đòi hỏi nhiều hơn bằng minimum_evaluator_agreement, so sánh với cận dưới đó, và validate từ chối một giám khảo dưới mức đó. Hướng dẫn Giám khảo trình bày mức yêu cầu, độ lệch, các phép thăm dò và oloproof review để gán nhãn trong terminal.
Giờ hãy quyết định lại lần chạy đã lưu mà không gọi bộ tóm tắt hay giám khảo:
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)Giám khảo giờ được phép quyết định, và quyết định là về bộ tóm tắt: tỷ lệ mà nó nêu, 0.500, không phải con số 45% của giám khảo. Vì lần chạy này có một mẫu nhãn đo lường ngẫu nhiên và mù, cổng đọc giám khảo đã được hiệu chỉnh bằng các nhãn đó ("Cổng có hiệu chỉnh cho giám khảo" trong hướng dẫn Giám khảo). Phép hiệu chỉnh là PPI, suy luận được hỗ trợ bởi dự đoán: nó dùng mẫu đã gán nhãn để đo tỷ lệ của giám khảo cách tỷ lệ của con người bao xa, rồi dịch ước lượng và mở rộng khoảng đúng bằng mức đó. Đó cũng là điều mà các ghi chú về PPI của lệnh xuất nhắc tới. Dù theo cách nào, đường cơ sở không đạt mức sàn, và thêm trường hợp sẽ không thay đổi điều đó.
Thực hiện một thay đổi thật
app_v2.py bỏ qua các câu xã giao ngắn và giữ hai câu tiếp theo. Sao chép nó đè lên app.py, đặt version: skip-pleasantries dưới system trong oloproof.yaml, để giám khảo tiếp tục chạy, và:
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 missGiám khảo vẫn là cùng phiên bản đã được xác thực, nên quy tắc của nó quyết định trực tiếp. Sáu phán quyết đến từ bộ nhớ đệm, trên những bản tóm tắt mà cả hai phiên bản viết giống hệt nhau. Không ai gán nhãn cho các bản tóm tắt mới này; việc xác thực giám khảo là điều cho phép các phán quyết của nó đứng vững.
So sánh ứng viên với đường cơ sở
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)Một phép so sánh không áp dụng hiệu chỉnh PPI: nó so sánh chính các phán quyết của giám khảo trên hai lần chạy, đó là lý do mức tăng bắt đầu từ 45% của giám khảo chứ không phải từ 0.500 đã hiệu chỉnh ở trên. Mười một bản tóm tắt được cải thiện và không bản nào tệ đi; khoảng cho mức tăng nằm hoàn toàn trên 0, nên quy tắc vượt trội đạt và lệnh thoát với 0. Định dạng được bảo vệ bởi các quy tắc của lần chạy, vốn không cho phép thất bại nào, chứ không phải bởi một phép so sánh: trên 20 trường hợp, một phép so sánh hai điểm định dạng hoàn hảo chỉ có thể nói rằng khác biệt nằm trong phạm vi 23,6 điểm.
Tùy chọn: một mô hình thật làm giám khảo
Bước này rời khỏi lộ trình ngoại tuyến. Nó cần một máy chủ mô hình, và với một nhà cung cấp đám mây thì cần một khóa và tiền.
- Cục bộ, không khóa và không chi phí: Ollama, LM Studio hoặc llama.cpp trên localhost. Tải một mô hình chat (với Ollama, ollama pull llama3.1).
- Đám mây: provider: anthropic hoặc openai với api_key_env nêu biến chứa khóa của bạn, hoặc openai_compatible với base_url và api_key_env. Mỗi trường hợp là một lần gọi giám khảo (hai lần khi câu trả lời đầu tiên không phải JSON hợp lệ), được tính phí theo giá của nhà cung cấp, và Oloproof không bao giờ gọi lại giám khảo cho một câu trả lời đã được chấm.
Viết giám khảo nháp trong một tệp riêng, như nó sẽ xuất hiện dưới 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.mdvà thử nó trên các câu trả lời mà người xem xét của bạn đã gán nhãn, mà không xác thực hay áp dụng nó:
oloproof evaluators try live_judge.yamlTheo mặc định, các máy chủ cục bộ trả lời từng yêu cầu một; hãy thêm concurrency: {system: 2, judge: 2} vào oloproof.yaml để các lần gọi đang xếp hàng không hết thời gian. Một lần chạy bước này với một mô hình cục bộ nhỏ (qwen2.5vl) trên một máy tính xách tay đã in ra:
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.769Mười một lần gọi hết thời gian, và khoảng đồng thuận tính mỗi lần theo cả hai hướng, nên nó kéo xuống tới 19,1%: một giám khảo không trả lời thì không được đo. Cách sửa là một mô hình lớn hơn, thời gian chờ dài hơn, hoặc ít lần gọi đồng thời hơn. Để áp dụng mô hình, hãy đặt nó vào oloproof.yaml thay cho giám khảo thay thế. Đó là một phiên bản bộ đánh giá mới: cấu hình của nó (mô hình, endpoint, rubric) là danh tính của nó, nên việc xác thực của giám khảo thay thế không được chuyển sang. Chạy lại đường cơ sở với nó và xác thực nó so với các nhãn, như trên.
Khắc phục sự cố
| Triệu chứng | Nguyên nhân và cách sửa |
|---|---|
| covers_facts thiếu toàn bộ, no_observations | Máy chủ giám khảo không chạy hoặc không ở base_url. Mọi lần gọi giám khảo đều lỗi; oloproof inspect RUN_ID --failures cho thấy lý do. |
| evaluator_not_validated sau khi bạn đã xác thực | Bạn đã thay đổi giám khảo (mô hình, endpoint, cổng, rubric) và tạo ra một phiên bản mới. Hãy xác thực phiên bản đó. |
| labels import từ chối tệp và nêu một dòng | Dòng đó nêu một trường hợp hoặc lần thực thi mà lần chạy không có; hãy xuất lại từ lần chạy mà bạn gán nhãn. |
| labels export nói không thể kết nối tới một không gian làm việc | Bạn đang đăng nhập vào một không gian, nên nó đã yêu cầu không gian đó rút mẫu. --local rút mẫu ở đây thay vào đó. |
| Một giám khảo đám mây thất bại trước mọi lần gọi | Khóa của nó không có trong biến mà api_key_env nêu. |
Giới hạn
- Giám khảo thay thế là một phép khớp cụm từ. Nó minh họa quy trình, không phải chất lượng chấm.
- Không có bộ đánh giá BLEU, ROUGE hay độ tương đồng embedding. Trong SDK, hãy tự viết một bộ bằng @evaluator; oloproof.yaml chưa thể nêu một bộ đánh giá tùy chỉnh.
- Một giám khảo thấy văn bản: JSON của đầu vào, tham chiếu và đầu ra. Nó không thấy hình ảnh hay âm thanh.
- Hai mươi nhãn cho một khoảng đồng thuận rộng. Hãy gán nhãn nhiều hơn, ngẫu nhiên và mù, cho một giám khảo mà bạn dựa vào.
- Một mẫu cục bộ chỉ mang tính thiện chí. Với một giám khảo mà người khác dựa vào, hãy push lần chạy và để một không gian làm việc được lưu trữ rút mẫu (Giám khảo).