---
title: "เครื่องมือฟังก์ชัน"
description: "มอบเครื่องมือฟังก์ชันให้ AI เอเจนต์ของคุณเพื่อเรียกใช้ API ภายนอกระหว่างการสนทนา — ดึงข้อมูลลูกค้า จองนัดหมาย อัปเดตระเบียน — ด้วยพารามิเตอร์ที่กำหนดประเภท"
---

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

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

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

| ความสามารถ | ตำแหน่งที่ทำงาน | การตั้งค่า |
| --- | --- | --- |
| [เครื่องมือในตัว](/th/guides/built-in-tools) | ThunderPhone | คำสั่งในพรอมป์ต์ เครื่องมือบางรายการต้องมีการตั้งค่าเอเจนต์ด้วย |
| [การเชื่อมต่อแอป](/th/guides/connect-apps) | ThunderPhone และผู้ให้บริการที่เชื่อมต่อ | เชื่อมต่อบัญชีและแนบการดำเนินการที่อนุมัติแล้ว |
| [การเชื่อมต่อ API](/th/guides/api-connections) และเครื่องมือฟังก์ชัน | HTTP API ของคุณ | กำหนด endpoint และสคีมา หรือรับการเรียกใช้ฟังก์ชันผ่านเว็บฮุก |
| [เซิร์ฟเวอร์ MCP](/th/guides/mcp-servers) | เซิร์ฟเวอร์ MCP ระยะไกล | เพิ่มเซิร์ฟเวอร์ ค้นหาเครื่องมือ และแนบเข้ากับเอเจนต์ |

---

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

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

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

### การกำหนดค่าเครื่องมือ

| ฟิลด์ | ประเภท | จำเป็น | คำอธิบาย |
|-------|------|----------|-------------|
| `timeout` | number | ไม่ | เวลาดำเนินการสูงสุดเป็นวินาที (ค่าเริ่มต้น: `20` สูงสุด: `180`) |

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

| ฟิลด์ | ประเภท | จำเป็น | คำอธิบาย |
|-------|------|----------|-------------|
| `name` | string | ใช่ | ตัวระบุเฉพาะสำหรับเครื่องมือ |
| `description` | string | ใช่ | อธิบายให้ AI ทราบว่าเมื่อใดควรใช้เครื่องมือนี้ |
| `parameters` | object | ใช่ | JSON Schema สำหรับอาร์กิวเมนต์ของเครื่องมือ |

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

| ฟิลด์ | ประเภท | จำเป็น | คำอธิบาย |
|-------|------|----------|-------------|
| `url` | string | ใช่ | URL endpoint ของ API คุณ |
| `method` | string | ไม่ | เมธอด HTTP (ค่าเริ่มต้น: `POST`) |
| `headers` | object | ไม่ | เฮดเดอร์แบบกำหนดเองที่จะรวมไว้ |

<Note>
  ระบบจะไม่ส่งการกำหนดค่า `endpoint` ไปยังโมเดล AI แต่ ThunderPhone ใช้เฉพาะสำหรับดำเนินการเรียกใช้เครื่องมือเท่านั้น
</Note>

---

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

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

