Tessl: Sản phẩmBlog
85

Thủ thuật

Justin Cormack và bài học từ việc dùng AI Agent viết 350.000 dòng mã Rust

(giờ Việt Nam)

Tóm tắt AI

Tessl chia sẻ trải nghiệm thực tế khi sử dụng AI Agent để xây dựng hệ thống lưu trữ tương thích S3 với 350.000 dòng mã Rust, nhấn mạnh tầm quan trọng của bằng chứng xác thực trong đánh giá AI.

Bản dịch AI

AI Agent Evaluation Starts With Evidence

Tôi yêu thích việc kiểm thử. Tôi luôn thích kiểm thử, và AI càng khiến tôi suy nghĩ nhiều hơn về vấn đề này. Nếu AI sẽ giúp chúng ta viết mã nguồn sản phẩm, thì câu hỏi quan trọng không phải là liệu nó có thể tạo ra nhiều mã nguồn một cách nhanh chóng hay không. Câu hỏi quan trọng là liệu chúng ta có thể xây dựng một vòng lặp phản hồi cho biết điều gì thực sự đang hoạt động hay không.

Đó là lý do cho bài nói chuyện của tôi: "Khi các bài kiểm thử nói dối: Sử dụng khả năng quan sát (observability) để giữ cho AI trung thực". Tôi muốn hiểu điều gì sẽ xảy ra khi bạn sử dụng AI cho một thứ gì đó lớn hơn nhiều so với một dự án đồ chơi. Các công cụ nhỏ thì rất thú vị. Bạn có thể viết chúng trong nửa ngày, kiểm thử chúng một cách quyết liệt và cảm thấy khá hài lòng về kết quả. Nhưng liệu bạn có thể sử dụng AI để xây dựng một hệ thống cơ sở hạ tầng lớn và phức tạp không?

Tôi đã quyết định thử nghiệm điều đó với bộ lưu trữ đối tượng (object storage) tương thích với S3. Lưu trữ đối tượng là dịch vụ đám mây yêu thích của tôi, và hầu hết các triển khai mà tôi từng xem qua đều mất ít nhất hai năm để viết. Một số mất cả thập kỷ. Tôi biết điều này sẽ rất lớn và phức tạp. Tại thời điểm diễn ra bài nói chuyện, cơ sở mã nguồn đã có khoảng 350.000 dòng Rust, và tôi sẽ không giả vờ rằng mình đã đọc từng dòng một.

Đó là một phần của thử nghiệm. Tôi muốn mã nguồn chất lượng cao. Tôi có những quan điểm về kiến trúc. Tôi quan tâm đến bảo mật, hiệu năng và hành vi của các hệ thống phân tán. Tôi cũng muốn duy trì sự hiện diện của con người trong vòng lặp, vì tôi muốn biết điều gì đã sai thay vì tự động hóa mọi thứ ngay từ đầu.

Sử dụng bài nói chuyện này làm ngữ cảnh cho tác nhân (agent)

Tessl đã biến bài nói chuyện AI Native DevCon của tôi thành một kỹ năng mà tác nhân của bạn có thể sử dụng làm ngữ cảnh. Bạn cũng có thể xem toàn bộ bản ghi hình.

Tại sao tôi lại kiểm thử dựa trên chính S3?

Điều tuyệt vời khi sao chép một hệ thống hiện có là bạn có được một "test oracle" (nguồn đối chiếu kiểm thử). Trong trường hợp của tôi, tôi có thể chạy các bài kiểm thử dựa trên S3, quan sát hành vi thực tế, và sau đó nói với AI rằng triển khai của chúng tôi phải hoạt động chính xác như vậy.

Điều đó đã thay đổi chất lượng công việc. Tôi kết thúc với khoảng 1.500 bài kiểm thử chạy dựa trên S3 và khóa chặt hành vi. Đối với một tác nhân, điều đó tốt hơn nhiều so với một chỉ dẫn mơ hồ. Nó cung cấp cho mô hình một nền tảng thực tế, và cung cấp cho tôi bằng chứng khi tôi quyết định xem có nên tin tưởng vào triển khai đó hay không.

