FDE PulseViệc làm FDE đang mở 434Mới đăng 7 ngày qua 27Chủ đề nổi bật: Đào tạo kỹ năng FDE tại Đông Nam Á
EN

Tờ báo của nghề Forward Deployed Engineer

Bách khoa

Viết eval đầu tiên với Inspect AI: dataset, solver, scorer và cách đọc log

Chỉ với ba câu hỏi về chính sách đổi trả, một scorer so chuỗi có thể chấm model đúng 3/3 trong khi thực tế model chỉ đúng 1/3, và chỉ có file log mới cho bạn thấy điều đó.

Tóm tắt nhanh

  • Một eval Inspect là Task gồm ba phần: dataset (input/target), solver và scorer.
  • includes() chỉ kiểm tra chuỗi con nên dễ chấm đúng một câu trả lời sai; model_graded_fact() để một model khác chấm theo fact.
  • Mỗi lần chạy sinh một EvalLog trong ./logs, có đủ input, output, target và điểm để debug và chạy lại.
Chia sẻLinkedInFacebookX
Đồ hoạCái bẫy 3/3: includes() chấm so với đọc log
includes() chấmĐọc output trong log
Câu 1: target '30 ngày'Đúng, vì chuỗi '30 ngày' có trong outputSai, model nói chỉ được đổi trong 7 ngày
Câu 2: target 'không'Đúng, vì chữ 'không' xuất hiện trong câuSai, model nói hàng giảm giá vẫn trả lại được
Câu 3: target 'miễn phí'ĐúngĐúng, model nói đổi hàng miễn phí vận chuyển
Tổng điểm3/31/3

So chuỗi con báo 3/3, nhưng đọc từng output trong log chỉ còn 1/3 câu đúng.

Đồ hoạ: FDE Times

Bạn đặt target là “30 ngày” cho câu hỏi về thời hạn đổi hàng. Model trả lời “Bạn được đổi trong 7 ngày, không phải 30 ngày”, và scorer vẫn chấm đúng. Lỗi này không nằm ở model. Nó nằm ở cách bạn viết eval, và bạn chỉ phát hiện ra khi chịu khó mở log.

Inspect là framework đánh giá AI do UK AI Security Institute và Meridian Labs phát triển. Với FDE, giá trị của nó rất cụ thể. Khi khách hàng hỏi “bản prompt mới có tốt hơn bản cũ không”, bạn cần một con số chạy lại được và một file log để chỉ ra từng câu sai, chứ không phải cảm giác sau vài lần thử tay.

Bài hướng dẫn này đi qua một ví dụ giả định: bot trả lời chính sách đổi trả của một công ty bán lẻ. Bạn sẽ viết dataset, chọn solver, thử hai loại scorer, chạy eval rồi đọc log.

Các đoạn code dưới đây được rút gọn để dễ theo dõi, nên hãy đối chiếu một lần đường dẫn import và tên tham số với docs của Inspect trước khi chạy.

Cần chuẩn bị gì?

Bạn cần Python, gói Inspect cài theo hướng dẫn trên trang docs, và API key của một nhà cung cấp model. Tạo một thư mục trống, ví dụ return-policy-eval/, và một file eval.py. Thế là đủ.

Bước 1: dataset ghi lại câu trả lời mà khách hàng coi là đúng

Dataset trong Inspect thường là một bảng có hai cột input và target. Inspect đọc sẵn CSV, JSON và JSON Lines. Với một eval nhỏ tự viết, cách nhanh nhất là tạo MemoryDataset từ một list Sample:

from inspect_ai.dataset import Sample, MemoryDataset

dataset = MemoryDataset([
    Sample(input="Tôi mua áo được bao lâu thì còn đổi được?", target="30 ngày"),
    Sample(input="Hàng giảm giá có được trả lại không?", target="không"),
    Sample(input="Đổi hàng có mất phí vận chuyển không?", target="miễn phí"),
])

Trước khi sang bước tiếp theo, hãy tự hỏi: nếu một nhân viên chăm sóc khách hàng đọc từng target, họ có gật đầu rằng đó đúng là câu trả lời họ cần không?

