OpenRouter: Announcements
85

Thủ thuật

Hướng dẫn xây dựng Agent tự động gọi công cụ với OpenRouter và TypeScript

(giờ Việt Nam)

Tóm tắt AI

OpenRouter chia sẻ hướng dẫn chi tiết cách dùng TypeScript SDK để tạo vòng lặp Agent, kết hợp dữ liệu thời tiết thực tế và các mô hình mạnh mẽ như Gemini 1.5 Flash.

Bản dịch AI

Build a Reliable Tool-Calling Agent Loop on OpenRouter

Một vòng lặp agent gọi công cụ (tool-calling agent loop) sẽ liên tục gửi nội dung hội thoại và các công cụ khả dụng đến mô hình, thực thi bất kỳ yêu cầu gọi công cụ nào từ mô hình, đính kèm kết quả và hỏi mô hình bước tiếp theo cần làm gì. Vòng lặp kết thúc khi mô hình không trả về yêu cầu gọi công cụ nào nữa hoặc khi một điều kiện dừng do ứng dụng định nghĩa được kích hoạt.

Mô hình sẽ quyết định công cụ nào cần yêu cầu, nhưng ứng dụng của bạn sẽ phân tích cú pháp các đối số, chạy hàm và quyết định thời điểm vòng lặp phải dừng lại.

Hướng dẫn này chỉ cho bạn cách xây dựng vòng lặp đó với OpenRouter TypeScript SDK. Ví dụ này sử dụng dữ liệu thời tiết cục bộ, vì vậy bạn có thể chạy nó mà không cần thiết lập thêm dịch vụ nào khác.

Tóm tắt (Tl;dr)

Cách thức hoạt động của vòng lặp agent gọi công cụ

Thiết lập tác vụ, công cụ và lịch sử tin nhắn, sau đó lặp lại các bước sau:

Vòng lặp cũng cần một giới hạn cứng. Một mô hình có thể lặp lại một lệnh gọi thất bại hoặc tiếp tục tìm kiếm câu trả lời tốt hơn. Nếu không có giới hạn số lần lặp, hành vi đó có thể tiếp diễn cho đến khi một phần khác của hệ thống ngăn chặn nó.

Bạn không cần một framework AI agent để xây dựng hoặc hiểu luồng điều khiển này. Một bản triển khai nhỏ cũng rất hữu ích ngay cả khi sau này bạn chuyển vòng lặp đó vào một thư viện.

Bước 1: Thiết lập client và định nghĩa các công cụ của bạn

Tạo một dự án TypeScript và cài đặt OpenRouter TypeScript SDK cùng với tsx:

Tạo một OpenRouter API key, sau đó cung cấp nó cho tiến trình:

Tạo file agent.ts và thêm client, danh sách mô hình theo thứ tự và một công cụ cục bộ:

Định nghĩa công cụ cho mô hình biết khi nào nên sử dụng hàm và những đối số nào được chấp nhận. Bản thân hàm đó vẫn nằm trong ứng dụng của bạn vì chỉ mã nguồn của bạn mới có thể chạy nó.

Hãy giữ phần mô tả cụ thể và bao gồm các chi tiết mà mô hình cần để sử dụng công cụ một cách chính xác. Ở đây, việc đặt tên cho hai thành phố được hỗ trợ giúp mô hình tạo ra các đối số hợp lệ.

Cả hai mô hình trong danh sách đều hỗ trợ gọi công cụ. Tính khả dụng của mô hình thay đổi theo thời gian, vì vậy hãy kiểm tra danh mục mô hình (model catalog) để biết danh sách hiện tại các mô hình hỗ trợ tham số tools trước khi bạn chọn mô hình cho riêng mình.

Bước 2: Gọi mô hình và đọc phản hồi

Tiếp theo, thêm một hàm hỗ trợ thực hiện một yêu cầu mô hình và trả về tin nhắn của trợ lý cùng với bất kỳ lệnh gọi công cụ nào:

SDK lồng phần thân yêu cầu vào chatRequest và sử dụng các trường dạng camelCase như toolChoice, maxCompletionTokens và toolCalls. Nó chuyển đổi chúng sang định dạng snake_case của API, vì vậy toolChoice sẽ được gửi dưới dạng tool_choice.

Luôn giữ các công cụ trong mọi lệnh gọi, bao gồm cả các lệnh gọi tiếp theo. Chúng tôi xác thực các lệnh gọi công cụ được trả về dựa trên các định nghĩa này, và mô hình cần chúng để quyết định xem có công cụ nào khác có thể hỗ trợ hay không.

Lần lặp đầu tiên sử dụng toolChoice: "required" để ví dụ luôn thực thi đường dẫn công cụ. Các lần lặp sau sử dụng "auto", cho phép mô hình trả về câu trả lời cuối cùng sau khi nhận được kết quả từ công cụ. Nếu mọi lần lặp đều yêu cầu một công cụ, mô hình sẽ không có cách nào để kết thúc bằng văn bản. Đây là lựa chọn của ví dụ này, không phải mặc định của API. Mặc định của API cho tool_choice là "auto" khi có các công cụ.

Bước 3: Thực thi các lệnh gọi công cụ và trả về kết quả

Thêm một hàm hỗ trợ chạy một lệnh gọi công cụ và tạo tin nhắn công cụ mà bạn sẽ gửi lại cho mô hình:

