เครื่องมือฟังก์ชัน

เครื่องมือฟังก์ชันช่วยให้ AI เอเจนต์ของคุณเรียกใช้ API ภายนอกระหว่างการโทรได้ ใช้เพื่อค้นหาข้อมูลลูกค้า ตรวจสอบเวลาว่าง จองนัดหมาย หรือดำเนินการใดๆ ที่แบ็กเอนด์ของคุณรองรับ

วิธีการทำงาน

  1. กำหนดเครื่องมือด้วยสคีมา (อาร์กิวเมนต์ที่เครื่องมือรับได้)
  2. ระบุการกำหนดค่า endpoint (ตำแหน่งที่ ThunderPhone เรียก API ของคุณ) หรือไม่ต้องระบุเพื่อรับการเรียกใช้เครื่องมือที่เว็บฮุกขององค์กร
  3. ระหว่างการโทร AI จะตัดสินใจว่าจะใช้เครื่องมือเมื่อใดตามบทสนทนา
  4. ThunderPhone เรียก endpoint ของคุณพร้อมอาร์กิวเมนต์ของเครื่องมือ
  5. ระบบจะส่งการตอบกลับจาก API ของคุณกลับไปยัง AI เพื่อดำเนินบทสนทนาต่อ

สคีมาเครื่องมือ

เครื่องมือแต่ละรายการมีโครงสร้างดังนี้:

{
  "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"
    }
  }
}

คำจำกัดความของฟังก์ชัน

ฟิลด์ประเภทต้องระบุคำอธิบาย
namestringใช่ตัวระบุที่ไม่ซ้ำกันสำหรับเครื่องมือ
descriptionstringใช่อธิบายให้ AI ทราบว่าควรใช้เครื่องมือนี้เมื่อใด
parametersobjectใช่JSON Schema สำหรับอาร์กิวเมนต์ของเครื่องมือ

การกำหนดค่า Endpoint

ฟิลด์ประเภทต้องระบุคำอธิบาย
urlstringใช่URL endpoint ของ API คุณ
methodstringไม่เมธอด HTTP (ค่าเริ่มต้น: POST)
headersobjectไม่เฮดเดอร์แบบกำหนดเองที่จะรวมไว้

เส้นทางการเรียกใช้สองแบบ

คำขอที่เซิร์ฟเวอร์ของคุณได้รับขึ้นอยู่กับว่าเครื่องมือมี endpoint หรือไม่:

เครื่องมือที่มี endpointเครื่องมือที่ไม่มี endpoint
ปลายทางของคำขอส่งไปยัง endpoint.url โดยตรงURL เว็บฮุกเดิม ขององค์กรคุณ
เนื้อหาคำขออาร์กิวเมนต์ของเครื่องมือโดยตรงซองข้อมูล telephony.tool / web.tool
เฮดเดอร์endpoint.headers ของคุณ + X-ThunderPhone-Call-ID + X-ThunderPhone-SignatureContent-Type + X-ThunderPhone-Signature
คีย์สำหรับการลงนามความลับเว็บฮุกขององค์กรความลับเว็บฮุกขององค์กร

ทั้งสองเส้นทางเป็นแบบ บล็อกการทำงาน — AI กำลังรอผลลัพธ์อยู่ระหว่างประโยค — โดยมีระยะหมดเวลา 20 วินาที ให้ตัวจัดการทำงานอย่างรวดเร็ว สามารถใช้ร่วมกันได้: ในการโทรที่องค์กรมี URL เว็บฮุก เครื่องมือที่มี endpoint จะถูก เรียกใช้โดยตรง และเครื่องมือที่เหลือจะกลับไปใช้เว็บฮุก

การเรียกใช้ endpoint โดยตรง

เมื่อ AI เรียกใช้เครื่องมือที่มี endpoint ThunderPhone จะส่ง คำขอไปยัง URL ของคุณ:

ส่วนหัวคำขอ

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-key

ส่วนหัวแบบกำหนดเองจาก endpoint.headers ของคุณจะถูกรวมไว้เสมอ ตามเดิม พร้อมส่วนหัวในเนมสเปซของ ThunderPhone สองรายการ:

ระบบจะตั้งค่า Content-Type: application/json เว้นแต่ endpoint.headers ของคุณจะเขียนทับ — Content-Type แบบกำหนดเองจะมีผลเหนือกว่า

เนื้อหาคำขอ

