Bạn đã xây dựng một công cụ nội bộ cho phép một nhóm chạy 28 unit test trên một tính năng vận hành bằng LLM mà không cần phải gọi API của mô hình. Bạn thực hiện điều này bằng cách bao bọc mô hình trong một interface có thể giả lập (fakeable interface) và thêm vào ba lớp đánh giá: dựa trên tính xác định (deterministic), heuristic và dựa trên LLM.

Các câu lệnh assertion tiêu chuẩn sẽ bị lỗi ngay khi LLM tạo ra văn bản. Cùng một prompt có thể tạo ra các câu khác nhau trong mỗi lần chạy, vì vậy assertEqual(output, expected) sẽ báo lỗi ngay cả khi mô hình hoạt động đúng. Hầu hết các nhóm kỹ thuật hoặc là phát hành tính năng mà không có sự xác minh, hoặc cố gắng kiểm thử chính mô hình đó, coi một mục tiêu luôn thay đổi như thể nó là một thư viện tĩnh.

Tại sao vấn đề này lại quan trọng

LLM hiện đang nằm trong các quy trình làm việc tiếp xúc với khách hàng—như gửi email tiếp cận, trả lời hỗ trợ, tạo nội dung. Một thông tin bị ảo giác (hallucinated fact) duy nhất hoặc một định danh bị rò rỉ có thể làm tổn hại danh tiếng thương hiệu, làm lộ dữ liệu riêng tư hoặc vi phạm các quy định tuân thủ. Nếu không có chiến lược kiểm thử đáng tin cậy, các nhóm sẽ lãng phí thời gian để chạy theo các lỗi chập chờn (flaky failures) hoặc phát hành các lỗi chỉ xuất hiện khi đã lên môi trường production.

Cách tiếp cận: thu hẹp trách nhiệm của mô hình

Bước đầu tiên là giới hạn những gì LLM thực sự làm. Trong hệ thống của tác giả, mô hình chỉ soạn thảo các tin nhắn tiếp cận. Tất cả logic điều hướng (routing logic), quản lý trạng thái (state management) và kiểm tra an toàn đều nằm trong mã nguồn thông thường. Bằng cách giới hạn mô hình trong một đầu ra duy nhất và được xác định rõ ràng, hệ thống xung quanh sẽ duy trì được tính xác định và có thể kiểm thử được.

Để làm được điều đó, LLM nằm sau một provider interface, cho phép sử dụng một phiên bản giả lập (fake version) trong các bài kiểm thử. Trong môi trường production, việc triển khai sẽ gọi API bên ngoài; trong bộ kiểm thử (test suite), một bản fake nhẹ sẽ trả về một phản hồi mẫu (canned response). Vì phần còn lại của mã nguồn chỉ tương tác với interface, toàn bộ quy trình có thể được thực hiện bởi các unit test mà không bao giờ chạm đến mạng. Kết quả là một lõi có thể dự đoán được mà 28 bài kiểm thử sẽ xác minh.

Một hệ thống đánh giá trung thực

Ngay cả khi phạm vi đã được thu hẹp, đầu ra của mô hình vẫn không mang tính xác định (nondeterministic). Do đó, tác giả đã xây dựng một hệ thống đánh giá (evaluation harness) ba lớp, mỗi lớp xử lý một loại rủi ro khác nhau.

  • Lớp 1 – Kiểm tra dựa trên tính xác định (Deterministic checks) Các quy tắc biểu thức chính quy (regular-expression) đơn giản sẽ bắt các lỗi cụ thể như sai ID tòa nhà hoặc các token bị cấm. Các kiểm tra này nhanh và đưa ra kết quả pass/fail nhị phân.

  • Lớp 2 – Kiểm tra heuristic Các script tìm kiếm các con số hoặc ngày tháng bị ảo giác, gắn cờ các thông tin sai lệch thực tế rõ ràng. Chúng có thể bỏ lỡ các tuyên bố sai mà không có manh mối về số liệu, và tác giả cũng thẳng thắn thừa nhận hạn chế này.

  • Lớp 3 – LLM judge Một mô hình phụ sẽ đánh giá tông giọng và tính chuyên nghiệp. Vì bước này dựa trên một hệ thống xác suất khác, nó chỉ được sử dụng cho các khía cạnh chủ quan mà các quy tắc xác định không thể thực hiện được.

Chìa khóa của hệ thống đánh giá này là bộ dữ liệu được sử dụng để đánh giá. Tác giả đã mã hóa các mẫu lỗi đã biết—các bẫy cụ thể và kiến thức chuyên môn—để hệ thống đánh giá kiểm tra chính xác những sai sót đã từng xảy ra trong thực tế. Đây không phải là một công cụ "bắt mọi lỗi" thần kỳ mà là một lưới an toàn có mục tiêu.

Điều này có ý nghĩa gì đối với các nhóm

  • Giữ vai trò của LLM ở mức nhỏ. Càng ít trách nhiệm thì việc cô lập và kiểm thử càng dễ dàng.
  • Đặt logic điều hướng, trạng thái và an toàn vào trong mã nguồn. Logic truyền thống sẽ duy trì tính xác định và có thể kiểm thử đầy đủ.
  • Phơi bày mô hình thông qua một interface có thể giả lập. Các unit test chạy mà không cần gọi bên ngoài, giúp bộ kiểm thử nhanh và đáng tin cậy.
  • Phân lớp các đánh giá của bạn. Bắt đầu với các quy tắc xác định, thêm các heuristic cho các lỗi ảo giác đã biết, và dành riêng LLM judge cho các kiểm tra chất lượng mang tính chủ quan.
  • Nêu rõ các giới hạn. Không có lớp nào đảm bảo sự hoàn hảo; hệ thống đánh giá chỉ bắt được những gì bạn lập trình cụ thể để phát hiện.

Quan điểm ngược lại: bạn vẫn không thể unit-test chính mô hình đó

Tác giả thừa nhận rằng một mô hình là một mục tiêu luôn thay đổi. Ngay cả lớp LLM judge cũng thừa hưởng tính không xác định tương tự như những gì nó cố gắng đánh giá. Do đó, hệ thống không bao giờ có thể đảm bảo rằng mọi sự ảo giác hoặc vi phạm chính sách đều sẽ được phát hiện trước khi phát hành. Cách tiếp cận này giúp giảm thiểu rủi ro chứ không loại bỏ hoàn toàn, và nó dựa vào khả năng của nhóm trong việc cập nhật dữ liệu đánh giá khi các dạng lỗi mới xuất hiện.

Bài học rút ra

Bạn không thể viết một unit test cổ điển để khẳng định chính xác đầu ra của LLM, nhưng bạn có thể xây dựng một hệ thống nơi tầm ảnh hưởng của mô hình được giới hạn, interface của nó có thể thay thế được, và đầu ra của nó được sàng lọc thông qua các lớp kiểm tra minh bạch. Sự kết hợp đó biến một thành phần vốn chập chờn thành một phần có thể dự đoán được của một ứng dụng lớn hơn và có thể kiểm thử được.