Mistral AI: News (Web)
92

Thủ thuật

Mistral chia sẻ kinh nghiệm dùng AI Agent chuyển đổi 40.000 dòng mã Fortran 77 sang C++

(giờ Việt Nam)

Tóm tắt AI

Mistral đã hỗ trợ một công ty năng lượng châu Âu hiện đại hóa hệ thống mô phỏng cũ kỹ bằng cách dùng AI Agent chuyển đổi 40.000 dòng mã Fortran 77 sang C++, đồng thời đúc kết quy trình thực hiện hiệu quả.

Bản dịch AI

Modernizing complex legacy code with AI agents.

Các cơ sở mã nguồn khoa học kế thừa (legacy) tích lũy qua nhiều thập kỷ, và khi các tác giả ban đầu rời đi, kiến thức ẩn chứa trong mã nguồn trở nên khó khôi phục. Hơn nữa, việc sử dụng các ngôn ngữ không có hệ sinh thái nhà phát triển tích cực đồng nghĩa với việc bỏ lỡ cơ hội phát triển dựa trên công trình của người khác. Mistral đã giúp một nhà điều hành năng lượng châu Âu chuyển đổi 40.000 dòng mã Fortran 77 sang C++, đây là một trình mô phỏng bể chứa đòi hỏi tính toán vật lý chuyên sâu, không có bộ kiểm thử (test suite) và không có tài liệu tập trung.

Vượt xa hơn việc dịch mã trong hiện đại hóa mã nguồn kế thừa.

Dịch cú pháp từ ngôn ngữ này sang ngôn ngữ khác là một nhiệm vụ phần lớn đã được giải quyết. Yêu cầu bất kỳ mô hình gần đây nào dịch một đoạn mã từ một ngôn ngữ không quá xa lạ sang ngôn ngữ khác, khả năng cao sẽ đạt được kết quả chấp nhận được chỉ sau vài lần lặp. Tuy nhiên, việc di chuyển toàn bộ hệ thống từ một ngôn ngữ thủ tục sang C++ hướng đối tượng tạo ra nhu cầu tái cấu trúc kiến trúc, khiến nhiệm vụ này trở nên không hề đơn giản.

Fortran 77 được chuẩn hóa vào năm 1977, đúng như tên gọi của nó, và mã nguồn viết bằng ngôn ngữ này phản ánh trực tiếp những hạn chế đó: không có module, không có namespace, không có kiểu dữ liệu cấu trúc. Trạng thái (state) nằm trong các khối COMMON—bộ nhớ toàn cục được chia sẻ trên toàn bộ chương trình. Các biến được định kiểu ngầm định theo chữ cái đầu tiên của chúng, vì vậy một cái tên bị viết sai chính tả sẽ âm thầm tạo ra một biến mới thay vì gây ra lỗi trình biên dịch.

Đối với một ví dụ đơn giản nhưng mang tính minh họa, hãy xem xét cách triển khai khai triển Taylor bậc nhất dưới đây. Các đầu vào và đầu ra là các biến toàn cục trong một khối COMMON, và IC là một số nguyên chỉ vì tên của nó bắt đầu bằng một chữ cái nằm giữa I và N. Tên biến khá khó hiểu vì độ dài của chúng bị giới hạn ở mức 6 ký tự.

SUBROUTINE GASDEN

INCLUDE 'common.h'

DO 10 IC = 1, NCELL

10 RHOG(IC) = ROG(IV) + DROG(IV)*(P(IC)-PTAB(IV))

END

Trong C++, người ta có thể tận dụng các kiểu dữ liệu tường minh, viết mã hướng đối tượng và trả về giá trị thay vì ghi vào biến toàn cục:

