Ở bài 6.6 bạn học: message.content[0].text — response là 1 text block.
- Hiểu multi-block response khi Claude dùng tool
- Phân biệt TextBlock và ToolUseBlock
- Append multi-block message vào history đúng cách
- Update helper functions để handle multi-block
Gọi API với tools
tools = list of schemas (bài 6.31).
messages = [{"role": "user", "content": "What's the exact time in HH:MM:SS?"}]
response = client.messages.create(
model=model,
max_tokens=1000,
messages=messages,
tools=[get_current_datetime_schema], # ← thêm tools param
)Anatomy multi-block response
3 loại block thường thấy:
- TextBlock — text Claude muốn nói
- ToolUseBlock — request tool call
- ThinkingBlock — (Module 6) reasoning process
response.content = [
TextBlock(
type="text",
text="I'll get the current time for you."
),
ToolUseBlock(
type="tool_use",
id="toolu_01ABC...",
name="get_current_datetime",
input={"date_format": "%H:%M:%S"}
)
]
response.stop_reason = "tool_use" # ← Claude dừng vì muốn toolToolUseBlock có gì?
- id — match với tool_result sau (critical nếu có multi-tool)
- name — function nào
- input — dict của arguments
ToolUseBlock(
type="tool_use",
id="toolu_01XYZ...", # Unique ID cho tool call
name="get_current_datetime", # Function name
input={"date_format": "%H:%M:%S"} # Arguments
)Check stop_reason
stop_reason="tool_use" là signal bạn cần process tool call.
if response.stop_reason == "tool_use":
# Claude muốn call tool → bạn execute
...
elif response.stop_reason == "end_turn":
# Claude done, không cần tool nữa
text = response.content[0].text
elif response.stop_reason == "max_tokens":
# Bị cắt
...Append multi-block vào messages
Quan trọng: phải append toàn bộ response.content (không chỉ text):
Lý do: Claude cần thấy full history. Nếu quên ToolUseBlock → turn tiếp theo Claude không biết mình đã request tool.
# ✅ Đúng
messages.append({
"role": "assistant",
"content": response.content # ← Entire list of blocks
})
# ❌ Sai — mất ToolUseBlock
messages.append({
"role": "assistant",
"content": response.content[0].text # chỉ text
})Extract specific block
Helper function:
# Find ToolUseBlock
tool_calls = [b for b in response.content if b.type == "tool_use"]
# Find TextBlocks
text_blocks = [b for b in response.content if b.type == "text"]
# Combine text
full_text = "\n".join(b.text for b in text_blocks)Extract specific block (tiếp)
def get_tool_calls(response):
return [b for b in response.content if b.type == "tool_use"]
def text_from_message(response):
return "\n".join(b.text for b in response.content if b.type == "text")Update helper functions
add_user_message cũ chỉ nhận string. Update để flexible:
Giờ có thể pass full response hoặc plain text.
from anthropic.types import Message
def add_user_message(messages, content):
"""Accept string, list of blocks, or Message object."""
if isinstance(content, str):
messages.append({"role": "user", "content": content})
elif isinstance(content, Message):
messages.append({"role": "user", "content": content.content})
else:
# Assume list of content blocks
messages.append({"role": "user", "content": content})
def add_assistant_message(messages, content):
if isinstance(content, str):
messages.append({"role": "assistant", "content": content})
elif isinstance(content, Message):
messages.append({"role": "assistant", "content": content.content})
else:
messages.append({"role": "assistant", "content": content})Update chat function
Thay vì return .content[0].text, return full message. Gọi side extract text nếu cần.
def chat(messages, system=None, temperature=1.0, stop_sequences=None, tools=None):
params = {
"model": model,
"max_tokens": 1000,
"messages": messages,
"temperature": temperature,
}
if system:
params["system"] = system
if stop_sequences:
params["stop_sequences"] = stop_sequences
if tools:
params["tools"] = tools
return client.messages.create(**params) # Return full MessageVí dụ đầy đủ — 1 tool call
messages = []
add_user_message(messages, "What is the exact time, formatted HH:MM:SS?")
# Step 1: Claude request tool
response = chat(messages, tools=[get_current_datetime_schema])
print(f"Stop reason: {response.stop_reason}") # "tool_use"
# Step 2: Inspect content blocks
for block in response.content:
print(f"Block type: {block.type}")
if block.type == "text":
print(f"Text: {block.text}")
elif block.type == "tool_use":
print(f"Tool: {block.name}, Input: {block.input}")
# Step 3: Append response to history
add_assistant_message(messages, response)
# messages giờ có: [user msg, assistant msg with 2 blocks]
# Bước 4: Execute tool (bài 6.34)
# ...Ví dụ: Multiple tool calls trong 1 response
Claude có thể request nhiều tool cùng lúc:
Loop qua tất cả:
# User: "What's 10+10 and what's 30+30?"
# Claude response:
response.content = [
TextBlock(text="Let me calculate both."),
ToolUseBlock(id="t1", name="add", input={"a": 10, "b": 10}),
ToolUseBlock(id="t2", name="add", input={"a": 30, "b": 30})
]Ví dụ: Multiple tool calls trong 1 response (tiếp)
Chi tiết xử lý ở bài 6.34.
tool_calls = [b for b in response.content if b.type == "tool_use"]
for tc in tool_calls:
result = run_tool(tc.name, tc.input)
# tracked với tc.idAnti-patterns
❌ Assume response.content[0] luôn là text
Với tool use, content[0] có thể là TextBlock HOẶC ToolUseBlock.
Fix: Dùng block.type check.
❌ Quên append ToolUseBlock vào history
Turn tiếp Claude không thấy đã call tool → re-request.
Fix: messages.append({"role": "assistant", "content": response.content}) — FULL list.
❌ Modify response.content
Không thêm/xóa block từ response.
Fix: Xem response là immutable.
❌ Hardcode block index
Fix: Filter by type.
tool_call = response.content[1] # assume always index 1Áp dụng ngay
Bài tập 1: Inspect tool response (15 phút)
Gọi Claude với tool, print chi tiết content:
Bài tập 2: Update helpers (15 phút)
Update add_user_message, add_assistant_message, chat theo code ở trên. Test với:
- Plain string input
- Message object input
- List of blocks input
response = chat([{"role": "user", "content": "Time now?"}],
tools=[get_current_datetime_schema])
for i, block in enumerate(response.content):
print(f"Block {i}: type={block.type}")
if block.type == "tool_use":
print(f" name: {block.name}")
print(f" input: {block.input}")
print(f" id: {block.id}")
elif block.type == "text":
print(f" text: {block.text}")Tóm tắt
🎯 Tool use → multi-block response. TextBlock + ToolUseBlock.
🎯 Check stop_reason="tool_use" để biết Claude muốn tool.
🎯 Append FULL response.content vào history — không chỉ text.
🎯 Update helpers flexible với string/Message/list.
🎯 Filter block by type — [b for b in content if b.type == "tool_use"].