Перейти к содержимому
ПРОИЗВОДИТЕЛЬНОСТЬ

Тюнинг латентности Claude API в 2026: −60% TTFT и общего времени

Streaming, prompt caching, выбор модели и concurrency вместе срезают латентность Claude API на 60%. Прод-плейбук с замерами.

Латентность — скрытый налог на любой продукт, построенный на Claude. Можно собрать самого умного агента в мире, но если первый токен появляется через три секунды, пользователь решит, что всё сломалось. В 2026 году, когда Opus 4.7 и Sonnet 4.6 уже в продакшене, а agent fan-out стал архитектурой по умолчанию, тюнинг латентности перестал быть оптимизацией и стал требованием. Это плейбук, которым мы пользуемся внутри и который рекомендуем командам, работающим с Claude API через Claudexia.

Анатомия запроса к Claude API

Прежде чем что-то крутить, нужен общий словарь. Имеет смысл отслеживать три числа:

  • TTFT (time to first token) — wall-clock время от отправки запроса до прихода первого стримового токена. Именно это пользователь воспринимает как «началось ли вообще что-то».
  • Total time — TTFT плюс время генерации остального ответа. Грубая модель: total = TTFT + output_tokens / tokens_per_second.
  • Tail latency (p99) — самый медленный 1% запросов. Хвост определяет, срабатывают ли таймауты и забиваются ли очереди. Медиана 800ms с p99 12s — это хуже, чем медиана 1.2s с p99 2.5s.

Если вы смотрите только на средние значения, вы летите вслепую. Считайте все три метрики по модели, по региону, по шаблону промпта.

TTFT по моделям, измеренный

Мы гоняем непрерывные пробы с EU PoP против шлюза Claudexia, который стоит в том же регионе. Цифры ниже — медианы за 30 дней, короткие промпты (до 1K input-токенов), без кеша:

  • Haiku — TTFT около 250ms, генерация около 180 токенов/сек.
  • Sonnet 4.6 — TTFT около 380ms, генерация около 95 токенов/сек.
  • Opus 4.7 — TTFT около 700ms, генерация около 55 токенов/сек.

Паттерн стабильный: больше модель — длиннее TTFT и медленнее стрим. Opus примерно в 3 раза медленнее на токен, чем Haiku. Для интерактивного UI это самый большой рычаг. Шаг классификации, который крутится на Opus «потому что команда стандартизировалась на Opus», скорее всего стоит вам секунды воспринимаемой латентности при нулевом выигрыше в качестве.

Почему стриминг режет воспринимаемую латентность вдвое

Не-стриминговый запрос блокируется, пока не сгенерится весь ответ. Для ответа в 500 токенов на Sonnet это примерно 380ms + 500/95 ≈ 5.6s, прежде чем UI хоть что-то покажет. Стриминг переворачивает ситуацию: UI начинает рендерить с момента TTFT (380ms), и пользователь читает ответ по мере генерации. Total time идентичный, но воспринимаемая латентность падает с 5.6s до 380ms. Пользователи устойчиво оценивают стриминговые ответы как «быстрые», даже если суммарное время больше, чем у не-стримингового аналога.

В 2026 году нет причин звать Messages API без stream: true в любом пользовательском пути. Исключения — батчевые джобы и оркестрация tool-call, где нужен полный message перед действием.

Prompt caching режет TTFT для кешированных блоков ~50%

Prompt caching от Anthropic обычно подают как оптимизацию стоимости — кешированные input-токены тарифицируются ~10% от обычной ставки — но эффект на латентность не менее важен. Для запросов, которые попадают в кешированный префикс, TTFT падает примерно на 50%, потому что модели не нужно заново обрабатывать кешированные токены. На Sonnet 20K-токенный системный промпт, который обычно добавляет ~600ms к TTFT, схлопывается до ~300ms после первого кеширования.

Если у вас длинный системный промпт, схема инструментов или стабильный few-shot блок — пометьте его cache_control: { type: "ephemeral" } и смотрите, как TTFT падает на втором и последующих запросах. TTL в пять минут короткий, но в загруженной проде вы будете попадать в него почти на каждом запросе.

Количество output-токенов — самый большой рычаг

Самая недооценённая оптимизация — просто генерировать меньше токенов. Каждый output-токен на Sonnet стоит ~10ms wall time. Ответ, который сжимается с 800 токенов до 300, экономит пять секунд. Три конкретных техники:

  1. Жёстко выставляйте max_tokens. Не передавайте max_tokens: 4096 «на всякий случай». Передавайте реальный потолок задачи — 200 для причины классификации, 500 для саммари, 1500 для правки кода.
  2. Инструктируйте на краткость. Добавьте «Ответь в пределах 100 слов» или «Выведи только JSON-объект, без объяснений» в системный промпт. Модели в 2026 отлично соблюдают ограничения по длине.
  3. Используйте stop sequences. Если знаете, что ответ заканчивается на </answer> или } — передайте это как stop sequence. Модель останавливается мгновенно, не догенеривая хвостовые пробелы или прощальные фразы.

