---
title: "สร้างการผสานรวมเครื่องมือ (API)"
description: "ให้เอเจนต์ของคุณเรียกใช้ API ของคุณระหว่างการสนทนา — ค้นหาฐานข้อมูล สร้างทิกเก็ต ค้นหาคำสั่งซื้อ"
---

การผสานรวมเครื่องมือ คือ HTTP endpoint ที่นำกลับมาใช้ซ้ำได้ซึ่งเอเจนต์สามารถ
เรียกใช้ระหว่างการโทร คุณให้ ThunderPhone คำอธิบาย JSON schema
ของเครื่องมือพร้อม URL ของ endpoint จากนั้นเอเจนต์จะตัดสินใจว่าจะเรียกใช้เมื่อใด
ตามการสนทนา และ ThunderPhone จะส่งคำขอ HTTP ขาออกจากเซิร์ฟเวอร์ของตน
และส่งคืนการตอบกลับให้เอเจนต์

<Note>
  แดชบอร์ดรองรับความต้องการด้านเครื่องมือส่วนใหญ่โดยไม่ต้องใช้ API นี้: **การเชื่อมต่อ
  → แอป** เชื่อมต่อ Slack, HubSpot, Salesforce, Google Calendar,
  Google Sheets และ Cal.com ได้ด้วยการคลิก OAuth เพียงไม่กี่ครั้ง; **การเชื่อมต่อ →
  API** เปลี่ยน HTTP API ใดก็ได้ให้เป็นการดำเนินการของเอเจนต์ (วางคำสั่ง cURL
  และวิซาร์ด AI จะร่างเครื่องมือให้ พร้อม Test Request ในตัว); และ **การเชื่อมต่อ → MCP**
  เพิ่มเซิร์ฟเวอร์ MCP ดู
  [การเชื่อมต่อ](/th/guides/concepts) คู่มือนี้ครอบคลุม
  API ระดับล่างที่อยู่ภายใต้ส่วน API
</Note>

คู่มือนี้จะอธิบายการสร้างเครื่องมือค้นหาสภาพอากาศแบบครบทุกขั้นตอน

## โครงสร้างของเครื่องมือ

มีสองส่วน:

1. **สคีมา** — นิยามฟังก์ชันรูปแบบ OpenAI
   (`{type: "function", function: {name, description, parameters}}`)
   ที่บอก LLM ว่าเครื่องมือนี้ทำอะไรและรับอาร์กิวเมนต์ใดบ้าง
2. **endpoint** — URL ที่เซิร์ฟเวอร์ของ ThunderPhone เรียกใช้เมื่อ
   LLM ตัดสินใจใช้เครื่องมือ คำขอเป็น JSON POST โดยมี
   อาร์กิวเมนต์ที่ LLM เลือกเป็นเนื้อหาคำขอ

## 1. เลือกตัวแก้ไข

<CardGroup cols={2}>
  <Card title="แดชบอร์ด" icon="window-maximize">
    เปิด **การเชื่อมต่อ → API** สร้างหรือแก้ไขการเชื่อมต่อ API
    เปลี่ยนตัวแก้ไขพารามิเตอร์เป็น **JSON** แล้วเพิ่มรูปแบบที่นั่น
  </Card>
  <Card title="API การผสานรวม" icon="plug">
    สร้างสเปกด้วย `POST /v1/integrations` หรืออัปเดตด้วย
    `PATCH /v1/integrations/{id}`
  </Card>
</CardGroup>

ทั้งสองวิธีจะสร้างการผสานรวมที่บันทึกไว้ แนบการผสานรวมนั้นเข้ากับ
เอเจนต์หลังจากบันทึกแล้ว Agents API ไม่มีฟิลด์ `tools` แบบอินไลน์ที่เขียนได้
คู่มือนี้ใช้เส้นทาง API การผสานรวม

## 2. สร้างการผสานรวม

```bash
curl -X POST https://api.thunderphone.com/v1/integrations \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Weather API",
    "spec": {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a zip code.",
        "parameters": {
          "type": "object",
          "properties": {
            "zip": { "type": "string", "description": "5-digit US ZIP code" }
          },
          "required": ["zip"]
        }
      }
    },
    "endpoint_url":    "https://api.example.com/weather",
    "endpoint_method": "GET",
    "headers": [
      { "key": "X-Api-Key", "value": "your-provider-key" }
    ]
  }'
```

