1 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Các đánh giá tác nhân lập trình tự chủ chủ yếu xem xét tỷ lệ hoàn thành tác vụ trên một codebase cố định, nhưng nghiên cứu này tách riêng và đo lường liệu độ sạch của chính mã nguồn có làm thay đổi chi phí khám phá và chỉnh sửa hay không
  • Nghiên cứu xây dựng 6 kho lưu trữ cặp tối thiểu có cùng kiến trúc, phụ thuộc và hành vi bên ngoài, chỉ khác nhau về số vi phạm quy tắc SonarQube và độ phức tạp nhận thức, cùng 33 tác vụ dựa trên kiểm thử ẩn
  • Chạy từng tác vụ bằng Claude Code và Claude Sonnet 4.6 ở cả hai phía của mỗi cặp kho lưu trữ, mỗi phía 10 lần, với tổng cộng 660 thí nghiệm; tác nhân không biết mình đang làm việc trên phía nào của mã
  • Độ sạch của mã không làm thay đổi tỷ lệ vượt qua, nhưng trên mã sạch hơn, các chỉ số tương đương token giảm 7~8% và số lần quay lại tệp giảm 34%
  • Không chỉ mô hình hay prompt, trạng thái của codebase cũng vẫn là một biến số thực tiễn chi phối chi phí tính toán và hiệu quả khám phá của tác nhân

Câu hỏi nghiên cứu và thiết lập vấn đề

  • Tác nhân lập trình tự chủ đang lan rộng nhanh chóng
    • Trong khảo sát 128.018 dự án GitHub năm 2026, chưa đầy một năm sau khi tác nhân thực dụng đầu tiên ra mắt, dấu vết hoạt động của tác nhân đã được phát hiện trong 22~29% dự án
  • Chi phí chạy tác nhân cũng không nhỏ
    • Trên SWE-bench Verified, một tác vụ đơn lẻ dùng trung bình khoảng 4 triệu token với các LLM tuyến đầu
    • Trong tổng mức sử dụng, token đầu vào chiếm phần lớn
  • Các đánh giá hiện có tập trung vào việc có giải được tác vụ hay không trên các benchmark như SWE-bench, và các nghiên cứu gần đây bắt đầu đo cả mức sử dụng tài nguyên cùng với tỷ lệ vượt qua
  • Cách so sánh phổ biến là cố định codebase rồi thay đổi tác nhân hoặc scaffolding
  • Nghiên cứu này làm ngược lại: cố định tác nhân và tác vụ, chỉ thay đổi độ sạch của codebase để so sánh

Độ sạch của mã và cách xây dựng cặp tối thiểu

  • Độ sạch của mã được xem như một tập hợp các đặc tính gắn với mã dễ bảo trì
    • Dễ đọc
    • Độ phức tạp nhận thức thấp
    • Helper được tách bạch tốt
    • Tên gọi rõ ràng
    • Ít mã chết, logic trùng lặp và coupling ngẫu nhiên
  • Nghiên cứu không cố định độ sạch của mã bằng một định nghĩa hình thức nghiêm ngặt, mà dùng số lượng vi phạm quy tắc phân tích tĩnh của SonarQube làm chỉ báo thay thế tương đối
    • Công cụ sử dụng là SonarQube Cloud Enterprise Edition
    • Bộ quy tắc là “default quality gate”
  • Các kho lưu trữ cặp tối thiểu được xây dựng sao cho chỉ khác về độ sạch bên trong, còn các điều kiện sau được khớp nhau
    • Cùng ngôn ngữ và framework
    • Cùng phụ thuộc
    • Cùng kiểm thử hoặc độ phủ kiểm thử tương đương
    • Cùng hành vi bên ngoài
  • Tương đương hành vi được hiểu là đầu ra và chuyển đổi trạng thái có thể quan sát từ bên ngoài giống nhau với cùng một đầu vào
    • Việc xác minh thực tế được thực hiện bằng cách vượt qua cùng một bộ kiểm thử với cùng độ phủ, hoặc vượt qua các cặp kiểm thử đã hiệu chỉnh cho những thay đổi không quan sát được như refactoring