Giờ đây tôi nghĩ rằng nếu bạn đang viết một hệ thống phức tạp, một bước khởi đầu tốt là xây dựng một phiên bản rất đơn giản trước. Nó không nhất thiết phải là kiến trúc cuối cùng. Nó có thể là một mô hình hành vi tối giản. Nhưng nếu bạn có thể xây dựng một bộ kiểm thử dựa trên phiên bản đơn giản đó, bạn có thể sử dụng nó như một "oracle" trong khi xây dựng phiên bản phức tạp hơn.

Điều này không hoàn hảo. S3 đôi khi có tính nhất quán cuối cùng (eventually consistent), đặc biệt là xung quanh hành vi ủy quyền, vì vậy các bài kiểm thử đôi khi cần chạy lại trước khi chúng thể hiện đúng hành vi thực tế. Một "oracle" không hoàn toàn giống như một đặc tả kỹ thuật. Bạn vẫn phải diễn giải những gì mình đang thấy.

Một khám phá khác là tài liệu là không đủ. S3 có rất nhiều tài liệu, nhưng khi đi vào chi tiết, tài liệu thường chỉ mang tính ước lệ, lỗi thời hoặc đơn giản là không mô tả hành vi mà bạn thực sự quan sát được. Hoặc chỉ đơn giản là sai! Tài liệu có thể cho bạn gợi ý về những gì cần kiểm thử. Các bài kiểm thử mới cho bạn biết điều gì thực sự xảy ra.

Tại sao 100 phần trăm độ bao phủ (coverage) là mục tiêu sai lầm

Ban đầu tôi đã cố gắng theo đuổi độ bao phủ kiểm thử 100 phần trăm, vì đó có vẻ là một ý tưởng hay. Tôi đã đo lường các loại độ bao phủ khác nhau, bao gồm cả độ bao phủ từ các bài kiểm thử tích hợp. Nó không giúp ích nhiều như mọi người đôi khi vẫn nghĩ.

Khi tôi yêu cầu một tác nhân AI đạt được độ bao phủ 100 phần trăm, nó đã viết những bài kiểm thử rất tầm thường. Một số trong đó về mặt kỹ thuật đã cải thiện con số, nhưng chúng không cải thiện sự tự tin của tôi. Tôi không cần một bài kiểm thử cho mọi đường dẫn lỗi của bộ tạo số ngẫu nhiên nếu hành vi đúng chỉ đơn giản là trả về một lỗi hoặc dừng chương trình (panic). Đó không phải là nơi chứa bằng chứng hữu ích nhất.

Tôi vẫn có rất nhiều bài kiểm thử. Hầu hết các tệp tin có độ bao phủ từ 75 đến 100 phần trăm. Vấn đề không phải là độ bao phủ là xấu. Vấn đề là độ bao phủ câu lệnh 100 phần trăm không phải là sự thay thế hữu ích cho tư duy.

Các bài kiểm thử là công cụ khám phá. Chúng không phải là câu trả lời kỳ diệu. Bạn thêm các bài kiểm thử vào nơi bạn không chắc chắn, nơi bạn nghi ngờ, và nơi bạn nghĩ rằng hệ thống có thể đang ẩn chứa lỗi. Nếu mã nguồn khiến bạn lo lắng, bạn hãy dành nhiều thời gian hơn để cố gắng phá vỡ nó.

Đó là tư duy mà tôi muốn từ quá trình phát triển có sự hỗ trợ của AI. Tác nhân có thể tạo ra các bài kiểm thử, nhưng tôi vẫn cần quyết định xem mình đang cố gắng phơi bày rủi ro nào.

Các trường hợp biên (edge cases) là nơi bộ kiểm thử tạo dựng niềm tin

Một trong những khoảnh khắc mang lại cho tôi sự tự tin là khi AI tìm thấy một lỗi 500 có thể lặp lại trong S3. Nó đang viết các bài kiểm thử dựa trên S3 cho một trường hợp biên và tìm thấy hành vi trông giống như một lỗi thực sự. Sau đó, nó lại tìm thấy một lỗi 500 có thể lặp lại khác.

