Xây dựng Customer Service Agent với Claude Tool Use
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1 Khai thác tối đa công cụ AI: Agent của chúng ta cần 3 tools để phục vụ khách hàng: Tool 1: getcustomerinfo getcustomerinfo = { "name":. Bí quyết nằm ở cách bạn cấu trúc yêu cầu — prompt càng rõ ràng, output càng sát nhu cầu thực tế.
- 2 Góc nhìn thực tế: Thay vì kết nối database thực, chúng ta dùng data tĩnh để demo: CUSTOMERS = { "CUST-001": { "name": "Nguyen Thi Mai",. Điều quan trọng là hiểu rõ khi nào nên và không nên áp dụng phương pháp này.
- 3 Lợi ích đo lường được: import anthropic client = anthropic.Anthropic SYSTEMPROMPT = """Ban la nhan vien ho tro khach hang cua ShopViet - mot. Phương pháp này giúp tiết kiệm đáng kể thời gian so với cách làm truyền thống.
- 4 Bước đầu tiên bạn nên làm: def democonversation: print"=== Customer Service Agent Demo === " history = Turn 1: Xem don hang response, history =. Áp dụng đúng cách sẽ thấy kết quả rõ rệt từ tuần đầu tiên.
- 5 Cần lưu ý: Authentication trong tools — Luôn verify user có quyền với resource họ request. Không phải lúc nào AI cũng cho kết quả hoàn hảo — bạn vẫn cần kiểm tra và điều chỉnh output trước khi sử dụng chính thức.
Trong bài này, chúng ta sẽ xây dựng một Customer Service Agent hoàn chỉnh — chatbot có thể tra cứu thông tin khách hàng, xem chi tiết đơn hàng, và thực hiện hủy đơn. Đây là ứng dụng Tool Use thực tế nhất, gần với production deployment nhất.
Điểm khác biệt với bài Calculator: ở đây chúng ta có multi-turn conversation, nhiều tools tương tác với nhau, và business logic phức tạp hơn. Kết thúc bài, bạn sẽ có một agent có thể xử lý cuộc hội thoại như:
"Tôi muốn hủy đơn hàng #12345 của tôi."
[Claude tra cứu đơn hàng, kiểm tra điều kiện hủy, thực hiện hủy, xác nhận với khách]
Thiết kế 3 Tools
Agent của chúng ta cần 3 tools để phục vụ khách hàng:
Tool 1: get_customer_info
get_customer_info = {
"name": "get_customer_info",
"description": "Tra cuu thong tin khach hang theo customer_id hoac email",
"input_schema": {
"type": "object",
"properties": {
"identifier": {
"type": "string",
"description": "Customer ID (VD: CUST-001) hoac dia chi email"
}
},
"required": ["identifier"]
}
}
Tool 2: get_order_details
get_order_details = {
"name": "get_order_details",
"description": "Xem chi tiet don hang theo order_id",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Ma don hang, bat dau bang #"
}
},
"required": ["order_id"]
}
}
Tool 3: cancel_order
cancel_order = {
"name": "cancel_order",
"description": "Huy don hang. Chi huy duoc don hang co trang thai pending hoac processing.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Ma don hang can huy"
},
"reason": {
"type": "string",
"description": "Ly do huy don hang"
}
},
"required": ["order_id", "reason"]
}
}
Chú ý description của cancel_order có ghi rõ điều kiện: "Chỉ hủy được đơn hàng có trạng thái pending hoặc processing." Claude đọc thông tin này và sẽ không cố gọi tool với đơn hàng đã giao.
Dữ liệu mẫu (Synthetic Backend)
Thay vì kết nối database thực, chúng ta dùng data tĩnh để demo:
CUSTOMERS = {
"CUST-001": {
"name": "Nguyen Thi Mai",
"email": "mai.nguyen@email.com",
"phone": "0901234567",
"loyalty_points": 1250,
"membership": "Gold"
},
"CUST-002": {
"name": "Tran Van Hung",
"email": "hung.tran@email.com",
"phone": "0912345678",
"loyalty_points": 320,
"membership": "Silver"
}
}
ORDERS = {
"#12345": {
"customer_id": "CUST-001",
"status": "processing",
"items": [
{"name": "Ao thun nam", "qty": 2, "price": 250000},
{"name": "Quan jeans", "qty": 1, "price": 650000}
],
"total": 1150000,
"created_at": "2026-03-20"
},
"#12346": {
"customer_id": "CUST-001",
"status": "delivered",
"items": [
{"name": "Giay the thao", "qty": 1, "price": 1200000}
],
"total": 1200000,
"created_at": "2026-03-10"
}
}
Implement Tool Execution
import json
def execute_tool(tool_name, tool_input):
"""Xu ly tat ca cac tool calls tu Claude"""
if tool_name == "get_customer_info":
identifier = tool_input["identifier"]
# Tim theo customer_id
if identifier in CUSTOMERS:
return json.dumps(CUSTOMERS[identifier], ensure_ascii=False)
# Tim theo email
for cust_id, cust_data in CUSTOMERS.items():
if cust_data["email"] == identifier:
return json.dumps({**cust_data, "customer_id": cust_id}, ensure_ascii=False)
return json.dumps({"error": "Khong tim thay khach hang"})
elif tool_name == "get_order_details":
order_id = tool_input["order_id"]
if order_id in ORDERS:
order = ORDERS[order_id]
# Tinh tong cho dep hon
formatted = {
**order,
"order_id": order_id,
"total_formatted": f"{order['total']:,}d"
}
return json.dumps(formatted, ensure_ascii=False)
return json.dumps({"error": f"Don hang {order_id} khong ton tai"})
elif tool_name == "cancel_order":
order_id = tool_input["order_id"]
reason = tool_input["reason"]
if order_id not in ORDERS:
return json.dumps({"success": False, "message": "Don hang khong ton tai"})
order = ORDERS[order_id]
if order["status"] not in ["pending", "processing"]:
return json.dumps({
"success": False,
"message": f"Khong the huy don hang co trang thai '{order['status']}'"
})
# Thuc hien huy (trong demo, chi cap nhat in-memory)
ORDERS[order_id]["status"] = "cancelled"
return json.dumps({
"success": True,
"message": f"Don hang {order_id} da duoc huy thanh cong",
"refund_amount": order["total"]
})
return json.dumps({"error": "Tool khong ton tai"})
Agent Loop với Multi-turn Support
import anthropic
client = anthropic.Anthropic()
SYSTEM_PROMPT = """Ban la nhan vien ho tro khach hang cua ShopViet - mot san thuong mai dien tu Viet Nam.
Ban co the:
- Tra cuu thong tin tai khoan khach hang
- Xem chi tiet don hang
- Ho tro huy don hang (chi don chua giao)
Hay luon lich su, than thien va nhanh chong giai quyet van de cua khach.
Neu khach hang chua cung cap du thong tin, hay hoi them truoc khi thuc hien tham so."""
ALL_TOOLS = [get_customer_info, get_order_details, cancel_order]
def run_customer_service_agent(user_message, conversation_history=None):
"""
Chay agent voi lich su hoi thoai (ho tro multi-turn).
conversation_history: list cac messages truoc do
"""
if conversation_history is None:
conversation_history = []
# Them message moi cua user
conversation_history.append({
"role": "user",
"content": user_message
})
while True:
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=2048,
system=SYSTEM_PROMPT,
tools=ALL_TOOLS,
messages=conversation_history
)
# Them response cua Claude vao history
conversation_history.append({
"role": "assistant",
"content": response.content
})
# Neu Claude da tra loi xong
if response.stop_reason == "end_turn":
# Lay text cuoi cung
final_text = ""
for block in response.content:
if hasattr(block, "text"):
final_text += block.text
return final_text, conversation_history
# Xu ly tool calls
if response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
print(f"[DEBUG] Claude goi tool: {block.name}({block.input})")
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
# Them ket qua tool vao history
conversation_history.append({
"role": "user",
"content": tool_results
})
else:
break
return "", conversation_history
Demo: Cuộc hội thoại thực tế
def demo_conversation():
print("=== Customer Service Agent Demo ===
")
history = []
# Turn 1: Xem don hang
response, history = run_customer_service_agent(
"Xin chao! Toi muon kiem tra don hang #12345 cua toi",
history
)
print(f"Agent: {response}
")
# Turn 2: Yeu cau huy
response, history = run_customer_service_agent(
"Toi muon huy don hang do vi toi dat nham mau. Duoc khong?",
history
)
print(f"Agent: {response}
")
# Turn 3: Xac nhan huy
response, history = run_customer_service_agent(
"Vang, toi xac nhan muon huy. Cam on ban.",
history
)
print(f"Agent: {response}
")
# Turn 4: Hoi ve don da giao (test edge case)
response, history = run_customer_service_agent(
"Con don hang #12346 toi cung muon huy duoc khong?",
history
)
print(f"Agent: {response}
")
demo_conversation()
Output mong đợi:
[DEBUG] Claude goi tool: get_order_details({'order_id': '#12345'})
Agent: Toi da kiem tra don hang #12345 cua ban:
- 2x Ao thun nam: 500.000d
- 1x Quan jeans: 650.000d
- Tong: 1.150.000d
- Trang thai: Dang xu ly
Ban can ho tro gi voi don hang nay?
[DEBUG] Claude goi tool: cancel_order({'order_id': '#12345', 'reason': 'dat nham mau'})
Agent: Toi da huy thanh cong don hang #12345 cho ban.
So tien 1.150.000d se duoc hoan tra trong 3-5 ngay lam viec.
[DEBUG] Claude goi tool: get_order_details({'order_id': '#12346'})
Agent: Rat tiec, don hang #12346 (Giay the thao) da duoc giao thanh cong
nen khong the huy. Neu san pham co van de, ban co the yeu cau doi/tra
hang trong vong 7 ngay.
Xử lý Multiple Tool Calls
Đôi khi Claude cần gọi nhiều tools trong một lượt. Ví dụ: "Kiểm tra thông tin tài khoản và tất cả đơn hàng của tôi là CUST-001" — Claude có thể gọi get_customer_info và sau đó gọi get_order_details nhiều lần.
Code của chúng ta đã xử lý điều này trong vòng lặp for block in response.content — nó thu thập tất cả tool_use blocks trước khi gửi tất cả kết quả một lúc.
Best Practices cho Production
- Authentication trong tools — Luôn verify user có quyền với resource họ request. Ví dụ: kiểm tra customer_id trong order khớp với user đang đăng nhập.
- Error handling rõ ràng — Tools nên trả về error messages thân thiện thay vì raise exceptions.
- Rate limiting — Giới hạn số lần gọi tool trong một session để tránh abuse.
- Audit logging — Log tất cả tool calls với user_id, timestamp, input/output để debug và compliance.
- Tool description cụ thể — Mô tả rõ điều kiện, giới hạn của từng tool để Claude không thử gọi tool sai lúc.
Mở rộng Agent
Từ skeleton này, bạn có thể thêm nhiều tools hơn:
- search_products — Tìm kiếm sản phẩm theo tên, category
- update_shipping_address — Cập nhật địa chỉ giao hàng (chỉ trước khi ship)
- create_return_request — Tạo yêu cầu đổi/trả hàng
- check_loyalty_rewards — Xem điểm tích lũy và ưu đãi
- escalate_to_human — Chuyển sang nhân viên thật khi cần
Bài tiếp theo: tìm hiểu tool_choice parameter — cách kiểm soát chính xác khi nào Claude gọi tool, khi nào không, và cách ép buộc Claude dùng một tool cụ thể.
Bai viet co huu ich khong?
Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.