Trường target có thể là một giá trị literal như “30 ngày”, hoặc một đoạn mô tả để một model khác dùng làm căn cứ chấm. Lựa chọn này quyết định bạn dùng scorer nào ở bước 3.

Lỗi hay gặp nhất là tự nghĩ ra câu hỏi. Ở site khách hàng, hãy lấy input từ log hỗ trợ thật hoặc từ những câu đội vận hành hay bị hỏi nhất. Khi dataset đã lớn hơn vài chục dòng, chuyển nó sang file CSV hoặc JSON Lines để người phía khách hàng có thể tự sửa.

Bước 2: solver quyết định model được hỏi như thế nào

Solver là một hàm Python nhận TaskState và một hàm generate, biến đổi state rồi trả lại. Solver đơn giản nhất là generate(): nó gọi model và thêm câu trả lời vào lịch sử hội thoại.

from inspect_ai import Task, task
from inspect_ai.solver import generate
from inspect_ai.scorer import includes

@task
def return_policy():
    return Task(
        dataset=dataset,
        solver=generate(),
        scorer=includes(),
    )

Bắt đầu với generate() trần là có chủ đích. Nó cho bạn một baseline. Sau này, khi thêm system prompt hay bước truy xuất tài liệu, bạn có một con số để so sánh.

Bước 3: chạy, và đừng tin ngay con số đầu tiên

Chạy eval từ dòng lệnh bằng inspect eval, chọn model qua --model:

inspect eval eval.py --model <provider/model-name>

Scorer includes() kiểm tra xem target có xuất hiện ở bất kỳ đâu trong output hay không, tức là so khớp chuỗi con. Nó nhanh, rẻ và đủ dùng khi đáp án là một con số hay một mã cụ thể. Nhưng quay lại ví dụ ở đầu bài, bạn sẽ thấy ngay giới hạn của nó.

Giả sử model trả lời câu đầu tiên: “Bạn được đổi trong 7 ngày, không phải 30 ngày như nhiều người nghĩ.” Chuỗi “30 ngày” có trong output, nên includes() chấm đúng.

Câu thứ hai cũng nguy hiểm không kém: target “không” gần như xuất hiện trong mọi câu tiếng Việt, kể cả câu “Có, hàng giảm giá vẫn trả lại được, không vấn đề gì.” Giả sử thêm rằng câu thứ ba model trả lời đúng là đổi hàng miễn phí vận chuyển. Bảng điểm sẽ báo 3/3, trong khi thực tế chỉ có 1/3 câu đúng.

Khi đáp án là một ý chứ không phải một chuỗi, hãy dùng model_graded_fact(). Scorer này để một model khác đánh giá xem output có chứa đúng fact nêu trong target hay không. Vì thế target nên viết thành câu mô tả thay vì chỉ một cụm từ:

from inspect_ai.scorer import model_graded_fact

dataset_graded = MemoryDataset([
    Sample(
        input="Tôi mua áo được bao lâu thì còn đổi được?",
        target="Khách được đổi hàng trong vòng 30 ngày kể từ ngày mua",
    ),
    Sample(
        input="Hàng giảm giá có được trả lại không?",
        target="Hàng giảm giá không được trả lại",
    ),
    Sample(
        input="Đổi hàng có mất phí vận chuyển không?",
        target="Đổi hàng được miễn phí vận chuyển",
    ),
])

@task
def return_policy_graded():
    return Task(
        dataset=dataset_graded,
        solver=generate(),
        scorer=model_graded_fact(),
    )

Chạy lại bằng đúng lệnh inspect eval như trên. Với hai câu trả lời sai ở ví dụ, thứ bạn chờ đợi là model chấm nhận ra “7 ngày” mâu thuẫn với fact “30 ngày”, và “vẫn trả lại được” mâu thuẫn với “không được trả lại”. Đừng mặc định là nó làm được: bước 4 là nơi bạn kiểm tra điều đó.

