부분 실패, 툴콜 루프에서 가장 먼저 깨지는 지점
챗봇이나 콜봇이 한 턴에서 검색·예약·결제 같은 툴을 동시에 부르면, Claude API는 tool_use 블록 하나마다 tool_result 블록 하나로 응답하기를 요구합니다. Anthropic 공식 가이드는 tool_result 블록이 대응하는 tool_use 블록 바로 다음 메시지에 와야 하고, 같은 사용자 메시지 안에서는 텍스트보다 먼저 배치돼야 한다고 규정합니다. 이전 글에서 다룬 턴 디텍션과 바지인 취소가 사용자 인터럽트에 대응하는 설계였다면, 이번 글은 툴콜 자체가 부분적으로 실패했을 때 루프를 어떻게 되돌리는가를 다룹니다. 순서가 깨지면 "tool_use ids were found without tool_result blocks immediately after" 오류가 그대로 반환되고, 세 개 중 하나가 실패했다고 그 블록만 빼면 나머지 두 개의 정상 결과까지 통째로 거부당합니다.
실패에도 등급이 있다: 실행 오류와 호출 오류
Anthropic 문서는 툴 실패를 실행 오류와 호출 오류로 나눕니다. 실행 오류는 결제 API가 500을 반환하는 것처럼 툴 자체가 죽는 경우이고, 호출 오류는 Claude가 예약 날짜 같은 필수 파라미터를 빠뜨려 요청 자체가 성립하지 않는 경우입니다. 호출 오류는 is_error: true와 함께 무엇이 빠졌는지 담아 돌려주면 Claude가 2~3회까지 스스로 정정을 시도한 뒤에야 사용자에게 사과로 넘어갑니다. 이 자기 수정 구간에 사람이 먼저 끼어들면 재시도 예산을 낭비하는 셈이라, 호출 오류와 실행 오류는 처음부터 다른 코드 경로로 분기해 두는 편이 낫습니다.
설계에서 운영까지: 멀티 툴콜 부분 실패 대응 가이드
목표 지표는 세 갈래로 잡습니다. 부분 실패가 감지된 시점부터 사용자에게 안내 문구가 노출되기까지 500ms 이내, 호출 오류의 자기 수정 재시도 성공률(3회 이내 정정 완료) 70% 이상, 같은 세션에서 같은 툴이 3회를 넘겨 실패하면 100% 사람 에스컬레이션으로 넘기는 상한을 코드로 고정합니다. 툴콜 루프의 반복 상한 설계가 무한 반복 자체를 막는 장치라면, 이 상한은 반복은 정상 범위 안인데 매번 같은 지점에서 실패하는 경우를 걸러내는 별도 장치입니다.
반복되는 실패는 크게 두 갈래입니다. 첫째, 실행 오류를 "failed"처럼 원인 없는 문구로만 돌려주면 Claude는 같은 입력으로 같은 툴을 다시 불러 같은 오류를 반복합니다. Anthropic 가이드는 "Rate limit exceeded. Retry after 60 seconds."처럼 원인과 다음 행동을 함께 담으라고 권장하며, 이 형식만 바꿔도 무의미한 재호출 없이 대기 후 재시도로 넘어가는 비율이 눈에 띄게 오릅니다. 둘째, 병렬로 부른 툴 중 하나가 실패했을 때 순차 실행으로 전환하면서 뒤에 남은 tool_use에 대한 tool_result 자체를 빼먹는 경우입니다.
두 번째 패턴의 해법은 실행하지 않은 호출에도 자리표시자 결과를 채우는 것입니다. Anthropic 문서는 앞선 호출이 실패해 이후 호출을 실행하지 않기로 했다면, 그 tool_use_id에도 is_error: true와 "Not executed: 앞선 호출 실패로 건너뜀" 같은 문구를 담은 tool_result를 반드시 반환하라고 명시합니다. 순서 보장이 없는 병렬 실행에서는 결과를 배열 위치가 아니라 tool_use_id로 매칭해야, 실패한 콜의 오류 메시지가 성공한 콜의 자리에 잘못 꽂히는 사고를 막을 수 있습니다.
배포 전 시나리오 테스트에는 강제 500 오류, 필수 파라미터 누락, 병렬 호출 중 한 건만 타임아웃 세 가지를 반드시 포함합니다. 로그에는 tool_use_id, 오류 유형(실행/호출), 재시도 횟수, 최종 해결 주체(모델 자기수정 또는 사람)를 필드로 남겨야 어떤 툴이 반복 실패의 진원지인지 세션 단위로 추적할 수 있습니다. 오류 메시지를 사용자에게 그대로 노출하기 전에는 결제 정보나 연락처 같은 개인정보가 섞이지 않았는지 마스킹 규칙을 거칩니다.
매주 세션 로그에서 3회 상한에 걸린 툴과 해결 주체 비율을 집계해, 어떤 오류 메시지 포맷이 재시도 성공률을 끌어올리는지 문구 단위로 비교합니다. 메시지 포맷을 바꿀 때마다 변경 이력을 코드 커밋과 별도로 남겨 두면, 다음 주 재시도 성공률이 오르거나 내렸을 때 원인을 문구 변경으로 좁혀 확인할 수 있습니다.
바로 쓰는 체크리스트
멀티 툴콜의 부분 실패는 하나의 오류가 아니라 실행 오류·호출 오류·미실행 자리표시자 세 갈래로 나눠 다뤄야 하는 프로토콜 문제입니다. tool_use_id로 결과를 매칭하고, 호출 오류는 모델의 2~3회 자기 수정에 먼저 맡기며, 실행 오류 메시지에는 원인과 다음 행동을 담아 두면 같은 세션 안에서 재시도가 무한히 반복되는 사고를 막을 수 있습니다.