Диагностика кэша
Диагностируйте неожиданные промахи кэша подсказок, сравнивая последовательные запросы и точно определяя, где разошёлся префикс подсказки.
Кэширование подсказок (prompt caching) значительно снижает задержку и стоимость, но только когда начало вашей подсказки побайтово идентично недавнему запросу. Переупорядоченный инструмент, временная метка, подставленная в вашу системную подсказку (system prompt), или правка более раннего сообщения могут незаметно сделать кэш недействительным. Без диагностики кэша единственным сигналом является падение usage.cache_read_input_tokens до нуля без какого-либо указания на то, что изменилось.
Диагностика кэша закрывает этот пробел. Передайте id вашего предыдущего ответа, и API сравнит два запроса и сообщит вам, где они разошлись (модель, системная подсказка, инструменты или история сообщений), чтобы вы могли устранить первопричину, а не гадать.
Как работает диагностика кэша
Когда присутствует бета-заголовок, API сохраняет лёгкий отпечаток (fingerprint) каждого запроса с ключом по id ответа. В следующем запросе включите этот id как diagnostics.previous_message_id. API заново строит отпечаток для нового запроса, сравнивает его с сохранённым и прикрепляет к ответу объект diagnostics, описывающий первую точку расхождения.
Сравнение касается структуры запроса и не зависит от того, произошло ли фактическое попадание в кэш. См. раздел Чтение диагностики вместе с usage, чтобы узнать, как сочетать результат diagnostics с usage.cache_read_input_tokens.
Отпечатки содержат только хэши и оценки количества токенов (никогда — исходное содержимое подсказки), хранятся ограниченное время, ограничены вашей организацией и рабочим пространством и не используются ни для каких других целей.
Базовое использование
Отправляйте бета-заголовок на каждом ходе. На первом ходе передайте "previous_message_id": null, чтобы включить функцию без предыдущего сообщения для сравнения. На последующих ходах передавайте id из предыдущего ответа.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
# Ход 1: включение через previous_message_id=None
r1 = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[{"role": "user", "content": "Summarize section 1."}],
diagnostics={"previous_message_id": None},
betas=["cache-diagnosis-2026-04-07"],
)
# Ход 2: ссылка на id предыдущего ответа
r2 = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
)
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")Потоковая передача
В ответах с потоковой передачей (streaming) diagnostics появляется в событии message_start.
# Ход 2: потоковая передача со ссылкой на id предыдущего ответа
with client.beta.messages.stream(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=[
{"role": "user", "content": "Summarize section 1."},
{"role": "assistant", "content": r1.content},
{"role": "user", "content": "Now summarize section 2."},
],
diagnostics={"previous_message_id": r1.id},
betas=["cache-diagnosis-2026-04-07"],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
r2 = stream.get_final_message()
diagnostics = r2.diagnostics
if diagnostics is None:
print("No divergence detected.")
elif diagnostics.cache_miss_reason is None:
print("Comparison still pending.")
else:
print(f"cache_miss_reason: {diagnostics.cache_miss_reason.type}")Событие message_start содержит полное поле diagnostics; возможные значения см. в разделе Формат ответа.
Передача диагностики через цикл диалога
В многоходовом диалоге передавайте id последнего ответа дальше как previous_message_id на каждом ходе. Первая итерация передаёт null для включения функции; каждая последующая итерация передаёт id из предыдущего ответа.
client = anthropic.Anthropic()
SYSTEM = "You are an AI assistant analyzing a large document. <document>...</document>"
messages = []
prev_id = None
for i, user_message in enumerate(
["Summarize section 1.", "Now section 2.", "Now section 3."]
):
messages.append({"role": "user", "content": user_message})
r = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system=SYSTEM,
messages=messages,
diagnostics={"previous_message_id": prev_id},
betas=["cache-diagnosis-2026-04-07"],
)
if r.diagnostics is not None and r.diagnostics.cache_miss_reason is not None:
print(f"Turn {i + 1} cache_miss_reason: {r.diagnostics.cache_miss_reason.type}")
messages.append({"role": "assistant", "content": r.content})
prev_id = r.idФормат ответа
Поле diagnostics в ответе Message имеет четыре возможных состояния:
| Значение | Смысл |
|---|---|
| поле отсутствует | Запрос не включал diagnostics, или бета-заголовок отсутствовал. |
null | Либо previous_message_id был null (первый ход, сравнивать не с чем), либо сравнение было выполнено и расхождений не обнаружено. |
{"cache_miss_reason": null} | Сравнение ещё выполнялось, когда ответ был сериализован. Это может произойти, когда ответ начинается очень быстро. Считайте результат неопределённым и проверьте следующий ход. |
{"cache_miss_reason": {...}} | Прикреплён cache_miss_reason. Для типов *_changed он указывает первую точку расхождения; previous_message_not_found и unavailable — это случаи, когда сравнение не было произведено. |
Когда cache_miss_reason не равен null, он выглядит так:
{
"id": "msg_01Xyz...",
"type": "message",
"role": "assistant",
"content": [{ "type": "text", "text": "..." }],
"usage": {
"input_tokens": 42,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 41850,
"output_tokens": 210
},
"diagnostics": {
"cache_miss_reason": {
"type": "system_changed",
"cache_missed_input_tokens": 41850
}
}
}Типы причин промаха кэша
cache_miss_reason — это размеченное объединение (discriminated union) по полю type. Ответ сообщает только о самом раннем расхождении, поэтому исправьте его первым; более поздние могут быть скрыты за ним.
| Тип | Что это означает | Что изменить |
|---|---|---|
model_changed | model отличается от предыдущего запроса (например, маршрутизатор, A/B-тест или резервный механизм выбрал другую модель). Кэш ведётся отдельно для каждой модели. | Сохраняйте модель неизменной в рамках кэшируемого диалога. |
system_changed | Параметр system отличается. Обычно в системную подсказку была подставлена временная метка, идентификатор запроса или другое значение, уникальное для запроса. | Сделайте системную подсказку побайтово стабильной константой и перенесите динамические данные в первое сообщение user после вашей точки разрыва кэша. |
tools_changed | Массив tools отличается: инструменты были добавлены, удалены или переупорядочены между ходами, либо JSON input_schema инструмента был сериализован недетерминированно. | Отправляйте один и тот же список инструментов на каждом ходе в фиксированном порядке с детерминированно сериализованными схемами (например, сортируйте ключи). |
messages_changed | Модель, system и tools совпадают, но более ранняя запись в messages была изменена, переупорядочена или удалена, а не дополнена. Обычно история диалога была усечена или отредактирована, либо ходы ассистента и блоки tool_result были повторно сериализованы иначе при повторной отправке. | Относитесь к истории как к допускающей только добавление; возвращайте content ассистента и результаты инструментов дословно. |
previous_message_not_found | Для указанного previous_message_id не существует сохранённого отпечатка. Это не свидетельствует о том, что ваш запрос изменился. Обычно предыдущий запрос не содержал бета-заголовка, поступил из другого рабочего пространства, или с момента его отправки прошло слишком много времени. | Отправляйте бета-заголовок на каждом ходе и держите последовательные ходы близко друг к другу по времени. |
unavailable | Диагностическая информация была недоступна для этого запроса. Сюда входит случай, когда model, system и tools совпадают, но отличается другой влияющий на подсказку параметр запроса (tool_choice, thinking, context_management, output_config, output_format или набор активных заголовков anthropic-beta), а также очень длинные диалоги, где расхождение находится за горизонтом сравнения. Ваш запрос был обработан в обычном режиме. | Сохраняйте влияющие на подсказку параметры запроса неизменными на протяжении всего кэшируемого диалога. Если проблема сохраняется, примените ручные проверки из раздела Устранение распространённых проблем на странице кэширования подсказок. |
Чтение диагностики вместе с usage
diagnostics отвечает на вопрос «изменился ли мой запрос?», а usage.cache_read_input_tokens — на вопрос «произошло ли попадание в кэш?». Их сочетание подсказывает, где искать.
Эта матрица применима к ходам, на которых вы передали реальный previous_message_id. На первом ходе (previous_message_id: null) diagnostics всегда равен null, а cache_read_input_tokens обычно равен нулю, поскольку кэш записывается, а не читается; устранение неполадок не требуется. Матрица также не применима, когда cache_miss_reason равен null (сравнение ещё выполняется; проверьте следующий ход) или когда его type — previous_message_not_found или unavailable (сравнение не было произведено).
| Результат диагностики | Токены чтения из кэша | Интерпретация |
|---|---|---|
null | много | Работает как ожидается. Ваш префикс стабилен, и произошло попадание в кэш. |
null | мало или ноль | Ваши запросы совпадают, но запись кэша больше не была доступна. Рассмотрите сокращение промежутков между ходами или использование TTL кэша в 1 час. |
cache_miss_reason имеет тип *_changed | мало или ноль | Ваша ошибка. Запрос изменился; устраните причину, указанную в type. |
cache_miss_reason имеет тип *_changed | много | Редко. Изменение произошло ближе к концу подсказки, но более ранняя точка разрыва cache_control всё же сработала. Стоит исправить, но влияние невелико. |
Ограничения
- Бета: Имена полей и семантика могут измениться, пока эта функция находится в бета-версии.
- Только Claude API: Недоступно на Amazon Bedrock или Google Cloud.
- Ограниченное хранение: Отпечатки для поиска по
previous_message_idистекают через короткий период. Выполняйте диагностические сравнения между близко расположенными по времени запросами. - То же рабочее пространство: Предыдущий запрос должен был выполняться в той же организации и рабочем пространстве. Для проверки сравните заголовок ответа
anthropic-workspace-idв двух ответах. - Горизонт сравнения: Для очень длинных диалогов, где единственное изменение находится глубоко в списке сообщений, ответ может быть
unavailableвместо точного местоположения. - По мере возможности: Диагностика никогда не блокирует и не приводит к сбою вашего запроса. Если диагностическая информация недоступна, ответ возвращает
unavailableилиcache_miss_reason: null, если сравнение ещё выполнялось.
Хранение данных
Диагностика кэша соответствует требованиям ZDR (с оговорками). Anthropic не хранит исходный текст ваших подсказок или выходных данных Claude для этой функции.
Отпечаток, сохраняемый для каждого запроса, состоит только из криптографических хэшей и оценок количества токенов, имеет ключ по id ответа и ограничен вашей организацией и рабочим пространством. Отпечатки истекают через короткий период и не используются ни для каких других целей.
Сведения о соответствии ZDR для всех функций см. в разделе API и хранение данных.
См. также
Compatibility
| Supported platforms |
|
|---|
Was this page helpful?