สำหรับ POST / PUT / PATCH เนื้อหาจะมี เฉพาะ อาร์กิวเมนต์ของเครื่องมือเท่านั้น (ไม่มีตัวห่อ) ซึ่งจัดลำดับแบบมาตรฐาน (เรียงคีย์ ตัวคั่นแบบกระชับ):

{"date":"2025-01-02","service":"consultation"}

สำหรับ GET / DELETE อาร์กิวเมนต์จะถูกส่งเป็น พารามิเตอร์ query และเนื้อหาจะว่างเปล่า — จากนั้นลายเซ็นจะคำนวณจาก สตริงไบต์ว่าง ดู ยืนยันลายเซ็น webhook

การตอบกลับ

ส่งคืนการตอบกลับ JSON พร้อมผลลัพธ์ของเครื่องมือ:

{
  "available_slots": ["9:00 AM", "2:00 PM", "4:30 PM"],
  "timezone": "America/Los_Angeles"
}

ระบบจะจัดรูปแบบการตอบกลับและส่งให้ AI เพื่อดำเนิน การสนทนาต่อ การตอบกลับที่ไม่ใช่ JSON จะถูกห่อเป็น {"data": "<text>"} การหมดเวลาและการเชื่อมต่อล้มเหลวจะถูกรายงานให้ AI เป็นข้อผิดพลาด เพื่อให้ เอเจนต์ขออภัยและดำเนินการต่อได้แทนที่จะหยุดค้าง

การส่งต่อในโหมด webhook

เครื่องมือที่ ไม่มี endpoint จะถูกส่งต่อไปยัง URL webhook แบบเดิม ขององค์กรคุณในรูปแบบคำขอ telephony.tool (การโทรศัพท์) หรือ web.tool (การเรียกผ่านเว็บ) ที่ลงลายเซ็นแล้ว ซึ่งต่างจาก การแจ้งเตือนสำหรับการตรวจสอบ ที่ส่งไปยัง endpoint ของ webhook หลังการดำเนินการ คำขอนี้ คือ การดำเนินการ — การตอบกลับ HTTP ของคุณคือผลลัพธ์ของเครื่องมือ

{
  "type": "telephony.tool",
  "data": {
    "call_id": 987654321,
    "tool_name": "search_appointments",
    "arguments": { "date": "2026-04-21" },
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  }
}

web.tool มี origin_domain แทน from_number / to_number ตอบกลับด้วยผลลัพธ์ของเครื่องมือในรูปแบบ JSON — เป็นสัญญาการตอบกลับเดียวกัน กับการเรียกใช้ endpoint โดยตรง คำขอจะลงลายเซ็นด้วยข้อมูลลับ webhook ขององค์กร บนเนื้อหาแบบดิบ เช่นเดียวกับ webhook อื่นทั้งหมด


การตรวจสอบลายเซ็น

การเรียกใช้เครื่องมือโดยตรงจะมีการลงลายเซ็นด้วยวิธีเดียวกับ webhook:

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 });
});

ตัวอย่างฉบับสมบูรณ์ — รวมถึงกรณีเนื้อหาว่างและข้อควรระวังเมื่อไม่มี secret — อยู่ใน ตรวจสอบลายเซ็น webhook


ตัวอย่าง: ขั้นตอนการจองแบบสมบูรณ์

ต่อไปนี้คือชุดเครื่องมือสำหรับระบบจองนัดหมายแบบสมบูรณ์:

{
  "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" }
      }
    }
  ]
}

แนวทางปฏิบัติที่ดีที่สุด

เขียนคำอธิบายให้ชัดเจน

ฟิลด์ description ช่วยให้ AI เข้าใจว่าควรใช้เครื่องมือ เมื่อใด ระบุให้ชัดเจนว่าเครื่องมือทำอะไรและเหมาะสมที่จะใช้เมื่อใด

จัดการข้อผิดพลาดอย่างเหมาะสม

ส่งข้อความข้อผิดพลาดที่ AI เข้าใจได้ เช่น {"error": "No slots available for that date"} แทนข้อผิดพลาด 500 แบบทั่วไป

ตอบกลับอย่างกระชับ

ส่งกลับเฉพาะสิ่งที่ AI ต้องใช้เพื่อสนทนาต่อ เพย์โหลดขนาดใหญ่ทำให้เวลาตอบสนองช้าลง

ใช้ฟิลด์ที่จำเป็นอย่างรอบคอบ

กำหนดฟิลด์เป็น required เฉพาะเมื่อจำเป็นจริง ๆ AI จะขอข้อมูลที่จำเป็นจากผู้ใช้ก่อนเรียกใช้เครื่องมือ


ที่เกี่ยวข้อง