Thủ thuật
Hãy ngừng sử dụng OpenCode ngay lập tức
(giờ Việt Nam)
Tóm tắt AI
OpenCode tiềm ẩn rủi ro bảo mật nghiêm trọng và hiệu năng kém do lỗi quản lý bộ nhớ đệm LLM, khiến các phiên làm việc bị gián đoạn liên tục.
Bản dịch AI
Nếu bạn chưa biết OpenCode là gì, hãy tưởng tượng một chiếc ủng đang giẫm lên mặt người mãi mãi. Chiếc ủng đó được làm từ TypeScript, còn khuôn mặt chính là tất cả những gì chúng ta đã học về bảo mật và phần mềm hệ thống kể từ khi máy tính điện tử ra đời vào những năm 1940. Những người tạo ra nó mô tả đây là một AI coding agent. Theo những gì tôi biết, đây là coding agent mã nguồn mở phổ biến nhất, hiện đang có 161 nghìn sao trên GitHub.
Tôi đã thử nghiệm OpenCode với một LLM chạy cục bộ. Kết luận của tôi là OpenCode giống như một chiếc xe hề chạy bằng rác thải công nghệ với tư thế bảo mật kiểu “để tôi cúi xuống cho bạn làm gì tùy thích”. Bất cứ ai đang sử dụng nó nên dừng lại ngay.
Bài viết này có hai phần: những điều gây khó chịu và những điều đáng báo động. Phần thứ hai dài hơn. Tôi viết bài này dựa trên mã nguồn của OpenCode phiên bản git baef5cd4.
Tôi không coi bất kỳ nội dung nào trong bài viết này là một thông báo lỗ hổng bảo mật. OpenCode về cơ bản là một công cụ web-stack dùng để điều hướng llm | bash, và tất cả các vấn đề tôi mô tả đều nằm ở phần “đường ống” (pipe) đó. Cách nó thất bại thật thú vị ở tính chất phân mảnh trong việc ra quyết định kém cỏi, nhưng kết quả thì đã được định đoạt từ trước.
Tôi đã cố gắng tách biệt việc thảo luận về cách sử dụng LLM với việc liệu tất cả những người dùng LLM có nên để máy tính của họ bị khai thác dễ dàng hoặc vô tình bị xóa sạch dữ liệu hay không. Có một phần tái bút với vài suy nghĩ ngắn gọn về các LLM cục bộ.
Bài viết này đột nhiên nhận được sự chú ý. Đã có đủ thay đổi giữa phiên bản baef5cd4 (phiên bản mới nhất khi tôi viết bài này) và 743f6410 (HEAD hiện tại) đến mức sẽ là không trung thực nếu không đề cập đến chúng. Đây là những thay đổi liên quan mà tôi biết:
Ngoài thông báo cập nhật này, bài viết được giữ nguyên như bản gốc. Nhiều quan điểm vẫn còn giá trị; việc một bot GitHub tự động đóng các báo cáo bảo mật vì "cũ" là điều gây sốc, và nó đã xảy ra không chỉ một lần.
Các nhà phát triển OpenCode hiện đang làm việc trên phiên bản 2, có vẻ là một bản viết lại hoàn toàn. Chúc họ đạt được kết quả tốt nhất với bản phát hành này.
Những điều gây khó chịu
Hãy tạm gác vấn đề bảo mật sang một bên và xem xét cách OpenCode thất bại như một công cụ ngay cả khi nó không khiến bạn gặp rắc rối. Có một kiểu "Hiệu ứng Bethesda" với OpenCode, nơi không thể phân biệt được đâu là lỗi và đâu là tính năng được thiết kế, vì vậy tôi gọi chung là "gây khó chịu".
Trượt bộ nhớ đệm prompt (Prompt Cache Misses)
Hầu hết các máy chủ LLM cục bộ đều sử dụng một biến thể nào đó của API OpenAI /v1/chat/completions. Ý tưởng là:
Bạn gửi một JSON blob chứa toàn bộ cuộc trò chuyện cho đến thời điểm hiện tại thông qua phương thức POST.
Bạn nhận lại một luồng các sự kiện SSE cộng dồn thành phản hồi.
Chi phí tải lên trong một phiên làm việc tăng theo hàm bậc hai, và việc tải xuống bị khuếch đại do phải bao bọc các thay đổi nhỏ (deltas) trong JSON với siêu dữ liệu lặp đi lặp lại. Các lệnh gọi công cụ (tool calls) sử dụng kỹ thuật “mã hóa JSON kép” khó hiểu để chúng có thể được tuần tự hóa thành nhiều delta mã hóa JSON, sau đó lắp ghép lại thành nhiều JSON hơn.
Thiết lập này có một lợi ích là máy chủ không lưu trạng thái (stateless). Như thường lệ, cách để làm cho những thứ không trạng thái trở nên nhanh chóng là: sử dụng trạng thái. Máy chủ lưu trữ bộ nhớ đệm các đánh giá. Khi nhận được yêu cầu, nó sẽ:
Tìm tiền tố khớp dài nhất đã được lưu trong bộ nhớ đệm.
Đánh giá từ cuối tiền tố đến cuối tin nhắn được gửi gần nhất (“prefill”).
Tạo các token mới cho đến khi gặp token kết thúc chuỗi.
Tôi đã sử dụng Qwen3.6-27B dense trên chip M4 Max, vốn có băng thông bộ nhớ khá tốt (~0,5 TB/s, cao đối với SoC CPU, thấp đối với GPU). Việc tạo token ở mức dùng được nhưng lại cực kỳ tốn tài nguyên tính toán ở giai đoạn prefill. Nếu máy chủ của tôi không tìm thấy tiền tố khớp tốt cho prompt yêu cầu khi tôi đã đi sâu vào cửa sổ ngữ cảnh, tôi có thể phải đợi 10 phút sử dụng tối đa GPU để nó bắt đầu tạo phản hồi. Điều đó ổn, vì lẽ ra chuyện này hiếm khi xảy ra. Đáng lẽ là vậy.
Dưới đây là một số cách OpenCode đã bỏ lỡ vấn đề này:
Nó quét toàn bộ hệ thống tệp của bạn và đọc lại AGENTS.md (được chèn vào system prompt ở lượt 0) trong mỗi lượt SSE. Nếu bạn thêm một ghi chú nhanh vào AGENTS.md để đọc trong phiên tiếp theo, bạn buộc hệ thống phải đánh giá lại toàn bộ ngay lập tức.
Nó cắt tỉa ngữ cảnh từ các lệnh gọi công cụ ở mỗi lần chuyển đổi từ agent sang người dùng, làm mất hiệu lực một phần lớn của tiền tố.
Việc cắt tỉa chỉ loại bỏ các kết quả gọi công cụ nằm xa hơn một khoảng cách cố định const PRUNE_PROTECT = 40_000 so với vị trí ghi. Trong trường hợp tốt nhất, bạn cũng đang mất 40k ngữ cảnh, tương đương với việc đọc một cuốn tiểu thuyết dài sau mỗi hai hoặc ba lượt.
Việc chuyển đổi từ agent sang người dùng bao gồm cả sự gián đoạn, vì vậy nếu bạn cần kéo "cỗ máy" ra khỏi một ngõ cụt và điều hướng lại, OpenCode sẽ ngay lập tức làm hỏng bộ nhớ đệm prompt và bắt bạn phải chờ phản hồi.
Điều tôi thích nhất: nó đặt ngày hiện tại vào system prompt ở lượt 0 và đánh giá lại trong mỗi lượt SSE. Nếu bạn sử dụng OpenCode vào lúc nửa đêm, bạn sẽ bị trượt bộ nhớ đệm prompt hoàn toàn.
Đây là những lần trượt bộ nhớ đệm prompt chỉ nằm trong danh mục này. Còn nhiều nữa; tôi sẽ chỉ ra khi chúng ta tiếp tục.
Cắt tỉa (Pruning)
Tôi đã đề cập đến việc cắt tỉa ở phần trước. Những lần trượt bộ nhớ đệm prompt không đáng để đánh đổi nên tôi đã tắt nó đi. Vấn đề nhức nhối khác là thiếu sự bảo vệ cho các lần đọc sớm. Có thể không rõ ràng về việc nó hỏng hóc hoàn toàn như thế nào, vì vậy hãy xem xét một ví dụ. Giả sử bạn bắt đầu một phiên mới và bảo "cỗ máy" của mình đọc trước một bản đặc tả hoặc kế hoạch triển khai, sau đó viết mã:
Bản đặc tả được đọc vào ngữ cảnh.
"Cỗ máy" đi đọc mã liên quan, rất có khả năng đẩy nó vượt quá ngưỡng cắt tỉa cố định 40k.
"Cỗ máy" sẵn sàng triển khai, nhưng hoặc là ngay lập tức lao vào một ngõ cụt ngớ ngẩn, hoặc ngồi suy ngẫm (chain-of-thought) về một thứ gì đó thực ra rất đơn giản hoặc đã được chỉ định rõ ràng.
Bạn ngắt quãng "cỗ máy" để điều hướng lại.
Việc ngắt quãng khiến toàn bộ bản đặc tả bị xóa khỏi cửa sổ ngữ cảnh.
"Cỗ máy" viết mã mà không thể tham chiếu đến bản đặc tả.
Việc cắt tỉa áp dụng như nhau cho tất cả kết quả của mọi công cụ ngoại trừ skill, thứ không bao giờ bị cắt tỉa.
Nén (Compaction)
Bạn có muốn ngồi đợi 10 phút trong khi máy chủ LLM prefill toàn bộ phiên làm việc với một prompt mới được thêm vào tiền tố, chỉ để biến nó thành 5 gạch đầu dòng ở đầu một phiên mới không? Tôi cũng vậy. Tôi hiểu mục đích của họ, nhưng tôi chưa thấy nó hoạt động tốt. Cả việc nén và cắt tỉa đều không được triển khai tốt, và chúng tương tác với nhau rất tệ.
Nếu bạn muốn tóm tắt một phiên làm việc, prompt tóm tắt nên được chèn vào cuối để tránh việc prefill lại toàn bộ phiên từ đầu. Phương pháp tốt nhất tôi tìm thấy chỉ là bàn giao rõ ràng bằng cách bảo "cỗ máy" viết ra các ghi chú. Nó hơi xấu nhưng hoạt động tốt hơn cơ chế nén của OpenCode, và tạo ra một tệp tin trên đĩa mà tôi có thể chỉnh sửa hoặc tái sử dụng trong nhiều phiên.
Nén là một sự trừu tượng hóa rò rỉ (leaky abstraction) cố gắng làm cho một cửa sổ ngữ cảnh hữu hạn trông giống như vô hạn. Tốt hơn hết là chấp nhận cửa sổ ngữ cảnh và bộ nhớ đệm prompt như một tính năng hạng nhất trong việc điều khiển "cỗ máy", và cung cấp các nguyên hàm tốt hơn để quản lý chúng. Pi có một cách tiếp cận thú vị ở đây với các cây phiên làm việc (session trees), vốn khai thác bộ nhớ đệm prompt một cách có chủ đích.
Bài viết được AI dịch và tổng hợp tự động từ Hacker News Nổi bật (buzzing.cc bản dịch tiếng Trung). Liên kết bài gốc ở phía trên. Dữ liệu đồng bộ qua API công khai được ghi nguồn tại AI HOT (canonical) ↗. 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.