---
title: "AI API 延迟拆解：连接建立、网关往返与首 token 时间（TTFT）"
description: "API 延迟慢在哪里？把一次 AI API 调用拆成连接建立、网关往返和首 token 时间（TTFT）三段，给出可直接运行的 curl 测量命令，并说明连接复用和流式输出各自能缩短哪一段。"
url: https://cdnping.org/blog/api-latency-connect-rtt-ttft
language: zh-CN
published: 2026-10-17
category: "性能"
tags: ["API 延迟","TTFT","curl","流式输出","连接复用"]
source: cdnping.org
license: Free to quote and summarize with a link to the url above.
---
# AI API 延迟拆解：连接建立、网关往返与首 token 时间（TTFT）

一次 AI 调用的 API 延迟，通常是三段时间叠加：建立连接（DNS、TCP、TLS），请求到网关走一个来回，以及模型吐出第一个 token 之前的排队和预填充。前两段主要由网络决定，第三段主要由服务端和请求本身决定。用 `curl -w` 加一个流式请求，就能把三段分别量出来，再决定该改网络、改代码还是改请求。

## 三段延迟分别是什么

### 第一段：连接建立

客户端第一次访问某个 API 域名时，要先做三件事：

- DNS 解析：把 `api.example.com` 解析成 IP。命中本地缓存时接近 0，没有缓存时取决于解析器的距离和递归链路。
- TCP 握手：1 个往返（RTT）。
- TLS 握手：TLS 1.3 需要 1 个 RTT，TLS 1.2 需要 2 个 RTT。

所以一条全新连接在传任何业务数据之前，至少要花 2 到 3 个 RTT，再加上 DNS 时间。假设客户端到 API 入口的 RTT 是 200 ms、使用 TLS 1.3，光建连就要大约 400 ms 加 DNS。RTT 越大，这一段放大得越明显。

### 第二段：网关往返

连接建好后，发出请求、收到响应头，这个来回包含网络上的一个 RTT，加上服务端入口（负载均衡、鉴权、限流、路由）的处理时间。这一段不涉及模型推理，可以用一个不需要模型参与的请求单独测，例如不带密钥访问 `/v1/models`，网关通常会直接返回 401。这样测到的就是“网络 + 入口处理”的开销。

如果中间还有代理、中转或聚合网关，每多一跳，这一段就多一个往返和一次处理。

### 第三段：首 token 时间（TTFT）

TTFT（Time To First Token）是从请求发出到收到第一个生成内容的时间。连接是新建的话，它包含前两段，再加上服务端的：

- 排队等待推理资源；
- 预填充（prefill），即模型处理整段输入提示词，输入越长越久；
- 部分接口开启推理或思考模式时，会先生成不可见或单独返回的思考内容，第一个正文 token 会更晚出现。

TTFT 之后还有生成速度（每秒输出多少 token），它决定整段回答要多久，不在本文讨论的三段之内。

### 三段对照表

| 段 | 主要成因 | 受什么影响 | 能做的调整 |
|---|---|---|---|
| 连接建立 | DNS、TCP、TLS 握手 | 客户端到入口的 RTT、DNS 解析器、TLS 版本 | 连接复用、预热连接、使用就近的解析器 |
| 网关往返 | 1 个 RTT + 入口处理 | 网络路径、中转跳数、服务端入口负载 | 减少中转、选择离客户端近的入口 |
| TTFT（超出前两段的部分） | 排队、prefill、思考 | 输入长度、模型大小、服务端负载 | 缩短提示词、换更轻的模型 |

## 怎么用 curl 分别测出三段延迟

以下命令在 macOS 和 Linux 上都能运行，Windows 可以在 WSL 或 Git Bash 里执行。把 `API_HOST` 换成你要测的入口。

### 步骤 1：测连接建立的每个阶段

```bash
API_HOST=api.openai.com

curl -s -o /dev/null https://$API_HOST/v1/models -w '
DNS 解析        : %{time_namelookup}s
TCP 建连完成    : %{time_connect}s
TLS 握手完成    : %{time_appconnect}s
发出请求前      : %{time_pretransfer}s
收到首字节      : %{time_starttransfer}s
总耗时          : %{time_total}s
HTTP 状态码     : %{http_code}
'
```

