> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 构建工具集成（API）

> 让您的智能体在对话过程中调用您的 API——搜索数据库、创建工单、查询订单。

**工具集成**是一个可复用的 HTTP 端点，智能体可以在通话期间调用它。您向 ThunderPhone 提供该工具的 JSON Schema 描述和端点 URL；智能体会根据对话决定何时调用它，ThunderPhone 则会从其服务器发出出站 HTTP 请求，并将响应返回给智能体。

<Note>
  控制台无需使用此 API 即可满足大多数工具需求：**连接
  → 应用** 可通过几次 OAuth 点击连接 Slack、HubSpot、Salesforce、Google Calendar、
  Google Sheets 和 Cal.com；**连接 →
  API** 可将任何 HTTP API 转换为智能体操作（粘贴一条 cURL 命令后，AI 向导会起草工具，并提供内置的测试请求功能）；**连接 → MCP** 可添加 MCP 服务器。请参阅
  [连接](/zh/guides/concepts)。本指南介绍的是 API 界面底层的原始
  API。
</Note>

本指南将端到端演示如何构建天气查询工具。

## 工具的组成

包含两部分：

1. **Schema** —— OpenAI 风格的函数定义
   （`{type: "function", function: {name, description, parameters}}`），
   用于告知 LLM 该工具的功能及其接受的参数。
2. **端点** —— 当 LLM 决定使用该工具时，ThunderPhone 服务器调用的 URL。
   请求为 JSON POST，正文包含 LLM 选择的参数。

## 1. 选择存储策略

<CardGroup cols={2}>
  <Card title="在智能体中内联配置" icon="paperclip">
    将一次性工具附加到智能体的 `tools` 数组中。简单，但不可复用。
  </Card>

  <Card title="已保存的集成" icon="plug">
    将工具存储为可复用的[集成](/api-reference/integrations)，
    并从多个智能体中关联它。建议用于任何需要多次使用的工具。
  </Card>
</CardGroup>

本指南采用已保存的集成方式。

## 2. 创建集成

```bash theme={null}
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>

## 3. 在沙盒中测试端点

在将集成关联到智能体之前，请从 ThunderPhone 的服务器发出一个已签名请求以确认连通性：

```bash theme={null}
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 theme={null}
{
  "ok": true,
  "status": 200,
  "elapsed_ms": 187,
  "response_headers": { "content-type": "application/json" },
  "response_preview": "{\"temperature_f\": 64, ...}"
}
```

此测试还会强化 ThunderPhone 的 SSRF 防护机制——对 localhost 或私有 IP 范围的请求将返回 `400 code=url_not_allowed`。

## 4. 将集成关联到智能体

在创建或更新智能体时，通过 `integration_ids` 关联：

```bash theme={null}
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 会向您的 `endpoint_url` 发送已签名的 POST 请求：

```
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 theme={null}
{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}
```

LLM 会读取该响应，并向来电者口述自然语言摘要。

<Warning>
  签名使用与您的 webhook 端点相同的 `secret`，基于原始请求正文计算。**请验证签名**——工具端点面向互联网，与 webhook 一样存在伪造风险。请参阅
  [验证 webhook 签名](/zh/guides/verify-webhook-signatures)。
</Warning>

## 6. 测试完整流程

针对该智能体运行一个[麦克风会话](/api-reference/mic-sessions)，并提出您的工具可处理的问题（“94110 的天气怎么样？”）。通话的转录记录会显示完整的往返流程：

```json theme={null}
{
  "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="函数工具规范" icon="screwdriver-wrench" href="/zh/tools/overview">
    完整的 JSON 架构语法和已签名端点约定。
  </Card>

  <Card title="验证签名" icon="shield-check" href="/zh/guides/verify-webhook-signatures">
    将 Webhook 签名模式应用于工具端点。
  </Card>

  <Card title="通话记录 + 历史记录 API" icon="phone" href="/api-reference/calls">
    检查一次工具调用的完整往返流程。
  </Card>
</CardGroup>
