Bỏ qua để vào nội dung chính
Tool-call hỏng khiến agent 3-4B im lặng: 5 bug và cách sửa

Tool-call hỏng khiến agent 3-4B im lặng: 5 bug và cách sửa

Bởi Ethan Carter
15 thg 10, 20268 phút đọc

Agent trên model 3-4B hay báo xong mà không làm gì. Năm lỗi thật sự nằm ở parser tool-call, schema bị ẩn và timeout — kèm cách sửa cụ thể.

Bạn trỏ agent vào một model 4B chạy qua llama.cpp trên laptop. Lượt đầu nó gọi tool chuẩn, lượt sau nó báo đã xong — nhưng không file nào được ghi, không lệnh search nào chạy.

Phản xạ đầu tiên là kết luận model quá nhỏ để làm agent. Đội Bees mất gần trọn tháng 8 và tháng 9 để phát hiện phần lớn lỗi nằm trong code của chính họ, và năm lỗi dưới đây là những lỗi tốn thời gian nhất — kèm cách sửa bạn kiểm tra được ngay hôm nay.

Lỗi 1: agent báo xong, nhưng không có gì chạy

Model local đầu tiên Bees thử là Nanbeige 4.2 3B. Lượt đầu nó gọi tool hoàn hảo, sau đó run kết thúc: không báo lỗi, không kết quả.

Nguyên nhân cần một request hai lượt mới tái hiện được. Nanbeige gửi tool call đầu tiên dưới dạng JSON, nhưng khi history đã có một tool result, nó chuyển sang kiểu XML. Theo bài viết, llama.cpp khoá parser vào format phát hiện được đầu tiên, nên tool call lượt hai không bao giờ được parse: nó quay về dưới dạng text thuần trong content, với finish_reason: stop và tool_calls: null. Với agent loop, đó chính là tín hiệu "tôi làm xong rồi".

Đây không phải lỗi thiếu cờ --jinja — cờ đó đã bật mặc định trong build của họ. Cùng model còn một vấn đề nấp phía sau: catalog pin nó ở context 8k, trong khi prompt agent đo được 8.567 token, nên đoạn code tính kích thước context không bao giờ chạy.

Cách sửa: ngừng dùng model không giữ nổi một format tool-call xuyên suốt run. Bees chuyển sang Qwen3 4B Instruct. Bài học áp dụng cho mọi stack: khi một run "không làm gì", đọc raw reply trước khi đổ lỗi cho prompt hay model.

Lỗi 2: prompt nhắc tool mà model không hề được thấy

Request đầu tiên của một planning agent nặng khoảng 22k token, trong đó 15,6k chỉ là schema của 79 tool — không vừa một laptop chạy context 16k. Nên phần lớn schema nằm sau một search tool, nạp 4 schema khớp mỗi lần.

Hai thứ hỏng với model nhỏ. Thứ nhất, nó search theo từ ngữ của task chứ không theo capability: được giao lấy 5 tin hàng đầu, nó search, không khớp gì, rồi kết luận run này không có tool nào. Một run khác nó search "nepal news in nepali api", khớp một add-on không liên quan, và báo y hệt. Model lớn sẽ thử lần hai; model 4B coi câu trả lời đầu là sự thật.

Thứ hai, nặng hơn: prompt mâu thuẫn với danh sách tool. Prompt nói các tool đã liệt kê là sẵn sàng gọi và chỉ search khi không tool nào làm được việc, rồi hai dòng sau lại bảo model gọi tool delegation và knowledge — hai tool không nằm trong danh sách. Model lớn nhận ra và đi tìm; model nhỏ tin harness rồi dừng. Bug đó khiến tám model local "trượt" một bài test nội bộ trên một tool chúng chưa từng được trao.

Cách sửa là một đợt quét: grep mọi tên tool mà prompt và thông báo lỗi nhắc tới, đối chiếu với tập tool model thực sự nhìn thấy. Thứ nào được nêu tên mà bị ẩn đều là bug. Tool không thể hoạt động thì ẩn hẳn — web search của họ cần key, thiếu key thì mọi lời gọi đều fail, nhưng model vẫn gọi vì nó còn trong danh sách.

Lỗi 3: cap schema giết run dài một cách ngẫu nhiên

Search tool giữ 8 schema nạp gần nhất và bỏ cái cũ nhất. Tool vẫn chạy sau khi schema bị bỏ — chỉ phần mô tả rời khỏi prompt.

Trong một run email dài, sau 14 lần search, model gọi một browser tool đã nạp từ lâu. Adapter đối chiếu tên với danh sách của lượt đó, không thấy, ném "unknown tool" và giết cả run. Sự cố này xảy ra trên một model lớn chạy qua Claude Code, nhưng nó trúng mọi model.

Model không sai: nó nhớ một tool có thật. Lỗi là đội phát triển đã coi một cache miss trong prompt là vi phạm protocol. Cách sửa: adapter cho lời gọi đi tiếp — tool tồn tại thì chạy; model bịa tên thì nhận lại một tool error bình thường và tự phục hồi được.