Pipeline tạo cặp tối thiểu: Slopify và Vibeclean

  • Cặp tối thiểu được tạo theo hai chiều
    • Slopify biến kho lưu trữ sạch thành phiên bản lộn xộn hơn
    • Vibeclean dọn dẹp kho lưu trữ lộn xộn
  • Slopify

    • Biến một codebase sạch thành phiên bản như thể đã phát triển mà không có code review hay linting
    • Mục tiêu không phải là mã bị cố ý làm hỏng, mà là một phiên bản lịch sử thay thế khi không có phân tích tĩnh
    • Ba giai đoạn được thực hiện bởi các tác nhân mới khác nhau
      • Build: build kho lưu trữ, bảo đảm kiểm thử vượt qua, rồi cố định lệnh trong build instructions.md
      • Explore: rà soát kho lưu trữ và viết summary.md cho từng thư mục mục tiêu cần dọn dẹp
      • Transform: đưa các vi phạm quy tắc SonarQube vào thư mục được chỉ định, và sau mỗi lượt chạy lại kiểm thử để từ chối các thay đổi làm hỏng
    • Tăng độ phức tạp nhận thức bằng cách inline helper, nhân đôi logic theo từng đường dẫn, thêm mã chết, gộp một số module vào một tệp duy nhất, v.v.
  • Vibeclean

    • Dọn dẹp codebase vốn có nhiều vi phạm quy tắc tự nhiên trong khi vẫn giữ hành vi bên ngoài
    • Danh sách việc cần làm của tác nhân là danh sách issue do bộ phân tích phát hiện, mỗi issue gắn với một phạm vi mã
    • Phạm vi sửa đổi bị giới hạn ở các vấn đề mà bộ phân tích đánh dấu; thiết kế lại toàn bộ không phải mục tiêu
    • Hoạt động theo hai giai đoạn
      • Build: xác nhận lệnh build và kiểm thử, rồi cố định trong build instructions.md
      • Clean: dọn dẹp một cách cơ học các vi phạm quy tắc của bộ phân tích theo từng module, và sau khi xử lý module thì dùng kiểm thử để xác nhận tương đương hành vi
    • Thực hiện các việc như loại bỏ trùng lặp string literal, xóa mã đã bị comment, thay thế idiom collection cũ, loại bỏ nhánh chết
    • Khi bộ phân tích chỉ ra các cấu trúc lớn thực sự, tác nhân thay switch dispatch hơn 200 dòng bằng các helper có tên, hoặc trích xuất helper về tính bền vững từ một lớp 2.800 dòng
    • Tuy nhiên, việc trích xuất có thể phân phối lại độ phức tạp sang nhiều phương thức hơn thay vì loại bỏ nó, và một số cấu trúc lớn nhất vẫn được để là wontfix