บันทึก `id` ที่ส่งกลับมา (UUID)

<Tip>
  ใช้ความละเอียดรอบคอบกับ `description` ของเครื่องมือและพารามิเตอร์แต่ละรายการ
  LLM ใช้สตริงเหล่านี้ขณะรันไทม์เพื่อตัดสินใจว่าควรเรียกเครื่องมือหรือไม่
  และควรเรียกอย่างไร คำอธิบายที่คลุมเครือ → การเรียกเครื่องมือที่คลุมเครือ
</Tip>

### ประกาศ `format: "email"` สำหรับพารามิเตอร์ที่อยู่

พารามิเตอร์ที่รับที่อยู่อีเมลควรระบุไว้ในสคีมาดังนี้:

```json
"email": { "type": "string", "format": "email", "description": "The caller's email address" }
```

`format` เป็นมากกว่าคำใบ้ สำหรับสคีมาอีเมลที่ผ่านการแก้ไขแล้ว ก่อนเรียก endpoint ของคุณ ThunderPhone จะตัดช่องว่างรอบค่า เปลี่ยนโดเมนเป็นตัวพิมพ์เล็ก แปลงคำภาษาอังกฤษแบบเดี่ยว `at`, `dot`, `underscore`, `dash` และ `hyphen` เป็นอักขระที่เกี่ยวข้อง และลบช่องว่างที่อยู่ติดกับ `@`, `.`, `_` และ `-` โดยตรง คำเหล่านี้มีความหมายเดียวกันไม่ว่าบันทึกการสนทนาจะมี `@` แบบตัวอักษรอยู่แล้วหรือไม่:
`"john dot smith at gmail dot com"` จะกลายเป็น
`john.smith@gmail.com`

ช่องว่างภายในอื่น ๆ จะถูกปฏิเสธแทนที่จะถูกรวมเข้าด้วยกันโดยอัตโนมัติ คำตัวคั่นที่พูดรองรับเฉพาะภาษาอังกฤษ รูปแบบที่เว้นวรรคซึ่งไม่ใช่ภาษาอังกฤษหรือไม่รู้จักจะไม่ผ่านการตรวจสอบ โดเมนสากลที่ถูกต้องและส่วน local ของ SMTPUTF8 ได้รับการยอมรับ อินพุต Punycode จะยังคงเป็น Punycode และอินพุตโดเมน Unicode จะยังคงเป็น Unicode หลังการทำให้ตัวแยกวิเคราะห์เป็นมาตรฐาน ดังนั้น API ของคุณจะได้รับรูปแบบตามธรรมเนียมที่ผู้โทรระบุ หากค่าสุดท้ายไม่ถูกต้อง เครื่องมือจะ**ไม่ถูกเรียก** เอเจนต์จะได้รับ
`invalid_email_argument` เพื่อแจ้งให้ยืนยันการสะกดกับผู้โทรและส่งที่อยู่แบบตัวอักษรอีกครั้ง

อีเมลแบบไม่บังคับที่ไม่ได้ระบุจะไม่ถูกแก้ไข `null`, สตริงว่าง หรือสตริงที่มีแต่ช่องว่างก็จะไม่ถูกแก้ไขเช่นกันเมื่อพร็อพเพอร์ตีเป็นแบบไม่บังคับหรืออนุญาต nullable ค่าเดียวกันนี้จะถูกปฏิเสธสำหรับอีเมลที่จำเป็นและไม่อนุญาต null

ระบบจะตรวจสอบการอ้างอิงสคีมาในเครื่อง เช่น `#/$defs/email` และ
`#/definitions/email` รวมถึง `anyOf`, `oneOf` และ `allOf` โดยมีขีดจำกัดรอบและความลึก `$ref` ที่ไม่ใช่ในเครื่องหรือแก้ไขไม่ได้เป็นข้อจำกัดการบังคับใช้ที่ทราบ และจะถูกส่งผ่านโดยไม่เปลี่ยนแปลง เช่นเดียวกับการเรียกที่สแนปช็อตเครื่องมือไม่มีสคีมาที่ใช้งานได้ เก็บสคีมาอีเมลไว้ในเครื่องเมื่อคุณต้องการให้มีการใช้เกตนี้