Lỗi 4: model thinking vượt timeout của service

Có giai đoạn mọi lần save bộ nhớ của Bees đều fail với "Extraction failed". Memory service dùng model local để rút fact ra khỏi text, và model đó là Qwen3.5 4B — với chat template bật, nó thinking mặc định.

Nó viết 2.000 đến 8.500 token suy nghĩ cho mỗi lần trích fact, ở khoảng 30 token/giây, vượt xa timeout 300 giây. llama.cpp lại chỉ có một slot nên mọi lần save khác xếp hàng phía sau; khi laptop rơi sâu vào swap, output tụt còn khoảng 1 token/giây.

Sửa bằng đúng một field: bridge gửi chat_template_kwargs: { enable_thinking: false } cho các lời gọi memory. Cùng tác vụ đó hạ còn 1,8 giây và 43 token. Nếu bạn chạy reasoning model local sau bất cứ thứ gì có timeout, kiểm tra mặc định của nó trước.

Lỗi 5: prompt không ràng buộc model nhỏ — hãy ép bằng code

Sau tất cả các fix trên, model nhỏ vẫn đi đường tắt. Một run báo đã viết report trong khi file rỗng. Một summary mô tả lần search chưa từng xảy ra. Một model hỏi người dùng câu chỉ có đúng một đáp án rồi treo run. Một model kẹt vòng lặp phát lại y nguyên batch cũ. Prompt đã có luật cấm tất cả — nhưng model nhỏ đọc luật như một gợi ý.

Nên bước nộp kết quả giờ kiểm tra công việc thay vì tin mô tả: deliverable được nêu tên phải tồn tại và có nội dung, file rỗng không tính; summary không được nêu tool mà run chưa từng gọi (họ ghi lại mọi tool call thật nên check này gần như miễn phí); câu hỏi chỉ có một lựa chọn bị từ chối; delegation lặp chính xác batch trước bị từ chối.

Chi tiết đáng chú ý nhất: một model lớn hơn nhiều cũng thử đủ những đường tắt đó. Các check chặn lại, rồi nó làm thật. Vậy đây không phải nạng cho model nhỏ — đó là cách harness lẽ ra phải hoạt động từ đầu.

Vậy dùng free API thay vì chạy local?

NVIDIA Build cho gọi model hosted miễn phí qua endpoint https://integrate.api.nvidia.com/v1, wire format giống OpenAI chat completions, mở cho thành viên NVIDIA Developer Program và không cần thẻ. Theo một phân tích điều khoản công bố ngày 15/10/2026, có ba ràng buộc đáng cân.

Trần thực tế vào khoảng 40 request mỗi phút cho một key, dùng chung cho mọi model; moderator của NVIDIA trả lời trên forum rằng "there is no official way to circumvent this rate limit or to receive a rate limit increase on that same tier". Bản Trial Terms of Service tháng 10/2025 nói "not in production" ở hai chỗ, clause 1.2 và 1.4. Clause 3.3(iv) ghi NVIDIA thu thập, không định danh người dùng cụ thể, "User Content and Generated Content to improve NVIDIA products and services, including AI models" — tác giả bài phân tích đọc điều khoản này thành: hãy coi như mọi thứ bạn gửi đều có thể vào một tập training.

Catalog cũng đổi liên tục. Vẫn theo bài viết đó, MiniMax đã rời catalog, GPT-OSS-120B chỉ còn bản 20B, còn DeepSeek V4 Pro và bản V4 Flash gốc bị deprecate ngày 7/8/2026 mà không có thông báo trước. Quy tắc rút ra: đừng hard-code model id, hãy query /v1/models lúc khởi động và luôn có fallback.

Đọc theo nhu cầu: free API hợp để đánh giá model trước khi trả tiền, và cho một agent đơn luồng chấp nhận thỉnh thoảng dính 429. Model local hợp khi bạn chạy liên tục, fan-out nhiều agent song song, hoặc dữ liệu không được rời máy.

Bốn việc làm được trong tuần này

  • Khi một run "im lặng", log raw reply và kiểm tra finish_reason cùng tool_calls trước khi đổi model.
  • Grep tên tool trong toàn bộ prompt và thông báo lỗi, đối chiếu với danh sách model thực sự nhận được.
  • Tắt thinking cho mọi lời gọi nền có timeout, rồi đo lại thời gian và số token.
  • Chuyển các luật quan trọng nhất trong prompt thành check ở bước nộp kết quả.

Thứ đáng theo dõi tiếp: nếu bạn dựa vào một free tier, catalog model có thể đổi giữa hai lần deploy — hãy để việc chọn model thành cấu hình đọc lúc khởi động, không phải hằng số trong code.

Không spam, hủy đăng ký bất kỳ lúc nào.

Bài viết liên quan