Tool Calling (gọi hàm)
Tool Calling (còn gọi là Function Calling) cho phép các mô hình vượt ra ngoài việc tạo văn bản bằng cách trả về một “yêu cầu gọi hàm” có cấu trúc khi cần thiết. Chương trình của bạn thực thi logic thực tế (kiểm tra thời tiết, truy vấn cơ sở dữ liệu, đặt hàng), trả kết quả về cho mô hình, và mô hình tạo phản hồi cuối cùng dựa trên nó. RouteAPI hỗ trợ Tool Calling trên cả /v1/chat/completions (định dạng OpenAI) và /v1/messages (định dạng Claude).
1. Tổng quan về Tool Calling
Phần tiêu đề “1. Tổng quan về Tool Calling”Tool Calling là gì
Phần tiêu đề “Tool Calling là gì”Tool Calling là một cuộc trao đổi nhiều vòng:
- Bạn khai báo một tập “công cụ” trong yêu cầu (mỗi công cụ có tên, mô tả và schema tham số).
- Mô hình xác định liệu có cần công cụ hay không; nếu có, nó trả về một yêu cầu gọi với tham số thay vì trả lời trực tiếp.
- Mã của bạn phân tích tham số, thực thi logic thực tế và lấy kết quả.
- Bạn truyền kết quả trở lại cho mô hình, mô hình tạo phản hồi ngôn ngữ tự nhiên cho người dùng.
Bản thân mô hình không thực thi bất kỳ mã nào; nó chỉ quyết định “gọi công cụ nào” và “truyền tham số gì”. Việc thực thi thực tế luôn xảy ra ở phía bạn, có nghĩa là các ranh giới bảo mật (kiểm tra quyền, lọc tham số) nằm dưới sự kiểm soát của bạn.
Các trường hợp sử dụng
Phần tiêu đề “Các trường hợp sử dụng”| Kịch bản | Mô tả |
|---|---|
| Truy vấn dữ liệu thời gian thực | Thời tiết, tỷ giá hối đoái, giá cổ phiếu, tồn kho — thông tin không có trong dữ liệu huấn luyện của mô hình |
| Tích hợp hệ thống nội bộ | Truy vấn cơ sở dữ liệu, gọi API nội bộ, đọc trạng thái đơn hàng |
| Thực thi hành động | Đặt hàng, gửi email, tạo ticket — các thao tác có tác dụng phụ |
| Trích xuất có cấu trúc | Buộc mô hình xuất ra theo schema cố định, tương đương với phương pháp xuất có cấu trúc |
| Điều phối agent | Các framework agent sử dụng Tool Calling để điều khiển các tác vụ nhiều bước |
Các mô hình được hỗ trợ
Phần tiêu đề “Các mô hình được hỗ trợ”Khả năng Tool Calling phụ thuộc vào mô hình được chọn. Hầu hết các mô hình chính thống (dòng OpenAI GPT, Claude, Gemini, v.v.) đều hỗ trợ, nhưng các chi tiết như số lượng công cụ tối đa và hỗ trợ gọi song song khác nhau. Endpoint danh sách mô hình không trả về trường biểu thị khả năng Tool Calling; hãy tham khảo tài liệu của nhà cung cấp mô hình, hoặc gửi trực tiếp một request thực tế có kèm tools tới mô hình mục tiêu để xác minh, xem thêm Models.
2. Định dạng định nghĩa công cụ (OpenAI)
Phần tiêu đề “2. Định dạng định nghĩa công cụ (OpenAI)”Trong /v1/chat/completions, các công cụ được khai báo qua mảng cấp cao nhất tools, trong đó mỗi công cụ là một đối tượng lồng nhau với type: "function".
Cấu trúc mảng tools
Phần tiêu đề “Cấu trúc mảng tools”{ "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Truy vấn thời tiết hiện tại cho thành phố được chỉ định. Sử dụng tên đầy đủ của thành phố bằng tiếng Trung.", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "Tên thành phố, ví dụ: Bắc Kinh" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "Đơn vị nhiệt độ, mặc định là độ C" } }, "required": ["city"] } } } ]}function schema
Phần tiêu đề “function schema”| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
type | string | Có | Cố định là "function" |
function.name | string | Có | Tên công cụ, chỉ có thể chứa chữ cái, số, gạch dưới và gạch ngang |
function.description | string | Khuyến nghị | Mô tả mục đích công cụ, mô hình sử dụng điều này để quyết định có gọi hay không |
function.parameters | object | Không | Định nghĩa tham số, JSON Schema tiêu chuẩn |
Chất lượng của description trực tiếp quyết định liệu mô hình có chọn đúng công cụ hay không. Mô tả rõ ràng mục đích, ý nghĩa của từng tham số, phạm vi giá trị và điều kiện biên hiệu quả hơn việc điều chỉnh bất kỳ tham số lấy mẫu nào.
parameters (JSON Schema)
Phần tiêu đề “parameters (JSON Schema)”parameters sử dụng JSON Schema tiêu chuẩn để mô tả cấu trúc tham số:
type: Thường là"object".properties: Kiểu, mô tả, giá trị liệt kê cho từng tham số.required: Danh sách tên tham số bắt buộc.enum: Hạn chế phạm vi giá trị, giảm đáng kể xác suất mô hình truyền giá trị sai.
Các công cụ không có tham số vẫn phải cung cấp schema rỗng: "parameters": { "type": "object", "properties": {} }.
3. Định dạng định nghĩa công cụ (Claude)
Phần tiêu đề “3. Định dạng định nghĩa công cụ (Claude)”Trong /v1/messages, định nghĩa công cụ là cấu trúc phẳng không có wrapper bên ngoài type và function, và trường tham số được gọi là input_schema.
Sự khác biệt của mảng tools
Phần tiêu đề “Sự khác biệt của mảng tools”{ "tools": [ { "name": "get_weather", "description": "Truy vấn thời tiết hiện tại cho thành phố được chỉ định. Sử dụng tên đầy đủ của thành phố bằng tiếng Trung.", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "Tên thành phố, ví dụ: Bắc Kinh" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] } }, "required": ["city"] } } ]}input_schema
Phần tiêu đề “input_schema”Cấu trúc bên trong của input_schema giống hệt với parameters của OpenAI, cả hai đều là JSON Schema tiêu chuẩn. Sự khác biệt chỉ ở wrapper bên ngoài.
So sánh hai định dạng
Phần tiêu đề “So sánh hai định dạng”| Mục | OpenAI (/v1/chat/completions) | Claude (/v1/messages) |
|---|---|---|
| Wrapper bên ngoài | { "type": "function", "function": {...} } | Cấu trúc phẳng trực tiếp, không có wrapper |
| Trường tên công cụ | function.name | name |
| Trường mô tả | function.description | description |
| Trường tham số | function.parameters | input_schema |
| Schema tham số | JSON Schema tiêu chuẩn | JSON Schema tiêu chuẩn (giống hệt) |
| Trả về từ mô hình | Mảng message.tool_calls | Khối tool_use trong content |
| Vai trò truyền kết quả | Tin nhắn role: "tool" độc lập | Khối tool_result trong tin nhắn user |
| Trường liên kết kết quả | tool_call_id | tool_use_id |
Để biết chi tiết đầy đủ về giao thức Claude (bao gồm is_error, streaming input_json_delta, v.v.), xem Giao thức Claude Messages. Các ví dụ tiếp theo trên trang này mặc định sử dụng định dạng OpenAI.
4. Các tùy chọn tool_choice
Phần tiêu đề “4. Các tùy chọn tool_choice”tool_choice kiểm soát cách mô hình chọn công cụ.
| Giá trị | Hành vi |
|---|---|
"auto" | Mô hình tự quyết định có gọi công cụ hay không và gọi cái nào. Giá trị mặc định khi có tools |
"none" | Cấm gọi bất kỳ công cụ nào, mô hình chỉ xuất văn bản |
"required" | Phải gọi ít nhất một công cụ, nhưng mô hình chọn cái nào |
{ "type": "function", "function": { "name": "get_weather" } } | Buộc gọi công cụ được chỉ định |
auto (mặc định)
Phần tiêu đề “auto (mặc định)”{ "tool_choice": "auto" }Phổ biến nhất. Phù hợp cho các kịch bản “câu hỏi của người dùng đôi khi cần công cụ, đôi khi trả lời trực tiếp”.
{ "tool_choice": "none" }Tạm thời vô hiệu hóa công cụ trong khi giữ định nghĩa. Thường được sử dụng ở giai đoạn kết thúc “để mô hình tóm tắt, không gọi lại công cụ”.
required
Phần tiêu đề “required”{ "tool_choice": "required" }Buộc mô hình đi theo đường công cụ. Phù hợp cho các kịch bản như trích xuất có cấu trúc mà “phải tạo ra kết quả có cấu trúc”.
Chỉ định công cụ cụ thể
Phần tiêu đề “Chỉ định công cụ cụ thể”{ "tool_choice": { "type": "function", "function": { "name": "get_weather" } }}Tương đương định dạng Claude là { "type": "tool", "name": "get_weather" }, required tương ứng với { "type": "any" }, none tương ứng với { "type": "none" }.
5. Quy trình Tool Calling
Phần tiêu đề “5. Quy trình Tool Calling”Một cuộc gọi công cụ hoàn chỉnh bao gồm ít nhất hai vòng yêu cầu.
Vòng đầu tiên: mô hình trả về tool_calls
Phần tiêu đề “Vòng đầu tiên: mô hình trả về tool_calls”Gửi yêu cầu với tools:
curl https://api.routeapi.ai/v1/chat/completions \ -H "Authorization: Bearer $ROUTEAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Thời tiết ở Bắc Kinh bây giờ thế nào?" } ], "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Truy vấn thời tiết hiện tại cho thành phố được chỉ định.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } } ] }'Khi mô hình xác định cần một công cụ, finish_reason là tool_calls, message.content là null, và tool_calls chứa yêu cầu gọi:
{ "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } } ] }, "finish_reason": "tool_calls" } ]}Lưu ý arguments là một chuỗi JSON, không phải đối tượng; bạn cần tự phân tích nó bằng JSON.parse / json.loads. Mô hình đôi khi có thể tạo JSON không hợp lệ, vì vậy phân tích phải nằm trong try/catch.
Thực thi công cụ
Phần tiêu đề “Thực thi công cụ”Phân phối theo function.name đến logic thực tế của bạn, thực thi với các tham số đã phân tích:
import json
args = json.loads(tool_call["function"]["arguments"])result = get_weather(**args) # "Bắc Kinh, nắng, 23 độ C"Vòng thứ hai: truyền kết quả công cụ
Phần tiêu đề “Vòng thứ hai: truyền kết quả công cụ”Thêm tin nhắn assistant của vòng đầu tiên (với tool_calls) trở lại messages nguyên trạng, sau đó thêm một tin nhắn role: "tool" mang kết quả. tool_call_id phải khớp chính xác với id từ vòng đầu tiên:
{ "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Thời tiết ở Bắc Kinh bây giờ thế nào?" }, { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } } ] }, { "role": "tool", "tool_call_id": "call_abc123", "content": "Bắc Kinh, nắng, nhiệt độ 23 độ C, độ ẩm 45%." } ], "tools": []}Mô hình tạo phản hồi cuối cùng
Phần tiêu đề “Mô hình tạo phản hồi cuối cùng”Yêu cầu vòng thứ hai trả về kết quả ngôn ngữ tự nhiên, finish_reason trở về stop:
{ "choices": [ { "message": { "role": "assistant", "content": "Bắc Kinh hiện tại trời nắng, nhiệt độ 23 độ C, độ ẩm 45%, khá thoải mái." }, "finish_reason": "stop" } ]}6. Tool Calling nhiều vòng
Phần tiêu đề “6. Tool Calling nhiều vòng”Gọi tuần tự nhiều công cụ
Phần tiêu đề “Gọi tuần tự nhiều công cụ”Mô hình có thể cần nhiều vòng gọi công cụ để hoàn thành nhiệm vụ: trước tiên kiểm tra số đơn hàng, sau đó sử dụng số đơn hàng để kiểm tra vận chuyển. Mỗi vòng tuân theo vòng lặp “mô hình trả về tool_calls → thực thi → truyền trở lại kết quả” cho đến khi finish_reason trở về stop. Mã sản xuất nên được viết dưới dạng vòng lặp với giới hạn số vòng tối đa để ngăn vòng lặp vô hạn:
MAX_TURNS = 5for _ in range(MAX_TURNS): resp = call_model(messages) msg = resp["choices"][0]["message"] messages.append(msg) if not msg.get("tool_calls"): break # Mô hình đưa ra phản hồi cuối cùng for tc in msg["tool_calls"]: result = dispatch(tc) # Thực thi và trả về chuỗi messages.append({ "role": "tool", "tool_call_id": tc["id"], "content": result, })Gọi công cụ song song
Phần tiêu đề “Gọi công cụ song song”Trong một vòng, mô hình có thể đồng thời yêu cầu nhiều công cụ độc lập (ví dụ: kiểm tra thời tiết ở cả Bắc Kinh và Thượng Hải), dẫn đến tool_calls là một mảng nhiều phần tử. Bạn cần thêm một tin nhắn role: "tool" tương ứng cho từng tool_call, với tool_call_id căn chỉnh một-một; thiếu một cái sẽ gây lỗi trong vòng tiếp theo.
Để vô hiệu hóa tính song song và buộc mô hình chỉ gọi một công cụ tại một thời điểm, thêm "parallel_tool_calls": false ở định dạng OpenAI, hoặc thêm "disable_parallel_tool_use": true trong tool_choice cho định dạng Claude.
7. Tool Calling streaming
Phần tiêu đề “7. Tool Calling streaming”Khi đặt stream: true, các tham số gọi công cụ được trả về dần dần theo từng phần.
tool_calls trong đầu ra streaming
Phần tiêu đề “tool_calls trong đầu ra streaming”delta.tool_calls của mỗi chunk SSE chứa index (xác định cuộc gọi công cụ nào), và function.arguments là một đoạn của JSON tham số:
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"id":"call_abc123","type":"function","function":{"name":"get_weather","arguments":""}}]}}]}
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":"}}]}}]}
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"北京\"}"}}]}}]}
data: {"choices":[{"finish_reason":"tool_calls"}]}
data: [DONE]Cách xử lý delta gia tăng
Phần tiêu đề “Cách xử lý delta gia tăng”Tích lũy theo nhóm index: id và name thường chỉ xuất hiện trong đoạn đầu tiên, arguments cần nối tất cả các đoạn trước khi phân tích. Không cố phân tích các trạng thái trung gian trong quá trình nối (đó là JSON chưa hoàn chỉnh).
buffers = {} # index -> {"id", "name", "args"}for chunk in stream: for tc in chunk["choices"][0]["delta"].get("tool_calls", []): i = tc["index"] buf = buffers.setdefault(i, {"id": "", "name": "", "args": ""}) if tc.get("id"): buf["id"] = tc["id"] fn = tc.get("function", {}) if fn.get("name"): buf["name"] = fn["name"] if fn.get("arguments"): buf["args"] += fn["arguments"]
# Phân tích sau khi stream kết thúcfor buf in buffers.values(): args = json.loads(buf["args"])Tham số công cụ streaming định dạng Claude được trả về dần dần qua partial_json của sự kiện input_json_delta, tích lũy theo index rồi phân tích; chi tiết trong Giao thức Claude Messages.
8. Tình trạng hỗ trợ của các mô hình
Phần tiêu đề “8. Tình trạng hỗ trợ của các mô hình”Các mô hình hỗ trợ Tool Calling
Phần tiêu đề “Các mô hình hỗ trợ Tool Calling”Hầu hết các mô hình chính thống được tích hợp bởi RouteAPI đều hỗ trợ Tool Calling, bao gồm dòng OpenAI GPT, Claude, Gemini, v.v. Trước tiên hãy dùng endpoint danh sách mô hình để xác nhận mô hình có khả dụng trong tài khoản của bạn:
curl https://api.routeapi.ai/v1/models \ -H "Authorization: Bearer $ROUTEAPI_KEY"Endpoint này chỉ trả về việc mô hình có khả dụng hay không và các endpoint dùng được, không trả về khả năng Tool Calling. Hãy căn cứ vào tài liệu của nhà cung cấp hoặc một request thực tế có kèm tools để xác định mô hình có hỗ trợ Tool Calling.
Giới hạn của các mô hình
Phần tiêu đề “Giới hạn của các mô hình”Các mô hình khác nhau có sự khác biệt trong các khía cạnh sau; xác minh trong môi trường thử nghiệm trước khi đưa vào sản xuất:
| Khía cạnh | Mô tả |
|---|---|
| Số lượng công cụ tối đa | Giới hạn trên của các công cụ có thể được khai báo trong một yêu cầu khác nhau tùy mô hình |
| Gọi song song | Một số mô hình không hỗ trợ trả về nhiều tool_calls trong một vòng |
Hỗ trợ tool_choice | Không phải tất cả các mô hình đều hỗ trợ required / chỉ định công cụ cụ thể |
| Độ phức tạp tham số | JSON Schema lồng sâu hoặc rất lớn có thể bị cắt bớt hoặc bỏ qua bởi một số mô hình |
| Độ chi tiết gia tăng streaming | Cách phân đoạn arguments không nhất quán giữa các mô hình; phải tích lũy theo index |
9. Ví dụ hoàn chỉnh
Phần tiêu đề “9. Ví dụ hoàn chỉnh”Ví dụ công cụ truy vấn thời tiết (từ đầu đến cuối)
Phần tiêu đề “Ví dụ công cụ truy vấn thời tiết (từ đầu đến cuối)”Ba đoạn mã sau có chức năng tương đương: định nghĩa công cụ → vòng đầu tiên lấy tool_calls → thực thi → vòng thứ hai truyền trở lại kết quả → lấy phản hồi cuối cùng.
curl (hoàn thành thủ công hai vòng):
# Vòng đầu tiên: gửi yêu cầu với công cụcurl https://api.routeapi.ai/v1/chat/completions \ -H "Authorization: Bearer $ROUTEAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "messages": [{ "role": "user", "content": "Thời tiết ở Bắc Kinh bây giờ thế nào?" }], "tools": [{ "type": "function", "function": { "name": "get_weather", "description": "Truy vấn thời tiết hiện tại cho thành phố được chỉ định.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } }] }'
# Vòng thứ hai: truyền trở lại kết quả công cụ (tool_call_id sử dụng giá trị từ vòng đầu tiên)curl https://api.routeapi.ai/v1/chat/completions \ -H "Authorization: Bearer $ROUTEAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.5", "messages": [ { "role": "user", "content": "Thời tiết ở Bắc Kinh bây giờ thế nào?" }, { "role": "assistant", "content": null, "tool_calls": [{ "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"北京\"}" } }] }, { "role": "tool", "tool_call_id": "call_abc123", "content": "Bắc Kinh, nắng, nhiệt độ 23 độ C, độ ẩm 45%." } ] }'Python (SDK OpenAI, tự động hoàn thành hai vòng):
import jsonimport osfrom openai import OpenAI
client = OpenAI( api_key=os.environ["ROUTEAPI_KEY"], base_url="https://api.routeapi.ai/v1",)
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Truy vấn thời tiết hiện tại cho thành phố được chỉ định. Sử dụng tên đầy đủ của thành phố bằng tiếng Trung.", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "Tên thành phố, ví dụ: Bắc Kinh"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}, }, "required": ["city"], }, }, }]
def get_weather(city: str, unit: str = "celsius") -> str: # Thay thế bằng cuộc gọi dịch vụ thời tiết thực tế return f"{city}, nắng, nhiệt độ 23 độ C, độ ẩm 45%."
messages = [{"role": "user", "content": "Thời tiết ở Bắc Kinh bây giờ thế nào?"}]
# Vòng đầu tiênresp = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools)msg = resp.choices[0].message
if msg.tool_calls: # Tin nhắn assistant phải được thêm trở lại nguyên trạng, nếu không tool_call_id không thể căn chỉnh messages.append(msg) for tc in msg.tool_calls: args = json.loads(tc.function.arguments) result = get_weather(**args) messages.append( {"role": "tool", "tool_call_id": tc.id, "content": result} )
# Vòng thứ hai resp = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools )
print(resp.choices[0].message.content)Node.js (gói openai, tự động hoàn thành hai vòng):
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.ROUTEAPI_KEY, baseURL: 'https://api.routeapi.ai/v1',});
const tools = [ { type: 'function', function: { name: 'get_weather', description: 'Truy vấn thời tiết hiện tại cho thành phố được chỉ định. Sử dụng tên đầy đủ của thành phố bằng tiếng Trung.', parameters: { type: 'object', properties: { city: { type: 'string', description: 'Tên thành phố, ví dụ: Bắc Kinh' }, unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }, }, required: ['city'], }, }, },];
function getWeather(city, unit = 'celsius') { // Thay thế bằng cuộc gọi dịch vụ thời tiết thực tế return `${city}, nắng, nhiệt độ 23 độ C, độ ẩm 45%.`;}
const messages = [{ role: 'user', content: 'Thời tiết ở Bắc Kinh bây giờ thế nào?' }];
// Vòng đầu tiênlet resp = await client.chat.completions.create({ model: 'gpt-5.5', messages, tools,});const msg = resp.choices[0].message;
if (msg.tool_calls) { messages.push(msg); // Thêm tin nhắn assistant trở lại nguyên trạng for (const tc of msg.tool_calls) { const args = JSON.parse(tc.function.arguments); const result = getWeather(args.city, args.unit); messages.push({ role: 'tool', tool_call_id: tc.id, content: result }); }
// Vòng thứ hai resp = await client.chat.completions.create({ model: 'gpt-5.5', messages, tools, });}
console.log(resp.choices[0].message.content);Ví dụ công cụ truy vấn cơ sở dữ liệu
Phần tiêu đề “Ví dụ công cụ truy vấn cơ sở dữ liệu”Sử dụng công cụ như wrapper bảo mật cho hệ thống nội bộ. Quan trọng: SQL không nên được tạo trực tiếp bởi mô hình; thay vào đó, mô hình chọn tham số, và mã của bạn tạo các truy vấn có tham số để tránh injection.
tools = [ { "type": "function", "function": { "name": "query_order", "description": "Truy vấn trạng thái đơn hàng và số tiền theo số đơn hàng.", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "Số đơn hàng, như ORD-20260917-001", } }, "required": ["order_id"], }, }, }]
def query_order(order_id: str) -> str: # Sử dụng truy vấn có tham số, không bao giờ nối đầu ra mô hình trực tiếp vào SQL row = db.execute( "SELECT status, amount FROM orders WHERE order_id = %s", (order_id,), ).fetchone() if row is None: return json.dumps({"found": False}) return json.dumps({"found": True, "status": row[0], "amount": row[1]})Kết quả công cụ nên được truyền trở lại dưới dạng chuỗi JSON; mô hình có thể phân tích các trường có cấu trúc một cách đáng tin cậy hơn.
Ví dụ điều phối nhiều công cụ
Phần tiêu đề “Ví dụ điều phối nhiều công cụ”Khai báo nhiều công cụ cùng lúc; mô hình chọn theo nhu cầu hoặc thậm chí gọi song song. Ở đây sử dụng hai công cụ: thời tiết + tỷ giá hối đoái:
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Truy vấn thời tiết hiện tại cho thành phố được chỉ định.", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }, }, { "type": "function", "function": { "name": "get_exchange_rate", "description": "Truy vấn tỷ giá hối đoái giữa hai loại tiền tệ.", "parameters": { "type": "object", "properties": { "from_currency": {"type": "string", "description": "Như USD"}, "to_currency": {"type": "string", "description": "Như CNY"}, }, "required": ["from_currency", "to_currency"], }, }, },]
dispatch = { "get_weather": lambda city: f"{city}, nắng, 23 độ C.", "get_exchange_rate": lambda from_currency, to_currency: f"1 {from_currency} = 7.2 {to_currency}",}
messages = [{"role": "user", "content": "Thời tiết ở Bắc Kinh thế nào? Cũng cho tôi biết tỷ giá USD sang CNY."}]
# Vòng lặp để xử lý gọi công cụ nhiều vòng / song song, đặt giới hạn để ngăn vòng lặp vô hạnfor _ in range(5): resp = client.chat.completions.create( model="gpt-5.5", messages=messages, tools=tools ) msg = resp.choices[0].message messages.append(msg) if not msg.tool_calls: break # Trong cuộc gọi song song, tool_calls là mảng nhiều phần tử; mỗi cái phải được truyền trở lại for tc in msg.tool_calls: args = json.loads(tc.function.arguments) result = dispatch[tc.function.name](**args) messages.append( {"role": "tool", "tool_call_id": tc.id, "content": result} )
print(messages[-1]["content"])10. Xử lý lỗi
Phần tiêu đề “10. Xử lý lỗi”Tool Calling giới thiệu ba điểm lỗi tiềm năng: phía mô hình, phía mã của bạn và phía dịch vụ upstream.
Xác thực tham số công cụ thất bại
Phần tiêu đề “Xác thực tham số công cụ thất bại”Mô hình có thể trả về JSON không hợp lệ, hoặc thiếu tham số bắt buộc, hoặc truyền giá trị ngoài phạm vi enum. Đảm bảo:
- Bọc
JSON.parse/json.loadstrong try/catch. - Sau khi phân tích, xác thực các trường bắt buộc và phạm vi giá trị theo schema.
- Khi xác thực thất bại, truyền thông báo lỗi trở lại như kết quả công cụ để cho phép mô hình tự sửa, thay vì ném trực tiếp ngoại lệ để kết thúc cuộc trò chuyện:
try: args = json.loads(tc.function.arguments) city = args["city"] # Xác thực trường bắt buộcexcept (json.JSONDecodeError, KeyError) as exc: result = f"Phân tích tham số thất bại: {exc}. Vui lòng cung cấp lại tham số city hợp lệ."else: result = get_weather(city)
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})Thực thi công cụ hết thời gian
Phần tiêu đề “Thực thi công cụ hết thời gian”Công cụ được hỗ trợ bởi các dịch vụ thực tế có thể hết thời gian hoặc không khả dụng. Đặt giới hạn thời gian chờ cho mỗi cuộc gọi công cụ; nếu hết thời gian, truyền kết quả trở lại dưới dạng mô tả lỗi rõ ràng để cho phép mô hình chuyển sang chiến lược khác:
try: result = call_service(args, timeout=5)except TimeoutError: result = "Dịch vụ hết thời gian, không lấy được dữ liệu, vui lòng thử lại sau hoặc sử dụng phương pháp khác."Không thực hiện thử lại tự động cho các công cụ có tác dụng phụ (đặt hàng, gửi email), vì chúng có thể thực thi lặp lại. Thiết kế idempotent hoặc kiểm tra trước khi ghi an toàn hơn.
Công cụ trả về lỗi
Phần tiêu đề “Công cụ trả về lỗi”Lỗi cấp độ nghiệp vụ (không tìm thấy đơn hàng, không có quyền) cũng nên được truyền trở lại cho mô hình, thay vì trả về giá trị rỗng một cách im lặng. Truyền trở lại thông tin lỗi có cấu trúc; mô hình có thể cung cấp giải thích hợp lý cho người dùng:
messages.append({ "role": "tool", "tool_call_id": tc.id, "content": json.dumps({"error": "order_not_found", "order_id": order_id}),})Định dạng Claude tương ứng đặt "is_error": true trên khối tool_result, xem Giao thức Claude Messages.
Nhắc nhở về khả năng tương thích
Phần tiêu đề “Nhắc nhở về khả năng tương thích”- Khả năng Tool Calling, số lượng công cụ tối đa, hỗ trợ gọi song song phụ thuộc vào mô hình được chọn; xác minh trong môi trường thử nghiệm trước khi đưa vào sản xuất.
argumentsluôn là chuỗi JSON, không phải đối tượng; phải phân tích rõ ràng.- Trong các kịch bản streaming, phải tích lũy các đoạn
argumentstheoindex, phân tích sau khi nối hoàn chỉnh. - Các tham số tùy chọn được truyền rõ ràng là
0hoặcfalseđược coi là do người dùng đặt, không được coi là giá trị mặc định và loại bỏ. - Ghi lại request ID, ID mô hình, mã trạng thái và sử dụng token cho mỗi yêu cầu để khắc phục sự cố dễ dàng hơn. Chi tiết cấu trúc lỗi trong Lỗi và gỡ lỗi.