พารามิเตอร์ที่ไม่มีรูปแบบอีเมลซึ่งถูกบังคับใช้จะถูกส่งผ่านตามที่โมเดลสร้างขึ้นทุกประการ

รูปแบบที่รองรับคือ `date-time`, `time`, `date`, `duration`,
`email`, `hostname`, `ipv4`, `ipv6` และ `uuid` โดยปัจจุบันมีเพียง `email` เท่านั้นที่ถูกทำให้เป็นมาตรฐานและบังคับใช้

## 3. ทดสอบ endpoint ในแซนด์บ็อกซ์

ก่อนเชื่อมโยงการผสานรวมกับเอเจนต์ ให้ส่งคำขอที่ลงนามจากเซิร์ฟเวอร์ของ ThunderPhone เพื่อยืนยันการเชื่อมต่อ:

```bash
curl -X POST https://api.thunderphone.com/v1/integrations/test-request \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://api.example.com/weather?zip=94110",
    "method": "GET",
    "headers": { "X-Api-Key": "your-provider-key" }
  }'
```

```json Response
{
  "ok": true,
  "status": 200,
  "elapsed_ms": 187,
  "response_headers": { "content-type": "application/json" },
  "response_preview": "{\"temperature_f\": 64, ...}"
}
```

การทดสอบนี้ยังเสริมความแข็งแกร่งให้กับตัวป้องกัน SSRF ของ ThunderPhone ด้วย โดยคำขอไปยัง localhost หรือช่วง IP ส่วนตัวจะส่งกลับ `400 code=url_not_allowed`

## 4. เชื่อมการผสานรวมกับเอเจนต์

แนบผ่าน `integration_ids` เมื่อสร้างหรืออัปเดตเอเจนต์:

```bash
curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_ids": ["f9b5a1a4-..."]
  }'
```

คุณสามารถเชื่อมการผสานรวมหลายรายการกับเอเจนต์หนึ่งตัวได้ พรอมต์ของเอเจนต์สามารถ
อ้างอิงการผสานรวมตามชื่อได้ — "ใช้ `get_weather` เมื่อผู้โทรถาม
เกี่ยวกับสภาพอากาศ" — หรือให้เอเจนต์ค้นพบโดยอัตโนมัติจาก
คำอธิบายสคีมาก็ได้

## 5. ติดตั้งใช้งานเอนด์พอยต์

เมื่อเอเจนต์เรียกใช้เครื่องมือ ThunderPhone จะส่ง POST ที่มีลายเซ็นไปยัง
`endpoint_url` ของคุณ:

```
POST /weather HTTP/1.1
Host: api.example.com
X-Api-Key: your-provider-key
X-ThunderPhone-Signature: <HMAC-SHA256 hex>
X-ThunderPhone-Call-ID: 987654321
Content-Type: application/json

{"zip": "94110"}
```

เซิร์ฟเวอร์ของคุณตอบกลับด้วย JSON ซึ่งจะส่งกลับไปยัง LLM:

```json
{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}
```

LLM จะรับข้อมูลจากการตอบกลับนั้นและพูดสรุปที่เข้าใจง่ายให้ผู้โทรฟัง

<Warning>
  ลายเซ็นจะคำนวณจากเนื้อหาคำขอแบบดิบโดยใช้ `secret` เดียวกับเอนด์พอยต์
  เว็บฮุกของคุณ **ตรวจสอบลายเซ็น** — เอนด์พอยต์เครื่องมือเปิดเผยต่ออินเทอร์เน็ต
  และมีความเสี่ยงต่อการปลอมแปลงเช่นเดียวกับเว็บฮุก ดู
  [ตรวจสอบลายเซ็นเว็บฮุก](/th/guides/verify-webhook-signatures)
</Warning>

## 6. ทดสอบลูป

