Cơ chế gọi công cụ của AI hoạt động thế nào chỉ với 40 dòng JavaScript thuần
Bài học giải thích cách các mô hình ngôn ngữ lớn gọi công cụ thông qua một vòng lặp bốn bước đơn giản, không cần framework phức tạp. Tác giả minh họa bằng code JavaScript và Python hoàn chỉnh, đồng thời phân tích chi phí token và bốn nguyên tắc quan trọng giúp tránh lỗi khi xây dựng agent.
Nhiều người mới bắt đầu với AI thường nghĩ rằng mô hình ngôn ngữ có thể tự chạy code hay thực thi hành động nào đó. Thực tế phũ phàng hơn nhiều: mô hình không bao giờ chạy thứ gì cả. Nó chỉ dừng viết văn xuôi, phát ra một khối dữ liệu có cấu trúc gồm tên hàm và tham số JSON, rồi chương trình của bạn — không phải mô hình — mới là thứ thực sự gọi hàm, đọc đĩa, truy vấn cơ sở dữ liệu và gửi kết quả trả về.
Vòng lặp bốn trạm: bản chất của mọi AI agent
Toàn bộ cơ chế gọi công cụ (tool calling) gói gọn trong bốn trạm nối tiếp nhau:
- Tin nhắn — lịch sử hội thoại cộng với danh sách công cụ bạn cho phép
- Mô hình — trả lời bằng văn bản hoặc một khối
tool_use - Code của bạn — chạy hàm thật, gọi mạng, đọc đĩa, truy vấn database
- Kết quả — một khối
tool_resultmang đúng id tương ứng
Trạm 3 là nơi duy nhất mọi thứ thực sự xảy ra, và đó là code của bạn, không phải của mô hình.
Vòng lặp tiếp tục cho đến khi mô hình trả lời bằng văn bản thuần thay vì gọi công cụ. Điều kiện đó — và chỉ có thế — chính là định nghĩa của việc "agent đã xong việc". Không có bộ nhớ, không có module lập kế hoạch, không có framework. Mảng hội thoại chính là trạng thái, và vòng lặp chính là chương trình.
Mô tả công cụ thực chất là một prompt
Bạn khai báo công cụ một lần duy nhất bằng JSON Schema, gồm tên, một câu mô tả và cấu trúc tham số. Mô hình đọc phần mô tả đó giống như đọc mọi thứ khác, rồi tự sinh ra tham số khớp với schema.
Có hai hệ quả quan trọng mà lập trình viên thường bỏ qua:
- Tham số đến dưới dạng JSON, nên hãy parse chúng, tuyệt đối không so khớp chuỗi thô
- Phần mô tả chính là prompt, nên một công cụ bị mô hình dùng sai thường là do bạn mô tả dở
Bạn sẽ dành nhiều thời gian chỉnh sửa một câu mô tả đó hơn là chỉnh sửa vòng lặp.
Code JavaScript hoàn chỉnh, chạy được ngay
Bài học cung cấp code đầy đủ chỉ với ba phần: hàm thật, phần mô tả công cụ và vòng lặp. Dưới đây là phiên bản JavaScript rút gọn:
const client = new Anthropic(); // đọc ANTHROPIC_API_KEY
// 1. công cụ — một hàm bình thường, không có gì đặc biệt
function getWeather({ city }) {
const readings = { Paris: "18°C, mưa nhẹ", Tokyo: "27°C, trời quang" };
return readings[city] ?? `không có dữ liệu cho ${city}`;
}
// 3. vòng lặp — toàn bộ agent nằm ở đây
while (true) {
const reply = await client.messages.create({
model: "claude-opus-5", max_tokens: 4096, tools, messages,
});
messages.push({ role: "assistant", content: reply.content });
if (reply.stop_reason !== "tool_use") break;
// chạy mọi yêu cầu và trả lời mọi yêu cầu
}
Một chi tiết trông có vẻ kỳ lạ: kết quả công cụ được gửi trả với role: "user". Chúng không đến từ người dùng, nhưng đó đơn giản là nơi giao thức đặt chúng — lượt của mô hình, rồi lượt trả lời nó.
Bốn nguyên tắc giúp bạn tiết kiệm cả cuối tuần
Qua quá trình thực hành, tác giả đúc kết bốn quy tắc quan trọng:
- Trả lời mọi lời gọi, kể cả khi thất bại. Nếu hàm của bạn ném lỗi, đừng bỏ kết quả. Gửi lại dưới dạng
tool_resultvớiis_error: true. Mô hình sẽ đọc lỗi và thử lại hợp lý. Một kết quả bị thiếu là vi phạm giao thức; một lỗi được trả về chỉ là thông tin. - Trả tất cả kết quả trong một tin nhắn. Mô hình có thể yêu cầu ba công cụ cùng lúc. Chạy chúng rồi gửi cả ba khối trong một tin nhắn
userduy nhất. Tách ra nhiều tin nhắn sẽ âm thầm dạy mô hình ngừng hỏi song song. - Ghi lại toàn bộ phản hồi. Đẩy nguyên
reply.content, không phải chuỗi bạn tự dựng lại từ nó. - Giới hạn vòng lặp.
while (true)ổn trong bài học, nhưng trong thực tế hãy đếm lượt và dừng ở hai mươi. Một mô hình hiểu sai mô tả công cụ sẽ vui vẻ gọi nó bốn mươi lần.
Chi phí thực tế: con số không hề nhỏ
Một điểm quan trọng mà nhiều người bỏ qua là bạn gửi lại toàn bộ mảng hội thoại trong mỗi lượt. Mô hình không có bộ nhớ giữa các request — mảng chính là bộ nhớ.
Ví dụ cụ thể: một câu hỏi với năm request tiêu tốn 0.3k + 0.9k + 2.0k + 2.9k + 4.2k = 10.3k token đầu vào cho một cuộc hội thoại kết thúc ở 4.2k. Bạn trả gấp 2.5 lần kích thước thứ mình tạo ra.
Giờ hãy thử làm một công cụ phình to. Một read_file trả về file nguồn 8k token ở lượt 2 của agent mười lượt sẽ bị gửi lại trong tám request tiếp theo: 8 × 8k = +64k token, tương đương 0.32 USD chỉ từ một kết quả công cụ. Chạy agent đó một nghìn lần mỗi ngày, bạn đang đốt 320 USD mỗi ngày cho một read_file không bao giờ được cắt gọn.
Hãy cắt gọn kết quả công cụ, không phải prompt. Prompt chỉ gửi một lần. Kết quả công cụ được gửi trong mọi lượt sau đó.
Hai cách khắc phục: trả về ít hơn (dùng dải dòng thay vì cả file, dùng số đếm thay vì dump toàn bộ) và cache tiền tố với cache_control, giúp phần tiền tố lặp lại chỉ tính khoảng 0.1 lần giá đầu vào.
Đánh đổi: tự viết vòng lặp hay dùng SDK
Cả hai SDK chính thức đều chạy vòng lặp thay bạn thông qua tool_runner và decorator beta_tool trong Python, hay toolRunner với betaZodTool trong TypeScript. Chỉ mười dòng thay vì hai mươi, và bốn quy tắc trên được áp dụng miễn phí.
Nhưng bạn đánh đổi quyền kiểm soát luồng. Mọi thứ bạn muốn chèn giữa các lượt — cổng phê duyệt trước khi ghi, log từng lời gọi, đếm lượt riêng — đều phải đi qua hook của runner thay vì một dòng bạn tự thêm vào. Đó là đánh đổi hợp lý trong dự án thực tế, nhưng là đánh đổi tồi khi đang học. Hãy tự viết vòng lặp đúng một lần, để runner không bao giờ khiến bạn bất ngờ.
Bài tập thực hành và bài học tiếp theo
Bài học đề xuất thực hành trong một môi trường ảo với 21 công cụ nối vào hệ thống file ảo trong localStorage của trình duyệt — hoàn toàn an toàn để phá thử. Bạn được khuyến khích:
- Tạo file
notes/paris.mdvới ba dòng về thời tiết, rồi đọc lại - Tắt một công cụ trong TOOLS và yêu cầu nó bất chấp
- Hỏi điều gì đó không công cụ nào đáp ứng được
- Cố tình viết sai
tool_use_idđể xem thông báo lỗi
Hai mươi dòng code, bốn trạm. Đó là toàn bộ khoảng cách giữa một mô hình viết về thời tiết và một chương trình thực sự đi kiểm tra thời tiết. Mỗi công cụ bạn thêm vào từ đây là một việc mà phần mềm của bạn có thể làm thay ai đó — và chọn công cụ nào xứng đáng nằm trong mảng đó mới chính là nghề thực sự.