`curl -w` 输出的都是从开始计时的累计值，每段耗时要相减：

- DNS = `time_namelookup`
- TCP 握手 = `time_connect − time_namelookup`，约等于 1 个 RTT
- TLS 握手 = `time_appconnect − time_connect`
- 网关往返 = `time_starttransfer − time_pretransfer`

这个请求没带密钥，正常会返回 401。401 由网关给出，不经过模型，所以 `time_starttransfer − time_pretransfer` 对应的就是第二段。

### 步骤 2：看连接复用能省掉多少

在同一条 curl 命令里写同一个 URL 多次，curl 会复用第一条连接：

```bash
curl -s -o /dev/null -o /dev/null -o /dev/null \
  https://$API_HOST/v1/models \
  https://$API_HOST/v1/models \
  https://$API_HOST/v1/models \
  -w 'connect=%{time_connect}s tls=%{time_appconnect}s total=%{time_total}s new_conns=%{num_connects}\n'
```

第一行的 `connect` 和 `tls` 有数值，后两行接近 0，`new_conns` 为 0 表示这次没有新建连接。第一行和后两行 `total` 的差值，大致就是连接复用每次能省下的时间。cdnping 首页的“往返”指标也是这个思路：连接复用后请求 3 次取中位数。

### 步骤 3：测真实的 TTFT

`time_starttransfer` 不能直接当 TTFT。流式接口往往先返回响应头，再逐步推送内容，首字节可能早于第一个 token。下面的脚本以第一行带内容的 `data:` 为准：

```bash
API_HOST=api.openai.com
API_KEY=你的密钥
MODEL=你的模型名

start=$(date +%s%N)
curl -sN https://$API_HOST/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"model\":\"$MODEL\",\"stream\":true,\"messages\":[{\"role\":\"user\",\"content\":\"说一个字\"}]}" \
| while IFS= read -r line; do
    case "$line" in
      *'"content":"'[!\"]*)
        now=$(date +%s%N)
        echo "TTFT: $(( (now - start) / 1000000 )) ms"
        break ;;
    esac
  done
```

macOS 自带的 `date` 不支持 `%N`，可以先 `brew install coreutils`，再把 `date` 换成 `gdate`。Anthropic 格式接口的路径、请求头和事件结构都不同，判断条件要按官方文档调整。

### 步骤 4：把三段放在一起看

在同一时间、同一网络下各跑 3 到 5 次，取中位数，填进下表：

| 测量项 | 计算方式 | 你的结果 |
|---|---|---|
| DNS | `time_namelookup` | |
| TCP + TLS | `time_appconnect − time_namelookup` | |
| 网关往返 | `time_starttransfer − time_pretransfer`（401 请求） | |
| TTFT | 步骤 3 的脚本 | |
| 模型侧耗时（估算） | TTFT − DNS − TCP/TLS − 网关往返 | |

判断时看哪一项占大头：TCP 握手本身就有几百毫秒，先查网络路径；建连和往返都不高但 TTFT 很长，问题在服务端或请求本身，先缩短提示词、换一个更轻的模型再测。

## 连接复用和流式输出分别能缩短哪一段

### 连接复用：省掉第一段

代码里最常见的问题是每次请求都新建 HTTP 客户端。官方 SDK 会在客户端实例内部维护连接池，前提是你复用同一个实例：

```python
# 不推荐：每次调用都重新建连
def ask(q):
    client = OpenAI()
    return client.chat.completions.create(...)

# 推荐：进程内复用同一个客户端
client = OpenAI()
def ask(q):
    return client.chat.completions.create(...)
```

另外几点：

- 服务端会关闭空闲一段时间的连接，低频调用的服务可以在业务请求前先发一个轻量请求预热；
- HTTP/2 允许在一条连接上并发多个请求，并发量大时比开很多条 HTTP/1.1 连接省握手；
- 无服务器函数冷启动时连接池是空的，第一次调用一定要付建连成本。

