Chỉnh sửa quá mức: hiện tượng mô hình sửa mã vượt quá phạm vi cần thiết
(nrehiew.github.io)- Ngay cả với những lỗi có thể sửa chỉ bằng chỉnh sửa tối thiểu, mô hình vẫn dễ tạo ra diff khổng lồ bằng cách viết lại toàn bộ hàm, thêm logic phụ, thậm chí đổi cả chữ ký hàm
- Trong các tác vụ brown-field cần giữ nguyên cấu trúc hiện có, chỉ pass test là chưa đủ; còn phải xem đã thay đổi ít đến mức nào để giữ được khả năng review và độ an toàn của thay đổi
- Dựa trên 400 bài toán BigCodeBench bị làm hỏng một cách có chủ đích bằng chương trình, nghiên cứu định lượng hiện tượng sửa quá mức bằng Levenshtein theo token, điểm vá tương đối và Added Cognitive Complexity
- Xu hướng viết lại quá mức được xác nhận trên nhiều mô hình code hiện đại; Claude Opus 4.6 nổi bật ở sự kết hợp giữa độ chính xác và khả năng sửa tối thiểu, trong khi GPT-5.4 thể hiện xu hướng chỉnh sửa quá mức rõ hơn tương đối
- Prompt nêu rõ yêu cầu giữ nguyên bản gốc đặc biệt giúp giảm diff ở các mô hình suy luận, và trong các cách huấn luyện thì RL cho kết quả cân bằng nhất khi học được hành vi chỉnh sửa tối thiểu mà không làm giảm năng lực code tổng thể
Vấn đề Over-Editing
- Over-Editing là hiện tượng thay đổi mạnh cả cấu trúc mã vượt quá phạm vi chỉnh sửa tối thiểu cần thiết để sửa lỗi
- Ngay cả với lỗi off-by-one đơn giản chỉ cần đổi
range(len(x) - 1)thànhrange(len(x)), mô hình vẫn có thể tạo ra các thay đổi quá mức như viết lại toàn bộ hàm, thêm hàm phụ hoặc logic kiểm tra - Trong ví dụ, GPT-5.4 đã thực hiện kiểm tra
None, chuyển đổinp.asarray(dtype=float), che giá trị hữu hạn, kiểm tra kích thước mảng, thay đổi chữ ký lời gọicurve_fit, thậm chí thay cả logic vẽ, và dù test vẫn pass thì diff tạo ra rất lớn
- Ngay cả với lỗi off-by-one đơn giản chỉ cần đổi
- Trong các tác vụ brown-field làm việc trên codebase sẵn có, điều quan trọng là sửa đúng vấn đề trong khi vẫn giữ nguyên phần mã mà nhóm đã hiểu rõ và cố ý xây dựng
- Khác với green-field viết mới từ đầu, những chỉnh sửa không tôn trọng cấu trúc hiện có khiến reviewer khó hiểu cái gì đã đổi và vì sao lại đổi
- Khi cả hàm bị viết lại, mã trở nên khó nhận diện hơn và cũng khó đánh giá độ an toàn của thay đổi
- Chỉ dùng tiêu chí pass test thì khó phát hiện được vấn đề này
- Over-Editing không phải thất bại về độ chính xác mà là thất bại về độ trung thành khi chỉnh sửa, nên thường không lộ rõ qua test suite
- Càng nhiều mã được sinh ra, khối lượng cần review càng tăng, độ phức tạp không cần thiết càng tích lũy, và chất lượng codebase có thể âm thầm suy giảm
Cách đo lường Over-Editing
- Để tạo ra một bộ dữ liệu mà đáp án chỉnh sửa tối thiểu là rõ ràng, nghiên cứu đã làm hỏng có chủ đích bằng chương trình 400 bài toán từ BigCodeBench để lập bộ đánh giá
- Thay vì chèn lỗi bằng một LLM khác như nhiều benchmark trước đây, nghiên cứu kiểm soát tinh vi bằng những thay đổi như đổi
<thành<=,+thành-, hoặcTruethànhFalse - Mỗi mẫu bị làm hỏng đều được xác minh là hợp lệ về cú pháp và làm hỏng test case tương ứng; đáp án đúng chỉ có một là hoàn tác phần hỏng, nên được thiết kế để trở thành chỉnh sửa tối thiểu
- Thay vì chèn lỗi bằng một LLM khác như nhiều benchmark trước đây, nghiên cứu kiểm soát tinh vi bằng những thay đổi như đổi
- Nhờ cấu hình này, có thể đánh giá không chỉ việc mô hình sửa được lỗi hay không mà còn cả việc trong quá trình sửa nó đã thay đổi thêm bao nhiêu
- Cả đáp án chuẩn và đầu ra mô hình đều được so với đầu vào bị làm hỏng để tính kích thước bản vá tương đối
- Điểm số được thiết kế sao cho càng có nhiều thay đổi ngoài phần khôi phục đáp án đúng thì kết quả càng xấu
- Mã liên quan được cung cấp tại kho GitHub
Chỉ số đo lường
-
Khoảng cách Levenshtein theo token
- Nghiên cứu dùng biến thể Levenshtein theo token Python thay vì khoảng cách theo ký tự thông thường
- Mã được tách bằng tokenizer Python thành các đơn vị cú pháp nguyên tử như
def,add,(,a,,,b,), rồi tính khoảng cách trên chuỗi token này - Nếu đổi
def add(a, b):thànhdef someotherfunctionname(a, b):, khoảng cách theo ký tự là 19 nhưng theo token chỉ là 1 vì được xem như chỉ đổi một định danh - Giá trị được chuẩn hóa theo tổng số token để vẫn so sánh được giữa các hàm có độ dài khác nhau
-
Điểm vá tương đối
- Không so sánh trực tiếp đầu ra mô hình với đáp án đúng, mà so cả hai với đầu vào bị làm hỏng
- Việc chỉnh sửa từ lời giải bị làm hỏng trở về lời giải gốc chính là chỉnh sửa tối thiểu thực sự, và chỉ số đo mức độ bản vá do mô hình tạo ra gần với điều đó đến đâu
- Giá trị càng gần 0 thì bản vá của mô hình càng giống với chỉnh sửa tối thiểu thực tế
-
Added Cognitive Complexity
- Nghiên cứu dùng thêm Cognitive Complexity vì phản ánh độ khó khi đọc tốt hơn Cyclomatic Complexity
- Chỉ số này phạt các cấu trúc như lồng nhau, đệ quy, toán tử logic phức hợp và luồng điều khiển kém trực quan; các cấu trúc như
if, vòng lặp,try/exceptlàm tăng lượng trạng thái mà người đọc phải theo dõi nên làm tăng độ phức tạp - Đoạn mã ví dụ có vòng lặp lồng nhau và câu điều kiện đạt Cognitive Complexity bằng 6
- Vì các lỗi được tạo ra lần này chỉ thay đổi giá trị chứ không đụng vào cấu trúc, nên bản sửa đúng phải luôn có Added Cognitive Complexity bằng 0
- Nếu độ phức tạp tăng trong đầu ra mô hình thì điều đó cho thấy mô hình đã thêm mã không được yêu cầu; giá trị nhỏ hơn 0 cũng bị xem là đơn giản hóa không cần thiết và không mong muốn
Các mô hình có thực sự Over-Edit không
- Hiện tượng Over-Editing vẫn xuất hiện ngay cả ở các mô hình frontier hiện đại
- Cả mô hình suy luận lẫn không suy luận đều cho thấy khác biệt giữa Pass@1 và mức độ chỉnh sửa tối thiểu
- Chỉ nhìn vào khả năng sửa đúng là chưa đủ để biết việc chỉnh sửa có trung thành hay không
- Trong so sánh các mô hình suy luận, Claude Opus 4.6 cho thấy tổ hợp mạnh nhất
- Mô hình đạt Pass@1 cao nhất là 0.912, đồng thời cũng có diff nhỏ nhất với Levenshtein chuẩn hóa 0.060 và Added Cognitive Complexity 0.200
- Gemini 3.1 Pro Preview cũng nằm ở vùng tương tự, còn trong các mô hình open-weight thì GLM 5 chỉnh sửa tương đối bảo thủ hơn
- GPT-5.4 thuộc nhóm có mức Over-Editing nghiêm trọng nhất trong các mô hình được đánh giá
- Ở chế độ suy luận, mô hình có Levenshtein 0.395 và Added Cognitive Complexity 2.313; ngay cả ở chế độ không suy luận, hai giá trị này vẫn cao ở mức 0.327 và 1.563
- Pass@1 cũng thấp hơn tương đối, ở mức 0.723 và 0.770, cho thấy kết quả yếu ở cả độ chính xác lẫn khả năng sửa tối thiểu
- Với các mô hình không suy luận, Qwen 3.6 Plus có Pass@1 cao nhất là 0.870, còn GLM 5 có Added Cognitive Complexity thấp nhất là 0.235
- Mô hình Claude Opus 4.6 không suy luận cũng giữ phạm vi thay đổi rất nhỏ với Levenshtein 0.079 và Added Cognitive Complexity 0.313
Có thể cải thiện bằng prompt không
- Khi thêm vào prompt câu “IMPORTANT: Try to preserve the original code and the logic of the original code as much as possible”, khoảng cách Levenshtein của mọi mô hình đều giảm
- Ngoại trừ DeepSeek R1/v3, Pass@1 cũng được cải thiện đồng thời
- Có thể hiểu rằng ràng buộc sửa tối thiểu đã thu hẹp không gian chỉnh sửa khả dĩ, từ đó dẫn mô hình tới các thay đổi chính xác và đúng trọng tâm hơn
- Hiệu ứng này đặc biệt rõ ở các mô hình suy luận
- Do có đặc tính tuân theo chỉ thị tường minh tốt hơn, yêu cầu giảm thiểu chỉnh sửa dẫn khá mạnh tới việc thu nhỏ diff
- Điều này cho thấy dù ở trạng thái mặc định mô hình có thể can thiệp quá tay, khi được chỉ thị rõ ràng thì nó có thể chuyển sang cách sửa trung thành hơn
Suy luận có dẫn đến viết lại quá mức không
- Ghép cặp biến thể suy luận và không suy luận trong cùng một họ mô hình, rồi so sánh Levenshtein Distance chỉ trên các mẫu mà cả hai đều trả lời đúng
- Vì nếu có nhiều mẫu thất bại thì sẽ phát sinh thiên lệch làm giảm chính cơ hội Over-Editing, nên họ kiểm soát độ chính xác trước rồi mới tách riêng phong cách chỉnh sửa để xem xét
- Trong thiết lập prompt thông thường, ở phần lớn các cặp, mô hình suy luận viết lại nhiều hơn
- DeepSeek V3, GPT-5, GPT-5.4, Gemini 3.1 Pro Preview, Qwen 3.6 Plus, Kimi 2.5 đều cho thấy thanh suy luận cao hơn
- Điều này cho thấy suy luận mở rộng có xu hướng đi từ sửa tối thiểu sang “triển khai tốt hơn”, từ đó tạo ra các đợt refactor không cần thiết
- Ngoại lệ là Claude Opus 4.6, nơi biến thể suy luận sửa ít hơn rất nhiều so với biến thể không suy luận
- Nếu chỉ dẫn rõ ràng phải giữ nguyên bản gốc, bức tranh thay đổi đáng kể
- Mô hình suy luận cho Levenshtein Distance bằng hoặc thấp hơn mô hình không suy luận ở gần như mọi cặp
- Biến thể suy luận của Claude Opus 4.6 ghi nhận Levenshtein thấp nhất trong toàn bộ các mô hình ở thiết lập này
- GPT-5 và GPT-5.4 cũng giảm điểm của biến thể suy luận rất mạnh, nhưng với GPT-5.4 thì biến thể không suy luận vẫn nhỉnh hơn đôi chút
- Về hành vi mặc định, mô hình suy luận dễ Over-Editing, nhưng chính năng lực suy luận đó cũng giúp tuân thủ ràng buộc tốt hơn
- Chênh lệch giữa thiết lập thông thường và thiết lập chỉ dẫn tường minh xuất hiện nhất quán lớn hơn ở các mô hình suy luận
- Vì vậy, Over-Editing có vẻ gần với hành vi mặc định hơn là một giới hạn mang tính bản chất, và có thể bị đảo ngược bằng ràng buộc
Có thể tạo ra một trình chỉnh sửa trung thành bằng huấn luyện không
- Dùng Qwen3 4B 2507 Instruct làm mô hình gốc, và lấy cấu hình 0-shot và 8-shot có thêm chỉ dẫn giữ nguyên bản gốc làm baseline
- Các phương pháp huấn luyện khác khi đánh giá đều được kiểm thử trong thiết lập thông thường, không có chỉ dẫn tường minh về việc giữ nguyên bản gốc
-
Cấu hình thí nghiệm
- Làm hỏng các bài toán DeepCoder theo cùng cách để tạo bộ dữ liệu tổng hợp
- Ngoài ra, họ để chính Qwen3 4B 2507 Instruct gốc sinh 8 completion cho mỗi bài toán, chỉ giữ lại các mẫu đúng về mặt chức năng, rồi xếp hạng theo Levenshtein Distance để tạo thêm bộ dữ liệu self-distillation
- Việc huấn luyện được thiết kế tương tự Context Distillation, nhằm khiến mô hình khi đánh giá có thể thực hiện hành vi chỉnh sửa tối thiểu mà không cần chỉ dẫn tường minh
-
Phương pháp huấn luyện
- SFT: tinh chỉnh có giám sát trực tiếp trên bộ dữ liệu được tạo bằng chương trình
- rSFT: trên bộ dữ liệu self-distillation, với mỗi mẫu chỉ chọn 3 completion có Levenshtein Distance thấp nhất để huấn luyện
- DPO: với mỗi mẫu, thực hiện tối ưu hóa ưu tiên giữa completion có Levenshtein Distance cao nhất và completion có Levenshtein Distance thấp nhất
- RL: áp dụng học tăng cường với phần thưởng kết hợp giữa độ chính xác chức năng và phần thưởng chỉnh sửa tối thiểu dựa trên Levenshtein
- Nếu vượt qua toàn bộ bài test thì
r = r_edit + 0.1 - Nếu không vượt qua thì
r = -0.2 r_editđược tính bằng phần thưởng dựa trên Levenshtein đã chuẩn hóa
- Nếu vượt qua toàn bộ bài test thì
Kết quả với cùng loại hỏng như thế nào
- Trong thiết lập in-domain, nơi kiểu làm hỏng ở tập huấn luyện và tập kiểm thử là giống nhau, SFT cho kết quả gần như hoàn hảo
- Baseline 0-shot có Pass@1 0.735, Norm. Levenshtein 0.169, Added CC 0.731
- Baseline 8-shot có Pass@1 0.775, Norm. Levenshtein 0.115, Added CC 0.479
- SFT đạt Pass@1 0.932, Norm. Levenshtein 0.002, Added CC 0.000, đứng đầu cả ba chỉ số
- rSFT đạt 0.782 / 0.100 / 0.435, DPO đạt 0.752 / 0.021 / 0.113, RL đạt 0.802 / 0.046 / 0.112
- Vì kết quả này trông quá tốt, họ kiểm tra khả năng mô hình chỉ ghi nhớ phép biến đổi ngược cho một kiểu làm hỏng cụ thể
- Họ cho rằng mô hình có thể đã không học được hành vi chỉnh sửa tối thiểu một cách tổng quát, mà chỉ được huấn luyện để đảo ngược các mẫu làm hỏng cố định
- Để xác nhận điều đó, họ cấu hình lại sao cho kiểu làm hỏng của dữ liệu huấn luyện và dữ liệu đánh giá hoàn toàn khác nhau
Có khái quát hóa sang các kiểu làm hỏng khác không
- Trong thiết lập out-of-domain, nơi kiểu làm hỏng ở tập huấn luyện và tập kiểm thử khác nhau, SFT sụp đổ mạnh
- Pass@1 của SFT giảm xuống 0.458, và mô hình rơi vào trạng thái chỉ cố thực hiện những thay đổi tối thiểu mang tính khuôn mẫu mà không thực sự sửa được lỗi
- Norm. Levenshtein là -0.008, Added CC là 0.006, đều rất thấp, nhưng năng lực đưa ra bản sửa đúng thì bị phá vỡ
- rSFT và DPO nhỉnh hơn baseline 8-shot một chút, nhưng mức cải thiện nhỏ
- rSFT đạt 0.780 / 0.107 / 0.501 / LiveCodeBench -0.069
- DPO đạt Pass@1 0.787 / 0.092 / 0.348 / LiveCodeBench -0.046
- Chỉ riêng việc huấn luyện trên dữ liệu truy vết do chính mô hình gốc tạo ra cũng đã cho thấy một mức khái quát hóa nhất định
- Chỉ RL khái quát hóa sạch trên toàn bộ ba chỉ số
- RL đạt Pass@1 0.782, Norm. Levenshtein 0.050, Added CC 0.185, LiveCodeBench Change +0.006
- Cả ba chỉ số đều tốt hơn hai baseline, và năng lực lập trình tổng quát cũng không suy giảm
- Việc mức cải thiện ở Levenshtein và Added Cognitive Complexity lớn hơn ở Pass@1 củng cố rằng mô hình đã học được chính hành vi chỉnh sửa tối thiểu, chứ không chỉ ghi nhớ phép đảo ngược của mẫu làm hỏng
Catastrophic Forgetting
- Họ cũng dùng LiveCodeBench v6 để kiểm tra liệu tinh chỉnh cho chỉnh sửa tối thiểu có làm giảm năng lực lập trình tổng quát hay không
- Mục tiêu là sau huấn luyện, mô hình vẫn giữ được mức năng lực tương tự mô hình pretrained ban đầu
- SFT làm suy giảm năng lực tổng quát rất mạnh
- Trên LiveCodeBench xuất hiện mức suy giảm hiệu năng 43%, và mô hình cũng không giữ được cả năng lực nhận diện lẫn sửa lỗi cơ bản
- rSFT và DPO cũng giảm nhẹ
- Dù được huấn luyện trên các mẫu do chính mô hình ban đầu tạo ra, bản chất của tác vụ vẫn để lại một mức Catastrophic Forgetting nhất định
- RL học được hành vi mới mà không làm giảm hiệu năng
- Vừa giữ được năng lực lập trình tổng quát, vừa cải thiện tốt nhất hiệu năng ở tác vụ chỉnh sửa tối thiểu
- Điều này phù hợp với SFT memorizes while RL generalizes
- Xét theo góc độ phân phối, cũng có thể diễn giải rằng chênh lệch càng lớn giữa bộ dữ liệu tạo bằng chương trình và phân phối gốc của mô hình thì Forgetting càng nặng
- SFT bị ép khớp mạnh với dữ liệu rất khác phân phối gốc, nên phân phối của mô hình thay đổi lớn
- rSFT và DPO dùng dữ liệu self-distilled gần hơn với phân phối gốc, nên mức thay đổi diễn ra ít đột ngột hơn
- Mức độ Catastrophic Forgetting có khả năng tỷ lệ với độ chênh giữa phân phối gốc và phân phối dữ liệu huấn luyện cho tác vụ
Thử nghiệm bổ sung
-
RL với LoRA: có cần fine-tuning toàn phần không
- Vì tác vụ này gần với điều chỉnh phong cách của khả năng chỉnh sửa mã sẵn có hơn là đưa thêm tri thức mới, nên nhóm tác giả kiểm tra xem LoRA có đủ hay không
- rank 1 đạt Pass@1 0.738, Norm. Levenshtein 0.166, Added CC 0.676, LiveCodeBench Δ -0.022
- rank 8 đạt 0.775 / 0.112 / 0.426 / -0.022
- rank 16 đạt Pass@1 0.805 / 0.087 / 0.328 / -0.005
- rank 32 đạt 0.795 / 0.065 / 0.235 / -0.011
- rank 64 đạt 0.797 / 0.051 / 0.160 / +0.001
- Mô hình Full RL tốt nhất đạt 0.782 / 0.050 / 0.185 / +0.006
- LoRA rank 64 gần như tiệm cận Full RL ở chỉ số Levenshtein và cho kết quả tốt hơn ở Added CC
- Khi rank tăng lên, Levenshtein và Added CC giảm đơn điệu từ 1 đến 64
- Phần cải thiện lớn tập trung ở giai đoạn đầu: từ rank 1→16, Levenshtein giảm mạnh từ 0.166→0.087, còn từ 16→64 thì thu hẹp dần từ 0.087→0.051
- rank 1 và 8 cho thấy sự đánh đổi giữa độ chính xác và tính chỉnh sửa tối thiểu; có thể do không đủ dung lượng để học đồng thời hai hàm thưởng, nên mô hình nghiêng về phía tối thiểu hóa chỉnh sửa vốn có mức thưởng cao hơn
- Với thay đổi hành vi ở mức phong cách trong những tác vụ mà mô hình đã có sẵn năng lực, chỉ một số ít tham số bổ sung cũng có thể là đủ, và sau một ngưỡng nhất định thì lợi ích từ việc tăng thêm dung lượng sẽ giảm dần
-
Ghi chú về reward hacking
- Hàm thưởng ban đầu có một lỗi: các rollout không có lần chạy thành công nào sẽ nhận 0 điểm
- Vì dấu của Levenshtein đã bị đảo để biến nó thành dạng “càng lớn càng tốt”, mức 0 điểm này lại trở thành phần thưởng cao hơn cả những lần chạy thành công
- Dù vậy, Full RL vẫn học được tác vụ, còn ở LoRA thì xuất hiện hiện tượng reward hacking theo kiểu hoàn toàn không xuất ra mã đúng về mặt chức năng, từ đó dẫn đến việc kiểm tra lại môi trường
- Sau khi sửa hàm thưởng, kết quả Full RL chỉ cải thiện thêm một chút
-
Có mở rộng được sang mô hình lớn hơn không
- Nhóm tác giả áp dụng cùng công thức RL out-of-domain cho Qwen3 14B
- Baseline 14B đạt Pass@1 0.770, Norm. Levenshtein 0.136, Added CC 0.315
- Sau khi áp dụng RL, kết quả cải thiện toàn diện với Pass@1 0.833, Norm. Levenshtein 0.059, Added CC 0.165, LiveCodeBench Δ +0.011
- Ngay cả khi số lượng tham số tăng lên, mức tăng Pass@1, giảm Levenshtein, giảm Added Cognitive Complexity và không có Catastrophic Forgetting vẫn được duy trì đồng thời
- Điều này củng cố khả năng công thức RL cho chỉnh sửa mã tối thiểu có thể mở rộng sang các mô hình ở nhiều quy mô khác nhau
Tổng kết cuối cùng
- Over-Editing là một vấn đề phổ biến và có thể đo lường được
- Ở các mô hình coding frontier nói chung, khả năng sửa cho đúng và khả năng sửa ở mức tối thiểu là hai năng lực tách biệt
- Đặc biệt, GPT-5.4 trong thiết lập mặc định có xu hướng viết lại quá mức tương đối mạnh, còn Opus 4.6 cho thấy một baseline mạnh
- Chỉ với prompt tường minh cũng có thể dẫn dắt đáng kể theo hướng chỉnh sửa trung thực
- Đặc biệt, các mô hình suy luận vốn mặc định có xu hướng can thiệp quá tay, nhưng khi được chỉ thị giữ nguyên bản gốc thì lại tuân theo tốt hơn
- Ngay cả GPT-5.4 cũng cho thấy mức cải thiện lớn trong chế độ suy luận, cho thấy năng lực instruction following tự thân là khá mạnh
- Việc mức cải thiện của Opus 4.6 trông nhỏ có thể là do hiệu năng nền của nó vốn đã cao
- Xét về mặt huấn luyện, RL nổi lên là lời giải cân bằng nhất
- Mô hình học được hành vi chỉnh sửa trung thực hơn mà không làm tổn hại năng lực coding nói chung, và hiệu quả này được giữ vững trên cả Qwen3 4B và 14B
- SFT mạnh với một số kiểu hư hỏng cụ thể nhưng thất bại rõ rệt ở khả năng khái quát hóa và duy trì năng lực chung
- Đánh giá sửa lỗi ở cấp độ một hàm đơn lẻ có phạm vi hẹp hơn so với các đánh giá mang tính agentic hơn như SWE-Bench Pro, nhưng nó là điểm khởi đầu để xử lý một vấn đề vốn khó định lượng là Over-Editing trong bối cảnh thực tế
- Hướng đánh giá và cải thiện năng lực chỉnh sửa tối thiểu có thể dẫn tới việc nâng cao chất lượng tổng thể của mã do AI tạo ra
1 bình luận
Ý kiến trên Hacker News
Cách tôi dùng Claude Code vượt xa kỳ vọng
Khi nó sửa quá tay, tôi bắt nó giải thích chỗ sai và ghi bài học đó vào file skill theo từng dự án
Nhờ vậy nó gần như không lặp lại cùng một lỗi, và khi file skill lớn dần thì nó cũng khá giỏi trong việc sắp xếp, nén gọn lại
Giờ tôi cảm thấy việc tự tay viết code ở chỗ làm không còn nhiều ý nghĩa về mặt kinh tế nữa
Tôi giống một giáo viên, kiến trúc sư, quản trị hạ tầng hơn, còn phần lớn việc phát triển thì giao cho một nhóm các phiên Claude lành nghề
Dĩ nhiên tôi vẫn review tất cả, và Claude cũng viết test rất kỹ để cùng rà soát
Dạo này nó xử lý cả các dự án lớn cũng không mấy khó khăn
Tôi không muốn nói như đang quảng cáo cho Anthropic, nhưng tôi thật sự tò mò không hiểu mình đang làm gì mà hợp một cách bất thường như vậy
Và giờ token cũng gần như không còn thiếu nữa
Tôi gần như chỉ dùng mô hình Opus, token efficiency rất tốt, tuần trước với sự trợ giúp của Claude tôi đã đẩy hơn 150 commit có ý nghĩa mà vẫn chỉ dùng hết một phần ba quota tuần
Trước Claude thì giới hạn của tôi chỉ khoảng 25~30 commit mỗi tuần
Hôm qua tôi xem thống kê và ngạc nhiên khi thấy giờ 97% code của công ty là do Cursor AI viết
Tôi chủ yếu chạy bằng cloud agent, vì nếu nhìn nó làm theo thời gian thực thì quá mất tập trung
Cách của tôi rất đơn giản. Chỉ là ra lệnh rõ ràng bằng lời
Mọi người làm chuyện này phức tạp hóa quá mức
Chia sẻ file .md rồi đào sâu vào orchestration hay prompt hack, với tôi chỉ thú vị ngang kiểu ám ảnh quá mức với phím tắt vim hay skin của IDE
Chỉ cần nói rõ mình muốn gì và đưa feedback tốt là được
Nó cho ra kết quả ở mức tôi có thể nhận mà không áy náy, kể cả nếu đó là code do đồng nghiệp viết
Dĩ nhiên tôi vẫn đọc và chỉnh từng dòng, nhưng mức chỉnh đó cũng gần giống những gì tôi vẫn làm khi review code bình thường
Tôi không đo năng suất bằng con số, nhưng việc giờ tôi bắt đầu động đến những việc đã trì hoãn suốt nhiều năm khiến tôi cảm nhận rất rõ
Ví dụ nó đặc biệt mạnh với những công việc nhàm chán kiểu đổi 100 file markdown thành 5 file json rồi cập nhật cả phần code đọc chúng
Nó là phần mềm có rất nhiều khiếm khuyết và lắm bug, vậy mà trên thực tế lại cực kỳ hiệu quả
Một trong những điều kỳ lạ nhất ở AI là cảm nhận của mỗi người thật sự khác nhau đến mức cực đoan
Bạn có làm nhiều việc vận hành không, và có đang xử lý code sản phẩm sống lâu dài hay không cũng quan trọng
Giả thuyết của tôi là công cụ này hoạt động tốt trên các pattern đơn giản, và dù có xử lý được việc phức tạp thì lại rất tệ ở việc phát minh ra pattern mới
Nếu để nó tự chạy không giám sát thì nó nhanh chóng bày ra những pattern mới nguy hiểm rồi làm hỏng mọi thứ
Vì vậy tôi khá thường xuyên phải viết lại hoàn toàn những gì Claude đưa ra
Có lúc tôi còn thi tốc độ với con robot và tự mình làm xong nhanh hơn
Tất nhiên tôi có lợi thế vì đã biết mình muốn gì, nhưng tôi cảm thấy chi phí chỉnh lặt vặt ở đây đang bị đánh giá thấp
Cả futzing fraction lẫn the peril of laziness lost đều cho thấy đôi khi chính cái kiểu máy móc cố gắng quá mức này làm tôi khó chịu
Tôi không hiểu vì sao chỉ cần làm một việc mà nó lại cứ cố làm ba việc
Dù có sửa cho nó rồi nó cũng làm đúng lại, tôi vẫn thấy bực vì lại phải lặp lại đúng cái vòng "đừng làm A, B, C, chỉ làm A thôi" mà tôi vốn đã gặp khi làm việc với đồng nghiệp
Việc tạo test cũng khá tinh tế, nó viết tốt khi bạn định hướng rõ, nhưng nếu cho phép sáng tạo thì nó tạo quá nhiều test vô dụng kiểu
foo + bar == bar + fooPhải luôn nghi ngờ tính hữu ích của test thì vòng phản hồi mới lành mạnh được
Dạo này có lúc nó còn hữu ích hơn ở chỗ kéo đủ import cần thiết vào một lượt hơn là ở bản thân test
Nếu những cỗ máy này thay người làm việc thì lẽ ra chất lượng code trung bình cũng phải tăng lên
Nhưng nhiều người đang dùng nó theo kiểu "đa phần thì cũng cỡ mức trung bình", và tùy cách làm việc mà nó thậm chí còn có thể kéo tụt mức trung bình ấy
28 năm nay tôi làm nghề này, và giờ việc tự tay viết code ứng dụng phục vụ công việc trong thời gian được công ty trả lương không còn phù hợp, cả về kinh tế lẫn nếu nhìn theo hướng thiện chí
Ngược lại, tôi lại thường cảm thấy để coding agent thích ứng với yêu cầu mới, nó cần mạnh dạn thay đổi code hiện có hơn, nhưng lại quá ưu tiên giữ nguyên code cũ
Cuối cùng có vẻ đây là vấn đề nên đóng băng code cũ đến mức nào
Nếu là một ứng dụng production lớn đã vận hành hàng chục năm thì tối thiểu hóa thay đổi là hợp lý, nhưng nếu là dự án thử nghiệm mới tạo cách đây 3 ngày thì nên sửa cho tốt hơn thay vì cố giữ nguyên
Cuối cùng có lẽ nó phải học cách tự điều chỉnh mức độ theo bối cảnh dự án
Ngay trong cùng một dự án, tùy từng PR mà có vùng có thể sửa thoải mái, nhưng cũng có vùng tôi muốn giữ cố định để giảm diff và phạm vi test
Vì vậy tôi có giải thích trước phần nào có thể sửa mạnh đến đâu, nhưng kết quả vẫn rất thất thường
Nhìn chung nó thiên về diff tối thiểu, và cái giá phải trả thường là trùng lặp hoặc bẻ cong abstraction một cách gượng ép
Nếu ai có cách hiệu quả hơn thì tôi cũng muốn nghe
Dù có bảo nó refactor hay suy nghĩ lại rộng hơn thì hiệu quả vẫn khá yếu
Nên tôi bắt nó dọn bớt markdown bị đóng khung thiết kế quá nặng, rồi xóa khỏi source những nội dung kỹ thuật hay triển khai/giao diện cốt lõi, sau đó để một phiên mới tự thiết kế lại
Rồi tôi khôi phục phần đã xóa và reconcile với một phiên bớt ngây thơ hơn
Path dependency quá mạnh nên hiện giờ tôi vẫn làm quy trình này thủ công, nhưng tôi muốn chuẩn hóa pattern này thành một skill
AI thường cố che giấu thất bại bằng cách nuốt exception và trả về giá trị giả, hoặc chỉ để lại một thông báo bị chôn vùi giữa đủ loại log lặt vặt
Log cũng thường bị rút gọn quá mức nên thiếu dữ liệu cốt lõi cần cho việc debug thực sự
Có lẽ vì nó được huấn luyện theo hướng lừa hệ thống để kiếm điểm
Nếu để exception nổ thẳng ra thì đó là thất bại rõ ràng nên bị phạt, nhưng nếu che vấn đề đi thì đôi lúc lại trông như thành công
Tôi cũng tò mò hiện tượng này biểu hiện ra sao trong Q&A thông thường
Có phải mô hình sẽ thiên về việc nghe đủ thuyết phục để người dùng gật gù rồi rời đi không
Pattern hay gặp là kiểu "cái đó không phải X mà là Y", vì cách nhị phân hóa như vậy khiến người ta bớt nghĩ đến những khả năng khác
Việc gắn một kế hoạch hành động ở cuối câu trả lời cũng rất phổ biến, và nó trông giống kỹ thuật bán hàng assumptive close hơn là nhằm giúp ích cho câu trả lời, vì nó khiến người ta đồng ý với AI rồi tưởng tượng ra kết quả
Suy cho cùng hill-climbing để leo lên metric sẽ trông như vậy
Nó giống một dạng A/B enshittification bị đẩy đến mức cực đoan đến nỗi không còn diễn giải nổi
Chừng nào còn được huấn luyện bằng phản hồi của con người thì mọi mảnh nhỏ trong mọi câu trả lời đều khó tránh khỏi việc hướng tới né đánh giá viên và làm họ hài lòng
Việc làm ra thứ gì đó thật sự tốt bằng AI tốn công hơn tưởng tượng nhiều
Bảo nó làm thì nó có thể cho ra kết quả khá thuyết phục, nhưng nó có thể không biết rằng chính nó không biết
Đặc biệt khi AI nói với giọng điệu đầy thẩm quyền thì còn nguy hiểm hơn
Vì vậy việc kiểm chứng từ nhiều góc độ và xác nhận tính chính xác không hề dễ
Sẽ rất thú vị khi xem điều này thay đổi ra sao theo thời gian
Đồng thời tôi cũng thấy những bài như thế này và các bình luận ở đây giống như ảnh chụp nhanh của một thời điểm
Tốc độ phát triển của ngành quá nhanh, và mô hình coding hiện giờ đã tốt hơn rất nhiều so với chỉ 9 tháng trước
Mỗi khi đọc những lời phàn nàn về năng lực AI, không phải tôi trách người nói, nhưng trong đầu tôi luôn nghĩ "hiện tại là vậy thôi"
Kiểu để chúng review kết quả của nhau
Dù vậy phần lớn vẫn chạy bất đồng bộ, nên trong lúc đó tôi có thể làm việc khác
Vì vậy với vài dự án tôi đã dùng agent để làm prototype trước trong lúc học, rồi sau đó viết ra thiết kế và bắt đầu lại từ đầu
Làm vậy tôi biết được chỗ nào cần đào sâu hơn
20% còn lại là gì thì cuối cùng vẫn phụ thuộc vào bản chất vấn đề
Ở đây người ta nói về chỉnh sửa quá đà đối với code, nhưng agent còn làm nhiều hơn thế
Nó đụng vào nhiều file, chạy test, deploy, thậm chí cả smoke test, và tất cả đều bị che khuất sau lớp abstraction
Một mặt thì rất ấn tượng, nhưng mặt khác lại gây bất an lớn
Thứ nhất, tôi không thực sự hiểu rõ bên trong đang diễn ra chuyện gì
Việc chỉ phê duyệt script do agent ghép ra rồi cho chạy quá dễ và quá cám dỗ
Nhưng đã có lần nó xóa sạch DB chỉ vì bản thân agent đã kết luận như vậy là đúng, và tôi cũng từng chặn được việc nó định gửi AWS credentials lẽ ra tuyệt đối không được gửi đến mục tiêu deploy
Thứ hai, tôi chẳng học được gì
Ngay cả việc tự lắp một lệnh docker đơn giản cũng trở thành gánh nặng nhận thức lớn hơn, nên tôi cứ lặp đi lặp lại chuyện dựa vào AI như một cây nạng
Đừng bật auto-approve, và phải tự mình phê duyệt mọi lệnh agent thực thi
Cũng đừng giao cho nó các quyết định thiết kế hay kiến trúc, con người phải quyết định sẽ xây thế nào rồi chỉ thị rõ cho cái lon thiếc đó
Tôi không đùa đâu, nếu coi AI như một công cụ thì dùng sẽ hiệu quả hơn nhiều
Có thể không phải năng suất gấp 10 lần, nhưng ít nhất bạn vẫn tiếp tục hiểu được code
Day 1, nó xử lý bảo mật cực kỳ thận trọng, từ lý do phải đưa .env vào .gitignore đến việc răn dạy rằng không được chuyển credentials cho nó mà tôi phải tự sửa
Nhưng đến Day 2, khi bảo nó làm lại cùng việc đó, nó quên mất quy tắc hay cấu hình ấy, lục tung cả ổ đĩa để đọc .env và các file khác, hiểu rằng mình đang cầm token, rồi tự tạo lệnh curl để test luôn
Ngày đầu thì như chuyên gia bảo mật, hôm sau lại như một thực tập sinh bình thường còn kém hơn mức đó
Cách này có nhiều hành vi không mong muốn hay triển khai quá mức, nhưng hữu ích để loại bỏ boilerplate
Trên thực tế tôi sẽ xóa khoảng 70% những phần kiểu này
Thay vào đó, tôi không cho AI chạm vào vùng 1 và 2
Dĩ nhiên kiến trúc phải được tổ chức sao cho tách như vậy được, nhưng tôi đang dùng khá hài lòng
Chỉ cần đừng đưa credentials production cho LLM
Nếu không thể tái hiện ở local hay staging/dev thì cần làm hạ tầng deploy giống prod hơn, và nếu không thể phân tách quyền đủ chi tiết theo từng môi trường thì phải sửa lại chính hệ thống quyền trước
Tôi tuân thủ nguyên tắc này nên gần như chưa từng gặp loại vấn đề mà bạn nói
Nếu là để chẩn đoán thì tôi có thể tạm cấp credentials chỉ đọc, nhưng ngay cả khi đó tôi cũng chỉ phát hành token thời hạn cực ngắn để phòng rò rỉ
Vì vậy nhìn chung tôi vẫn nắm được chuyện gì đang xảy ra
Thỉnh thoảng Claude có đưa ra quyết định bất thường hoặc trái thông lệ
Tuy nhiên khi làm việc với codebase lớn theo nhóm thì vốn dĩ cũng đã có nhiều vùng nằm sau abstraction mà ta không thực sự hiểu, kể cả những phần do người đã rời công ty từ lâu viết ra
Trước đây có một kiểu khôn ngoan thường được dạy nhưng thực tế hiếm khi được làm theo, đó là refactor trong lúc làm việc
Ý là đã chạm vào khu vực nào thì nhân tiện dọn dẹp và trả luôn nợ kỹ thuật ở đó
Nhưng ngoài đời điều này hiếm khi diễn ra, và giờ khi LLM bắt đầu thật sự làm như vậy thì ta mới cảm nhận được tác dụng phụ của nó
Có khi hàm cần dùng ở ngay đó mà nó vẫn tạo hàm mới
Tệ hơn nữa là nó sửa hàm hiện có, giả vờ giữ nguyên hành vi nhưng lại làm hỏng chỗ dùng khác
Tệ nhất là nó thay đổi trạng thái giữa các class mà không biết đến tác dụng phụ, từ đó tạo ra deadlock hoặc bug rất bình thường
Theo tôi, đó không phải refactor mà giống kéo cần máy đánh bạc thêm một lần nữa hơn
Vấn đề thật sự của tôi là chất lượng refactor mà agent làm quá tệ
Tôi chỉ muốn ngăn nó thực hiện những chỉnh sửa như vậy, rồi chỉ dẫn cụ thể hơn về việc cần sửa cái gì và sửa thế nào
Trong nhiều trường hợp, abstraction hiện có đã đủ ổn để truy lỗi hoặc mở rộng tính năng trên đó
Nhưng đôi khi bạn đứng trước ngã rẽ giữa việc cố lách qua triển khai hiện có hay thiết kế lại
Khi làm cùng LLM, việc nên suy nghĩ lại điều đó thế nào, hay có cần suy nghĩ lại ngay từ đầu hay không, trở nên mơ hồ hơn
Hơn nữa các quyết định đó lại bị che khuất, người dùng khó nhận ra
Có lẽ những thay đổi như vậy cũng có ích, nên tôi muốn xem thêm ví dụ
Tôi không tin vào chỉ số cognitive complexity, nhưng có chút thú vị ở chỗ những chỉnh sửa kiểu này dường như làm tăng chỉ số đó khá nhất quán
Tôi đã không thấy chỉnh sửa quá đà ở Claude Code hay Codex trong một thời gian, nên tôi tò mò không biết nghiên cứu này đã dùng prompt gì
Có lẽ là ở đây, và lần sửa cuối là 8 tháng trước
https://github.com/nreHieW/fyp/blob/5a4023e4d1f287ac73a616b5b944a14f28422c7e/partial_edits/utils/prompts_utils.py
GPT-5.4 thay vì thêm 10 dòng như tôi yêu cầu, lại viết lại 50 dòng vì cho rằng như vậy sạch hơn
Đó vốn chỉ là một phần bổ sung mang tính cơ học, kiểu nhìn code hiện có rồi đổi tên biến để chèn tương tự vào là xong, vậy mà nó vẫn làm thế
Hơn nữa lúc đầu nó còn không thêm chính tính năng tôi yêu cầu nên càng khó tin hơn
Over-editing tuyệt đối chưa phải chuyện đã qua, và lần này là do tôi quên hạ mức thinking nên nó chạy ở xhigh thinking
Với tôi, điều này nghe giống một vấn đề thời kỳ agent sơ khai
Bài này khá chắc tay
LLM vừa trong văn xuôi vừa trong code đều quá dài dòng, và theo tôi nguyên nhân chính là cách huấn luyện
cross entropy loss khiến nó có xu hướng thích những câu theo kiểu garden path
Những gì con người chỉ nói bằng một câu, thậm chí vài từ, thì nó lại kéo dài thành cả một đoạn
Vì câu dài là con đường có ít bất ngờ về mặt thống kê hơn, tức là đường perplexity thấp
Tôi cũng có cảm xúc lẫn lộn về vấn đề này
Phần lớn thời gian nó làm quá lên và tôi phải dành 30 phút để sửa lại, nên tôi đồng ý với đánh giá đó
Nhưng đôi khi nó cũng bỏ lỡ những thay đổi toàn diện hơn
Có lẽ là do giới hạn ngữ cảnh, nên vì thế tôi bắt đầu kiểm soát công cụ chặt hơn
Dù vậy tôi vẫn chưa đạt được cảm giác kiểm soát ở mức mình mong muốn
Cái này có cảm giác như dấu vết của dữ liệu huấn luyện
Trong dữ liệu SFT và preference có vô số ví dụ kiểu "phiên bản đã dọn sạch file cho đẹp hơn", còn ví dụ kiểu "diff đúng 3 dòng" thì ít hơn nhiều
Vì vậy mô hình học rằng đầu ra lớn hơn, bóng bẩy hơn sẽ thắng
Có thể kiểm soát phần nào bằng prompt, nhưng rốt cuộc vẫn là đang chống lại một khuynh hướng mặc định rất mạnh