Kho lưu trữ benchmark và thiết kế tác vụ

  • Benchmark được xây dựng trên Harbor framework v0.4.0
  • Tổng cộng sử dụng 6 kho lưu trữ cặp tối thiểu
    • 3 kho chủ yếu là Java, 3 kho chủ yếu là Python
    • Một số kho có chứa một lượng nhỏ mã bằng ngôn ngữ khác
    • Gồm 3 kho mã nguồn mở công khai và 3 codebase SonarSource không công khai
    • Các cặp không công khai đóng vai trò chống ghi nhớ, phòng khả năng LLM được đánh giá đã học từ kho công khai
  • Các số liệu chính của phía sạch và phía lộn xộn theo từng kho như sau
    • sonar-sca*: issue 94 / 2.825, mật độ issue 0,73 / 20,66, mật độ độ phức tạp nhận thức 30,6 / 56,5
    • sonar-caas-poc*: issue 16 / 855, mật độ issue 0,61 / 27,16, mật độ độ phức tạp nhận thức 179,8 / 218,9
    • sonarcloud-codedatalake*: issue 199 / 1.319, mật độ issue 4,36 / 34,39, mật độ độ phức tạp nhận thức 34,0 / 216,5
    • commons-bcel: issue 694 / 2.711, mật độ issue 12,60 / 49,46, mật độ độ phức tạp nhận thức 102,8 / 108,3
    • genie: issue 152 / 1.262, mật độ issue 1,28 / 10,81, mật độ độ phức tạp nhận thức 22,2 / 23,5
    • ckan: issue 1.006 / 3.632, mật độ issue 7,54 / 27,50, mật độ độ phức tạp nhận thức 69,3 / 76,5
  • Thiết kế tác vụ tuân theo ba quy tắc
    • Đi qua hotspot: đặt tác vụ sao cho đi qua các vùng mã có chênh lệch lớn về mật độ issue và độ phức tạp nhận thức ở cả hai phía của cặp
    • Mô tả có thể quan sát từ bên ngoài: chỉ cung cấp input, output và kịch bản ví dụ, không cung cấp tên tệp, hàm hay cấu trúc nội bộ
    • Kiểm thử qua bề mặt công khai: chạy kiểm thử ẩn thông qua các giao diện mà ứng dụng cung cấp cho bên gọi như CLI, route HTTP, thư viện/API
  • Việc tạo tác vụ được chia giữa tác nhân và con người
    • Tác nhân so sánh biến thể sạch và biến thể lộn xộn để lập bản đồ khác biệt
    • Một tác nhân khác viết phác thảo tác vụ và khả năng kiểm thử
    • Con người chọn, chỉnh sửa và tuyển chọn các phác thảo hợp lý và thú vị trong số đó
    • Tác nhân thứ ba tạo chỉ dẫn thực tế, kiểm thử ẩn qua bề mặt công khai và implementation tham chiếu dùng nội bộ
    • Implementation tham chiếu phải vượt qua kiểm thử ẩn trên cả hai kho lưu trữ
    • Kho lưu trữ trước khi sửa không được vượt qua kiểm thử ẩn
    • Những tác vụ vẫn không đáp ứng điều kiện sau hai vòng lặp sẽ được con người viết lại hoặc loại bỏ
  • Số tác vụ cuối cùng là 33, chia thành ba track
    • 13 tác vụ hotspot nhận thức: đi qua vùng phức tạp mật độ cao trong một phương thức hoặc một lớp đơn lẻ
    • 14 tác vụ đa module: cần thay đổi trải qua từ hai module trở lên
    • 6 tác vụ hiệu chỉnh: thực hiện tác vụ đơn giản trên cùng một vùng ở cả hai phía để kiểm tra liệu có biến thiên không liên quan đến độ sạch hay không