Các đối số công cụ được gửi đến dưới dạng chuỗi JSON, vì vậy JSON.parse cần nằm trong khối try. JSON không hợp lệ, tên hàm không xác định hoặc trình xử lý bị lỗi sẽ trở thành kết quả công cụ thay vì làm treo vòng lặp. Sau đó, mô hình có thể thay đổi đối số, chọn công cụ khác hoặc giải thích lỗi.

Kết quả cũng mang ID lệnh gọi gốc dưới dạng toolCallId. Đây là cách mô hình khớp từng kết quả với lệnh gọi đã yêu cầu nó. Một phản hồi có thể chứa nhiều hơn một lệnh gọi và mỗi lệnh gọi cần kết quả riêng.

Ví dụ này trả về các lỗi phân tích cú pháp và thực thi dự kiến cho mô hình. Các lỗi xác thực, mạng và các lỗi cấp yêu cầu khác vẫn nên thoát khỏi vòng lặp để ứng dụng bao quanh có thể xử lý chúng.

Bước 4: Bao bọc các lệnh gọi trong một vòng lặp có giới hạn

Bước 2 và 3 xử lý một lượt phản hồi của mô hình. Thêm runAgent để kết nối chúng:

Mỗi lượt chạy sẽ gọi mô hình, kiểm tra xem nó đã hoàn thành chưa, sau đó đính kèm tin nhắn của trợ lý và kết quả công cụ. Lượt tiếp theo sẽ gửi lịch sử đã mở rộng đó qua sendTurn. Hãy đính kèm tin nhắn của trợ lý trước kết quả công cụ để toàn bộ lượt phản hồi được bảo toàn.

Giới hạn số lần lặp được kiểm tra sau khi mô hình phản hồi và trước khi bất kỳ công cụ nào chạy. Kết quả công cụ chỉ hữu ích trong yêu cầu mô hình tiếp theo, vì vậy khi mô hình vẫn yêu cầu công cụ ở lần lặp cuối cùng cho phép, vòng lặp sẽ dừng mà không thực thi chúng. Việc chạy chúng ở đó sẽ tạo ra các tác dụng phụ mà mô hình không bao giờ có thể thấy hoặc báo cáo.

Giới hạn là giới hạn cứng duy nhất trong vòng lặp, và việc kiểm tra so sánh số lần lặp với maxIterations để xác định sự bằng nhau. runAgent sẽ từ chối giới hạn không phải là số nguyên dương an toàn trước yêu cầu đầu tiên, vì các giá trị như 0, 1.5 hoặc NaN sẽ không bao giờ khớp và vòng lặp sẽ chạy cho đến khi mô hình ngừng yêu cầu công cụ. Number.isSafeInteger cũng từ chối các giá trị lớn hơn Number.MAX_SAFE_INTEGER, nơi mà iteration++ ngừng tạo ra các giá trị riêng biệt và không bao giờ có thể đạt đến giới hạn.

Bộ đếm dấu vân tay (fingerprint counter) dừng quá trình chạy sau khi cùng một công cụ và chuỗi đối số xuất hiện ba lần. Hai lần sẽ dừng một mô hình thử lại một lần sau một kết quả trống hoặc tạm thời. Ba lần cho phép thử lại một lần đó và vẫn dừng nhanh một mô hình bị kẹt. Ngưỡng này và mặc định của maxIterations là lựa chọn của ứng dụng, không phải mặc định của OpenRouter.

Trong một ứng dụng thực tế, hãy chuẩn hóa các đối số đã phân tích cú pháp trước khi so sánh chúng để một lệnh gọi được định dạng lại nhưng giống hệt nhau vẫn được tính là lặp lại. Bạn cũng có thể đặt giới hạn khác nhau cho từng công cụ.

Kiểm thử vòng lặp

Hoàn thiện agent.ts với một hàm main nhỏ:

Chạy nó từ terminal:

Bạn sẽ thấy một hoặc nhiều lần lặp gọi get_weather, theo sau là một so sánh cuối cùng. Các giá trị đến từ bản đồ cục bộ trong Bước 1, vì vậy bạn có thể kiểm tra toàn bộ vòng lặp trước khi thay thế trình xử lý bằng một dịch vụ thực tế. Đây là kết quả đầu ra từ một lần chạy với API:

Lần lặp đầu tiên trả về hai lệnh gọi get_weather trong một phản hồi, vòng lặp đã thực thi chúng song song. Lần lặp thứ hai không trả về lệnh gọi công cụ nào, vì vậy vòng lặp trả về văn bản. Kết quả chạy của bạn có thể khác về số lần lặp, cách diễn đạt câu trả lời và độ trễ.

Thêm các biện pháp kiểm soát dự phòng và đồng thời

Mỗi biện pháp kiểm soát ở đây xử lý một kiểu lỗi khác nhau. Giới hạn số lần lặp và số lần lặp lại giúp ngăn chặn các hành vi không hiệu quả bên trong ứng dụng của bạn. Lựa chọn về tính đồng thời giúp các công cụ chạy song song không làm hỏng dữ liệu của nhau. Cơ chế dự phòng mô hình xử lý lỗi từ mô hình đã chọn. Auto Exacto thay đổi thứ tự nhà cung cấp khi có các yêu cầu gọi công cụ.

Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ OpenRouter: Announcements. Liên kết bài gốc ở phía trên. 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.