Concurrency: agent fan-out через Promise.all

Если агенту нужно сделать три вызова модели для независимых подзадач (извлечь сущности, оценить тональность, сделать саммари) — не сериализуйте их. Последовательные вызовы складывают свои TTFT; параллельные прячут их за самым медленным.

const [entities, sentiment, summary] = await Promise.all([
  client.messages.create({ model: "claude-haiku-4", ... }),
  client.messages.create({ model: "claude-haiku-4", ... }),
  client.messages.create({ model: "claude-sonnet-4.6", ... }),
])

Total time теперь max(TTFT_a, TTFT_b, TTFT_c) + max(generation_a, b, c) вместо суммы. Для трёхшагового агента это обычно режет общее время вдвое.

География важнее, чем принято признавать

Основной inference Anthropic — в США. Round-trip из Франкфурта в us-east-1 добавляет около 90ms на запрос ещё до того, как модель начнёт работу. Для стримингового UI, делающего 10 последовательных вызовов за сессию, это почти секунда чистой сетевой латентности.

EU PoP Claudexia терминирует TLS-хендшейк в регионе и проксирует к модели по тёплому пуленному соединению. Для европейских клиентов это обычно убирает 60–120ms из TTFT по сравнению с прямым обращением к Anthropic через Атлантику. Это самый дешёвый выигрыш по латентности — никаких изменений кода, просто другой base URL.

Код: baseline vs streaming vs cached vs concise

Одна и та же задача — суммаризировать 5K-токенный документ — на четырёх уровнях оптимизации, против https://api.claudexia.tech/v1:

import Anthropic from "@anthropic-ai/sdk"

const client = new Anthropic({
  apiKey: process.env.CLAUDEXIA_API_KEY,
  baseURL: "https://api.claudexia.tech/v1",
})

// 1. Baseline: без стриминга, без кеша, без дисциплины max_tokens
// Замер: TTFT 4.2s (т.к. для не-стриминга TTFT == total time)
await client.messages.create({
  model: "claude-sonnet-4.6",
  max_tokens: 4096,
  messages: [{ role: "user", content: longDocument + "\n\nСделай саммари." }],
})

// 2. Добавляем стриминг. Total time не меняется, воспринимаемый TTFT — 0.5s
const stream = await client.messages.stream({
  model: "claude-sonnet-4.6",
  max_tokens: 4096,
  messages: [{ role: "user", content: longDocument + "\n\nСделай саммари." }],
})

// 3. Добавляем prompt caching на документе
await client.messages.stream({
  model: "claude-sonnet-4.6",
  max_tokens: 4096,
  system: [
    { type: "text", text: longDocument, cache_control: { type: "ephemeral" } },
  ],
  messages: [{ role: "user", content: "Сделай саммари документа выше." }],
})

// 4. Добавляем инструкцию на краткость + жёсткий max_tokens
await client.messages.stream({
  model: "claude-sonnet-4.6",
  max_tokens: 300,
  stop_sequences: ["</summary>"],
  system: [
    { type: "text", text: longDocument, cache_control: { type: "ephemeral" } },
  ],
  messages: [{
    role: "user",
    content: "Саммари в пределах 150 слов, оберни в <summary>...</summary>.",
  }],
})

Методология замеров

Тюньте то, что измеряете. Две метрики, которые стоит инструментировать на каждом запросе:

const t0 = performance.now()
let ttft: number | null = null
let outputTokens = 0

const stream = await client.messages.stream({ ... })
for await (const event of stream) {
  if (event.type === "content_block_delta" && ttft === null) {
    ttft = performance.now() - t0
  }
  if (event.type === "message_delta") {
    outputTokens = event.usage.output_tokens
  }
}
const total = performance.now() - t0

metrics.histogram("claude.ttft_ms", ttft, { model, cached })
metrics.histogram("claude.total_ms", total, { model, cached })
metrics.histogram("claude.output_tokens", outputTokens, { model })

Снимайте TTFT и total отдельно. Тегируйте по модели, по факту попадания в кеш и по шаблону промпта. Без этого вы не сможете понять, сработали ли ваши оптимизации.

Итог: 4.2s → 1.6s на реальной нагрузке

Пример выше — суммаризация 5K-токенного документа на Sonnet — идёт от baseline в 4.2 секунды total wall time до 1.6 секунды после применения стриминга, кеширования, жёсткого max_tokens и работы через EU PoP Claudexia. Это −62% по total time и −91% по воспринимаемому TTFT (с 4.2s до 380ms).

Ни одна из техник не экзотическая. Все доступны в официальном SDK, описаны в API-референсе Anthropic и не требуют изменений в инфраструктуре дальше смены baseURL на https://api.claudexia.tech/v1. Команды, которые в 2026 шипят самые быстрые продукты на Claude, не используют секретную модель — они просто дисциплинированы по TTFT, длине вывода и cache hit rate.

Если ваш p99 всё ещё измеряется в секундах — начните со стриминга, потом кеширования, потом дисциплины output, потом географии. Именно в таком порядке. Большую часть выигрыша вы получите из первых двух.