Tình huống Scorer nên dùng Rủi ro cần canh
Đáp án là mã đơn, số tiền, tên sản phẩm includes() Chấm đúng khi đáp án nằm trong một câu phủ định
Đáp án là một chính sách hay một ý giải thích model_graded_fact() Model chấm có thể sai, nên vẫn phải đọc mẫu

Bước 4: mở log, vì đó mới là sản phẩm thật

Mặc định Inspect ghi log vào thư mục con ./logs của thư mục bạn đang đứng. Bạn có thể đổi chỗ bằng biến môi trường INSPECT_LOG_DIR, hữu ích khi muốn gom log của nhiều dự án khách hàng vào một nơi.

Từ phiên bản v0.3.46, định dạng mặc định là .eval, một dạng nhị phân gọn và nhanh. Nếu cần một file text để đọc bằng mắt thì dùng .json.

Mỗi lần chạy sinh ra một EvalLog có cấu trúc. Ba trường bạn sẽ dùng nhiều nhất là status (lần chạy có hoàn tất không), samples (input, output, target và điểm của từng mẫu) và results (các con số tổng hợp từ metric).

Hamel Husain, người đã viết ghi chú chi tiết về Inspect, nhận xét rằng log này giữ đủ ngữ cảnh để debug, phân tích và quan trọng nhất là tái lập lại eval.

from inspect_ai.log import read_eval_log

log = read_eval_log("logs/<ten-file>.eval")
print(log.status)
for s in log.samples:
    print(s.input, "|", s.output, "|", s.target, "|", s.scores)

Sau bước này, kiểm tra hai điều. status phải báo hoàn tất trước khi bạn tin vào results. Sau đó lọc ra mọi sample được chấm đúng và đọc output của chúng. Đây chính là chỗ bạn bắt được câu “7 ngày, không phải 30 ngày”, và cũng là chỗ bạn xác nhận lần chạy với model_graded_fact() đã chấm lại đúng hay chưa.

File log có thể lớn tới nhiều GB. read_eval_log hỗ trợ chỉ đọc phần header, nên khi chỉ cần trạng thái và kết quả tổng hợp, đừng nạp toàn bộ samples vào bộ nhớ.

Ở site khách hàng, kỹ năng này trông ra sao?

Thử hình dung tuần thứ hai của một dự án. Đội vận hành phía khách hàng muốn đổi prompt và hỏi bản mới có tốt hơn không. Nếu không có eval, cuộc trò chuyện sẽ xoay quanh vài ảnh chụp màn hình.

Còn nếu có, bạn chạy cùng một Task trên hai cấu hình, mở hai log cạnh nhau và chỉ ra chính xác những câu nào được sửa, những câu nào bị hỏng thêm.

Vì thế, việc đầu tiên nên làm ở khách hàng là ngồi với người hiểu nghiệp vụ nhất và cùng viết 20 Sample, kèm target dạng mô tả họ đồng ý được. Bộ dữ liệu này thường đáng giá hơn mọi tinh chỉnh prompt về sau, vì nó biến “đúng” thành thứ hai bên đã thống nhất.

Nếu bạn đang ứng tuyển vị trí FDE, hãy để ý những JD nhắc đến “evaluation”, “eval harness” hay “đo chất lượng LLM”. Trong CV, đừng chỉ viết “có kinh nghiệm với Inspect”.

Hãy mô tả một con số: bạn viết bao nhiêu mẫu, phát hiện scorer nào chấm sai, và sau khi đổi cách chấm thì kết quả thay đổi thế nào. Người tuyển dụng tin một file log hơn một dòng giới thiệu bản thân.

Một eval tốt không phải để chứng minh model đã giỏi. Nó là chỗ để bạn biết model đang sai ở đâu, sớm hơn khách hàng.

6 nguồn
Đọc tiếp trên lộ trình · Chặng 6: Đo lườngTừ nút thumbs-down đến bộ eval: biến lời phàn nàn của người dùng thành test caseKhi khách hàng gửi bạn một file toàn những lượt bấm “không hài lòng”, việc đầu tiên là đọc trace và gắn nhãn, không phải đếm số lượt bấm.