"zero data retention"(제로 데이터 보존), 즉 ZDR이 이 기능에 적용되는 방식은 API 및 데이터 보존을 참조하세요.
프롬프트 캐싱은 latency(지연 시간)와 비용을 크게 줄여주지만, 프롬프트의 시작 부분이 최근 요청과 바이트 단위로 동일할 때만 그렇습니다. 순서가 바뀐 도구, 시스템 프롬프트에 삽입된 타임스탬프, 또는 이전 메시지에 대한 편집이 조용히 캐시를 무효화할 수 있습니다. 캐시 진단이 없으면 유일한 신호는 usage.cache_read_input_tokens가 0으로 떨어지는 것뿐이며, 무엇이 변경되었는지에 대한 표시는 없습니다.
캐시 진단은 그 간극을 메웁니다. 이전 응답의 id를 전달하면 API가 두 요청을 비교하여 어디에서 달라졌는지(모델, 시스템 프롬프트, 도구 또는 메시지 기록)를 알려주므로, 추측하는 대신 근본 원인을 수정할 수 있습니다.
캐시 진단은 베타 버전입니다. 이 기능을 사용하려면 API 요청에 베타 헤더 cache-diagnosis-2026-04-07을 포함하세요.
캐시 진단은 현재 Claude API에서만 사용할 수 있습니다. Amazon Bedrock 또는 Google Cloud에서는 지원되지 않습니다.
베타 헤더가 있으면 API는 응답 id를 키로 하여 각 요청의 경량 핑거프린트를 저장합니다. 다음 요청에서 해당 id를 diagnostics.previous_message_id로 포함하세요. API는 새 요청에 대한 핑거프린트를 다시 생성하고 저장된 것과 비교한 다음, 첫 번째 분기 지점을 설명하는 diagnostics 객체를 응답에 첨부합니다.
이 비교는 캐시가 실제로 적중했는지 여부와 무관하게 요청 구조에 관한 것입니다. diagnostics 결과를 usage.cache_read_input_tokens와 결합하는 방법은 usage와 함께 진단 읽기를 참조하세요.
핑거프린트는 해시와 토큰 수 추정치만 포함하며(원시 프롬프트 내용은 절대 포함하지 않음), 제한된 시간 동안만 보관되고, 조직 및 워크스페이스 범위로 제한되며, 다른 목적으로 사용되지 않습니다.
모든 턴에서 베타 헤더를 전송하세요. 첫 번째 턴에서는 비교할 이전 메시지 없이 옵트인하기 위해 "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}")스트리밍 응답에서 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를 전달합니다.
이 워크플로는 일회성 셸 명령으로는 잘 표현되지 않습니다. 루프 패턴은 SDK 탭을 참조하세요. 턴별 HTTP 요청은 기본 사용법과 동일합니다.
응답 Message의 diagnostics 필드는 네 가지 가능한 상태를 가집니다:
| 값 | 의미 |
|---|---|
| 필드 없음 | 요청에 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은 type을 기준으로 하는 판별 유니온입니다. 응답은 가장 이른 분기만 보고하므로 먼저 이를 수정하세요. 이후의 분기는 그 뒤에 숨겨져 있을 수 있습니다.
| 유형 | 의미 | 변경할 사항 |
|---|---|---|
model_changed | model이 이전 요청과 다릅니다(예: 라우터, A/B 테스트 또는 폴백이 다른 모델을 선택함). 캐시는 모델별로 관리됩니다. | 캐시된 대화 내에서 모델을 일정하게 유지하세요. |
system_changed | system 매개변수가 다릅니다. 일반적으로 타임스탬프, 요청 ID 또는 기타 요청별 값이 시스템 프롬프트에 삽입된 경우입니다. | 시스템 프롬프트를 바이트 단위로 안정적인 상수로 만들고 동적 데이터를 캐시 중단점 이후의 첫 번째 user 메시지로 옮기세요. |
tools_changed | tools 배열이 다릅니다. 턴 사이에 도구가 추가, 제거 또는 재정렬되었거나, 도구 input_schema JSON이 비결정적으로 직렬화되었습니다. | 모든 턴에서 동일한 도구 목록을 고정된 순서로, 결정적으로 직렬화된 스키마(예: 키 정렬)와 함께 전송하세요. |
messages_changed | 모델, 시스템, 도구는 모두 일치하지만 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 헤더 집합)가 다른 경우와, 분기가 비교 범위를 벗어난 매우 긴 대화가 포함됩니다. 요청은 정상적으로 처리되었습니다. | 캐시된 대화가 유지되는 동안 프롬프트에 영향을 주는 요청 매개변수를 일정하게 유지하세요. 문제가 지속되면 프롬프트 캐싱 페이지의 일반적인 문제 해결에 있는 수동 확인을 적용하세요. |
네 가지 *_changed 유형에는 cache_missed_input_tokens 정수도 포함됩니다. 이는 분기 지점 이후에 위치한 입력 토큰 수의 추정치로, 캐시 가능한 접두사가 얼마나 손실되었는지 감을 잡을 수 있게 해줍니다. 토큰화 이전의 바이트 길이에서 파생되므로 청구 수치가 아닌 규모 지표로 취급하세요. usage.input_tokens와 다를 수 있으며(때로는 초과할 수도 있습니다).
diagnostics는 "내 요청이 변경되었는가?"에 답하고, usage.cache_read_input_tokens는 "캐시가 적중했는가?"에 답합니다. 이 둘을 결합하면 어디를 살펴봐야 할지 알 수 있습니다.
이 매트릭스는 실제 previous_message_id를 전달한 턴에 적용됩니다. 첫 번째 턴(previous_message_id: null)에서는 diagnostics가 항상 null이고 cache_read_input_tokens는 캐시가 읽히는 것이 아니라 쓰이고 있기 때문에 일반적으로 0입니다. 문제 해결이 필요하지 않습니다. 또한 이 매트릭스는 cache_miss_reason이 null인 경우(비교가 아직 진행 중이므로 다음 턴을 확인하세요)나 type이 previous_message_not_found 또는 unavailable인 경우(비교가 생성되지 않음)에는 적용되지 않습니다.
| 진단 결과 | 캐시 읽기 토큰 | 해석 |
|---|---|---|
null | 높음 | 예상대로 작동합니다. 접두사가 안정적이고 캐시가 적중했습니다. |
null | 낮음 또는 0 | 요청은 일치하지만 캐시 항목을 더 이상 사용할 수 없었습니다. 턴 사이의 간격을 줄이거나 1시간 캐시 TTL을 사용하는 것을 고려하세요. |
cache_miss_reason이 *_changed 유형 | 낮음 또는 0 | 사용자 측 버그입니다. 요청이 변경되었습니다. type이 나타내는 원인을 수정하세요. |
cache_miss_reason이 *_changed 유형 | 높음 | 드문 경우입니다. 프롬프트 후반부에서 변경이 발생했지만 이전 cache_control 중단점이 여전히 적중했습니다. 수정할 가치는 있지만 영향은 적습니다. |
previous_message_id 조회를 위한 핑거프린트는 짧은 기간 후에 만료됩니다. 시간적으로 가까운 요청 간에 진단 비교를 실행하세요.unavailable일 수 있습니다.unavailable을 반환하거나, 비교가 아직 실행 중이었던 경우 cache_miss_reason: null을 반환합니다.캐시 진단은 ZDR 적격(qualified)입니다. Anthropic은 이 기능을 위해 프롬프트의 원시 텍스트나 Claude의 출력을 저장하지 않습니다.
각 요청에 대해 저장되는 핑거프린트는 암호화 해시와 토큰 수 추정치로만 구성되며, 응답 id를 키로 하고 조직 및 워크스페이스 범위로 제한됩니다. 핑거프린트는 짧은 기간 후에 만료되며 다른 목적으로 사용되지 않습니다.
모든 기능에 대한 ZDR 적격성은 API 및 데이터 보관을 참조하세요.
Was this page helpful?