Đến cuối hướng dẫn này, bạn sẽ triển khai được vòng lặp gọi hàm với OpenAI: định nghĩa công cụ, gửi công cụ vào request, đọc tool_calls hoặc function_call, parse đối số JSON, chạy hàm trong ứng dụng của bạn, rồi trả kết quả về cho mô hình. Bạn cũng sẽ bật strict, kiểm soát parallel_tool_calls, và dùng Apidog để xác thực schema và mô phỏng API phía sau trước khi đưa vào production. Khi cần đối chiếu chi tiết API, hãy mở tài liệu gọi hàm của OpenAI; nếu bạn đang xây dựng tác nhân, xem thêm bài về xây dựng tác nhân với OpenAI Agents SDK.
Những gì bạn cần trước khi bắt đầu
Gọi hàm hay tool calling là cơ chế để mô hình tạo ra một yêu cầu có cấu trúc cho mã của bạn. Mô hình không tự chạy hàm. Nó chỉ trả về tên hàm và chuỗi JSON chứa đối số. Ứng dụng của bạn chịu trách nhiệm parse, xác thực, thực thi và trả kết quả lại cho mô hình.
Ví dụ, người dùng hỏi:
Lấy thời tiết ở Paris.
Mô hình có thể trả về lời gọi:
get_weather({ "location": "Paris, France" })
Thay vì phải phân tích một đoạn văn tự do, bạn nhận được dữ liệu có cấu trúc để xử lý trong code.
Bạn cần chuẩn bị:
- API key của OpenAI.
- Một hàm thật trong ứng dụng, ví dụ
get_weather. - JSON Schema mô tả đối số mà hàm chấp nhận.
- Quyết định dùng endpoint nào:
-
Chat Completions API: cấu trúc cũ hơn, dùng
toolsvàtool_calls. -
Responses API: cấu trúc mới hơn, dùng tool definition phẳng hơn và trả về
function_calltrongoutput.
-
Chat Completions API: cấu trúc cũ hơn, dùng
Các bước dưới đây minh họa cả hai cấu trúc khi cần.
Bước 1: Định nghĩa công cụ của bạn
Một công cụ gồm 3 phần chính:
-
name: tên hàm mà ứng dụng của bạn sẽ map tới. -
description: mô tả khi nào mô hình nên dùng hàm. -
parameters: JSON Schema cho đối số.
Với Chat Completions, định nghĩa tool có dạng:
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city. Use when the user asks about temperature or conditions.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country, e.g. Bogotá, Colombia"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
Với Responses API, các trường name, description, parameters và strict nằm trực tiếp ở cấp tool, không lồng trong khóa function.
Nếu bạn đã có OpenAPI spec cho API phía sau, hãy tái sử dụng phần schema đó để định nghĩa tool. Cách này giúp schema phục vụ cả API testing lẫn function calling. Xem thêm hướng dẫn tạo bộ sưu tập kiểm thử từ đặc tả OpenAPI.
Bước 2: Gửi request đầu tiên
Gửi tin nhắn người dùng cùng danh sách tools cho mô hình. Ví dụ với Chat Completions:
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4.1",
"messages": [
{
"role": "user",
"content": "What is the weather in Paris right now?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string"
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
]
}'
Ở lượt này, mô hình sẽ quyết định:
- Trả lời bằng text thông thường.
- Hoặc trả về một tool call nếu thấy cần gọi
get_weather.
Bạn không nên giả định mô hình luôn gọi hàm, trừ khi bạn cấu hình tool_choice để ép hành vi đó.
Bước 3: Đọc tool call từ phản hồi
Khi mô hình chọn gọi hàm, phản hồi sẽ chứa lời gọi công cụ thay vì câu trả lời cuối cùng.
Trong Chat Completions, tool call nằm trong message.tool_calls:
{
"id": "call_12345xyz",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
}
Trong Responses API, lời gọi nằm trong mảng output:
{
"type": "function_call",
"call_id": "call_12345xyz",
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
Điểm quan trọng: arguments là chuỗi JSON, không phải object đã được parse. Bạn cần parse thủ công trước khi truyền vào hàm.
Ví dụ Node.js:
const toolCall = response.choices[0].message.tool_calls[0];
const functionName = toolCall.function.name;
const args = JSON.parse(toolCall.function.arguments);
if (functionName === "get_weather") {
const result = await getWeather(args);
}
Nên luôn validate args trước khi chạy hàm thật, kể cả khi bạn bật strict mode.
Bước 4: Chạy hàm và trả kết quả về mô hình
Sau khi parse đối số, ứng dụng của bạn gọi hàm nội bộ hoặc API phía sau.
Ví dụ:
async function getWeather({ location }) {
// Ví dụ: gọi API thời tiết thật hoặc mock server
return {
location,
temperature: 18,
unit: "celsius",
condition: "cloudy"
};
}
Với Chat Completions, bạn gửi tiếp lịch sử hội thoại, bao gồm:
- Tin nhắn user ban đầu.
- Tin nhắn assistant chứa
tool_calls. - Tin nhắn
toolchứa kết quả, gắn vớitool_call_id.
Ví dụ dạng message:
{
"role": "tool",
"tool_call_id": "call_12345xyz",
"content": "{\"location\":\"Paris, France\",\"temperature\":18,\"unit\":\"celsius\",\"condition\":\"cloudy\"}"
}
Sau đó gọi model lần nữa để mô hình tạo câu trả lời cuối cùng cho người dùng.
Với Responses API, bạn gửi item function_call_output được gắn bằng call_id.
Luồng tổng quát luôn là:
User request
→ Model trả tool call
→ App parse arguments
→ App chạy hàm
→ App trả output cho model
→ Model trả câu trả lời cuối
Bước 5: Bật strict mode và kiểm soát parallel calls
Khi luồng cơ bản đã chạy được, hãy thêm hai cấu hình để tăng độ tin cậy.
parallel_tool_calls
Mặc định, mô hình có thể trả về nhiều tool call trong cùng một lượt. Ví dụ người dùng hỏi thời tiết ở Paris, Tokyo và Berlin, bạn có thể nhận 3 lời gọi get_weather.
Nếu các lời gọi độc lập, bạn có thể chạy song song:
const results = await Promise.all(
toolCalls.map(async (call) => {
const args = JSON.parse(call.function.arguments);
return getWeather(args);
})
);
Nếu các lời gọi phụ thuộc thứ tự hoặc bạn chỉ muốn xử lý từng cái một, đặt:
{
"parallel_tool_calls": false
}
strict
Đặt strict: true để buộc đối số mô hình tạo ra khớp với JSON Schema.
Ví dụ định nghĩa tool chặt chẽ hơn:
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string"
},
"unit": {
"type": ["string", "null"],
"enum": ["celsius", "fahrenheit", null]
}
},
"required": ["location", "unit"],
"additionalProperties": false
}
}
}
Khi dùng strict mode, cần lưu ý:
- Mỗi object nên có
additionalProperties: false. - Tất cả field trong
propertiesphải nằm trongrequired. - Field “tùy chọn” nên cho phép
null, thay vì bỏ khỏirequired.
Ví dụ unit là tùy chọn về mặt nghiệp vụ, nhưng trong strict schema bạn vẫn khai báo trong required và cho phép null. Nhờ vậy code của bạn luôn biết key nào sẽ xuất hiện.
| Cài đặt | Nó kiểm soát điều gì | Mặc định | Khi nào nên thay đổi |
|---|---|---|---|
parallel_tool_calls |
Liệu nhiều lệnh gọi công cụ có thể quay lại trong một lượt | true |
Đặt false khi các lệnh gọi phụ thuộc vào nhau hoặc phải chạy theo thứ tự |
strict |
Liệu các đối số có bị buộc phải khớp với schema | cố gắng hết sức trừ khi được đặt; khuyến nghị bật | Bật cho bất kỳ lệnh gọi nào bạn phân tích mà không cần mã phòng thủ |
tool_choice |
Liệu mô hình có thể gọi hàm nào và có gọi hay không | auto |
required để buộc gọi, none để tắt, hoặc đặt tên để ghim nó |
Strict mode giúp giảm lỗi cấu trúc JSON, nhưng không thay thế validation nghiệp vụ. Ví dụ location có thể là string hợp lệ nhưng lại nằm ngoài khu vực bạn hỗ trợ. Bạn vẫn cần kiểm tra trong code.
Cách kiểm thử trong Apidog
Trước khi nối tool call vào hàm production, hãy kiểm thử hai phần:
- Đối số mô hình tạo ra có khớp schema không.
- API phía sau mà hàm gọi có phản hồi đúng như ứng dụng kỳ vọng không.
Apidog phù hợp cho phần hợp đồng API: validate request/response, kiểm tra schema và mock API phụ thuộc. Apidog không chạy thay hàm trong ứng dụng của bạn; ứng dụng của bạn vẫn là nơi thực thi business logic.
1. Xác thực cấu trúc arguments
Lấy chuỗi arguments từ phản hồi OpenAI:
"{\"location\":\"Paris, France\",\"unit\":\"celsius\"}"
Parse thành JSON:
{
"location": "Paris, France",
"unit": "celsius"
}
Sau đó dùng Apidog để validate như một request body:
-
locationtồn tại. -
locationlà string. -
unitchỉ nhậncelsius,fahrenheithoặcnull. - Không có field ngoài schema nếu bạn dùng
additionalProperties: false.
Bạn có thể dùng biểu thức JSONPath để kiểm tra field cụ thể, hoặc dùng xác thực dựa trên JSON Schema để kiểm tra toàn bộ payload.
2. Mô phỏng API phía sau
Giả sử get_weather gọi một API thời tiết. Trong quá trình phát triển, API thật có thể:
- Bị rate limit.
- Tốn phí.
- Chưa sẵn sàng.
- Khó tạo các lỗi như timeout hoặc HTTP 429.
Bạn có thể tạo một API giả lập trong Apidog trả về payload thời tiết mẫu:
{
"location": "Paris, France",
"temperature": 18,
"unit": "celsius",
"condition": "cloudy"
}
Sau đó trỏ hàm get_weather vào mock endpoint trong môi trường dev:
async function getWeather({ location, unit }) {
const res = await fetch(`${process.env.WEATHER_API_BASE_URL}/weather`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ location, unit })
});
if (!res.ok) {
throw new Error(`Weather API failed: ${res.status}`);
}
return res.json();
}
Với mock API, bạn có thể chủ động test:
- Response thành công.
- Thiếu field.
- Sai kiểu dữ liệu.
- HTTP 429.
- HTTP 500.
- Timeout.
Quy trình thực tế nên là:
Capture tool call từ OpenAI
→ Parse arguments
→ Validate arguments bằng schema trong Apidog
→ Chạy hàm với mock API của Apidog
→ Kiểm tra output
→ Chỉ sau đó mới nối API thật
Câu hỏi thường gặp
Gọi hàm có hoạt động trong cả Chat Completions và Responses API không?
Có. Cả hai endpoint đều hỗ trợ function calling.
Khác biệt chính:
- Chat Completions lồng định nghĩa hàm trong khóa
functionvà trả vềtool_calls. - Responses API dùng định nghĩa tool phẳng hơn và trả về item
function_calltrong mảngoutput.
Tại sao arguments là chuỗi thay vì object?
arguments là JSON được mã hóa dưới dạng text. Bạn phải parse nó:
const args = JSON.parse(toolCall.function.arguments);
Không nên truyền thẳng chuỗi này vào hàm. Hãy parse, validate, rồi mới thực thi. Nếu muốn bắt lỗi payload sớm, dùng xác thực JSON Schema trước khi gọi business logic.
Strict mode có đảm bảo hàm chạy thành công không?
Không. Strict mode chỉ đảm bảo cấu trúc đối số khớp JSON Schema. Nó không đảm bảo:
- Giá trị hợp lệ về nghiệp vụ.
- API phía sau hoạt động.
- Hàm của bạn không ném lỗi.
Bạn vẫn cần validation nghiệp vụ, xử lý lỗi và retry nếu cần.
Apidog có chạy hàm thật của tôi không?
Không. Apidog không thay thế runtime của ứng dụng. Nó giúp bạn:
- Xác thực payload mà mô hình tạo ra.
- Kiểm tra schema.
- Mock API mà hàm của bạn phụ thuộc.
- Test các response thành công và lỗi.
Ứng dụng của bạn vẫn là nơi parse tool call, chạy hàm và trả kết quả lại cho OpenAI.
Tổng kết
Bạn đã có luồng triển khai function calling đầy đủ:
- Định nghĩa tool bằng JSON Schema.
- Gửi tool cùng request tới OpenAI.
- Đọc
tool_callshoặcfunction_call. - Parse
arguments. - Validate đối số.
- Chạy hàm trong ứng dụng.
- Trả output lại cho mô hình.
- Bật
strictvà cấu hìnhparallel_tool_callstheo nhu cầu. - Dùng Apidog để validate schema và mock API phụ thuộc trước khi lên production.
Nếu bạn muốn kiểm thử phần hợp đồng API, hãy Tải Apidog để xác thực đối số gọi công cụ theo schema và mô phỏng các API mà hàm của bạn phụ thuộc.

Top comments (0)