Công cụ hàm
Cung cấp cho tác nhân AI của bạn các công cụ hàm để gọi API bên ngoài trong khi trò chuyện — truy xuất dữ liệu khách hàng, đặt lịch hẹn, cập nhật bản ghi — với tham số có kiểu.
Công cụ hàm cho phép tác nhân AI của bạn gọi các API bên ngoài trong cuộc gọi điện thoại. Dùng chúng để tra cứu dữ liệu khách hàng, kiểm tra tình trạng còn chỗ, đặt lịch hẹn hoặc thực hiện bất kỳ hành động nào mà backend của bạn hỗ trợ.
Cách hoạt động
- Bạn định nghĩa công cụ bằng một lược đồ (các đối số mà công cụ chấp nhận)
- Bạn cung cấp cấu hình
endpoint(nơi ThunderPhone gọi API của bạn) — hoặc bỏ qua để nhận các lệnh gọi công cụ trên webhook của tổ chức - Trong cuộc gọi, tác nhân AI quyết định thời điểm sử dụng công cụ dựa trên cuộc hội thoại
- ThunderPhone gọi endpoint của bạn với các đối số của công cụ
- Phản hồi API của bạn được gửi lại cho tác nhân AI để tiếp tục cuộc hội thoại
Lược đồ công cụ
Mỗi công cụ tuân theo cấu trúc này:
{
"type": "function",
"function": {
"name": "search_appointments",
"description": "Find available appointment slots for a given date",
"parameters": {
"type": "object",
"properties": {
"date": {
"type": "string",
"description": "Date in YYYY-MM-DD format"
},
"service": {
"type": "string",
"description": "Type of service (e.g., 'consultation', 'follow-up')"
}
},
"required": ["date"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/search",
"method": "POST",
"headers": {
"X-Api-Key": "your-api-key"
}
},
"timeout": 120
}Cấu hình công cụ
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
timeout | số | Không | Thời gian thực thi tối đa tính bằng giây (mặc định: 20, tối đa: 180) |
Định nghĩa hàm
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
name | chuỗi | Có | Mã định danh duy nhất cho công cụ |
description | chuỗi | Có | Cho tác nhân AI biết khi nào cần sử dụng công cụ này |
parameters | đối tượng | Có | JSON Schema cho các đối số của công cụ |
Cấu hình endpoint
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
url | chuỗi | Có | URL endpoint API của bạn |
method | chuỗi | Không | Phương thức HTTP (mặc định: POST) |
headers | đối tượng | Không | Header tùy chỉnh cần bao gồm |
Hai cách gọi
Yêu cầu mà máy chủ của bạn nhận được phụ thuộc vào việc công cụ có
endpoint hay không:
Công cụ có endpoint | Công cụ không có endpoint | |
|---|---|---|
| Nơi gửi yêu cầu | Trực tiếp đến endpoint.url | URL webhook cũ của tổ chức bạn |
| Nội dung | Chỉ các đối số của công cụ | Envelope telephony.tool / web.tool |
| Header | endpoint.headers của bạn + X-ThunderPhone-Call-ID + X-ThunderPhone-Signature | Content-Type + X-ThunderPhone-Signature |
| Khóa ký | Secret webhook của tổ chức | Secret webhook của tổ chức |
Cả hai cách đều chặn — tác nhân AI đang chờ kết quả ngay giữa câu
nói. Thời gian chờ mặc định là 20 giây; đặt timeout ở cấp cao nhất
của công cụ để cho phép thời gian thực thi dài hơn, tối đa 180 giây
theo giới hạn nền tảng. Giữ trình xử lý nhanh. Bạn có thể kết hợp:
trong cuộc gọi mà tổ chức có URL webhook, các công cụ có endpoint được
gọi trực tiếp và các công cụ còn lại sẽ dùng webhook.
Lệnh gọi endpoint trực tiếp
Khi tác nhân AI gọi một công cụ có endpoint, ThunderPhone sẽ gửi
một yêu cầu đến URL của bạn:
Header yêu cầu
POST /appointments/search HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature: abc123...
X-ThunderPhone-Call-ID: 987654321
X-Api-Key: your-api-keyCác header tùy chỉnh từ endpoint.headers của bạn luôn được đưa vào
nguyên văn, cùng với hai header có không gian tên ThunderPhone:
X-ThunderPhone-Signature— HMAC-SHA256 của chính xác các byte trong phần thân yêu cầu, sử dụng secret webhook của tổ chức làm khóaX-ThunderPhone-Call-ID— ID cuộc gọi hiện tại
Content-Type: application/json được đặt trừ khi endpoint.headers
của bạn ghi đè nó — Content-Type tùy chỉnh được ưu tiên.
Phần thân yêu cầu
Với POST / PUT / PATCH, phần thân chỉ chứa các đối số của công cụ
(không có lớp bao), được tuần tự hóa theo chuẩn (khóa được sắp xếp, dấu
phân cách gọn):
{"date":"2025-01-02","service":"consultation"}Với GET / DELETE, các đối số được gửi dưới dạng tham số truy vấn
và phần thân để trống — khi đó chữ ký được tính trên chuỗi byte rỗng.
Xem
Xác minh chữ ký webhook.
Phản hồi
Trả về phản hồi JSON chứa kết quả công cụ:
{
"available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
"timezone": "America/Los_Angeles"
}Phản hồi được định dạng và cung cấp cho AI để tiếp tục cuộc trò chuyện.
Phản hồi không phải JSON được bao trong {"data": "<text>"}; lỗi hết
thời gian chờ và lỗi kết nối được báo cho AI dưới dạng lỗi, để tác nhân
AI có thể xin lỗi và tiếp tục thay vì bị đình trệ.
Điều phối chế độ webhook
Các công cụ không có endpoint được điều phối đến URL webhook cũ
của tổ chức bạn dưới dạng yêu cầu telephony.tool (cuộc gọi điện thoại)
hoặc web.tool (cuộc gọi web) có chữ ký. Không giống thông báo kiểm
toán được gửi đến endpoint webhook sau khi thực thi,
yêu cầu này chính là lần thực thi — phản hồi HTTP của bạn là kết quả
công cụ.
{
"type": "telephony.tool",
"data": {
"call_id": 987654321,
"tool_name": "search_appointments",
"arguments": { "date": "2026-04-21" },
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}web.tool mang origin_domain thay cho from_number /
to_number. Phản hồi bằng kết quả công cụ dưới dạng JSON — cùng hợp
đồng phản hồi như các lệnh gọi endpoint trực tiếp. Yêu cầu được ký bằng
secret webhook của tổ chức trên phần thân thô, giống mọi webhook khác.
Xác minh chữ ký
Các lệnh gọi công cụ trực tiếp được ký giống như webhook:
- HMAC-SHA256 trên chính xác byte của phần thân yêu cầu (JSON chuẩn hóa — khóa được sắp xếp, không có khoảng trắng thừa)
- Dùng secret webhook của tổ chức bạn làm khóa
- Công cụ
GET/DELETEký chuỗi byte rỗng
import hmac
import hashlib
def verify_tool_call(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
@app.post("/appointments/search")
async def search_appointments(request: Request):
body = await request.body()
signature = request.headers.get("X-ThunderPhone-Signature", "")
if not verify_tool_call(body, signature, WEBHOOK_SECRET):
raise HTTPException(status_code=401)
data = json.loads(body)
date = data["date"]
# Look up availability
slots = await get_available_slots(date)
return {"available_slots": slots}app.post('/appointments/search', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-thunderphone-signature'] || '';
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!signature ||
signature.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).send('Invalid signature');
}
const { date, service } = JSON.parse(req.body);
// Look up availability
const slots = getAvailableSlots(date, service);
res.json({ available_slots: slots });
});Các hướng dẫn đầy đủ — bao gồm trường hợp phần thân rỗng và lưu ý khi không có secret — có trong Xác minh chữ ký webhook.
Ví dụ: Quy trình đặt lịch hoàn chỉnh
Dưới đây là bộ công cụ cho hệ thống đặt lịch hẹn hoàn chỉnh:
{
"tools": [
{
"type": "function",
"function": {
"name": "search_appointments",
"description": "Find available appointment slots",
"parameters": {
"type": "object",
"properties": {
"date": { "type": "string", "description": "YYYY-MM-DD" },
"service": { "type": "string" }
},
"required": ["date"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/search",
"method": "POST",
"headers": { "X-Api-Key": "key" }
}
},
{
"type": "function",
"function": {
"name": "book_appointment",
"description": "Book an appointment at a specific time",
"parameters": {
"type": "object",
"properties": {
"date": { "type": "string", "description": "YYYY-MM-DD" },
"time": { "type": "string", "description": "HH:MM format" },
"customer_name": { "type": "string" },
"customer_phone": { "type": "string" }
},
"required": ["date", "time", "customer_name"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/book",
"method": "POST",
"headers": { "X-Api-Key": "key" }
}
},
{
"type": "function",
"function": {
"name": "cancel_appointment",
"description": "Cancel an existing appointment",
"parameters": {
"type": "object",
"properties": {
"confirmation_number": { "type": "string" }
},
"required": ["confirmation_number"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/cancel",
"method": "POST",
"headers": { "X-Api-Key": "key" }
}
}
]
}Thực hành tốt nhất
Viết mô tả rõ ràng
Trường description giúp tác nhân AI hiểu khi nào cần sử dụng công cụ. Hãy nêu rõ công cụ làm gì và khi nào nên dùng.
Xử lý lỗi hợp lý
Trả về thông báo lỗi mà tác nhân AI có thể hiểu: {"error": "No slots available for that date"} thay vì lỗi 500 chung chung.
Giữ phản hồi ngắn gọn
Chỉ trả về thông tin tác nhân AI cần để tiếp tục cuộc hội thoại. Payload lớn làm chậm thời gian phản hồi.
Sử dụng trường bắt buộc một cách hợp lý
Chỉ đánh dấu trường là required khi thực sự cần thiết. Tác nhân AI sẽ hỏi người dùng thông tin bắt buộc trước khi gọi công cụ.
Liên quan
Công cụ do nền tảng quản lý cho HubSpot, Salesforce, Slack, Google Calendar, Google Sheets và Cal.com — không cần endpoint.
Gắn máy chủ MCP và để tác nhân AI gọi các công cụ của máy chủ.
Tích hợp REST có thể tái sử dụng mà bạn có thể gắn vào tác nhân AI.
Một trợ giúp xác minh cho webhook và lệnh gọi công cụ.