| | เครื่องมือ**ที่มี** `endpoint` | เครื่องมือ**ที่ไม่มี** `endpoint` |
|---|---|---|
| ปลายทางของคำขอ | ส่งตรงไปยัง `endpoint.url` | [URL เว็บฮุกแบบเดิม](/api-reference/organizations#legacy-single-url-webhook) ขององค์กรคุณ |
| เนื้อหาคำขอ | **อาร์กิวเมนต์ของเครื่องมือโดยตรง** | ซองข้อมูล `telephony.tool` / `web.tool` |
| เฮดเดอร์ | `endpoint.headers` ของคุณ + `X-ThunderPhone-Call-ID` + `X-ThunderPhone-Signature` | `Content-Type` + `X-ThunderPhone-Signature` |
| คีย์สำหรับลงนาม | ซีเคร็ตเว็บฮุกขององค์กร | ซีเคร็ตเว็บฮุกขององค์กร |

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

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

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

### ส่วนหัวคำขอ

```http
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 อีก 2 รายการ:

- `X-ThunderPhone-Signature` — HMAC-SHA256 ของไบต์เนื้อหาคำขอ
  ที่ตรงกันทุกประการ โดยใช้ **ความลับ webhook ขององค์กร** เป็นคีย์
- `X-ThunderPhone-Call-ID` — ID การโทรปัจจุบัน

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

<Warning>
  ลายเซ็นใช้ความลับ webhook ระดับองค์กรจาก
  [`GET /v1/webhook`](/api-reference/organizations#legacy-single-url-webhook) เป็นคีย์
  หากองค์กรของคุณไม่เคยกำหนดค่า webhook แบบเดิม จะไม่มี
  ความลับ และการเรียกใช้เครื่องมือจะมี **เฉพาะ**
  `X-ThunderPhone-Call-ID` — ตัวจัดการที่ล้มเหลวทันทีเมื่อไม่มีลายเซ็นจะปฏิเสธคำขอเหล่านั้น
  ให้กำหนดค่า webhook แบบเดิมเพื่อรับความลับ หรือใส่ความลับที่ใช้ร่วมกันของคุณเองใน
  `endpoint.headers`
</Warning>

### เนื้อหาคำขอ

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

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

สำหรับ `GET` / `DELETE` อาร์กิวเมนต์จะถูกส่งเป็น **พารามิเตอร์ query**
และเนื้อหาจะว่างเปล่า — จากนั้นลายเซ็นจะคำนวณจาก
สตริงไบต์ว่าง ดู
[ตรวจสอบลายเซ็น webhook](/th/guides/verify-webhook-signatures)

### การตอบกลับ

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

```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`
(การโทรผ่านเว็บ) ที่มีลายเซ็น ซึ่งต่างจาก[การแจ้งเตือนการตรวจสอบ](/th/webhooks/events)
ที่ส่งไปยัง endpoint ของ webhook หลังการดำเนินการ คำขอนี้**คือ**
การดำเนินการ — การตอบกลับ HTTP ของคุณคือผลลัพธ์ของเครื่องมือ

```json
{
  "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 อื่นทั้งหมด

<Note>
  [endpoint ของ webhook](/th/webhooks/endpoints) ที่สมัครรับข้อมูลจะได้รับ
  การ**แจ้งเตือน `telephony.tool` / `web.tool` ที่ไม่บล็อก
  หลังจาก** เครื่องมือแต่ละรายการทำงานเพิ่มเติม (ไม่ว่าจะดำเนินการผ่านเส้นทางใด)
  รวมถึงการตอบกลับของเครื่องมือ — มีประโยชน์สำหรับบันทึกการตรวจสอบ ดู
  [แค็ตตาล็อกเหตุการณ์](/th/webhooks/events)
</Note>

---

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

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

- HMAC-SHA256 บนไบต์ของเนื้อหาคำขอแบบตรงตัว (JSON มาตรฐาน —
  เรียงลำดับคีย์ ไม่มีช่องว่างเพิ่มเติม)
- ใช้ข้อมูลลับเว็บฮุกขององค์กรคุณเป็นคีย์
- เครื่องมือ `GET` / `DELETE` ลงลายเซ็นสตริงไบต์ว่าง

<CodeGroup>
```python Python
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}
```

```javascript Node.js
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 });
});
```
</CodeGroup>

สูตรการใช้งานฉบับสมบูรณ์ — รวมถึงกรณีเนื้อหาว่างและข้อควรระวังเมื่อไม่มีข้อมูลลับ —
อยู่ใน[ตรวจสอบลายเซ็นเว็บฮุก](/th/guides/verify-webhook-signatures)

---

## ตัวอย่าง: โฟลว์การจองแบบครบถ้วน

นี่คือชุดเครื่องมือสำหรับระบบจองนัดหมายแบบครบถ้วน:

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

---

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

<AccordionGroup>
  <Accordion title="เขียนคำอธิบายให้ชัดเจน">
    ฟิลด์ `description` ช่วยให้ AI เข้าใจว่า<strong>เมื่อใด</strong>ควรใช้เครื่องมือ โปรดระบุให้ชัดเจนว่าเครื่องมือทำอะไรและเหมาะจะใช้เมื่อใด
  </Accordion>

  <Accordion title="จัดการข้อผิดพลาดอย่างเหมาะสม">
    ส่งข้อความข้อผิดพลาดที่ AI เข้าใจได้ เช่น `{"error": "No slots available for that date"}` แทนข้อผิดพลาด 500 แบบทั่วไป
  </Accordion>

  <Accordion title="ตอบกลับอย่างกระชับ">
    ส่งคืนเฉพาะสิ่งที่ AI ต้องใช้เพื่อดำเนินการสนทนาต่อไป เพย์โหลดขนาดใหญ่ทำให้เวลาตอบสนองช้าลง
  </Accordion>

  <Accordion title="ใช้ฟิลด์ที่จำเป็นอย่างรอบคอบ">
    กำหนดฟิลด์เป็น `required` เฉพาะเมื่อจำเป็นจริง ๆ AI จะขอข้อมูลที่จำเป็นจากผู้ใช้ก่อนเรียกใช้เครื่องมือ
  </Accordion>
</AccordionGroup>

---

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

<CardGroup cols={2}>
  <Card title="เครื่องมือในตัว" icon="wrench" href="/th/guides/built-in-tools">
    สั่งให้ดำเนินการโทรที่แพลตฟอร์มจัดการโดยไม่ต้องกำหนดเอนด์พอยต์
  </Card>
  <Card title="การเชื่อมต่อแอป" icon="plug" href="/th/guides/connect-apps">
    เครื่องมือที่แพลตฟอร์มจัดการสำหรับ HubSpot, Salesforce, Slack, Google
    Calendar, Google Sheets และ Cal.com — ไม่ต้องมีเอนด์พอยต์
  </Card>
  <Card title="เซิร์ฟเวอร์ MCP" icon="server" href="/th/guides/mcp-servers">
    แนบเซิร์ฟเวอร์ MCP และให้เอเจนต์เรียกใช้เครื่องมือของเซิร์ฟเวอร์
  </Card>
  <Card title="การเชื่อมต่อ API" icon="code" href="/th/guides/api-connections">
    การผสานรวม REST ที่ใช้ซ้ำได้ซึ่งคุณสามารถแนบกับเอเจนต์ได้
  </Card>
  <Card title="ตรวจสอบลายเซ็น Webhook" icon="shield-check" href="/th/guides/verify-webhook-signatures">
    ตัวช่วยตรวจสอบเดียวสำหรับ Webhook และการเรียกใช้เครื่องมือ
  </Card>
</CardGroup>
