CPN 한국어 자습서 · 러닝패스 2 / 4 — Building with the Claude API
도구 사용
Handling message blocks
스키마를 요청에 담아 Claude를 호출하면, 처음 보는 구조의 응답이 옵니다. 지금까지는 content에 text 블록 하나뿐이었지만, 도구를 쓰면 content가 text 블록 + tool_use 블록의 리스트가 됩니다. 그리고 대화 기록은 우리가 직접 관리해야 합니다.
Stephen Grider · Anthropic 기술 스태프
3단계입니다. 이제 JSON 스키마와 사용자 메시지를 담아 Claude를 호출합니다. 서버에서 평소처럼 요청을 보내되, 이번엔 이 도구 스키마를 함께 포함합니다. 그러면 Claude는 자신에게 사용할 수 있는 도구가 있다는 걸 알게 됩니다. 노트북으로 돌아가, 이전에 만든 헬퍼 함수(chat 같은)를 쓰지 않고 손으로 직접 요청해 봅니다.
새 셀을 만들어 빈 메시지 리스트를 두고, 거기에 사용자 메시지를 직접 추가합니다. role은 user, content는 “What is the exact time, formatted as HH:MM:SS?”입니다.
그 아래에서 client.messages.create를 호출합니다. 모델, max_tokens, 메시지 리스트를 지정하고, 이번엔 Claude에 도구가 있음을 알리는 tools 키워드 인자를 더합니다. 이건 리스트이고, 우리가 만든 모든 JSON 스키마가 들어갑니다. 지금은 하나뿐 — get_current_datetime_schema입니다. 맨 아래에서 response를 출력해 실행합니다.
그러면 지금까지 본 적 없는 구조의 응답이 돌아옵니다. 이전의 모든 메시지는 content가 리스트였고 그 안에 text 블록 하나가 있었습니다. text 블록 안에는 사용자에게 보여 줄 텍스트가 들어 있었죠. 그런데 도구를 쓰니 이 content 리스트가 조금 다릅니다. 리스트 안에 두 번째 블록 — tool_use 블록 — 이 생깁니다.
이게 우리의 첫 멀티 블록 메시지입니다. 메시지는 assistant 메시지이거나 user 메시지입니다. 보통은 메시지 안에 약간의 텍스트가 들어 있고, 지금까지 본 건 그게 전부였습니다. 하지만 텍스트 외에도 다른 종류의 데이터가 메시지에 담길 수 있습니다. Claude가 도구를 쓰기로 하면, 아주 흔히 text 블록과 tool_use 블록을 둘 다 담은 assistant 메시지를 보내옵니다.
text 블록은 사용자에게 보여 줘 무슨 일이 일어나는지 알려 주는 텍스트입니다 — 예: “현재 시각을 찾아드릴게요. 정보를 가져오겠습니다.” 그리고 tool_use 블록은, 우리 개발자에게 Claude가 도구를 쓰고 싶어 한다는 신호입니다. 이 블록은 호출하려는 도구 함수의 name을 적고(여기선 get_current_datetime), 그 함수에 넘길 input(인자들)도 함께 줍니다.
다음 단계는 알맞은 도구를 찾아 실제로 실행하는 것입니다. 하지만 그 전에, content 리스트에 여러 블록이 들어 있다는 점과 관련해 꼭 처리해야 할 중요한 게 있습니다. 다시 떠올려 봅시다 — 우리는 서버에서 Claude로 요청을 보냈고, 그 요청엔 도구 스키마를 포함한 사용자 메시지 하나가 있었습니다. 이제 응답을 받았고, 그 안엔 text 블록과 tool_use 블록을 담은 assistant 메시지가 있습니다.
여기서 Claude에 대해 기억할 게 있습니다. Claude는 메시지 기록이나 대화에 관한 어떤 것도 저장하지 않습니다. 대화나 기록을 유지하고 싶다면 직접 관리해야 합니다. 즉, 나중에 이 tool_use 블록을 받아 실제 함수를 호출하고 Claude에 다시 응답할 때, 결정적으로 전체 대화 기록을 포함해야 합니다 — 코스 내내 해 온 것처럼요. 이번엔 한 가지만 다릅니다. 메시지가 여러 블록을 담을 수 있다는 점입니다.
이 메시지들을 관리하기 위해, 응답을 받는 맨 아래 셀로 가서 response를 리스트에 새 assistant 메시지로 추가합니다. response를 지우고, messages.append로 role은 assistant, content는 방금 받은 응답의 content 블록 리스트 그대로 — 즉 response.content — 를 넣습니다.
이제 messages를 출력해 셀을 다시 실행하면, 처음의 user 메시지가 있고, 그다음 assistant 메시지가 있으며, 그 안에 text 블록과 tool_use 블록이 들어 있습니다. 이렇게 우리는 여러 메시지의 모든 블록을 포함해 대화 기록을 올바르게 쌓아 갑니다. (참고: 나중에 add_user_message·add_assistant_message 두 헬퍼를, 이렇게 여러 블록을 다룰 수 있게 갱신할 것입니다. 지금은 단일 text 블록만 지원하거든요.)
이 장에서 배우는 것What you'll learn
약 6분도구 사용 3단계 — 스키마를 tools로 포함해 Claude 호출
client.messages.create(..., tools=[...])를 손으로 직접
응답 content가 text 블록 + tool_use 블록의 리스트로 옴
tool_use 블록 = 도구를 쓰겠다는 신호 — name·input 포함
Claude는 기록을 저장하지 않음 — 대화 기록은 직접 관리
messages.append({"role":"assistant", "content": response.content})
content 리스트의 한 항목. text·tool_use 등 종류가 있다. ‘part’라고도 부른다.name과 넘길 input(인자)을 담는다."tool_use"가 된다 — 멀티턴 루프의 핵심 신호.3단계입니다. 평소처럼 요청을 보내되, 이번엔 tools 키워드 인자로 스키마를 포함합니다. 헬퍼 없이 손으로 직접 호출해 봅니다.
messages = []
messages.append({
"role": "user",
"content": "What is the exact time, formatted as HH:MM:SS?",
})
response = client.messages.create(
model=model,
max_tokens=1000,
messages=messages,
tools=[get_current_datetime_schema], # ← 도구가 있음을 알림
)
responsetools에는 우리가 만든 모든 스키마가 들어갑니다. 지금은 하나 — get_current_datetime_schema — 뿐입니다. 이걸로 Claude는 “쓸 수 있는 도구가 있다”는 걸 알게 됩니다.
돌아온 응답은 지금까지와 다릅니다. content 리스트 안에 text 블록뿐 아니라 tool_use 블록이 함께 들어 있습니다 — 우리의 첫 멀티 블록 메시지입니다.
Message(
id='msg_01YMMjWw5TFYK1bUc3afhKLM',
content=[
TextBlock(
text="I'll get the current time for you in the HH:MM:SS format.",
type='text',
),
ToolUseBlock(
id='toolu_01NJdk5KQk3CxTr9EkcQxKpG',
input={'date_format': '%H:%M:%S'},
name='get_current_datetime',
type='tool_use',
),
],
stop_reason='tool_use', # ← 도구를 쓰려 함
type='message',
)name(get_current_datetime)과 넘길 input({date_format: "%H:%M:%S"})을 담습니다.text 블록은 사용자에게 보여 줄 텍스트, tool_use 블록은 “도구를 쓰겠다”는 신호입니다. 후자는 호출할 도구 name과 넘길 input(인자)을 담고, stop_reason은 "tool_use"가 됩니다.
Claude는 대화 상태를 저장하지 않습니다. 기록은 우리가 직접 관리해야 합니다 — 다음 요청에 전체 messages를 다시 보내야 하죠. 받은 응답을 assistant 메시지로 추가합니다.
messages.append({
"role": "assistant",
"content": response.content, # ← 블록 리스트를 통째로
})
messages이제 messages를 출력하면 user 메시지에 이어 assistant 메시지가 있고, 그 안에 두 블록이 모두 들어 있습니다.
[
{'role': 'user', 'content': 'What is the exact time, formatted as HH:MM:SS?'},
{
'role': 'assistant',
'content': [
TextBlock(text="I'll get the current time for you...", type='text'),
ToolUseBlock(id='toolu_01NJ...', input={'date_format': '%H:%M:%S'},
name='get_current_datetime', type='tool_use'),
],
},
]차이는 하나뿐입니다 — 메시지가 여러 블록을 담을 수 있다는 것. response.content(블록 리스트)를 그대로 content에 넣어 기록을 올바르게 쌓습니다. (헬퍼 add_assistant_message 등은 나중에 멀티 블록을 지원하도록 갱신합니다.)
아래 인스펙터로 블록을 눌러 역할을 확인하고, 도구 응답과 일반 응답을 비교해 보세요. 그다음 퀴즈로 정리합니다.
도구를 쓰면 content는 여러 블록의 리스트가 되고 stop_reason이 tool_use가 됩니다. 일반 응답은 text 블록 하나에 stop_reason이 end_turn입니다.
tools로 포함해 client.messages.create 호출.content가 text 블록 + tool_use 블록의 리스트가 된다.name과 input을 담고, stop_reason은 tool_use.response.content를 assistant 메시지로 직접 추가.Q1도구를 쓰는 응답에서 content 리스트에 들어 있는 것은?
Claude가 도구를 쓰기로 하면 보통 두 블록을 함께 보냅니다 — 사용자용 text 블록과, 도구 호출 신호인 tool_use 블록.
Q2tool_use 블록이 담는 정보는?
tool_use 블록은 “이 도구를, 이 인자로 부르고 싶다”는 신호일 뿐입니다. 실제 실행과 결과는 우리가 다음 단계에서 처리합니다.
Q3응답을 받은 뒤 대화 기록에 무엇을 추가하나요?
Claude는 상태를 저장하지 않습니다. response.content(여러 블록)를 그대로 넣어 기록을 직접 관리해야 합니다.
이제 tool_use 블록을 받았으니, 알맞은 함수를 실행하고 그 결과를 tool_result 블록으로 되돌려 보냅니다. → 도구 결과 보내기
전 코스는 계속 무료입니다. 등록하면 이 코스의 남은 76개 레슨을 끝까지 읽을 수 있습니다.
이미 등록하셨다면 그때 쓰신 이메일을 넣어 주세요.