ThunderPhone 2.0 เปิดให้ใช้งานแล้วเริ่มใช้งานได้ด้วยตัวเอง ราคาเริ่มต้น 2 เซนต์ต่อนาที.อ่านประกาศเปิดตัว

Developer cookbook

สร้างการผสานรวมเครื่องมือ (API)

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

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

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

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

มีสองส่วน:

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

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

แดชบอร์ด

เปิด การเชื่อมต่อ → API สร้างหรือแก้ไขการเชื่อมต่อ API เปลี่ยนตัวแก้ไขพารามิเตอร์เป็น JSON แล้วเพิ่มรูปแบบที่นั่น

API การผสานรวม

สร้างสเปกด้วย POST /v1/integrations หรืออัปเดตด้วย PATCH /v1/integrations/{id}

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

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

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)

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

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

"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 เพื่อยืนยันการเชื่อมต่อ:

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" }
  }'
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 เมื่อสร้างหรืออัปเดตเอเจนต์:

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:

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

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

6. ทดสอบลูป

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

{
  "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; สตรีมเหตุการณ์แบบดิบ (พร้อมเวลาของแต่ละรายการและตำแหน่งออฟเซ็ตเสียง) อยู่ที่ GET /v1/calls/{call_id}/history

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

เอเจนต์ไม่เรียกใช้เครื่องมือ

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

เครื่องมือส่งคืนข้อมูลมากเกินไป

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

หมดเวลา

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

การกำหนดเวอร์ชัน

ทุกการ PATCH การผสานรวมจะสร้างรีวิชันใหม่ ตรวจสอบ GET /v1/integrations/{id}/versions เพื่อดูว่าใครเปลี่ยนแปลงอะไร หากคุณทำให้สคีมาของเครื่องมือใช้งานไม่ได้ คุณสามารถ ย้อนกลับด้วยตนเองได้โดย PATCH สแนปช็อตเก่ากลับเข้าไป


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