기본적으로 Claude는 단일 응답에서 여러 도구를 호출할 수 있습니다. 이 페이지에서는 이러한 호출을 실행하는 방법, 병렬 처리가 계속 작동하도록 메시지 히스토리를 포맷팅하는 방법, 그리고 필요할 때 병렬 도구 사용을 비활성화하는 방법을 다룹니다. 단일 호출 흐름에 대해서는 도구 호출 처리를 참조하세요.
Claude가 도구를 호출하면 응답의 stop_reason은 tool_use이며, 단일 어시스턴트 턴에 여러 개의 tool_use 블록이 포함될 수 있습니다. 이러한 호출을 어떻게 실행할지는 사용자의 결정입니다. API는 실행 순서를 규정하지 않습니다. 호출을 동시에(Promise.all, asyncio.gather) 실행하거나, 나타나는 순서대로 순차적으로 실행하거나, 도구에 적합한 어떤 조합으로든 실행할 수 있습니다.
도구가 수행하는 작업에 따라 전략을 선택하세요. 독립적이고 읽기 전용인 작업은 일반적으로 병렬로 실행해도 안전하며 "latency"(지연 시간)를 줄일 수 있습니다. 부작용이 있거나, 공유 상태를 가지거나, 순서 요구 사항이 있는 도구는 순차적으로 실행하는 것이 더 나을 수 있습니다.
어떤 전략을 사용하든, 각 tool_use 블록마다 하나의 tool_result를 반환하되 모두 다음 사용자 메시지에 함께 포함하세요. tool_use_id로 각 결과를 해당 호출과 매칭하고, 해당 메시지에서 모든 tool_result 블록을 텍스트 콘텐츠보다 앞에 배치하세요. 전체 포맷팅 규칙은 도구 호출 처리를 참조하세요. 특정 호출을 실행하지 않기로 선택한 경우(예: 배치를 순차적으로 실행했는데 이전 호출이 실패한 경우)에도 해당 호출에 대해 is_error: true와 간단한 설명을 포함한 tool_result를 반환하세요.
{
"type": "tool_result",
"tool_use_id": "toolu_02",
"is_error": true,
"content": "Not executed: the preceding write_file call failed."
}대부분의 애플리케이션에는 Tool Runner를 사용하세요: SDK의 Tool Runner는 여러 도구 호출이 포함된 응답을 처리하고 결과를 자동으로 포맷팅하므로 이러한 처리를 직접 작성할 필요가 없습니다. 사용자 지정 배치 처리, 순서 지정, 오류 처리 등 호출 실행 방식을 직접 제어해야 하는 경우에는 이 페이지의 수동 패턴을 사용하세요.
다음 스크립트는 병렬 도구 호출을 트리거해야 하는 요청을 보내고, 응답에 병렬 호출이 포함되어 있는지 확인하며, 병렬 처리가 계속 작동하도록 도구 결과를 포맷팅합니다. 환경에 ANTHROPIC_API_KEY를 설정한 후 실행하세요:
client = Anthropic()
# 도구 정의
tools = [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
},
{
"name": "get_time",
"description": "Get the current time in a given timezone",
"input_schema": {
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "The timezone, e.g. America/New_York",
}
},
"required": ["timezone"],
},
},
]
# 병렬 도구 호출이 포함된 대화 테스트
messages = [
{
"role": "user",
"content": "What's the weather in SF and NYC, and what time is it there?",
}
]
# 초기 요청 생성
print("Requesting parallel tool calls...")
response = client.messages.create(
model="claude-opus-4-8", max_tokens=1024, messages=messages, tools=tools
)
# 병렬 도구 호출 확인
tool_uses = [block for block in response.content if block.type == "tool_use"]
print(f"\n✓ Claude made {len(tool_uses)} tool calls")
if len(tool_uses) > 1:
print("✓ Parallel tool calls detected!")
for tool in tool_uses:
print(f" - {tool.name}: {tool.input}")
else:
print("✗ No parallel tool calls detected")
# 도구 실행을 시뮬레이션하고 결과를 올바르게 포맷
tool_results = []
for tool_use in tool_uses:
if tool_use.name == "get_weather":
if "San Francisco" in str(tool_use.input):
result = "San Francisco: 68°F, partly cloudy"
else:
result = "New York: 45°F, clear skies"
else: # get_time
if "Los_Angeles" in str(tool_use.input):
result = "2:30 PM PST"
else:
result = "5:30 PM EST"
tool_results.append(
{"type": "tool_result", "tool_use_id": tool_use.id, "content": result}
)
# 도구 결과와 함께 대화 계속
messages.extend(
[
{"role": "assistant", "content": response.content},
{"role": "user", "content": tool_results}, # All results in one message!
]
)
# 최종 응답 받기
print("\nGetting final response...")
final_response = client.messages.create(
model="claude-opus-4-8", max_tokens=1024, messages=messages, tools=tools
)
final_text = next(
block.text for block in final_response.content if block.type == "text"
)
print(f"\nClaude's response:\n{final_text}")
# 포맷 확인
print("\n--- Verification ---")
print(f"✓ Tool results sent in single user message: {len(tool_results)} results")
print("✓ No text before tool results in content array")
print("✓ Conversation formatted correctly for future parallel tool use")마지막의 요약 라인은 병렬 처리가 계속 작동하도록 하는 두 가지 포맷팅 규칙을 다시 설명합니다. 모든 도구 결과는 단일 사용자 메시지로 반환되며, 해당 메시지에서 도구 결과 앞에는 텍스트 콘텐츠가 나타나지 않습니다.
Claude 4 모델은 요청이 여러 도구의 이점을 얻을 수 있을 때 기본적으로 병렬 도구 호출을 수행합니다. 모든 모델에서 타겟팅된 프롬프팅으로 병렬 도구 호출 가능성을 높일 수 있습니다:
병렬 도구 사용은 기본적으로 활성화되어 있습니다. 비활성화하려면 tool_choice 객체 내부에 disable_parallel_tool_use: true를 설정하세요. 이는 최상위 요청 매개변수가 아닙니다. 효과는 tool_choice 타입에 따라 달라집니다.
tool_choice 타입이 auto(기본값)일 때 disable_parallel_tool_use: true를 설정하면 Claude는 응답당 최대 하나의 도구를 호출합니다. Claude는 여전히 도구를 호출하지 않고 일반 텍스트로 답변할 수 있습니다. 강조 표시된 라인이 표준 도구 사용 요청과의 유일한 차이점입니다:
client = Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
],
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
messages=[
{
"role": "user",
"content": "What is the weather in San Francisco and New York?",
}
],
)
print(response.content)tool_choice 타입이 any 또는 tool일 때 disable_parallel_tool_use: true를 설정하면 Claude는 정확히 하나의 도구를 호출합니다. 다음 예제는 any를 사용합니다. 동일한 필드가 tool에서도 작동합니다:
client = Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
],
tool_choice={"type": "any", "disable_parallel_tool_use": True},
messages=[
{
"role": "user",
"content": "What is the weather in San Francisco and New York?",
}
],
)
print(response.content)Claude가 예상대로 병렬 도구 호출을 수행하지 않는 경우 다음과 같은 일반적인 문제를 확인하세요:
1. 잘못된 도구 결과 포맷팅
가장 흔한 문제는 대화 히스토리에서 도구 결과를 잘못 포맷팅하는 것입니다. 이는 Claude가 병렬 호출을 피하도록 "학습"시킵니다.
병렬 도구 사용과 관련하여 구체적으로:
// Wrong: separate user messages reduce parallel tool use
[
{"role": "assistant", "content": [tool_use_1, tool_use_2]},
{"role": "user", "content": [tool_result_1]},
{"role": "user", "content": [tool_result_2]} // Separate message
]
// Correct: one user message with all results maintains parallel tool use
[
{"role": "assistant", "content": [tool_use_1, tool_use_2]},
{"role": "user", "content": [tool_result_1, tool_result_2]} // Single message
]다른 포맷팅 규칙은 도구 호출 처리를 참조하세요.
2. 약한 프롬프팅
기본 프롬프팅으로는 충분하지 않을 수 있습니다. 병렬 도구 사용 극대화의 더 강력한 시스템 프롬프트를 사용하세요.
3. 병렬 도구 사용 측정
병렬 도구 호출이 작동하는지 확인하려면:
messages = [] # Message objects returned by client.messages.create across your run
tool_call_messages = [
msg for msg in messages if any(block.type == "tool_use" for block in msg.content)
]
total_tool_calls = sum(
len([block for block in msg.content if block.type == "tool_use"])
for msg in tool_call_messages
)
avg_tools_per_message = (
total_tool_calls / len(tool_call_messages) if tool_call_messages else 0.0
)
print(f"Average tools per message: {avg_tools_per_message}")
# 병렬 호출이 작동하면 1.0보다 커야 합니다4. 배치 내 호출이 서로 의존하는 것처럼 보이는 경우
실행 순서는 사용자가 선택합니다. 도구에 순서 의존성이 있는 경우, 배치를 순차적으로 실행하고 첫 번째 실패 시 중단하는 것도 유효한 전략입니다. 실행하지 않은 호출에 대해서는 is_error: true를 반환하세요. 병렬로 실행했는데 선행 조건이 완료되지 않아 호출이 실패한 경우, 자연스러운 오류 메시지와 함께 is_error: true를 반환하세요. Claude는 다음 턴에 해당 호출을 다시 실행합니다. 의존적인 호출이 함께 나타나는 것을 줄이려면 시스템 프롬프트에 다음을 추가하세요: "Only batch tool calls that are independent of each other."
SDK의 Tool Runner 추상화를 사용하여 에이전틱 루프, 오류 래핑, 타입 안전성을 자동으로 처리하세요.
tool_use 블록을 파싱하고, tool_result 응답을 포맷팅하며, is_error로 오류를 처리하세요.
도구 스키마를 지정하고, 효과적인 설명을 작성하며, Claude가 도구를 호출하는 시점을 제어하세요.
Was this page helpful?