툴을 서너 개 붙인 Claude 에이전트를 만들다가 이상한 걸 봤다. 확장된 사고(extended thinking)를 켜두면 맨 처음엔 꼼꼼히 계획을 세우는데, 정작 툴이 결과를 돌려준 다음에는 그걸 제대로 안 보고 바로 다음 툴을 불러버리는 경우가 있었다. 검색 결과가 비어 있는데도 그 결과를 쓴다고 가정하고 다음 단계로 넘어가는 식이다.
이유는 단순했다. 기본 확장된 사고는 첫 응답에서 한 번 생각하고 끝난다. 툴 결과를 받은 뒤의 턴에서는 다시 생각하는 블록이 안 생긴다. 그래서 도구가 돌려준 값을 보고 판단을 고쳐야 하는 에이전트엔 이게 꽤 치명적이다.
interleaved thinking 베타 켜기
이걸 해결하는 게 인터리브드 사고(interleaved thinking)다. 베타 헤더 하나만 붙이면, Claude가 툴 호출 사이사이마다 thinking 블록을 끼워넣는다. 툴 결과를 받으면 "이 결과가 내가 기대한 거 맞나?"를 먼저 추론하고, 그 다음에 행동한다.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
thinking={"type": "enabled", "budget_tokens": 2048},
extra_headers={
"anthropic-beta": "interleaved-thinking-2025-05-14"
},
tools=[search_tool, fetch_tool],
messages=[{"role": "user", "content": "최신 환율 찾아서 100달러 환산해줘"}],
)
차이는 응답 블록 순서에서 바로 드러난다. 베타를 안 켜면 thinking → tool_use로 끝나지만, 켜면 툴 결과를 돌려준 뒤 턴에서 thinking → tool_use 또는 thinking → text가 또 나온다. 즉 검색 → (결과 보고 다시 생각) → 계산 → (검산) → 답변 흐름이 된다.
주의: thinking 블록을 돌려줘야 한다
한 가지 꼭 지켜야 할 게 있다. 다음 턴 요청을 보낼 때 이전 턴의 thinking 블록을 assistant 메시지에 그대로 다시 넣어야 한다. 빼먹으면 Claude가 추론 맥락을 잃어서 400 에러가 나거나 사고가 끊긴다.
messages.append({"role": "assistant", "content": response.content}) # thinking 블록 포함 전체
messages.append({"role": "user", "content": tool_results})
response.content 전체를 그대로 붙이면 thinking 블록까지 자동으로 따라간다. 직접 text만 뽑아서 재구성하면 안 된다.
결론
여러 툴을 순차로 쓰고, 중간 결과에 따라 다음 행동이 달라지는 에이전트라면 인터리브드 사고가 체감 차이가 크다. 빈 검색 결과를 무시하거나 엉뚱한 툴을 부르던 게 눈에 띄게 줄었다. 반대로 툴이 하나뿐이거나 단순 추출 작업이면 토큰만 더 먹으니 굳이 켤 필요는 없다. "결과 보고 판단을 고쳐야 하는가"가 켜고 끄는 기준이다.