LLM không can thiệp vào mã nguồn của bạn – chúng chỉ gửi cho bạn một yêu cầu, và bạn mới là người thực thi hàm. Sự thật đơn giản này đã bác bỏ lầm tưởng rằng "mô hình có thể tự gọi hàm Python của tôi một cách thần kỳ", đồng thời buộc các nhà phát triển phải tư duy lại về việc gỡ lỗi (debugging) và bảo mật.
Vòng lặp điều phối (dispatch loop), từng bước một
Khi một mô hình ngôn ngữ lớn (LLM) cần một công cụ, nó tuân theo một trình tự xác định:
- Lập kế hoạch (Planning) – mô hình quyết định cần thực hiện một hành động (ví dụ: "hoàn tiền thanh toán").
- Tạo yêu cầu (Generating a request) – nó xuất ra văn bản có cấu trúc—thường là JSON—để gọi tên công cụ và cung cấp các tham số.
- Phân tích cú pháp (Parsing) – ứng dụng hoặc framework hỗ trợ của bạn sẽ đọc văn bản đó.
- Khớp lệnh (Matching) – framework sẽ tra cứu tên trong danh sách các hàm thực tế mà bạn đã cung cấp.
- Xác thực (Validating) – nó kiểm tra xem các tham số có khớp với schema của hàm hay không và người gọi có được cấp quyền hay không.
- Thực thi (Executing) – hàm đã khớp sẽ chạy trong môi trường của bạn để thực hiện công việc.
- Trả kết quả (Returning) – kết quả được đóng gói và gửi lại cho mô hình để tiếp tục quá trình suy luận.
Hãy coi LLM là người lập kế hoạch, framework là người điều phối, và hàm là người công nhân thực sự thực hiện việc di chuyển dữ liệu hoặc tiền tệ.
Tại sao lầm tưởng về sự "thần kỳ" vẫn tồn tại
Hầu hết các nhà phát triển khi thấy một dòng đầu ra của mô hình trông giống như một lời gọi hàm sẽ mặc định rằng chính mô hình đã thực hiện thao tác đó. Thuật ngữ "tool calling" trong tài liệu của các nhà cung cấp nghe có vẻ như mô hình đang trực tiếp gọi mã nguồn.
Trên thực tế, mô hình chỉ tạo ra văn bản để mô tả một lời gọi. Quy trình của bạn mới là bên thực hiện các công việc nặng nhọc—tra cứu, kiểm tra kiểu dữ liệu, thực thi quyền hạn và xử lý lỗi.
Các framework che giấu các lớp xử lý bên dưới (plumbing)
Các thư viện như PydanticAI và LangChain trừu tượng hóa vòng lặp này để bạn có thể tập trung vào logic nghiệp vụ. Chúng tự động:
- Xác thực tham số dựa trên một schema (ví dụ: một Pydantic model).
- Thực thi quyền hạn, đảm bảo người dùng có quyền kích hoạt công cụ.
- Thử lại khi thất bại, gửi yêu cầu ngược lại mô hình khi một công cụ trả về lỗi.
- Ngăn chặn các vòng lặp mất kiểm soát, giới hạn số lần gọi công cụ liên tiếp.
- Duy trì trạng thái hội thoại, lồng ghép kết quả của công cụ vào cuộc đối thoại.
Ngay cả với những công cụ hỗ trợ này, mô hình vẫn không bao giờ thực thi mã nguồn.
Hỗ trợ gọi công cụ gốc (native tool-calling) từ các nhà cung cấp
Một số nhà cung cấp cung cấp giao diện "native tool-calling" giúp chuẩn hóa các định nghĩa công cụ và định dạng yêu cầu. Điều này giúp việc tích hợp trở nên mượt mà hơn nhưng không loại bỏ bước điều phối. Bạn vẫn phải viết (hoặc nhập) mã nguồn để thực sự chạy thao tác được yêu cầu.
Việc gỡ lỗi sẽ dễ dàng hơn khi bạn gọi đúng tên vấn đề
Thay vì đổ lỗi cho một "agent đang bị bối rối", hãy nói rằng vấn đề là "phản hồi của mô hình không chứa lời gọi công cụ nào". Sự phân biệt này rất quan trọng:
- Không có lời gọi công cụ (No tool call) – mô hình trả lời trực tiếp hoặc không thể tạo ra một yêu cầu đúng định dạng.
- Yêu cầu sai định dạng (Malformed request) – JSON sai cú pháp hoặc thiếu các trường bắt buộc, khiến bộ điều phối từ chối.
- Lỗi xác thực (Validation failure) – các tham số không khớp với schema, gây ra lỗi trước khi thực thi.
Việc phân loại các lỗi cho phép bạn ghi nhật ký (log) từng giai đoạn của vòng lặp và xác định chính xác nơi vấn đề phát sinh.
Các mẹo thực tế để xây dựng một pipeline đáng tin cậy
- Coi đầu ra của mô hình là đầu vào không đáng tin cậy. Chạy mọi yêu cầu qua bước xác thực mang tính xác định (deterministic validation) trước khi gọi bất kỳ mã nguồn nào có gây ra tác động phụ (side-effect).
- Ghi nhật ký yêu cầu thô (raw request) và kết quả của từng bước xác thực. Điều này tạo ra một dấu vết có thể tái hiện lại khi có lỗi xảy ra.
- Thiết lập giới hạn rõ ràng cho các lần gọi công cụ liên tiếp; một vòng lặp mất kiểm soát có thể làm cạn kiệt tài nguyên hoặc chạm ngưỡng giới hạn tốc độ (rate limits).
- Bọc mỗi hàm trong khối try/except để trả về một đối tượng lỗi có cấu trúc mà mô hình có thể hiểu được, từ đó thúc đẩy việc thử lại hoặc chuyển sang phương án dự phòng (fallback) một cách mượt mà.
- Tách biệt việc kiểm tra quyền hạn khỏi logic nghiệp vụ. Xác minh quyền của người gọi trước khi hàm chạy, đặc biệt là đối với các hành động đặc quyền như "xóa người dùng".
- Sử dụng các định nghĩa dựa trên schema (ví dụ: Pydantic models) để framework có thể tự động tạo ra JSON schema mà mô hình phải tuân theo.
Những điều cần theo dõi tiếp theo
Khi các nhà cung cấp tinh chỉnh các API native tool-calling, hãy kỳ vọng vào các quy ước chặt chẽ hơn về định dạng yêu cầu và các mã lỗi phong phú hơn. Những thay đổi đó sẽ giúp việc xác thực dễ dàng hơn và cho phép các nhà phát triển xây dựng các rào cản bảo mật nghiêm ngặt hơn. Hãy chú ý đến các bản cập nhật thư viện—nhiều thư viện đang bổ sung hỗ trợ tích hợp cho các tính năng mới nhất của nhà cung cấp.
Bài học rút ra
LLM là một trình tạo văn bản tinh vi, không phải là một bộ thực thi. Mã nguồn của bạn vẫn là thực thể duy nhất có quyền thực hiện các hành động, và bộ điều phối (dispatcher) mà bạn xây dựng (hoặc nhập vào) chính là chốt chặn giúp xác thực, cấp quyền và thực thi các hành động đó. Việc tái định nghĩa quy trình làm việc sẽ loại bỏ lầm tưởng về sự "ma thuật", giúp việc gỡ lỗi trở nên hiệu quả hơn và thiết lập kỷ luật bảo mật mà mọi hệ thống production đều cần.