Điều đó thật thú vị vì nó có nghĩa là bộ kiểm thử không chỉ kiểm tra các đường dẫn hiển nhiên. Nó đang khám phá đủ không gian hành vi để tìm ra các trường hợp kỳ lạ. Khi bạn đang xây dựng một hệ thống phức tạp, bạn dành nhiều thời gian để chuyển đổi giữa "mọi thứ thật tồi tệ và cái này sẽ không bao giờ hoạt động" và "thực ra, cái này đang hoạt động trở lại". Các bài kiểm thử tốt giúp bạn quay trở lại trạng thái tự tin.

Điều buồn cười là tôi giỏi hơn AI trong việc tìm ra một số trường hợp biên từ tài liệu. Tôi sẽ đọc tài liệu của AWS, nghĩ rằng "liệu điều đó có thực sự đúng không?", yêu cầu AI viết các bài kiểm thử, và sau đó tìm thấy hành vi chỉ tương đương một cách xấp xỉ với tài liệu. Khi tôi hướng AI vào tài liệu và yêu cầu nó tìm trực tiếp các trường hợp biên, nó lại không làm tốt lắm.

Điều đó nói lên một điều quan trọng về vai trò của con người. Tôi vẫn phải suy nghĩ như một người kiểm thử. Tôi phải đặt câu hỏi về độ dài bằng không, độ dài bằng một, độ dài 10.001 và những góc khuất nơi các hệ thống thường dễ bị hỏng. Tác nhân có thể giúp biến sự nghi ngờ đó thành các bài kiểm thử có thể thực thi, nhưng sự nghi ngờ vẫn là điều quan trọng.

Đừng bao giờ bỏ qua các bài kiểm thử không ổn định (flaky tests)

Các bài kiểm thử không ổn định là một trong những phần thú vị nhất của dự án. AWS hội tụ về sự thật theo thời gian, và điều đó đã gây lãng phí rất nhiều thời gian. Nhưng quy tắc cứng của tôi rất đơn giản: không bao giờ để các bài kiểm thử không ổn định tồn tại với AI. Hãy sửa chúng ngay lập tức.

Lý do là các tác nhân có thể học sai bài học từ văn hóa xung quanh các bài kiểm thử không ổn định. Đôi khi có cảm giác như dữ liệu huấn luyện nói với mô hình rằng các nhà phát triển không sửa các bài kiểm thử không ổn định, vì vậy nó nên bỏ qua chúng. Tôi phải nhắc nhở nó rằng trong cơ sở mã nguồn này, chúng tôi sửa các bài kiểm thử không ổn định, và điều này đã được viết trong các chỉ dẫn dành cho tác nhân.

Sự nguy hiểm là rất rõ ràng. Nếu một bài kiểm thử thất bại không liên tục, tác nhân có thể quyết định rằng hệ thống bên ngoài đã thay đổi, hoặc bài kiểm thử không đáng tin cậy, hoặc triển khai nên tiếp tục thay đổi để phù hợp với nhiễu. Điều đó hoàn toàn ngược đời. Hãy sửa bài kiểm thử trước.

Các bài kiểm thử nhanh giúp điều này trở nên khả thi. Tại thời điểm bài nói chuyện, tôi có khoảng 5.000 bài kiểm thử chạy trong khoảng hai phút. Hai phút là giới hạn chấp nhận được của tôi. Khi các bài kiểm thử chạy nhanh, bạn có thể chạy chúng nhiều lần và bạn sẽ tìm thấy các lỗi không ổn định sớm hơn. Đối với các điều kiện hiếm gặp, tôi cũng chạy các bài kiểm thử lặp đi lặp lại qua đêm trên nhiều máy.

Đây là một nơi mà AI thực sự hữu ích. Nó rất giỏi trong việc sửa các bài kiểm thử không ổn định nếu bạn đặt đó là nhiệm vụ và từ chối để sự không ổn định trở thành điều bình thường.

Các bài kiểm thử không thể cho bạn biết điều gì?