double gasDensity(const GasProperties& gas, double pressure) {

size_t i = lookup(gas.pressure, pressure);

return gas.density[i] + gas.slope[i] * (pressure - gas.pressure[i]);

Các mảng COMMON phân tán trở thành một tham số GasProperties duy nhất và vòng lặp lưới được chuyển ra ngoài cho hàm gọi, vì vậy không có sự tương ứng dòng-theo-dòng để kiểm tra, đây chính là điều khiến việc xác minh quá trình di chuyển trở nên khó khăn.

Những khác biệt về cấu trúc này, cộng với yêu cầu tích hợp các khung tính toán khoa học hiện đại như PetSc, đã đặt ra một vài câu hỏi quan trọng ngay cả trước khi bắt đầu di chuyển:

Làm thế nào để chứng minh cơ sở mã nguồn đã di chuyển khớp với mã nguồn kế thừa về mặt số học?

Làm thế nào để chia nhỏ quá trình di chuyển thành các phần có thể quản lý được?

Làm thế nào để sử dụng tốt nhất các tác nhân tự hành (autonomous agents) nhằm tăng tốc quá trình?

Xây dựng một bộ khung đối chiếu (parity harness) trước khi di chuyển mã nguồn kế thừa.

Trước khi để các tác nhân hoạt động, chúng tôi cần một cách để chứng minh hai cơ sở mã nguồn khớp với nhau. Ở đây, "khớp" có nghĩa là sự bằng nhau về mặt số học của các đầu ra—cả kết quả cuối cùng và một tập hợp các điểm trung gian quan trọng được các kỹ sư bể chứa của khách hàng đánh dấu.

Chúng tôi đã thêm:

các chương trình con cho phép xuất trạng thái của cơ sở mã nguồn Fortran

một khung kiểm thử để tải các điểm kiểm tra (checkpoints) vào C++

các tệp Skill.md để hướng dẫn các tác nhân sử dụng chúng một cách chính xác

Trong các quy trình di chuyển, các tác nhân đã thực hiện thành công việc đo đạc cơ sở mã nguồn Fortran để kết xuất các bản chụp trạng thái và sử dụng khung kiểm thử C++ để xác minh tính đúng đắn của các module đã di chuyển.

Việc xây dựng phần này của bộ khung trước là một khoản đầu tư mang lại lợi ích ròng cho dự án: nó giúp các lần chạy tác nhân dài an toàn hơn, và sự tương đương về số học là một lập luận dễ xác minh và thuyết phục để chứng minh một đoạn mã đã được di chuyển thành công. Chúng tôi tin rằng đây nên là một trong những bước đầu tiên cho bất kỳ dự án hiện đại hóa mã nguồn nào.

Ví dụ dưới đây minh họa điều này. Trước tiên, chúng tôi chèn một dòng vào mã Fortran để kết xuất giá trị của biến RHOG (42.71834 trong lần chạy này), sau đó sử dụng chính giá trị đó làm điểm kiểm tra tham chiếu khi kiểm thử module C++ đã di chuyển.

Sử dụng các tác nhân AI để hiểu và lập tài liệu cho các cơ sở mã nguồn kế thừa.

Tài liệu của dự án nằm rải rác trong các tệp PDF cũ và các chú thích bị chôn vùi trong chính mã Fortran, và một trong những thành công phụ lớn nhất của toàn bộ nỗ lực này là đối chiếu tài liệu này và di chuyển nó đến cạnh mã nguồn.

May mắn thay, mã thủ tục như Fortran có một đặc tính thuận tiện: toàn bộ chương trình có thể được vẽ dưới dạng một cây gọi hàm (caller-callee tree) duy nhất. Chúng tôi đã tạo ra cây đó bằng cách phân tích cơ sở mã nguồn với một trình phân tích cú pháp tùy chỉnh, sau đó sử dụng Vibe CLI để khởi chạy hơn một trăm tác nhân nhằm lập tài liệu cho nó. Mỗi tác nhân có thể lấy các tệp PDF liên quan thông qua các thư viện tài liệu và Mistral OCR.

Bắt đầu từ các lá của cây và đi ngược lên trên, mỗi nút khởi chạy một tác nhân phụ để lập tài liệu cho nó và mở một PR (Pull Request) tới kho lưu trữ gốc. Một tác nhân đánh giá chạy trong một vòng lặp theo lịch trình cron sẽ tìm kiếm các PR mới mở, đánh giá chúng và lên lịch các tác vụ sửa lỗi khi cần thiết.

Sử dụng các tác nhân AI để hiện đại hóa mã nguồn.

Trong lần thử nghiệm đầu tiên, chúng tôi trao cho các tác nhân sự tự chủ hoàn toàn: một tác nhân cho mỗi chương trình con Fortran, mỗi tác nhân dịch chức năng của nó sang C++ một cách độc lập trong suốt một tuần. Kết quả là mã nguồn hoạt động được, nhưng không thể gọi đó là hiện đại hóa mã nguồn. Các khối COMMON trở thành các struct toàn cục, theo kiểu một-đối-một. Luồng điều khiển dựa trên GOTO vẫn còn nguyên vẹn thay vì được tái cấu trúc thành các vòng lặp hoặc các lệnh trả về sớm. Nó trông giống như Fortran được gõ lại bằng cú pháp C++ hơn là mã nguồn đã được hiện đại hóa.

Trong lần thử nghiệm thứ hai, chúng tôi giải quyết vấn đề này bằng cách cung cấp cho các tác nhân cấu trúc thay vì chỉ sự tự chủ: một người lập kế hoạch, một lập trình viên, một người kiểm thử và một người đánh giá chất lượng mã cùng làm việc trên mỗi module. Chất lượng mã đã cải thiện đáng kể so với lần đầu tiên. Nhưng độ phức tạp của mã nguồn cuối cùng cũng làm khó các tác nhân. Chúng gặp lỗi, thử vài cách sửa và bị đình trệ, không có ai can thiệp.

Chúng tôi đã đi đến một giải pháp trung gian: một con người vận hành quy trình làm việc gồm các tác nhân lập trình viên, kiểm thử và đánh giá, di chuyển cơ sở mã nguồn theo từng module. Điều này bảo toàn chất lượng mã của lần thử thứ hai trong khi vẫn thêm một điểm kiểm tra của con người để giải tỏa các tác nhân khi chúng bị mắc kẹt. Phần tiếp theo sẽ đề cập chi tiết về quy trình làm việc này.

Vận hành các quy trình làm việc của tác nhân AI có cấu trúc cho việc di chuyển mã nguồn phức tạp.

Với cơ sở mã nguồn đã được lập tài liệu và bộ khung đối chiếu đã sẵn sàng, phần thú vị còn lại là điều chỉnh mức độ tự chủ mà chúng tôi có thể trao cho các tác nhân trong khi vẫn nhận được mã nguồn có thể hợp nhất (mergeable). Chúng tôi đã thử cả hai thái cực, từ các lần chạy hoàn toàn tự động đến các phiên làm việc thủ công được giám sát chặt chẽ. Quy trình làm việc có cấu trúc dưới đây là nơi chúng tôi đã chốt lại cho trường hợp sử dụng này.

Làm việc với các kỹ sư bể chứa của khách hàng, chúng tôi đã sử dụng cây gọi hàm để xác định các module độc lập—các cây con khép kín có kích thước vừa phải (theo kinh nghiệm là dưới ~10.000 dòng Fortran). Mỗi module đều trải qua cùng một quy trình làm việc:

AI AgentLập trìnhHiện đại hóa mã nguồnMistralKỹ thuật phần mềm
Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ Mistral AI: News (Web). 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.