Thiết lập thí nghiệm và chỉ số đo lường

  • Tất cả thí nghiệm được thực hiện bằng Claude Code với bộ công cụ mặc định
  • Các con số được báo cáo đến từ lần chạy Claude Sonnet 4.6
    • Claude Haiku 4.5 cũng được rà qua trên cùng bộ tác vụ, nhưng bị loại khỏi kết quả chính vì tỷ lệ vượt qua quá thấp nên khó đọc rõ khác biệt footprint
  • Tác nhân chỉ đọc mô tả tác vụ
    • Không nhận thêm mồi nhắc nào về độ sạch của mã
    • Không biết mình đang làm việc trên phía nào của cặp tối thiểu
  • Mỗi tác vụ được chạy 10 lần ở mỗi phía của cặp
    • Tổng số thí nghiệm là 33 × 2 × 10 = 660 lần
  • Mỗi lần chạy được thực hiện trong sandbox container hóa
    • CPU, bộ nhớ, lưu trữ và thời gian đồng hồ thực bị giới hạn
    • Có thể truy cập registry gói công khai
    • Image cơ sở bao gồm toolchain, cache build và dịch vụ theo từng kho lưu trữ
    • Bên trong mỗi cặp, chỉ cây mã nguồn được mount vào /app là khác nhau
  • Có 10 chỉ số được ghi lại
    • Tỷ lệ vượt qua: tỷ lệ kiểm thử ẩn vượt qua ở trạng thái cuối cùng
    • Token đầu vào: số token mô hình đọc qua mọi turn, chủ yếu là nội dung tệp và việc gửi lại hội thoại trước đó
    • Token đầu ra: toàn bộ sản phẩm do mô hình và tác nhân con tạo ra, bao gồm văn xuôi, mã, dấu vết suy luận và lời gọi công cụ
    • Số ký tự suy luận: do Anthropic API không phơi bày riêng token suy luận nên đếm số ký tự văn bản thuần trong các block nội dung suy luận
    • Số turn hội thoại: tổng số lượt trao đổi tác nhân-công cụ
    • Số turn trước lần chỉnh sửa đầu tiên: số turn cần đến trước khi sửa tệp lần đầu
    • Số ký tự trước lần chỉnh sửa đầu tiên: số ký tự hội thoại trong cùng khoảng đó
    • Số tệp đã đọc: số tệp duy nhất đã mở trong quá trình chạy
    • Lần quay lại tệp: số lần đọc lại một tệp đã đọc và chỉnh sửa trước đó
    • Số dòng đã sửa: số dòng mã nguồn bị thay đổi trong patch cuối cùng
  • Lần quay lại tệp xuất hiện trong luồng như đọc → chỉnh sửa → có thể làm việc khác → đọc lại
    • Nghiên cứu diễn giải đây là tín hiệu về sự bất định đối với chỉnh sửa trước đó hơn là khám phá rộng
  • Các chỉ số footprint của tác nhân có thể biến động lớn ngay cả khi lặp lại cùng một tác vụ ở nhiệt độ cố định, nên áp dụng bộ lọc ngoại lệ
    • Trong mỗi tổ hợp (tác vụ, phía), những lần chạy lệch hơn 50% so với trung vị của 10 lần lặp sẽ bị loại trước khi tính trung bình
    • Trên thực tế, 9,7% tổng số lần chạy bị loại
  • Các con số ở cấp dataset được tính bằng trung bình vi mô trên 33 tác vụ
    • Với từng chỉ số, cộng trung bình phía sạch và trung bình phía lộn xộn theo từng tác vụ rồi tính chênh lệch tỷ lệ
    • Riêng tỷ lệ vượt qua được báo cáo bằng chênh lệch điểm phần trăm tuyệt đối giữa phía sạch và phía lộn xộn

Kết quả: tác động đến chi phí khám phá hơn là tỷ lệ thành công

  • Độ sạch của mã không tạo ra thay đổi đáng kể đối với tỷ lệ vượt qua của tác nhân
  • Trên mã sạch hơn, các chỉ số tương đương token giảm 7~8%
  • Số lần quay lại tệp giảm 34%, cho thấy mã sạch có thể giảm chi phí đọc lại ngay cả với cùng một tác vụ
  • Vì vậy, độ sạch của mã có thể được xem là một trục riêng chi phối chi phí chạy tác nhân, bên cạnh lựa chọn mô hình, harness và prompt