Các bài kiểm thử là thiết yếu, nhưng chúng không cho bạn biết mọi thứ. Đôi khi chúng có thể tìm thấy các lỗi tranh chấp (race conditions), đặc biệt là khi chúng nhanh và chạy thường xuyên. Chúng có thể giúp ích với nhiều dạng hành vi. Các bài kiểm thử fuzz và kiểm thử dựa trên thuộc tính (property-based tests) đã tìm ra vấn đề cho tôi. Việc hỏi AI xem chúng ta nên có những loại bài kiểm thử nào sau khi xảy ra lỗi thường tạo ra những ý tưởng kiểm thử mới hữu ích. AI có rất nhiều kiến thức nền tảng về các loại kiểm thử khác nhau.

Nhưng các bài kiểm thử không tự động tìm ra các vấn đề bảo mật. Chúng không quyết định liệu kiến trúc của bạn có tốt hay không. Chúng không cho bạn biết những gì bạn đã không đo lường. Nếu bạn không thể quan sát một thứ gì đó, bạn không thể thực sự kiểm thử nó.

Điều đó khiến tôi suy nghĩ kỹ hơn về khả năng kiểm thử (testability). Bất cứ thứ gì cung cấp cho bạn tín hiệu từ "hộp đen" đều hữu ích. Nếu có tín hiệu, hãy nắm bắt nó. Nếu API công khai không cung cấp đủ, hãy xây dựng các giao diện quản lý, báo cáo hoặc backend cho phép bạn hiểu hệ thống tốt hơn.

Một điều tôi hối tiếc là không xây dựng thêm các giao diện quản lý và báo cáo đó sớm hơn. Tôi tập trung mạnh vào API công khai vì đó là thứ tôi đang cố gắng sao chép và là nơi tôi có nguồn đối chiếu hữu ích. Nhưng hành vi nội bộ cũng quan trọng, và càng nhiều tín hiệu có cấu trúc mà bạn có thể phơi bày, thì việc kiểm thử và gỡ lỗi càng dễ dàng hơn.

Tại sao khả năng quan sát lại quan trọng đến vậy?

Truy vết (tracing) trở nên cực kỳ hữu ích. Tôi đã để AI xây dựng một khung truy vết được duy trì thủ công, và ngay cả điều đó cũng đủ để thay đổi quy trình gỡ lỗi. Nó không cần phải được tích hợp vào một hệ thống quan sát sản phẩm để trở nên có giá trị.

Lý do rất đơn giản: khi bạn đưa cho AI một lỗi hiếm gặp mà không có cách tái hiện, nó có thể lãng phí rất nhiều thời gian. Nó có thể thất bại trong việc tái hiện vấn đề, đoán cách sửa hoặc thực hiện một thay đổi hợp lý nhưng thực tế không giải quyết được vấn đề.

Khi tôi có thể đưa cho nó một bản truy vết từ lần chạy qua đêm và nói: "điều này đã xảy ra, chúng ta cần sửa nó", công việc đã thay đổi. Bản truy vết cung cấp cho nó thứ gì đó cụ thể để suy luận. Nó có thể cố gắng tái hiện cùng một điều kiện, so sánh hành vi và thu hẹp vấn đề thực sự thay vì đoán mò. Việc AI đoán cách sửa thường không chính xác, nhưng với một bản tái hiện, nó có thể viết ra bản sửa lỗi đúng.

Công việc tối ưu hiệu năng cũng có bài học tương tự. AI hành xử rất giống con người khi làm kỹ thuật hiệu năng. Nó có thể thử một cái gì đó có vẻ như sẽ giúp ích, và sau đó thay đổi đó hoặc không làm gì cả, hoặc làm mọi thứ tồi tệ hơn. Điều đó không sao nếu bạn coi công việc đó là rẻ và có thể loại bỏ. Nếu nó không cải thiện hiệu năng, hãy vứt bỏ nó và thử thứ khác.

Justin Cormack
Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ Tessl: Sản phẩmBlog. Liên kết bài gốc ở phía trên. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.