Claude API에 11월 2일부터 'Message Threads(메시지 스레드)'라는 베타 기능이 추가되었습니다 (API 변경 이력). 이는 대화 기록을 서버 측에서 관리하게 하여, 두 번째 메시지부터는 새로운 메시지만 보내면 되는 기능입니다.
이를 읽고 제가 처음 생각한 것은, '대화 기록을 서버가 가지고 준다면, 채팅이나 에이전트의 기록 관리를 직접 만들 필요가 없어지지 않을까' 하는 것이었습니다.
하지만 공식 문서를 끝까지 읽어보니 답은 정반대였습니다.
Your application stays the source of truth for the conversation. Keep your own copy of every message, and build the replay path from the start.
'대화의 정본(source of truth)은 당신의 앱에 남아 있습니다. 모든 메시지의 복사본을 직접 보관하고, 처음부터 다시 재생할 경로를 만드세요'라고 쓰여 있습니다. 본문에서는 무엇이 편리해지고 무엇이 편리하지 않은지, 공식 문서와 SDK 내부 내용을 통해 확인한 결과를 정리했습니다.
실제로 API를 호출하여 속도를 측정하는 것은 하지 않았습니다. 읽은 내용은 공식 문서와 PyPI에 공개된 Python SDK 패키지 내용입니다 (확인 시점: 2026-11-13).
| 흔히 기대하는 점 | 공식 문서에 적힌 내용 |
|---|
| 대화 기록을 서버에 맡길 수 있다 | 스레드는 마지막 요청으로부터 5분 만에 끊깁니다. 늦어도 1시간 내에는 삭제됩니다. 복사본은 직접 보관해야 하며, 끊기면 전부 다시 보내야 합니다. |
| ... | 요금이나 레이트 제한도 변하지 않습니다. 캐시도 자동으로 걸리지 않습니다. |
| 빨라진다 | 전송하는 요청이 작아지고, 첫 글자가 반환되기까지의 시간이 '낮고 안정적'입니다. 다만 수치는 제시되어 있지 않습니다. |
- 편리해지는 부분은 '매번 대화 전체를 다시 보내는 것'뿐입니다. 기록을 저장하는 메커니즘은 지금까지와 같이 직접 가지고 있어야 합니다.
Python SDK를 2.2.0 이상으로 올리면, 2.2.0부터 2.8.0까지의 총 7개 버전 패키지 내용을 통해 확인했습니다. 스레드를 사용하고 싶을 때는 tool_runner
은 아무것도 지정하지 않아도 스레드를 사용합니다. thread=False를 전달합니다 - Message Batches, 토큰 수 계산, 압축(자동 요약)과 함께 사용할 수는 없습니다. Zero Data Retention (ZDR) 대상이 아닙니다. 대응하는 장소 목록에 Amazon Bedrock과 Vertex AI는 포함되어 있지 않습니다.
기존의 Messages API는 대화의 연속을 요청할 때마다 그전까지의 모든 대화를 보내야 했습니다. 스레드를 사용하면 서버가 대화를 짧은 시간 동안 기억해 줍니다.
| 단계 | 전송하는 내용 |
|---|
| 생성(create) | 지금까지와 같이 전체 대화와 system 및 tools, 그리고 ` |
응답이 저장될 때마다 5분 타이머가 다시 시작됩니다. 그럼에도 불구하고, 사용자가 5분보다 긴 간격을 두고 응답할 경우 해당 스레드는 더 이상 이어갈 수 없습니다.
이어가지 못했을 때는 404와 thread_not_found 오류가 반환됩니다. 공식 문서에서 언급하는 원인은 만료 기간 외에도 있습니다.
- 직전 응답이 저장되지 않은 경우(예:
max_tokens로 인해 중간에 잘린 도구 호출)
- 직전 응답을 폴백(fallback) 모델이 작성한 경우
- 직전 응답이 아직 생성 중인 경우
- 생성했을 때와 다른 조직/워크스페이스/사용자로부터 이어가려고 시도한 경우(공식 문서는 동일한 API 키와 워크스페이스를 계속 사용할 것을 권장합니다)
- 저장된 대화에 포함될 수 없는 내용을 추가한 경우(예: 이미지가 없는 대화에 첫 번째 이미지를 추가했을 때 등)
게다가, 해당 턴이 저장되었는지 여부는 응답만으로는 알 수 없습니다.
응답은 생성하거나 이어가기 요청 시 API가 해당 턴을 저장했는지 여부를 알려주지 않습니다. 다음 이어가기 요청에서야 알 수 있습니다.
즉, 다음에 이어서 보내려고 할 때 비로소 알게 된다는 것입니다. 따라서 사본을 가지고 다시 전송하는 경로는 어쨌든 필요합니다.
또 다른 점은, 스레드는 서버의 메모리상에 존재하며 디스크에는 기록되지 않고("never writes it to durable storage"), 늦어도 1시간 내에 사라진다는 것입니다. 대화를 오랫동안 보관할 수 있는 저장소로는 사용할 수 없습니다.
이어갈 때 보내야 하는 항목들에는 정해진 규칙이 있습니다.
| 구분 | 항목 | 규칙 |
|---|
| 생성 시에만 | system, tools | - |
이어갈 때 보낼 경우, null이라도 400 에러 발생 | model, thinking, tool_choice, output_config, context_management, mcp_servers, 상위 계층의 cache_control, 베타 헤더 조합 등 | 다른 값을 보내면 400(thread_fingerprint_mismatch) 발생 |
| 매번 변경 가능 | max_tokens, stop_sequences, stream, metadata 등 | 변경 가능 |
도중에 시스템 프롬프트나 도구를 변경하고 싶을 때는 새로운 스레드를 만들 수밖에 없습니다. 이때, Opus 5.5나 Fable 5.2 같은 모델에서는 대화 내용 중의 thinking 블록을 제외하고 보내야 합니다(제외하지 않으면 400 에러가 발생할 수 있습니다).
요금에 대한 언급은 단 한 줄입니다.
Threads do not change pricing or rate limits.
캐시와 관련해서도 "A thread does not cache your prompt for you"라고 명시되어 있습니다. 매번 대화를 캐시하고 싶다면, 지금까지처럼 cache_control을 추가해야 합니다. 캐시의 구분은 평소와 같이 요청 1회당 최대 4개이지만, 스레드에서는 생성 시에 system이나 tools에 추가한 구분도 이어갈 때마다 개수에 포함됩니다(상위 계층의 cache_control도 1개로 계산합니다).
전송하는 데이터가 줄어든다고 해서 청구액이 줄어드는 것은 아닙니다. 좋아진다고 언급된 것은 요청의 크기와 첫 글자가 반환되기까지 걸리는 시간입니다.
공식 문서에서 "사용할 수 없다"고 명시한 내용은 다음과 같습니다.
- Message Batches(배치 처리)
- 토큰 수를 세는 API
- 자동 요약(Conversation summarization). 요약하고 싶다면 직접 요약을 작성하여 새로운 스레드를 만들어야 합니다.
- 컨텍스트 편집(
clear_thinking_20251015를 keep: "all"로 사용하는 경우 제외) - HIPAA 대응 또는 Inference hooks가 활성화된 조직
대응할 수 있는 곳으로 나열된 것은 Claude API, Claude Platform on AWS, Claude Models on Google Cloud(Anthropic이 운영하는 것), Microsoft Foundry 네 가지입니다. Amazon Bedrock과 Google의 Vertex AI는 포함되어 있지 않습니다.
데이터 처리는 “Message threads are not ZDR eligible”입니다. 제로 데이터 보유(Zero Data Retention) 계약을 사용하고 있다면, 스레드 내용은 그 대상이 되지 않습니다.
여기 부분만 직접 확인했습니다. PyPI에서 Python SDK (anthropic)의 2.1.0부터 2.8.0까지 총 8개 버전을 다운로드하여 실행하지 않고 내용물만 조사했습니다.
| 버전 (PyPI 공개일) | 브랜치명 message-threads-2026-08-12 | client.beta.messages.thread() | tool_runner의 thread 인자 |
|---|
| 2.1.0 (10/21) | 없음 | 없음 | 없음 |
| 2.2.0 (10/23) | 있음 | 있음 | 있음 (기본적으로 스레드 사용) |
| ... | | | |
2.2.0의 tool_runner 설명에는 다음과 같이 쓰여 있습니다.
The loop runs over a message thread by default, so each turn sends only new messages. Pass `thread=False` to send the full history every turn.
도구를 호출하며 여러 번의 왕복을 하는 에이전트가 스레드의 효과를 가장 잘 볼 수 있는 사용법입니다. 반면, tool_runner를 사용하는 경우 SDK만 업데이트해도 대화 내용이 서버 메모리에 최대 1시간 동안 보관될 수 있습니다. 제로 데이터 보유 계약이 있거나 대화를 서버에 두고 싶지 않다면, thread=False를 명시하는 것이 더 안전합니다.
공식 문서에 따르면, tool_runner가 생성하는 스레드는 스레드를 사용할 수 없는 조직(예: HIPAA 대응)에서는 자동으로 스레드 사용 없이 전환됩니다.
직접 스레드 처리를 작성하는 것보다 SDK의 보조 기능을 사용하는 것이 더 쉽습니다. 첫 번째 턴에 스레드를 생성하고, 두 번째 턴부터는 새로운 메시지만 보내며, 끊어지면 한 번만 전체를 다시 전송해 줍니다. 아래는 공식 문서 예시입니다 (저는 API 키를 사용하지 않았기 때문에 실행하지 않았습니다).
client = anthropic.Anthropic()
# Create the helper. This call sends no request.
thread = client.beta.messages.thread(...)
사용하기 전에 확인해야 할 3가지 사항입니다.
-
대화 기록은 직접 저장해야 합니다. 보조 기능이 가진 기록은 메모리 안에만 존재하며, 프로세스가 끝나면 사라집니다.
-
대화가 5분 이상 중단될 때마다 “재전송”됩니다. 사람이 생각하며 답하는 채팅보다 도구를 연속적으로 호출하는 에이전트에게 더 적합합니다.
-
SDK를 2.2.0 이상으로 업데이트하면, 필요하지 않다면 tool_runner의 기본값이 스레드로 설정되어 있습니다. 이때는 thread=False를 사용해야 합니다.
-
API를 호출하지 않았기 때문에, 속도가 실제로 얼마나 달라지는지는 측정하지 못했습니다. 공식 문서에서도 수치를 제공하고 있지 않습니다.
-
SDK 내용을 확인한 것은 Python뿐입니다. 다른 언어의 SDK도 공식 문서에 예시가 있지만, 버전별 차이는 보지 못했습니다.
-
베타 기능이므로, 여기에 적힌 규칙(5분/1시간/구분 4개 등)은 변경될 가능성이 있습니다.
-
Claude Code를 새로운 Fable 5.2로 전환하면 빠르고 저렴해질까 — Claude Code 비용의 약 60%가 캐시 쓰기였던 측정 결과
-
Claude Code의 캐시, 도구를 사용한 턴에만 적용되게 되었다 — 캐시 적용 방식을 측정한 글
-
Claude Fable 5.1, 캐시 읽기는 4분의 1. 단, tool_choice가 400을 반환함 — API 사양 변화를 확인한 글
JQUIT의 엔지니어 95% 이상은 비경력자 채용입니다.
괜찮으시면 기업 사이트에도 방문해 주세요.
엔지니어 채용도 진행하고 있습니다. 관심이 있으시다면 둘러봐 주세요.
▶ 채용 사이트