Khi AI viết code: Xây dựng ứng dụng AI có khả năng tiến hóa
Khi các tác nhân AI có thể viết code trong vài giờ, câu hỏi đặt ra không còn là làm sao tạo ra ứng dụng chạy được, mà là làm sao xây dựng hệ thống có thể bảo trì và mở rộng. Bài viết phân tích vai trò của kiến trúc nền tảng, scaffold tái sử dụng và các nguyên tắc kỹ thuật phần mềm đối với nhà khoa học dữ liệu.

Trong thần thoại La Mã, Janus là vị thần của cổng, cánh cửa, ngưỡng cửa, sự khởi đầu và chuyển tiếp. Tháng Một (January) được đặt theo tên ông. Janus thường được mô tả với hai khuôn mặt — một nhìn về phía sau và một nhìn về phía trước.
Hình minh họa về hai góc nhìn của kỹ thuật phần mềm
Khi xây dựng phần mềm cùng các trợ lý AI, tầm nhìn hai chiều này ngày càng trở nên quan trọng. Với các tác nhân lập trình hiện đại, việc tạo ra một nguyên mẫu hoạt động chỉ mất vài giờ. Code trở nên rẻ hơn để sinh ra, dễ sửa hơn và nhanh hơn để lắp ghép. Nhưng tốc độ này cũng đẻ ra một vấn đề mới: khi code được tạo nhanh mà không có cấu trúc rõ ràng, dự án sẽ trở nên khó hiểu, khó bảo trì và khó mở rộng.
Từ notebook đến ứng dụng: cơ hội và cái bẫy
Đối với các nhà khoa học dữ liệu, sự thay đổi này đặc biệt đáng chú ý. Những ứng dụng trước đây đòi hỏi sự hỗ trợ đáng kể từ kỹ sư phần mềm nay có thể được tạo nguyên mẫu bằng ngôn ngữ tự nhiên và tác nhân AI. Việc chuyển từ notebook và thử nghiệm sang API, giao diện và ứng dụng đã triển khai trở nên dễ tiếp cận hơn.
Nhưng sinh ra một ứng dụng chạy được và thiết kế một hệ thống có thể tiến hóa là hai thách thức hoàn toàn khác nhau.
Rủi ro không chỉ nằm ở chỗ code hôm nay lộn xộn. Rủi ro sâu xa hơn là dự án không có ký ức về những bài học kiến trúc trong quá khứ và không có chỗ cho sự thay đổi trong tương lai. Một tác nhân AI có thể thêm hàm, tạo file, nối endpoint hay tích hợp framework rất nhanh. Nhưng nếu không có cấu trúc rõ ràng, nó có thể đặt logic ở bất cứ đâu thuận tiện nhất tại thời điểm đó — trong endpoint, trong một đối tượng đặc thù của framework, trong một hàm phụ trợ, hoặc trong một file lẽ ra không nên gánh trách nhiệm ấy.
Nếu AI có thể viết code, chúng ta còn cần hiểu điều gì để thiết kế phần mềm trường tồn?
1. Đường cơ sở kiến trúc: cho dự án AI một điểm khởi đầu
Một đường cơ sở (baseline) cho dự án một phiên bản rõ ràng. Nó định nghĩa chúng ta biết gì, chúng ta chấp nhận điều gì là điểm xuất phát hiện tại, và những nguyên tắc nào các vòng lặp tương lai phải giữ gìn.
Điều này đặc biệt quan trọng trong phát triển có AI hỗ trợ. Nếu không có kiến trúc thống nhất, không có ranh giới xác định và không có mẫu hình đã thiết lập, mỗi lần lặp có thể bẻ hệ thống theo một hướng khác. Ngay cả khi nhóm sử dụng file luật cho Cursor, Claude hay Codex, những chỉ dẫn đó cũng không thể thay thế một đường cơ sở kiến trúc.
Các cơ chế này vẫn hữu ích vì giúp tác nhân hiểu quy ước cục bộ và sinh code nhất quán hơn. Nhưng chúng phát huy tốt hơn khi đã có sẵn một cấu trúc để tuân theo.
Đối với nhà khoa học dữ liệu, đường cơ sở phụ thuộc vào loại ứng dụng. Một luồng công việc dạng tác nhân có thể cần ranh giới rõ ràng cho công cụ, quản lý trạng thái, phân quyền và kiểm toán. Một hệ thống xử lý tài liệu có thể tách phân loại, trích xuất, kiểm tra và duyệt thủ công. Một dịch vụ dự đoán có thể tách xử lý đặc trưng, suy luận mô hình, giám sát và cơ chế dự phòng.
Mục tiêu không phải áp đặt một kiến trúc duy nhất cho mọi dự án, mà là giữ gìn các nguyên tắc kỹ thuật có thể tái sử dụng, đồng thời giữ ứng dụng độc lập với công nghệ cụ thể.
2. Những lựa chọn kiến trúc nhà khoa học dữ liệu nên biết
Có nhiều cách tổ chức một hệ thống phần mềm, và mỗi lựa chọn giải quyết một mối quan tâm khác nhau. Vấn đề bắt đầu khi ứng dụng lớn lên mà không có ranh giới, trách nhiệm hay quy tắc phụ thuộc rõ ràng.
Điều này đặc biệt phổ biến khi chuyển từ notebook và script thử nghiệm sang ứng dụng production. Suy luận mô hình, tiền xử lý, kiểm tra, logic API, truy cập cơ sở dữ liệu, quy tắc nghiệp vụ và tích hợp bên ngoài có thể nhanh chóng đan xen vào nhau. Ứng dụng vẫn chạy, nhưng thay mô hình, đổi cơ sở dữ liệu hay kiểm thử từng thành phần trở nên ngày càng khó.
Kỹ thuật phần mềm cung cấp những nguyên tắc đã được kiểm chứng:
- Tách biệt mối quan tâm (Separation of Concerns) và nguyên tắc SOLID: giúp tổ chức trách nhiệm, giảm ghép nối và giữ các thành phần tập trung, dễ mở rộng, dễ thay thế.
- Kiến trúc sạch (Clean Architecture) và kiến trúc lục giác (Hexagonal Architecture): bảo vệ logic ứng dụng khỏi các phụ thuộc bên ngoài như cơ sở dữ liệu, framework, nhà cung cấp mô hình và dịch vụ bên thứ ba.
- Cổng (ports), bộ chuyển đổi (adapters) và tiêm phụ thuộc (dependency injection): biến ranh giới kiến trúc thành cơ chế thực tế, cho phép thay thế triển khai mà không đụng đến logic nghiệp vụ.
Hãy hình dung một ứng dụng dự đoán phụ thuộc vào một nhà cung cấp mô hình, một cơ sở dữ liệu và một framework API cụ thể. Nếu những phụ thuộc ấy bị nhúng thẳng vào logic dự đoán, việc thay đổi bất kỳ thành phần nào cũng có thể đòi hỏi sửa khắp ứng dụng. Bằng cách đưa vào giao diện và bộ chuyển đổi rõ ràng, hành vi cốt lõi vẫn ổn định trong khi các thành phần bên ngoài tiến hóa độc lập.
Nguyên tắc tương tự áp dụng cho luồng công việc dạng tác nhân. Một tác nhân không nên cần biết chi tiết triển khai của mọi công cụ, cơ chế lưu trữ hay dịch vụ bên ngoài mà nó dùng.
Các tiếp cận kiến trúc bổ trợ cho nhau
Một đường cơ sở AI thực dụng có thể kết hợp vertical slicing để tổ chức các năng lực liên quan, Clean Architecture để bảo vệ logic cốt lõi, Hexagonal Architecture để kết nối logic đó qua cổng và bộ chuyển đổi, cùng dependency injection để giữ các triển khai có thể hoán đổi cho nhau.
Mục tiêu không phải tuân theo một kiến trúc cụ thể một cách máy móc, mà là hiểu trách nhiệm nào nên ổn định và thành phần nào nên được tự do thay đổi.
3. Mẫu thiết kế như những viên gạch LEGO
Kiến trúc phần mềm định hình dáng tổng thể của hệ thống: ranh giới trách nhiệm, quy tắc phụ thuộc và sự tách biệt giữa logic ổn định với công nghệ hay thay đổi. Nhưng quyết định kiến trúc cuối cùng phải được chuyển thành code. Đây là lúc các mẫu thiết kế (design patterns) phát huy tác dụng.
Hãy coi mẫu thiết kế như những viên gạch LEGO: khối xây dựng tái sử dụng, giúp hiện thực hóa quyết định kiến trúc mà không phải phát minh lại giải pháp cho những vấn đề lặp đi lặp lại.
Ví dụ, nếu muốn thay nhà cung cấp LLM mà không viết lại ứng dụng, một Adapter có thể cô lập phần triển khai đặc thù của nhà cung cấp. Nếu muốn kiểm thử logic nghiệp vụ mà không kết nối cơ sở dữ liệu thật, giao diện Repository kết hợp Dependency Injection có thể tách lưu trữ khỏi hành vi ứng dụng. Nếu cần nhiều chiến lược chọn mô hình, mẫu Strategy giúp các lựa chọn ấy hoán đổi cho nhau.
Các mẫu khác như Factory và Registry giúp tạo, cấu hình và khám phá thành phần mà không cần mã hóa cứng mọi triển khai vào ứng dụng.
Những mẫu này không dành riêng cho phát triển AI. Chúng là thực hành kỹ thuật phần mềm đã được thiết lập, trở nên đặc biệt giá trị khi xây dựng ứng dụng cùng tác nhân lập trình. Thay vì liên tục yêu cầu tác nhân phát minh ra cấu trúc tích hợp mới, chúng ta có thể cung cấp những mẫu hình và quy ước quen thuộc để định hướng triển khai.
Mục tiêu không phải đưa vào càng nhiều mẫu càng tốt. Trừu tượng hóa quá mức có thể khiến một ứng dụng đơn giản trở nên phức tạp vô cớ. Giá trị nằm ở việc nhận ra vấn đề lặp lại và áp dụng tập mẫu nhỏ nhất giúp giữ ranh giới rõ ràng, khả năng kiểm thử và tính linh hoạt.
Kiến trúc định nghĩa ranh giới. Mẫu thiết kế cung cấp vật liệu để hiện thực chúng.
4. Từ đường cơ sở đến scaffold và harness
Hiểu nguyên tắc kiến trúc là hữu ích, nhưng áp dụng chúng nhất quán qua nhiều dự án lại là thách thức khác. Nhà khoa học dữ liệu thường phát triển ứng dụng có nền tảng tương tự nhau: endpoint API, dịch vụ suy luận mô hình, quản lý cấu hình, ghi log, kiểm thử, tích hợp bên ngoài và hạ tầng triển khai. Tái tạo những thành phần này cho mỗi dự án mới vừa tốn thời gian vừa tạo ra sự thiếu nhất quán.
Đây là lúc scaffold trở nên giá trị.
Đường cơ sở kiến trúc định nghĩa nguyên tắc, ranh giới và quy ước mà dự án nên tuân theo. Scaffold biến những quyết định đó thành cấu trúc khởi đầu tái sử dụng, với module, giao diện, cấu hình, kiểm thử và điểm mở rộng được định sẵn. Thay vì bắt đầu từ repository trống hay yêu cầu tác nhân AI phát minh toàn bộ cấu trúc ứng dụng, lập trình viên bắt đầu từ một nền tảng đã tích hợp sẵn các thực hành kỹ thuật đã được thiết lập.
Các công cụ như Cookiecutter, Copier hay Plop có thể tự động hóa quy trình này. Template engine sinh cấu trúc dự án ban đầu từ cấu hình định sẵn, còn những generator chuyên biệt có thể thêm thành phần lặp lại như endpoint API, adapter, repository hay test khi ứng dụng lớn lên.
Tuy nhiên, scaffold không nhất thiết chỉ giới hạn ở việc sinh ứng dụng một lần. Xung quanh nó, một generation harness có thể điều phối cách dự án được cấu hình, khởi tạo, mở rộng và kiểm chứng. Điều này có thể bao gồm schema cấu hình, generator, hook trước và sau sinh code, thiết lập phụ thuộc, định dạng và kiểm tra tự động.
Ví dụ, một hook trước sinh code có thể kiểm tra tên dự án và tùy chọn cấu hình, trong khi hook sau sinh code có thể đăng ký thành phần, khởi tạo phụ thuộc, định dạng code hoặc chạy test. Những công cụ như OpenAPI Generator có thể bổ trợ scaffold bằng cách sinh giao diện API và client code từ hợp đồng đã thiết lập.
Tác nhân AI lập trình thêm một lớp linh hoạt nữa. Chúng có thể sinh triển khai đặc thù theo miền nghiệp vụ mà template cố định không mô tả hết được — chẳng hạn một luồng phát hiện gian lận mới, một thành phần trích xuất tài liệu hay một dịch vụ suy luận mô hình.
Nghiên cứu gần đây về kỹ thuật harness mang đến góc nhìn thú vị cho thực hành đang hình thành này. Galster và cộng sự đã khảo sát cơ chế cấu hình cho các công cụ lập trình dạng tác nhân trên 2.853 repository GitHub, nhận diện những cách tiếp cận như file ngữ cảnh, skill và subagent. Phát hiện của họ cho thấy lập trình viên đang bắt đầu chính thức hóa chỉ dẫn và năng lực tái sử dụng dành cho tác nhân lập trình.
Điểm khác biệt quan trọng: generator tất định cung cấp cấu trúc dự đoán được, còn tác nhân lập trình cung cấp tính linh hoạt bên trong cấu trúc đó. Những thay đổi sinh ra sau đó có thể được đánh giá bằng kiểm tra phụ thuộc kiến trúc, kiểm chứng schema, linting, kiểm tra kiểu, quét bảo mật và test tự động.
Quy trình phát triển tái sử dụng từ đường cơ sở kiến trúc đến production
Ngoài sinh code, harness cho tác nhân lập trình có thể cung cấp chỉ dẫn, skill, plugin và công cụ bên ngoài tái sử dụng, giúp tác nhân hiểu và sửa ứng dụng đang có. Ví dụ, các công cụ như CodeGraph có thể phơi bày cấu trúc codebase, phụ thuộc và tác động thay đổi qua MCP, cung cấp ngữ cảnh có cấu trúc cho tác nhân trước khi sửa đổi. Những năng lực này bổ trợ cho scaffolding bằng cách hỗ trợ phát triển vượt ra ngoài giai đoạn thiết lập dự án ban đầu.
Trong khi generation harness chuẩn hóa cách ứng dụng được tạo và mở rộng, coding agent harness tổ chức ngữ cảnh, năng lực và cơ chế kiểm soát sẵn có cho tác nhân trong quá trình phát triển. Cùng nhau, chúng kết nối nền tảng kiến trúc tái sử dụng với triển khai do AI hỗ trợ.
Cách tiếp cận này không loại bỏ quyết định kỹ thuật hay đảm bảo mọi thành phần sinh ra đều đúng. Thay vào đó, nó giảm thiết lập lặp lại và tạo môi trường nhất quán hơn để lập trình viên cùng tác nhân AI xây dựng, kiểm thử và tiến hóa ứng dụng.
Kết luận: kỹ thuật quan trọng hơn bao giờ hết
Tác nhân AI lập trình đang thay đổi cách phần mềm được xây dựng. Những công việc từng đòi hỏi hàng giờ triển khai nay có thể giao cho hệ thống có khả năng sinh code, sửa repository, chạy test và đề xuất giải pháp hoàn chỉnh.
Nhưng khiến code dễ sinh ra hơn không đồng nghĩa với việc khiến phần mềm dễ thiết kế hơn.
Vẫn cần có người quyết định cách tách biệt trách nhiệm, phụ thuộc nào chấp nhận được, thành phần nào nên giữ khả năng thay thế, và hệ thống tiến hóa thế nào mà không phá vỡ hành vi hiện có. Với nhà khoa học dữ liệu đang bước ra khỏi thử nghiệm để phát triển ứng dụng, hiểu những quyết định này trở nên ngày càng quan trọng.
Đây là nơi đường cơ sở kiến trúc, scaffold tái sử dụng và harness hội tụ. Đường cơ sở ghi lại quyết định kỹ thuật và bài học kinh nghiệm. Scaffold chuyển chúng thành cấu trúc khởi đầu thực tế. Generation harness tự động hóa và kiểm chứng công việc phát triển lặp lại, trong khi coding agent harness cung cấp chỉ dẫn, năng lực, công cụ và cơ chế kiểm soát định hướng triển khai do AI hỗ trợ.
Tuy nhiên, những cơ chế này không nên thay thế tư duy kiến trúc. Chúng nên khiến tư duy ấy trở nên rõ ràng hơn, tái sử dụng được nhiều hơn và dễ kiểm chứng hơn. Nếu không, chúng ta có nguy cơ tự động hóa không chỉ việc sinh code mà cả việc tích lũy sai lầm kiến trúc.
Quay lại với Janus, kỹ thuật tốt đòi hỏi nhìn về phía sau để giữ gìn điều đã học và nhìn về phía trước để dự liệu điều có thể thay đổi. Mục tiêu không phải sinh ra nhiều code hơn, hay thậm chí sinh code nhanh hơn, mà là xây dựng những ứng dụng vẫn dễ hiểu, dễ bảo trì và dễ thích nghi khi yêu cầu, công nghệ và đội ngũ tiến hóa.
Càng dễ viết code bao nhiêu, việc thiết kế kỹ thuật cho những gì chúng ta xây dựng càng trở nên quan trọng bấy nhiêu.