### 流式输出：TTFT 基本不变，用户更早看到内容

开启 `stream: true` 不会让模型更快生成第一个 token。它改变的是用户什么时候看到内容：非流式要等整段生成完才返回，流式在第一个 token 生成后就开始显示。回答越长，两者的体感差别越大。

流式还有一个用处：首个内容事件到达的时间就是你能拿到的最准的 TTFT，方便做监控。如果链路里有反向代理，要确认它没有缓冲 SSE 响应，否则流式会退化成一次性返回。

## cdnping 边缘探测数据怎么读

cdnping 的 [API 状态页](/status) 从 Cloudflare 边缘每 5 分钟探测一次各官方 API 入口。下表取自 cdnping 在 2026 年 10 月 17 日的一份快照：执行探测的边缘节点是 DEN（美国丹佛），窗口为北京时间 16:40 至 18:05，约 85 分钟，所有入口合计 242 次探测。cdnping 从 2026-10-17 才开始采集，这份数据只覆盖这一小段时间，不是长期统计。数据以 CC BY 4.0 发布，测量方法见 [数据方法](/methodology)。

| 入口 | p50 | p95 |
|---|---|---|
| api.x.ai | 42 ms | 55 ms |
| openrouter.ai | 54 ms | 83 ms |
| api.groq.com | 61 ms | 131 ms |
| generativelanguage.googleapis.com | 69 ms | 89 ms |
| api.anthropic.com | 73 ms | 84 ms |
| api.openai.com | 96 ms | 194 ms |
| api.mistral.ai | 153 ms | 536 ms |
| api.deepseek.com | 353 ms | 414 ms |
| api.moonshot.cn | 375 ms | 1125 ms |
| open.bigmodel.cn | 395 ms | 674 ms |
| ark.cn-beijing.volces.com | 485 ms | 1149 ms |
| dashscope.aliyuncs.com | 615 ms | 1152 ms |
| api.siliconflow.cn | 631 ms | 1030 ms |

读这张表时注意三点：

1. p50 是中位数，一半探测比它快；p95 表示 95% 的探测不超过这个值，能反映抖动。例如 api.openai.com 的 p50 是 96 ms，p95 是 194 ms，多数时候稳定，偶尔会翻倍。
2. 这是从美国丹佛测的。海外入口在几十到一百多毫秒，国内入口在 350 到 630 ms，反映的主要是丹佛到各入口的网络距离，不代表模型快慢。在中国大陆测，排序很可能完全不同，具体数字要在自己的网络里量。
3. 探测不触发模型推理，对应的是本文的第一段和第二段，不包含 TTFT 里模型侧的部分。

聚合网关会多出一跳。以 AGI Plan 为例（AGI Plan 是 cdnping 的商业合作方），同一快照里 agiplan.dev 的 p50 和 p95 都是 883 ms。两个值相同，说明这个窗口里还看不出抖动情况，不宜下结论。经过网关的请求要多走“客户端到网关、网关到上游”两段网络，评估这类服务时，建议用上面的步骤 1 和步骤 3 在自己的网络里各测一遍，分别比较建连、往返和 TTFT。

## 测完之后可以接着查什么

- 打开 cdnping [在线测速](/)，在浏览器里看 15 个 AI API 入口从你当前网络测得的“首次连接”和“往返”，和 curl 的结果对照。
- 如果往返明显高于预期，用 [IP 与环境检测](/ip) 看出口 IP 的定位和延迟特征。它会对比浏览器往返和 Cloudflare 测得的出口 TCP 往返，用来判断请求是否经过了中转。检测结果可以生成带水印的结果图，分享前可以选择隐藏 IP 地址。
- 针对单个服务，看 [OpenAI API 状态](/status/openai) 这类分服务页面，区分是自己这边慢还是入口本身在抖。
- 想了解国内访问海外 AI API 的整体网络情况，可以读 [从中国访问 AI API 的延迟](/learn/ai-api-latency-china)。

部分海外 AI 服务有地区限制，请以服务方条款为准，并遵守当地法规。