เรียกใช้ [เซสชันไมโครโฟน](/api-reference/mic-sessions) กับเอเจนต์
และถามคำถามที่เครื่องมือของคุณรองรับ ("อากาศที่
94110 เป็นอย่างไร?") ทรานสคริปต์ของการโทรจะแสดงการทำงานครบวงจร:

```json
{
  "call_id": 987654321,
  "transcripts": [
    { "role": "user",
      "content": "What's the weather in 94110?" },
    { "role": "tool_call",
      "content": "{\"tool_call\": \"get_weather\", \"arguments\": {\"zip\": \"94110\"}}" },
    { "role": "tool_response",
      "content": "{\"tool_name\": \"get_weather\", \"response\": {\"temperature_f\": 64, \"condition\": \"Partly cloudy\"}}" },
    { "role": "agent",
      "content": "It's 64 degrees and partly cloudy." }
  ]
}
```

คุณสามารถดึงข้อมูลนี้ผ่าน
[`GET /v1/calls/{call_id}/transcript`](/api-reference/calls#get-transcript);
สตรีมเหตุการณ์แบบดิบ (พร้อมเวลาของแต่ละรายการและตำแหน่งออฟเซ็ตเสียง) อยู่ที่
[`GET /v1/calls/{call_id}/history`](/api-reference/calls#get-history)

## ข้อควรระวังที่พบบ่อย

<AccordionGroup>
  <Accordion title="เอเจนต์ไม่เรียกใช้เครื่องมือ">
    LLM ตัดสินใจจากคำอธิบายของเครื่องมือ หากคำถามของผู้โทร
    ไม่ตรงกับคำอธิบาย โมเดลจะไม่เรียกใช้
    เครื่องมือ ปรับคำอธิบายให้เฉพาะเจาะจงขึ้น (เพิ่มคำพ้องความหมายและ
    รูปแบบถ้อยคำที่พบบ่อย) หรือระบุอย่างชัดเจนในพรอมต์ของเอเจนต์ ("เมื่อ
    ผู้โทรถามเกี่ยวกับสภาพอากาศ ให้ใช้ `get_weather`")
  </Accordion>

  <Accordion title="เครื่องมือส่งคืนข้อมูลมากเกินไป">
    การตอบกลับที่มีขนาดเกิน 6 kB จะถูกตัดทอนในตัวอย่างทรานสคริปต์ ส่งคืน
    เฉพาะฟิลด์ที่ LLM ต้องการ — ไม่ใช่ทั้งแถวข้อมูลของคุณ
  </Accordion>

  <Accordion title="หมดเวลา">
    เอนด์พอยต์เครื่องมือมีระยะหมดเวลาเริ่มต้น 10 วินาที หากต้องการเวลานานกว่า
    ให้จัดการแบบอะซิงโครนัส: ส่งคืน `{"status": "pending", "request_id": "..."}`
    และแสดงผลลัพธ์ผ่านการเรียกใช้เครื่องมือแยกต่างหาก
  </Accordion>

  <Accordion title="การกำหนดเวอร์ชัน">
    ทุกการ `PATCH` การผสานรวมจะสร้างรีวิชันใหม่ ตรวจสอบ
    [`GET /v1/integrations/{id}/versions`](/api-reference/integrations#version-history)
    เพื่อดูว่าใครเปลี่ยนแปลงอะไร หากคุณทำให้สคีมาของเครื่องมือใช้งานไม่ได้ คุณสามารถ
    ย้อนกลับด้วยตนเองได้โดย PATCH สแนปช็อตเก่ากลับเข้าไป
  </Accordion>
</AccordionGroup>

---

## ขั้นตอนถัดไป

<CardGroup cols={2}>
  <Card title="ข้อมูลอ้างอิงการผสานรวม" icon="plug" href="/api-reference/integrations">
    CRUD การโอน และประวัติเวอร์ชัน
  </Card>
  <Card title="ข้อกำหนด Function Tools" icon="screwdriver-wrench" href="/th/tools/overview">
    ไวยากรณ์ JSON schema แบบเต็มและสัญญา signed-endpoint
  </Card>
  <Card title="ตรวจสอบลายเซ็น" icon="shield-check" href="/th/guides/verify-webhook-signatures">
    ใช้รูปแบบลายเซ็น webhook กับปลายทางเครื่องมือ
  </Card>
  <Card title="API สำหรับบันทึกการสนทนาและประวัติ" icon="phone" href="/api-reference/calls">
    ตรวจสอบการไป-กลับทั้งหมดของการเรียกใช้เครื่องมือ
  </Card>
</CardGroup>
