이 기능은 제한된 기술적 보존과 함께 Zero Data Retention (ZDR)의 적용 대상입니다. 보존되는 항목과 그 이유에 대한 자세한 내용은 데이터 보존 섹션을 참조하세요.
프롬프트 캐싱은 지연 시간과 비용을 크게 줄여주지만, 프롬프트의 시작 부분이 최근 요청과 바이트 단위로 동일할 때만 효과가 있습니다. 도구 순서 변경, 시스템 프롬프트에 삽입된 타임스탬프, 또는 이전 메시지 편집은 캐시를 조용히 무효화할 수 있습니다. 캐시 진단이 없으면 유일한 신호는 usage.cache_read_input_tokens가 0으로 떨어지는 것뿐이며, 무엇이 변경되었는지에 대한 표시는 없습니다.
캐시 진단은 이러한 간극을 메웁니다. 이전 응답의 id를 전달하면 API가 두 요청을 비교하여 어디에서 달라졌는지(모델, 시스템 프롬프트, 도구 또는 메시지 기록) 알려주므로 추측하는 대신 근본 원인을 해결할 수 있습니다.
캐시 진단은 베타 상태입니다. 이 기능을 사용하려면 API 요청에 베타 헤더 cache-diagnosis-2026-04-07을 포함하세요.
캐시 진단은 현재 Claude API에서만 사용할 수 있습니다. Amazon Bedrock 또는 Vertex AI에서는 지원되지 않습니다.
베타 헤더가 있으면 API는 응답 id를 키로 하여 각 요청의 경량 "fingerprint"(지문)를 저장합니다. 다음 요청에서 해당 id를 diagnostics.previous_message_id로 포함하세요. API는 새 요청에 대한 지문을 다시 생성하고 저장된 지문과 비교한 다음, 첫 번째 분기 지점을 설명하는 diagnostics 객체를 응답에 첨부합니다.
이 비교는 캐시가 실제로 적중했는지 여부와 무관하게 요청 구조에 관한 것입니다. 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-4-8",
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-4-8",
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-4-8",
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를 전달합니다.
응답 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?