Hãy hỏi một mô hình ngôn ngữ xem có bao nhiêu chữ cái trong từ “strawberry.” Khả năng cao là nó sẽ trả lời sai. Nó có thể nói là mười. Nó có thể đoán là mười một. Nó sẽ tỏ ra hoàn toàn chắc chắn về câu trả lời của mình, nhưng thực tế vẫn là sai. Hãy yêu cầu cùng một mô hình đó tính lãi kép cho một khoản vay, hoặc cộng hai số lớn, hoặc đếm số ngày làm việc giữa hai ngày, và bạn sẽ thường nhận được một câu trả lời trông có vẻ hợp lý nhưng các con số lại bị lệch một chút, một cách đầy nguy hiểm.
Điều này xảy ra vì các mô hình ngôn ngữ lớn không suy luận về con số theo cách con người làm. Chúng dự đoán các token. Một token có thể là cả một từ, một phần của từ, hoặc một chữ số đơn lẻ. Khi mô hình thấy từ “strawberry”, nó không thấy tám chữ cái riêng biệt xếp thành một hàng. Nó thấy một vài mẩu thông tin (chunks). Nó chưa bao giờ được dạy cách đếm ký tự, mà chỉ được dạy cách dự đoán mẩu văn bản nào sẽ xuất hiện tiếp theo. Hạn chế tương tự cũng áp dụng cho các phép tính số học. Mô hình không có máy tính nội bộ. Nó thiếu logic nhớ (carry logic). Nó không thực sự hiểu về giá trị hàng chữ số. Khi nó nhân 148 với 279, nó không thực hiện phép nhân. Nó đang khớp mẫu (pattern-matching) với các biểu thức tương tự mà nó đã thấy trong quá trình huấn luyện, rồi đoán xem chuỗi chữ số nào nên theo sau. Với các phép tính cực nhỏ, mẫu này đủ mạnh để hoạt động. Nhưng với bất kỳ thứ gì đòi hỏi độ chính xác thực sự, phán đoán đó cuối cùng sẽ sai lệch.
Hai Nhiệm Vụ, Một Bot
Các phương pháp nhắc (prompting) tiêu chuẩn yêu cầu một hệ thống duy nhất thực hiện hai việc rất khác nhau cùng một lúc. Thứ nhất, hiểu logic của vấn đề. Thứ hai, thực hiện phép toán chính xác. Mô hình thực sự rất ấn tượng ở nhiệm vụ đầu tiên. Nó có thể đọc một bài toán đố, trích xuất các biến, thiết lập các mối quan hệ và lập kế hoạch cho lộ trình giải quyết. Nhưng sau đó, nó lại phải đóng vai trò là máy tính của chính mình. Đó là lúc chuỗi logic bị đứt gãy. Chỉ cần một chữ số bị sai ở bước thứ ba sẽ làm hỏng mọi bước sau đó. Bản thân logic có thể hoàn hảo, nhưng câu trả lời cuối cùng lại là rác rưởi vì mô hình đã cộng sai.
Các Mô hình Ngôn ngữ Hỗ trợ Lập trình (Program-Aided Language Models, hay PAL) giải quyết vấn đề này bằng cách chia nhỏ công việc. Thay vì yêu cầu mô hình đưa ra câu trả lời, bạn yêu cầu nó viết một chương trình.
Đây là cách quy trình này thực sự hoạt động. Bạn đưa ra vấn đề. Mô hình tìm ra logic, xác định các biến và cấu trúc thuật toán. Sau đó, thay vì tự tính toán kết quả, nó viết một đoạn mã ngắn, thường là bằng Python. Đoạn mã đó được chuyển cho một trình thông dịch mã (code interpreter) thực thụ. Trình thông dịch sẽ chạy logic và trả về kết quả chính xác, mang tính xác định. Mô hình mô tả phép toán. Python thực hiện phép toán.
Suy luận có thể thực thi trong thực tế
Hãy coi PAL như là suy luận có thể thực thi. Nếu một đoạn mã có thể giải quyết được vấn đề, hãy để mô hình viết đoạn mã đó.
Hãy xem xét một ví dụ cụ thể. Bạn cần tính số tiền đáo hạn của một khoản tiền gửi cố định là ₹50,000 với lãi suất hàng năm là 8,5%, tính lãi kép theo quý, trong thời hạn bảy năm. Nếu hỏi trực tiếp một mô hình ngôn ngữ, nó có thể viết ra một công thức, thay thế các giá trị và tính toán kết quả thông qua chuỗi suy nghĩ (chain of thought). Tuy nhiên, nếu nhìn kỹ, bạn có thể thấy nó xử lý sai việc tính lãi kép theo quý bằng cách chia lãi suất không chính xác, hoặc nó làm tròn một bước trung gian và mang lỗi đó đi tiếp. Câu trả lời trông có vẻ hợp lý nhưng lại lệch tới hàng trăm rupee.
Với PAL, sự tương tác thay đổi. Bạn hướng dẫn mô hình tạo mã Python xác định principal = 50000, rate = 0.085, time = 7, và n = 4, sau đó tính amount = principal * (1 + rate/n) ** (n * time). Mô hình xuất mã. Một môi trường thực thi Python sẽ chạy nó. Bạn nhận được con số chính xác, đến từng chữ số thập phân cuối cùng, trong mọi lần thực hiện. Không có sự đoán mò trong phép nhân, không có số dư ảo, không có lỗi làm tròn đầy tự tin.
Mô hình này cũng áp dụng cho các phép toán về ngày tháng. Hãy hỏi một mô hình xem ngày nào sẽ rơi đúng vào 120 ngày làm việc kể từ hôm nay, không tính cuối tuần. Một mô hình chỉ thuần văn bản có thể đếm tiến lên và bị nhầm vào một ngày Thứ Bảy. Cách tiếp cận PAL sẽ để mô hình viết một đoạn mã sử dụng logic datetime và calendar, sau đó để trình thông dịch lặp lại chính xác. Thao tác dữ liệu cũng hoạt động theo cách tương tự. Nếu bạn cần phân tích một tệp CSV lộn xộn, lọc JSON lồng nhau hoặc chạy một phép biến đổi thống kê nhanh, mô hình nên phác thảo logic trong khi trình thông dịch xử lý việc lặp lại.
Tại sao điều này thực sự quan trọng
Sự chuyển dịch từ các câu trả lời bằng văn bản sang mã có thể thực thi mang lại ba lợi thế thực tế.
Tính tất định. Một mô hình ngôn ngữ khi được hỏi cùng một câu hỏi hai lần có thể thay đổi cách diễn đạt hoặc thay đổi một chữ số. Một trình thông dịch sẽ trả về cùng một kết quả đầu ra cho cùng một đầu vào trong mọi lần chạy. Sự ổn định đó đóng vai trò cực kỳ quan trọng trong kế toán, logistics, lập lịch và bất kỳ tính toán kỹ thuật nào mà tính nhất quán là điều bắt buộc.
Tính có thể kiểm chứng. Khi một mô hình đưa cho bạn ba đoạn văn lập luận, bạn phải đọc từng câu để săn tìm một con số sai sót duy nhất. Khi nó đưa cho bạn một đoạn mã mười dòng, bạn có thể xem lại mã đó. Bạn có thể xác minh rằng công thức lãi kép là chính xác trước khi trình thông dịch thực thi. Bạn có thể kiểm tra tên biến, phát hiện các lỗi off-by-one, và thậm chí là quản lý phiên bản cho giải pháp đó. Phạm vi tiềm ẩn các sai sót sẽ giảm đi đáng kể.
Độ tin cậy. Mô hình chỉ làm đúng vai trò của nó. Nó làm những gì nó được xây dựng để làm: lập luận về cấu trúc, ngữ nghĩa và phân rã vấn đề. Máy móc làm những gì nó được xây dựng để làm: tính toán chính xác. Sự phân tách các mối quan tâm (separation of concerns) này chính là cách mà các phần mềm đáng tin cậy được kiến trúc hóa. Tính lắp ghép (composition) luôn vượt trội hơn thiết kế nguyên khối (monolithic design).
Chạy nó như mã không đáng tin cậy
Cần phải có một lời cảnh báo. Mã được tạo ra nên được xử lý như một đầu vào không đáng tin cậy. Mô hình có thể viết một đoạn mã có vòng lặp vô hạn, một yêu cầu mạng không cần thiết, hoặc một thao tác trên hệ thống tệp mà bạn không yêu cầu. Luôn thực thi các chương trình này bên trong một môi trường sandbox cô lập. Hãy sử dụng các container với đặc quyền bị hạn chế, các hàm serverless không có quyền truy cập mạng, hoặc các môi trường được kiểm soát chặt chẽ với thời gian CPU hạn chế và không có lưu trữ lâu dài. Bảo mật không phải là một ghi chú phụ ở đây. Nó là một phần của thiết kế hệ thống.
Nơi PAL tỏa sáng, và nơi nó dừng lại
PAL hoạt động tuyệt vời đối với toán học, ngày tháng và thao tác dữ liệu có cấu trúc. Nó loại bỏ các lỗi cơ học vốn thường gây trở ngại cho việc lập luận chỉ bằng văn bản.
Tuy nhiên, nó không sửa được logic sai. Nếu mô hình chọn sai công thức,