1 bình luận

 
Ý kiến trên Hacker News
  • Đây là một câu hỏi thú vị đáng nghiên cứu, nhưng tôi rất hoài nghi về thiết kế thí nghiệm
    Trong thí nghiệm, họ dùng Opus 4.6 để tổng hợp các codebase “bị làm giảm chất lượng” hoặc “đã được dọn dẹp” rồi dùng để so sánh tương đối
    Tệ hơn nữa là họ không kiểm soát việc liệu các bài test của ứng dụng có bị phá hỏng hay không
    “Tỷ lệ vượt qua được tính bằng cách chấm trạng thái cuối cùng của agent theo các bài test ẩn mà chúng tôi viết cho từng tác vụ. Chúng tôi không kiểm tra liệu agent có làm hỏng các bài test không liên quan vốn đã có trong repository hay không; và ngay cả khi lời giải ở phía sạch và phía lộn xộn đều vượt qua các bài test ẩn, chúng vẫn có thể khác nhau ở các bài test không được chấm”
    Nếu không kiểm soát chất lượng của sản phẩm cuối cùng thì các kết luận về lượng token tiêu thụ gần như chẳng có nhiều ý nghĩa

    • Nếu so sánh dự án lộn xộn với dự án có cấu trúc tốt bằng số lượng test thất bại, tỷ lệ thành công có thể bị lệch về phía codebase lộn xộn, vốn nhiều khả năng ngay từ đầu đã có độ bao phủ test và độ vững chắc thấp hơn
      Để so sánh công bằng, cần viết một bộ test duy nhất chạy được trên cả hai dự án trong từng cặp
      Không có nghĩa là nghiên cứu này tốt, nhưng vì việc vượt qua test không nhất thiết tương quan với hiệu quả của agent, nên tôi có thể hiểu quyết định đó
    • Ngay cả khi kết luận có đứng vững, cùng lắm đây cũng chỉ là trường hợp tốt nhất đối với mã bị làm giảm chất lượng
      Nó chỉ cho thấy một tình huống trông có vẻ ổn về mặt chức năng nhưng tốn nhiều token hơn để hoàn thành tác vụ
    • Nếu không kiểm soát việc các bài test của ứng dụng bị phá hỏng thì về cơ bản đây là một nghiên cứu vô giá trị
      Sự mệt mỏi vì AI đã trở nên nhàm chán từ lâu, giờ thì chỉ còn đau đớn mà thôi
  • Theo kinh nghiệm của tôi, chênh lệch hiệu năng của agent là khá lớn giữa một codebase đầy dead code, mã trùng lặp, các nhánh thay thế không thể chạm tới, abstraction bị rò rỉ, các design pattern chưa chín, so với một codebase có luồng dữ liệu rõ ràng, đóng gói tốt và cấu trúc sạch
    Với mã xấu, mọi model tuyến đầu đều phải qua nhiều vòng review code, kiểm tra chất lượng và sửa lỗi; còn với mã tốt, tôi đã thấy chúng làm đúng ngay ở lần thử thứ nhất hoặc thứ hai

    • Những vấn đề như loại bỏ dead code, mã trùng lặp, mã không thể chạm tới đã nêu ở trên từ lâu đã được giải quyết bằng linter xác định trong hầu hết hệ sinh thái ngôn ngữ
      Có thể yêu cầu LLM chạy script kiểm tra các mục này, rồi ép cùng script đó chạy qua hook pre-commit
      Việc cấu hình nghiêm ngặt như vậy trong mọi codebase tôi làm việc đã đem lại hiệu quả lớn nhất cho kiểu lập trình bằng agent
      Tôi có bài viết trình bày chi tiết hơn về các linter tôi dùng ở đây: https://www.balajeerc.info/Use-Deterministic-Guardrails-for-...
    • Tôi đã làm việc với các công cụ này khá lâu, và lần nào cũng thấy chúng có vẻ hoạt động tốt hơn nếu được đối xử như đối xử với con người
      Tôi nghĩ agent cũng tất yếu làm tốt hơn trên codebase sạch so với một codebase khổng lồ hỗn độn
      Cũng giống như chúng làm tốt hơn khi có đặc tả tốt và quyền truy cập tài liệu
    • Khi làm việc với codebase lộn xộn, tôi cũng cảm thấy tương tự
      Đến một lúc nào đó, các pattern kinh khủng cũng bắt đầu lây sang cả tôi
    • Tôi vừa đọc vừa đồng ý, nhưng nghĩ xem vì sao nó lại giống một bình luận tệ, thì thấy những phát biểu mang tính giai thoại như thế này nằm ở phía đối lập với thảo luận khoa học
      Ở đây có một bài báo cố gắng trả lời câu hỏi, còn lời chứng giai thoại chỉ khiến độc giả thiên lệch chứ không thêm giá trị để kết luận khách quan về vấn đề
      Cuộc thảo luận hữu ích nhất sẽ là mọi người đọc bài báo rồi phê bình phương pháp luận hoặc kết quả
    • Đây cũng chỉ gần như là cảm giác, nhưng vì tôi quá lo xa nên thường xuyên làm các lượt refactor và dọn dẹp code, gần như không bao giờ bỏ qua, nên khó nói chắc liệu thực sự có khác biệt hiệu năng hay không
      Tuy vậy, những người phàn nàn rằng LLM không tốt lắm nhìn chung có vẻ là kiểu người sở hữu codebase lộn xộn
  • Mẹo tôi thấy hiệu quả là, nếu là Python, hãy yêu cầu refactor như sau
    “Hãy refactor mã Python để Pythonic hơn. Ví dụ, giảm bớt class và singleton, đặc biệt nếu điều đó giúp cải thiện tốc độ. Mã Python bắt buộc phải tuân theo các tiêu chuẩn tổ chức mã thường được kỳ vọng ở các gói Python mã nguồn mở phổ biến, mà không làm benchmark bị thụt lùi hiệu năng”
    Với mã Rust, tôi đã dùng một biến thể như sau
    “Codebase Rust trong /src đã phình to thành nhiều file dài hơn 1.000 dòng. Hãy refactor codebase Rust theo các tiêu chuẩn tổ chức mã thường được kỳ vọng ở mã Rust mã nguồn mở phổ biến, mà không làm benchmark bị thụt lùi hiệu năng”
    Các prompt như vậy dường như cũng cải thiện hiệu năng của agent vì a) chúng tái cấu trúc mã một cách logic và b) tên file cung cấp gợi ý ngữ nghĩa về vị trí của mã liên quan
    Trong một file phình to 5.000 dòng, agent phải đọc nhiều khối để tìm mã liên quan nên kém hiệu quả
    Hiệu năng benchmark thường cũng tốt hơn sau khi refactor; đặc biệt với Rust có biên dịch thì có vẻ chỉ là tình cờ, nhưng cũng chẳng có gì để phàn nàn

    • Đúng vậy. Chỉ cần yêu cầu công cụ lập trình kiểu agent dọn dẹp codebase, refactor có mục tiêu, áp dụng nguyên tắc SOLID và các thực hành tốt là đã có rất nhiều cải thiện dễ dàng
      Về cơ bản, công cụ lập trình kiểu agent có xu hướng ngại xóa mã. Ngay cả khi bảo nó xóa, nó vẫn tìm mọi cách giữ lại mã cũ hoặc thêm độ phức tạp để đoạn mã đó vẫn có thể tiếp tục được gọi
      Nếu chỉ đang prototyping thì điều này thật sự phiền phức, vì cuối cùng dead code sẽ tích tụ rất nhiều và gây nhầm lẫn khi sau này muốn thêm tính năng
      Một khi biết điều đó, chỉ cần yêu cầu nó loại bỏ legacy là được
      Giữ codebase sạch sẽ sẽ kích thích AI làm đúng việc. Nếu có nhiều test, khi tạo tính năng mới nó sẽ thêm nhiều test hơn; nếu có tài liệu, nó sẽ tự cập nhật mà không cần nói riêng
      Khi code harness được cải thiện, những thứ này sẽ ngày càng được tích hợp sẵn, và cả những người ít kinh nghiệm prompt cũng sẽ dễ đạt kết quả ổn hơn
    • Yêu cầu áp dụng nguyên tắc YAGNI dường như cũng rất hiệu quả trong việc thu gọn codebase
      Thường thì tôi trước hết để nó review và tạo danh sách các mục cần xem xét, rồi cùng xem từng mục để tôi quyết định có/không hoặc đề xuất chỉnh sửa thêm
    • Làm dần dần thì hoàn toàn dễ hiểu, nhưng làm kiểu này một phát cho toàn bộ bất kỳ codebase đang chạy production nào thì có vẻ cực kỳ nguy hiểm
      Đặc biệt nếu không có các bài test end-to-end cẩn thận cho toàn bộ hệ thống
    • Chỉ cần nói “refactor codebase” cũng hoạt động khá tốt
      Dù sao thì tôi đã đưa sẵn các quy tắc style code vào CLAUDE.md rồi
    • Từ bạn đang tìm là idiomatic
  • Cách tiếp cận kiểu “pipeline agent dọn dẹp một kho mã bừa bộn” trông thật tệ, và chỉ riêng điều đó đã đủ để phủ nhận toàn bộ nghiên cứu
    Có vẻ một nửa các cặp tối thiểu trong công trình này được tạo ra theo cách đó
    Tôi hoàn toàn không tin vào kết luận phải giả định rằng kho mã do AI “dọn dẹp” thực sự đại diện cho một codebase tốt

    • Tôi là tác giả thứ nhất. Tôi muốn làm rõ một điều
      Ở đây, “sạch” không phải là yêu cầu agent cứ viết mã tốt hơn
      Chúng tôi đưa danh sách 50–100 vi phạm quy tắc của bộ phân tích tĩnh cùng số dòng mã, rồi yêu cầu loại bỏ chúng
      Sau đó chúng tôi kiểm tra xem các vi phạm quy tắc đã được xử lý chưa
      Việc dùng LLM viết lại mã để loại bỏ các vi phạm như vậy là một thực hành khá được chấp nhận
      Cách tiếp cận one-shot dựa trên LLM hiện có của Sonar [1] đã vận hành hơn một năm, và cách tiếp cận dạng agent gần đây [2] cũng làm khá tốt cùng việc này
      [1] https://www.sonarsource.com/solutions/ai/ai-codefix/
      [2] https://www.sonarsource.com/products/sonarqube/remediation-a...
    • Nếu đó là một kho mã sạch nhưng bị AI làm rối lên thì bạn sẽ tin chứ?
  • Tôi nghĩ hiển nhiên là nó sẽ ảnh hưởng
    Không mô hình nào có thể đưa toàn bộ codebase thực tế vào ngữ cảnh, và phải lướt qua mã như con người
    Tức là tìm kiếm và đọc tệp
    Nếu tệp nằm ở vị trí dự kiến và được đặt bằng cái tên mà mô hình hoặc con người có khả năng tìm trước tiên, thì sẽ tìm thấy ngay lần đầu; nếu không, cần tìm sâu hơn và thử nhiều lần

    • LLM không cần giữ toàn bộ codebase trong ngữ cảnh
      Chỉ cần xem tất cả đường dẫn, bỏ qua những vùng đã xử lý và chuyển sang đường dẫn tiếp theo
      Khá giống cách lập trình viên làm
  • Chúng tôi cũng thấy kết quả tương tự trong một công trình tương tự đang được thực hiện ở NJIT. Chúng tôi gọi hiện tượng này là sự lây lan chất lượng theo ngữ cảnh
    Điểm thú vị ở đây là những tình huống thực tế phổ biến trong ngành: codebase có chất lượng lẫn lộn, codebase pha trộn các mẫu mã legacy với các mẫu “tốt” mới hơn khiến agent nhầm lẫn về quy ước, v.v.
    Thiết kế cặp tối thiểu thực ra là một trong những điểm mạnh, vì nó cố gắng tách riêng yếu tố sạch sẽ khỏi các yếu tố khác như cấu trúc, phụ thuộc và kiểm thử, thay vì so sánh giữa các kho mã
    Tuy nhiên, việc dùng mã “làm rối” do LLM tạo ra thì hơi đáng nghi, vì nó không mang tính cơ học hoặc do con người hướng dẫn
    Phê bình lớn nhất, như những người khác đã chỉ ra đúng, là lựa chọn không kiểm tra toàn bộ bộ kiểm thử. Tuyên bố “tương đương về hành vi” chỉ có giá trị trong phạm vi kiểm thử và độ bao phủ cho phép
    Giả thuyết này thuyết phục vì hai lý do. 1) LLM bắt chước những gì nó thấy trong codebase, nên rác vào thì rác ra là điều hợp lý 2) Nó khớp với trực giác mà nhiều kỹ sư đã có khi dùng các mô hình này trong 1–2 năm qua
    Greenfield hầu như luôn dễ hơn tham gia vào một codebase bận rộn, còn sự lộn xộn xuất hiện từ tích hợp phức tạp và việc duy trì các hệ thống vì mục đích legacy

  • Ngay cả khi agent học được cách xoay xở qua các stub và mã WET do chính nó để lại, bạn có thật sự muốn một codebase mà con người không thể theo dõi điều gì đang diễn ra không?

    • Ngay cả khi agent xử lý mọi thứ, tiếng Anh vẫn mô tả không chính xác những gì mã làm
      Vì vậy cá nhân tôi ít nhất vẫn muốn mã tự kể bằng mã nó đang làm gì
    • Tôi lại từng thấy trường hợp đẩy DRY đi quá xa
      Dù hai hàm nhỏ có logic có thể tách ra thành helper dùng chung, một lập trình viên con người đôi khi sẽ không làm vậy vì biết rằng phép trừu tượng đó sẽ rối rắm và dễ vỡ nếu chỉ cần thay đổi nhẹ một trong hai hàm
  • Thật thú vị khi thấy điều này được lượng hóa
    Cấu trúc sạch dường như làm giảm tải nhận thức cho cả con người lẫn agent, và điều đó giải thích vì sao đặt tên và mô-đun hóa quan trọng hơn ta tưởng

    • Tôi nghĩ chất lượng mã rốt cuộc nên được định nghĩa bằng việc có thể thay đổi mã một cách đúng đắn dễ đến mức nào
      Điều này khó định lượng, nhưng cuối cùng mọi chỉ số chất lượng mã đều cố nắm bắt chính điều đó
      Nhìn theo tiêu chuẩn đó, nếu các chỉ số chất lượng mã được dùng là hợp lý thì kết luận này không quá bất ngờ
      Nếu chỉ số chất lượng tốt trong bối cảnh agent lập trình, thì đây chính là kết quả đáng mong đợi
  • Nhiều token được dùng cho việc khám phá mã: tìm mã hoặc lần theo các điểm gọi để tạo đủ ngữ cảnh thực hiện tác vụ
    Nếu cấp cho agent một dạng quyền truy cập LSP, và với monorepo thì cung cấp hướng dẫn phân cấp bằng các tệp như AGENTS.md, có thể giảm đáng kể lượng token dùng cho việc khám phá
    Nhưng với codebase phân tán, rốt cuộc vẫn cần một dạng khám phá nào đó để giải từng tác vụ
    Và việc khám phá này không chỉ là sử dụng token đơn thuần. Ở mỗi bước lại có độ trễ khứ hồi lặp đi lặp lại: độ trễ của LLM, prefill, decoding, đầu ra được agent phân tích cú pháp, gọi công cụ, phản hồi công cụ, rồi quay lại LLM
    Một phần có thể song song hóa, nhưng trên thực tế phần lớn là tuần tự nên tác vụ trở nên khá chậm
    Để dùng agent hiệu quả, tính cục bộ và cấu trúc là then chốt. Cửa sổ ngữ cảnh luôn bị giới hạn, và sự chú ý bên trong nó cũng không nhất quán

  • Theo kinh nghiệm của tôi, mọi thứ ảnh hưởng đến kỹ sư cũng ảnh hưởng đến agent
    Các abstraction tốt, phương thức có kích thước vừa phải, tên gọi tốt, cấu trúc có nguyên tắc bên trong dịch vụ và giữa các dịch vụ, unit test, tất cả đều thuộc nhóm này
    Trong lịch sử, những thứ này là công việc của kỹ sư, nhằm giúp người khác dễ đóng góp vào mã hơn
    Giờ đây chúng không chỉ giúp người khác, mà còn giúp các agent khác đóng góp vào mã dễ hơn